JVariableList::MatchResult JVariableList::FindUniqueVarName ( const JCharacter* prefix, JIndex* index, JString* maxPrefix ) const { assert( !JStringEmpty(prefix) ); const JSize count = GetElementCount(); JArray<JIndex> matchList; for (JIndex i=1; i<=count; i++) { const JString& name = GetVariableName(i); if (name == prefix) { *index = i; *maxPrefix = name; return kSingleMatch; } else if (JStringBeginsWith(name, name.GetLength(), prefix)) { matchList.AppendElement(i); } } const JSize matchCount = matchList.GetElementCount(); if (matchCount == 0) { *index = 0; maxPrefix->Clear(); return kNoMatch; } else if (matchCount == 1) { *index = matchList.GetElement(1); *maxPrefix = GetVariableName(*index); return kSingleMatch; } else { *maxPrefix = GetVariableName( matchList.GetElement(1) ); for (JIndex i=2; i<=matchCount; i++) { const JString& varName = GetVariableName( matchList.GetElement(i) ); const JSize matchLength = JCalcMatchLength(*maxPrefix, varName); const JSize prefixLength = maxPrefix->GetLength(); if (matchLength < prefixLength) { maxPrefix->RemoveSubstring(matchLength+1, prefixLength); } } *index = 0; return kMultipleMatch; } }
JString JConvertToRelativePath ( const JCharacter* origPath, const JCharacter* origBase ) { // Check that they are both absolute paths. assert( origPath != NULL && origPath[0] == '/' && origBase != NULL && origBase[0] == '/' ); // Remove extra directory separators // and make sure that base ends with one. JString path = origPath; JCleanPath(&path); JString base = origBase; JCleanPath(&base); JAppendDirSeparator(&base); // Find and remove the matching directories at the beginning. // The while loop backs us up so we only consider complete directory names. JBoolean hadTDS = kJTrue; if (path.GetLastCharacter() != '/') { path.AppendCharacter('/'); hadTDS = kJFalse; } JSize matchLength = JCalcMatchLength(path, base); if (!hadTDS) { path.RemoveSubstring(path.GetLength(), path.GetLength()); } while (base.GetCharacter(matchLength) != '/') { matchLength--; } assert( matchLength >= 1 ); if (matchLength == 1) { return path; } if (matchLength > path.GetLength()) { base.RemoveSubstring(matchLength, matchLength); matchLength--; } path.RemoveSubstring(1, matchLength); base.RemoveSubstring(1, matchLength); if (base.IsEmpty()) { path.Prepend("./"); return path; } // The number of remaining directory separators in base // is the number of levels to go up. JSize upCount = 0; const JSize baseLength = base.GetLength(); for (JIndex i=1; i<=baseLength; i++) { if (base.GetCharacter(i) == '/') { upCount++; path.Prepend("../"); } } assert( upCount > 0 ); return path; }
JBoolean JXPathInput::Complete ( JXInputField* te, const JCharacter* basePath, // can be NULL JDirInfo* completer, JXStringCompletionMenu** menu // constructed if NULL ) { // only complete if caret is at end of text JIndex caretIndex; if (!te->GetCaretLocation(&caretIndex) || caretIndex != te->GetTextLength()+1) { return kJFalse; } // catch empty path if (te->IsEmpty()) { const JString path = JGetRootDirectory(); te->Paste(path); return kJTrue; } // convert to absolute path JString fullName; if (!JExpandHomeDirShortcut(te->GetText(), &fullName)) { return kJFalse; } if (JIsRelativePath(fullName)) { if (JStringEmpty(basePath)) { return kJFalse; } fullName = JCombinePathAndName(basePath, fullName); } // if completing ~ rather than ~/ if (fullName.EndsWith(ACE_DIRECTORY_SEPARATOR_STR) && !(te->GetText()).EndsWith(ACE_DIRECTORY_SEPARATOR_STR)) { JStripTrailingDirSeparator(&fullName); } // get path and wildcard filter JString path, name; if (fullName.EndsWith(ACE_DIRECTORY_SEPARATOR_STR)) { path = fullName; name = "*"; } else { JSplitPathAndName(fullName, &path, &name); name.AppendCharacter('*'); } // build completion list if (!(completer->GoTo(path)).OK()) { return kJFalse; } completer->SetWildcardFilter(name, kJFalse, kJTrue); if (completer->IsEmpty()) { return kJFalse; } // check for characters common to all matches JString maxPrefix = jGetFullName(completer, 1); const JSize matchCount = completer->GetEntryCount(); JString entryName; for (JIndex i=2; i<=matchCount; i++) { entryName = jGetFullName(completer, i); const JSize matchLength = JCalcMatchLength(maxPrefix, entryName); const JSize prefixLength = maxPrefix.GetLength(); if (matchLength < prefixLength) { maxPrefix.RemoveSubstring(matchLength+1, prefixLength); } } // use the completion list if (matchCount > 0 && maxPrefix.GetLength() > fullName.GetLength()) { maxPrefix.RemoveSubstring(1, fullName.GetLength()); if (matchCount == 1 && (completer->GetEntry(1)).IsDirectory()) { JAppendDirSeparator(&maxPrefix); } te->Paste(maxPrefix); // so Undo removes completion if (*menu != NULL) { (**menu).ClearRequestCount(); } return kJTrue; } else if (matchCount > 1) { if (*menu == NULL) { *menu = new JXStringCompletionMenu(te, kJFalse); assert( *menu != NULL ); } else { (**menu).RemoveAllItems(); } for (JIndex i=1; i<=matchCount; i++) { entryName = jGetName(completer, i); (**menu).AddString(entryName); } (**menu).CompletionRequested(name.GetLength()-1); return kJTrue; } else { return kJFalse; } }
void GDBGetCompletions::HandleSuccess ( const JString& data ) { JPtrArray<JString> lines(JPtrArrayT::kDeleteAll); lines.SetSortOrder(JOrderedSetT::kSortAscending); lines.SetCompareFunction(JCompareStringsCaseSensitive); // loop through each line and add each one to our list JIndex i = 1, j = 1; while (data.LocateNextSubstring("\n", &j)) { if (j > i) { JString* s = new JString(data, JIndexRange(i, j-1)); assert( s != NULL ); s->TrimWhitespace(); if (s->IsEmpty() || !lines.InsertSorted(s, kJFalse)) { delete s; } } i = j+1; j = i; } if (i <= data.GetLength()) { JString* s = new JString(data, JIndexRange(i, data.GetLength())); assert( s != NULL ); s->TrimWhitespace(); if (s->IsEmpty() || !lines.InsertSorted(s, kJFalse)) { delete s; } } if (lines.IsEmpty()) { (itsInput->GetDisplay())->Beep(); return; } // Check if we're done. If we find our test prefix in the array, and // the array has only one element, we're done. Otherwise, our test // prefix is the 'start' of several possible commands. const JSize stringCount = lines.GetElementCount(); JBoolean found; JIndex startIndex = lines.SearchSorted1(&itsPrefix, JOrderedSetT::kAnyMatch, &found); if (found) { if (stringCount == 1) { // The input text is already complete. We just need to add a // space at the end to show that it is a complete word. itsPrefix += " "; } else { // We can't add anything to what the user has types, so we show // all possible completions. itsHistory->PlaceCursorAtEnd(); itsHistory->Paste("\n"); itsHistory->Paste(data); } itsInput->SetText(itsPrefix); itsInput->SetCaretLocation(itsInput->GetTextLength() + 1); return; } JString maxPrefix; maxPrefix = *(lines.NthElement(startIndex)); if (stringCount == 1) { // There's only one completion, which must be what we meant so we // fill in the input with this word. maxPrefix += " "; itsInput->SetText(maxPrefix); itsInput->SetCaretLocation(itsInput->GetTextLength() + 1); return; } for (JIndex i=startIndex+1; i<=stringCount; i++) { const JString* s = lines.NthElement(i); const JSize matchLength = JCalcMatchLength(maxPrefix, *s); const JSize prefixLength = maxPrefix.GetLength(); if (matchLength < prefixLength) { maxPrefix.RemoveSubstring(matchLength+1, prefixLength); } } if (maxPrefix == itsPrefix) { // The input text is all that the words have in common so we can't // add anything to the input. We therefore need to dump everything // to the history window. itsHistory->PlaceCursorAtEnd(); itsHistory->Paste("\n"); itsHistory->Paste(data); } else { itsInput->SetText(maxPrefix); itsInput->SetCaretLocation(itsInput->GetTextLength() + 1); } }
JSize CBStringCompleter::Complete ( const JString& prefix, JString* maxPrefix, JXStringCompletionMenu* menu ) const { menu->RemoveAllItems(); JBoolean found; const JIndex startIndex = itsStringList->SearchSorted1(const_cast<JString*>(&prefix), JOrderedSetT::kAnyMatch, &found); const JSize stringCount = itsStringList->GetElementCount(); if (startIndex > stringCount) { maxPrefix->Clear(); return 0; } JPtrArray<JString> matchList(JPtrArrayT::kForgetAll, 100); *maxPrefix = *(itsStringList->NthElement(startIndex)); JSize matchCount = 0; JBoolean addString = kJTrue; for (JIndex i=startIndex; i<=stringCount; i++) { const JString* s = itsStringList->NthElement(i); if (!s->BeginsWith(prefix, itsCaseSensitiveFlag)) { break; } if (matchCount > 0) { const JSize matchLength = JCalcMatchLength(*maxPrefix, *s, itsCaseSensitiveFlag); const JSize prefixLength = maxPrefix->GetLength(); if (matchLength < prefixLength) { maxPrefix->RemoveSubstring(matchLength+1, prefixLength); } } matchCount++; if (itsCaseSensitiveFlag) { matchList.Append(const_cast<JString*>(s)); } else if (addString) { JString s1 = *s; MatchCase(prefix, &s1); addString = menu->AddString(s1); // must process all to get maxPrefix } } if (itsCaseSensitiveFlag && matchCount > 0) { matchList.SetSortOrder(JOrderedSetT::kSortAscending); matchList.SetCompareFunction(JCompareStringsCaseInsensitive); matchList.Sort(); assert( matchCount == matchList.GetElementCount() ); for (JIndex i=1; i<=matchCount; i++) { if (!menu->AddString(*(matchList.NthElement(i)))) { matchCount = i-1; break; } } } else if (!itsCaseSensitiveFlag) { MatchCase(prefix, maxPrefix); } return matchCount; }