further improved debugger tab auto complete (see #240)

This commit is contained in:
Thomas Jentzsch 2021-05-09 11:23:14 +02:00
parent 4ebf3f2203
commit abde496632
3 changed files with 52 additions and 82 deletions

View File

@ -467,13 +467,12 @@ just by re-running the relevant commands in the prompt.</p>
<h3><a name="TabCompletion">Tab Key Auto-Complete</a></h3> <h3><a name="TabCompletion">Tab Key Auto-Complete</a></h3>
<p>While entering a command, label or function, you can type a partial name and <p>While entering a command, label or function, you can type a partial name and
press the Tab key to attempt to auto-complete it. If you've ever used press the (Shift +) Tab key to attempt to auto-complete it. If you've ever used
"bash", this will be immediately familiar. If not, try it: load up "bash", this will be immediately familiar. If not, try it: load up
a ROM, go to the debugger, type "g" (but don't press Enter), a ROM, go to the debugger, type "g" (but don't press Enter),
then hit Tab. The "g" will change to "gfx" (since this is the only then hit Tab. The "g" will change to "gfx" (since this is the only
built-in command starting with a "g"). If there are multiple possible built-in command starting with a "g"). If there are multiple possible
completions (try with "tr" instead of "g"), you'll see a list of them, completions (try with "tr" instead of "g"), you can tab through them.
and your partial name will be completed as far as possible.
After the first character, the autocompletion considers all After the first character, the autocompletion considers all
characters in the right order as a match (e.g. "twf" will be completed to characters in the right order as a match (e.g. "twf" will be completed to
"trapWriteIf"). Alternatively you can make use of the camel case names and type "trapWriteIf"). Alternatively you can make use of the camel case names and type

View File

@ -160,6 +160,9 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
bool handled = true; bool handled = true;
bool dirty = false; bool dirty = false;
if(key != KBDK_TAB && !StellaModTest::isShift(mod))
_tabCount = -1;
switch(key) switch(key)
{ {
case KBDK_RETURN: case KBDK_RETURN:
@ -209,121 +212,87 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
// both at once. // both at once.
if(_currentPos <= _promptStartPos) if(_currentPos <= _promptStartPos)
break; break; // no input
scrollToCurrent(); scrollToCurrent();
int len = _promptEndPos - _promptStartPos; int len = _promptEndPos - _promptStartPos;
if(len > 255) len = 255;
if(_tabCount != -1)
len = int(strlen(_inputStr));
if(len > 255)
len = 255;
int lastDelimPos = -1; int lastDelimPos = -1;
char delimiter = '\0'; char delimiter = '\0';
char inputStr[256]; // NOLINT (will be rewritten soon) for(int i = 0; i < len; i++)
for (int i = 0; i < len; i++)
{ {
inputStr[i] = buffer(_promptStartPos + i) & 0x7f; // copy the input at first tab press only
if(_tabCount == -1)
_inputStr[i] = buffer(_promptStartPos + i) & 0x7f;
// whitespace characters // whitespace characters
if(strchr("{*@<> =[]()+-/&|!^~%", inputStr[i])) if(strchr("{*@<> =[]()+-/&|!^~%", _inputStr[i]))
{ {
lastDelimPos = i; lastDelimPos = i;
delimiter = inputStr[i]; delimiter = _inputStr[i];
} }
} }
inputStr[len] = '\0'; if(_tabCount == -1)
size_t strLen = len - lastDelimPos - 1; _inputStr[len] = '\0';
StringList list; StringList list;
string completionList;
string prefix;
if(lastDelimPos < 0) if(lastDelimPos == -1)
{
// no delimiters, do only command completion: // no delimiters, do only command completion:
const DebuggerParser& parser = instance().debugger().parser(); instance().debugger().parser().getCompletions(_inputStr, list);
parser.getCompletions(inputStr, list);
if(list.size() < 1)
break;
sort(list.begin(), list.end());
completionList = list[0];
for(uInt32 i = 1; i < list.size(); ++i)
completionList += " " + list[i];
prefix = getCompletionPrefix(list);
}
else else
{ {
// Special case for 'help' command size_t strLen = len - lastDelimPos - 1;
if(BSPF::startsWithIgnoreCase(inputStr, "help")) // do not show ALL commands/labels without any filter as it makes no sense
if(strLen > 0)
{ {
instance().debugger().parser().getCompletions(inputStr + lastDelimPos + 1, list); // Special case for 'help' command
} if(BSPF::startsWithIgnoreCase(_inputStr, "help"))
else instance().debugger().parser().getCompletions(_inputStr + lastDelimPos + 1, list);
{ else
// do not show ALL labels without any filter as it makes no sense
if(strLen > 0)
{ {
// we got a delimiter, so this must be a label or a function // we got a delimiter, so this must be a label or a function
const Debugger& dbg = instance().debugger(); const Debugger& dbg = instance().debugger();
dbg.cartDebug().getCompletions(inputStr + lastDelimPos + 1, list); dbg.cartDebug().getCompletions(_inputStr + lastDelimPos + 1, list);
dbg.getCompletions(inputStr + lastDelimPos + 1, list); dbg.getCompletions(_inputStr + lastDelimPos + 1, list);
} }
} }
if(list.size() < 1)
break;
sort(list.begin(), list.end());
completionList = list[0];
for(uInt32 i = 1; i < list.size(); ++i)
completionList += " " + list[i];
prefix = getCompletionPrefix(list);
} }
if(list.size() < 1)
break;
sort(list.begin(), list.end());
// TODO: tab through list if(StellaModTest::isShift(mod))
if(list.size() == 1)
{ {
// add to buffer as though user typed it (plus a space) if(--_tabCount < 0)
_currentPos = _promptStartPos + lastDelimPos + 1; _tabCount = int(list.size()) - 1;
const char* clptr = completionList.c_str();
while(*clptr != '\0')
putcharIntern(*clptr++);
putcharIntern(' ');
_promptEndPos = _currentPos;
} }
else else
{ _tabCount = (++_tabCount) % list.size();
nextLine();
// add to buffer as-is, then add PROMPT plus whatever we have so far
_currentPos = _promptStartPos + lastDelimPos + 1;
print("\n"); nextLine();
print(completionList); _currentPos = _promptStartPos;
print("\n"); killLine(1); // kill whole line
print(PROMPT);
_promptStartPos = _currentPos; // start with-autocompleted, fixed string...
for(int i = 0; i < lastDelimPos; i++)
putcharIntern(_inputStr[i]);
if(lastDelimPos > 0)
putcharIntern(delimiter);
if(prefix.length() < strLen) // ...and add current autocompletion string
{ print(list[_tabCount]);
for(int i = 0; i < len; i++) putcharIntern(' ');
putcharIntern(inputStr[i]); _promptEndPos = _currentPos;
}
else
{
for(int i = 0; i < lastDelimPos; i++)
putcharIntern(inputStr[i]);
if(lastDelimPos > 0)
putcharIntern(delimiter);
print(prefix);
}
_promptEndPos = _currentPos;
}
dirty = true; dirty = true;
break; break;
} }

View File

@ -122,6 +122,8 @@ class PromptWidget : public Widget, public CommandSender
int _historySize; int _historySize;
int _historyIndex; int _historyIndex;
int _historyLine; int _historyLine;
int _tabCount{-1};
char _inputStr[256];
int _kConsoleCharWidth, _kConsoleCharHeight, _kConsoleLineHeight; int _kConsoleCharWidth, _kConsoleCharHeight, _kConsoleLineHeight;