mirror of https://github.com/stella-emu/stella.git
Refactored PromptWidget a bit
This commit is contained in:
parent
e5e4e542b2
commit
a39a03309e
|
@ -345,52 +345,52 @@ size can be configured e.g. in the
|
|||
<p>
|
||||
<table BORDER=1 cellpadding=4>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Function</th>
|
||||
<th>Key</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control + S</td>
|
||||
<td>Step</td>
|
||||
<td>Control + S</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control + T</td>
|
||||
<td>Trace</td>
|
||||
<td>Control + T</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control + L</td>
|
||||
<td>Scan +1</td>
|
||||
<td>Control + L</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control + F</td>
|
||||
<td>Frame +1</td>
|
||||
<td>Control + F</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt + Left arrow</td>
|
||||
<td>Rewind 1</td>
|
||||
<td>Alt + Left arrow</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shift-Alt + Left arrow</td>
|
||||
<td>Rewind 10</td>
|
||||
<td>Shift-Alt + Left arrow</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt + Down arrow</td>
|
||||
<td>Rewind all</td>
|
||||
<td>Alt + Down arrow</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt + Right arrow</td>
|
||||
<td>Unwind 1</td>
|
||||
<td>Alt + Right arrow</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shift-Alt + Right arrow</td>
|
||||
<td>Unwind 10</td>
|
||||
<td>Shift-Alt + Right arrow</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt + Up arrow</td>
|
||||
<td>Unwind all</td>
|
||||
<td>Alt + Up arrow</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Backquote (`)</td>
|
||||
<td>Run, exits debugger</td>
|
||||
<td>Backquote (`)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
@ -428,25 +428,28 @@ or Supermon for the C=64.</p>
|
|||
Bash-style commands are also supported:</p>
|
||||
|
||||
<table border="1" cellpadding=4>
|
||||
<tr><th>Key</th><th>Function</th></tr>
|
||||
<tr><td>Home</td><td>Move cursor to beginning of line</td></tr>
|
||||
<tr><td>End</td><td>Move cursor to end of line</td></tr>
|
||||
<tr><td>Delete</td><td>Remove character to right of cursor</td></tr>
|
||||
<tr><td>Backspace</td><td>Remove character to left of cursor</td></tr>
|
||||
<tr><td>Control + A</td><td>Same function as 'Home'</td></tr>
|
||||
<tr><td>Control + E</td><td>Same function as 'End'</td></tr>
|
||||
<tr><td>Control + D</td><td>Same function as 'Delete'</td></tr>
|
||||
<tr><td>Control + K</td><td>Remove all characters from cursor to end of line</td></tr>
|
||||
<tr><td>Control + U</td><td>Remove all characters from cursor to beginning of line</td></tr>
|
||||
<tr><td>Control + W</td><td>Remove entire word to left of cursor</td></tr>
|
||||
<tr><td>Shift + PgUp</td><td>Scroll up through previous commands one screen/page</td></tr>
|
||||
<tr><td>Shift + PgDown</td><td>Scroll down through previous commands one screen/page</td></tr>
|
||||
<tr><td>Shift + Up</td><td>Scroll up through previous commands one line</td></tr>
|
||||
<tr><td>Shift + Down</td><td>Scroll down through previous commands one line</td></tr>
|
||||
<tr><td>Shift + Home</td><td>Scroll to beginning of commands</td></tr>
|
||||
<tr><td>Shift + End</td><td>Scroll to end of commands</td></tr>
|
||||
<tr><th>Function</th><th>Key</th></tr>
|
||||
<tr><td>Move cursor to beginning of line</td><td>Home</td></tr>
|
||||
<tr><td>Move cursor to end of line</td><td>End</td></tr>
|
||||
<tr><td>Remove character to right of cursor</td><td>Delete</td></tr>
|
||||
<tr><td>Remove character to left of cursor</td><td>Backspace</td></tr>
|
||||
<tr><td>Same function as 'Home'</td><td>Control + A</td></tr>
|
||||
<tr><td>Same function as 'End'</td><td>Control + E</td></tr>
|
||||
<tr><td>Same function as 'Delete'</td><td>Control + D</td></tr>
|
||||
<tr><td>Remove all characters from cursor to end of line</td><td>Control + K</td></tr>
|
||||
<tr><td>Remove all characters from cursor to beginning of line</td><td>Control + U</td></tr>
|
||||
<tr><td>Remove entire word to left of cursor</td><td>Control + W</td></tr>
|
||||
<tr><td>Copy current line</td><td>Control + C</td></tr>
|
||||
<tr><td>Cut current line</td><td>Control + X</td></tr>
|
||||
<tr><td>Paste over current line</td><td>Control + V</td></tr>
|
||||
<tr><td>Scroll up through previous commands one screen/page</td><td>Shift + PgUp</td></tr>
|
||||
<tr><td>Scroll down through previous commands one screen/page</td><td>Shift + PgDown</td></tr>
|
||||
<tr><td>Scroll up through previous commands one line</td><td>Shift + Up</td></tr>
|
||||
<tr><td>Scroll down through previous commands one line</td><td>Shift + Down</td></tr>
|
||||
<tr><td>Scroll to beginning of commands</td><td>Shift + Home</td></tr>
|
||||
<tr><td>Scroll to end of commands</td><td>Shift + End</td></tr>
|
||||
</table>
|
||||
<p>You can also scroll with the mouse. Copy and paste is not yet supported.</p>
|
||||
<p>You can also scroll with the mouse. Copy and paste is currently only supported for a complete line.</p>
|
||||
|
||||
<p>To see the available commands, enter "help". For extended help, type "help cmd",
|
||||
where 'cmd' is the command you wish to know about. The available commands are listed
|
||||
|
|
|
@ -65,7 +65,10 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
|
|||
setDefaultMapping(Event::NoType, EventMode::kMenuMode, updateDefaults);
|
||||
#ifdef GUI_SUPPORT
|
||||
setDefaultMapping(Event::NoType, EventMode::kEditMode, updateDefaults);
|
||||
#endif // DEBUG
|
||||
#endif
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
setDefaultMapping(Event::NoType, EventMode::kPromptMode, updateDefaults);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -195,6 +198,13 @@ void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mod
|
|||
setDefaultKey(item, event, EventMode::kEditMode);
|
||||
break;
|
||||
#endif
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
case EventMode::kPromptMode:
|
||||
// Edit mode events are always set because they are not saved
|
||||
for(const auto& item : FixedPromptMapping)
|
||||
setDefaultKey(item, event, EventMode::kPromptMode);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -470,7 +480,9 @@ bool PhysicalKeyboardHandler::addMapping(Event::Type event, EventMode mode,
|
|||
myKeyMap.erase(EventMode::kKeypadMode, key, mod);
|
||||
myKeyMap.erase(EventMode::kCompuMateMode, key, mod);
|
||||
}
|
||||
else if(evMode != EventMode::kMenuMode && evMode != EventMode::kEditMode)
|
||||
else if(evMode != EventMode::kMenuMode
|
||||
&& evMode != EventMode::kEditMode
|
||||
&& evMode != EventMode::kPromptMode)
|
||||
{
|
||||
// erase identical mapping for kCommonMode
|
||||
myKeyMap.erase(EventMode::kCommonMode, key, mod);
|
||||
|
@ -899,7 +911,28 @@ PhysicalKeyboardHandler::FixedEditMapping = {
|
|||
{Event::EndEdit, KBDK_KP_ENTER},
|
||||
{Event::AbortEdit, KBDK_ESCAPE},
|
||||
};
|
||||
#endif
|
||||
#endif // GUI_SUPPORT
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalKeyboardHandler::EventMappingArray
|
||||
PhysicalKeyboardHandler::FixedPromptMapping = {
|
||||
{Event::UINavNext, KBDK_TAB},
|
||||
{Event::UINavPrev, KBDK_TAB, KBDM_SHIFT},
|
||||
{Event::UIPgUp, KBDK_PAGEUP},
|
||||
{Event::UIPgUp, KBDK_PAGEUP, KBDM_SHIFT},
|
||||
{Event::UIPgDown, KBDK_PAGEDOWN},
|
||||
{Event::UIPgDown, KBDK_PAGEDOWN, KBDM_SHIFT},
|
||||
{Event::UIHome, KBDK_HOME, KBDM_SHIFT},
|
||||
{Event::UIEnd, KBDK_END, KBDM_SHIFT},
|
||||
{Event::UIUp, KBDK_UP, KBDM_SHIFT},
|
||||
{Event::UIDown, KBDK_DOWN, KBDM_SHIFT},
|
||||
{Event::UILeft, KBDK_DOWN},
|
||||
{Event::UIRight, KBDK_UP},
|
||||
|
||||
};
|
||||
#endif // DEBUGGER_SUPPORT
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoystickMapping = {
|
||||
|
|
|
@ -149,6 +149,9 @@ class PhysicalKeyboardHandler
|
|||
static EventMappingArray DefaultMenuMapping;
|
||||
#ifdef GUI_SUPPORT
|
||||
static EventMappingArray FixedEditMapping;
|
||||
#endif
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
static EventMappingArray FixedPromptMapping;
|
||||
#endif
|
||||
static EventMappingArray DefaultCommonMapping;
|
||||
// Controller specific mappings
|
||||
|
|
|
@ -48,6 +48,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(JoyHatDir, {
|
|||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(EventMode, {
|
||||
{EventMode::kEditMode, "kEditMode"},
|
||||
{EventMode::kPromptMode, "kPromptMode"},
|
||||
{EventMode::kMenuMode, "kMenuMode"},
|
||||
{EventMode::kEmulationMode, "kEmulationMode"},
|
||||
{EventMode::kJoystickMode, "kJoystickMode"},
|
||||
|
|
|
@ -158,291 +158,158 @@ bool PromptWidget::handleText(char text)
|
|||
bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||
{
|
||||
bool handled = true;
|
||||
bool dirty = false;
|
||||
bool dirty = true;
|
||||
|
||||
if(key != KBDK_TAB && !StellaModTest::isShift(mod))
|
||||
_tabCount = -1;
|
||||
|
||||
switch(key)
|
||||
// Uses normal edit events + special prompt events
|
||||
Event::Type event = instance().eventHandler().eventForKey(EventMode::kEditMode, key, mod);
|
||||
if(event == Event::NoType)
|
||||
event = instance().eventHandler().eventForKey(EventMode::kPromptMode, key, mod);
|
||||
|
||||
switch(event)
|
||||
{
|
||||
case KBDK_RETURN:
|
||||
case KBDK_KP_ENTER:
|
||||
case Event::EndEdit:
|
||||
{
|
||||
nextLine();
|
||||
|
||||
assert(_promptEndPos >= _promptStartPos);
|
||||
int len = _promptEndPos - _promptStartPos;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
// Copy the user input to command
|
||||
string command;
|
||||
for (int i = 0; i < len; i++)
|
||||
command += buffer(_promptStartPos + i) & 0x7f;
|
||||
|
||||
// Add the input to the history
|
||||
addToHistory(command.c_str());
|
||||
|
||||
// Pass the command to the debugger, and print the result
|
||||
string result = instance().debugger().run(command);
|
||||
|
||||
// This is a bit of a hack
|
||||
// Certain commands remove the debugger dialog from underneath us,
|
||||
// so we shouldn't print any messages
|
||||
// Those commands will return '_EXIT_DEBUGGER' as their result
|
||||
if(result == "_EXIT_DEBUGGER")
|
||||
{
|
||||
_exitedEarly = true;
|
||||
return true;
|
||||
}
|
||||
else if(result == "_NO_PROMPT")
|
||||
return true;
|
||||
else if(result != "")
|
||||
print(result + "\n");
|
||||
}
|
||||
if(execute())
|
||||
return true;
|
||||
|
||||
printPrompt();
|
||||
dirty = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case KBDK_TAB:
|
||||
{
|
||||
// Tab completion: we complete either commands or labels, but not
|
||||
// both at once.
|
||||
|
||||
if(_currentPos <= _promptStartPos)
|
||||
break; // no input
|
||||
|
||||
scrollToCurrent();
|
||||
|
||||
int len = _promptEndPos - _promptStartPos;
|
||||
|
||||
if(_tabCount != -1)
|
||||
len = int(strlen(_inputStr));
|
||||
if(len > 255)
|
||||
len = 255;
|
||||
|
||||
int lastDelimPos = -1;
|
||||
char delimiter = '\0';
|
||||
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
// copy the input at first tab press only
|
||||
if(_tabCount == -1)
|
||||
_inputStr[i] = buffer(_promptStartPos + i) & 0x7f;
|
||||
// whitespace characters
|
||||
if(strchr("{*@<> =[]()+-/&|!^~%", _inputStr[i]))
|
||||
{
|
||||
lastDelimPos = i;
|
||||
delimiter = _inputStr[i];
|
||||
}
|
||||
}
|
||||
if(_tabCount == -1)
|
||||
_inputStr[len] = '\0';
|
||||
|
||||
StringList list;
|
||||
|
||||
if(lastDelimPos == -1)
|
||||
// no delimiters, do only command completion:
|
||||
instance().debugger().parser().getCompletions(_inputStr, list);
|
||||
else
|
||||
{
|
||||
size_t strLen = len - lastDelimPos - 1;
|
||||
// do not show ALL commands/labels without any filter as it makes no sense
|
||||
if(strLen > 0)
|
||||
{
|
||||
// Special case for 'help' command
|
||||
if(BSPF::startsWithIgnoreCase(_inputStr, "help"))
|
||||
instance().debugger().parser().getCompletions(_inputStr + lastDelimPos + 1, list);
|
||||
else
|
||||
{
|
||||
// we got a delimiter, so this must be a label or a function
|
||||
const Debugger& dbg = instance().debugger();
|
||||
|
||||
dbg.cartDebug().getCompletions(_inputStr + lastDelimPos + 1, list);
|
||||
dbg.getCompletions(_inputStr + lastDelimPos + 1, list);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(list.size() < 1)
|
||||
break;
|
||||
sort(list.begin(), list.end());
|
||||
|
||||
if(StellaModTest::isShift(mod))
|
||||
{
|
||||
if(--_tabCount < 0)
|
||||
_tabCount = int(list.size()) - 1;
|
||||
}
|
||||
else
|
||||
_tabCount = (++_tabCount) % list.size();
|
||||
|
||||
nextLine();
|
||||
_currentPos = _promptStartPos;
|
||||
killLine(1); // kill whole line
|
||||
|
||||
// start with-autocompleted, fixed string...
|
||||
for(int i = 0; i < lastDelimPos; i++)
|
||||
putcharIntern(_inputStr[i]);
|
||||
if(lastDelimPos > 0)
|
||||
putcharIntern(delimiter);
|
||||
|
||||
// ...and add current autocompletion string
|
||||
print(list[_tabCount]);
|
||||
putcharIntern(' ');
|
||||
_promptEndPos = _currentPos;
|
||||
|
||||
dirty = true;
|
||||
case Event::UINavNext:
|
||||
dirty = autoComplete(+1);
|
||||
break;
|
||||
}
|
||||
|
||||
case KBDK_BACKSPACE:
|
||||
if (_currentPos > _promptStartPos)
|
||||
case Event::UINavPrev:
|
||||
dirty = autoComplete(-1);
|
||||
break;
|
||||
|
||||
case Event::UILeft:
|
||||
historyScroll(-1);
|
||||
break;
|
||||
|
||||
case Event::UIRight:
|
||||
historyScroll(+1);
|
||||
break;
|
||||
|
||||
case Event::Backspace:
|
||||
if(_currentPos > _promptStartPos)
|
||||
killChar(-1);
|
||||
|
||||
scrollToCurrent();
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case KBDK_DELETE:
|
||||
case KBDK_KP_PERIOD: // actually the num delete
|
||||
if(StellaModTest::isShift(mod))
|
||||
textCut();
|
||||
else
|
||||
killChar(+1);
|
||||
dirty = true;
|
||||
case Event::Delete:
|
||||
killChar(+1);
|
||||
break;
|
||||
|
||||
case KBDK_PAGEUP:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
// Don't scroll up when at top of buffer
|
||||
if(_scrollLine < _linesPerPage)
|
||||
break;
|
||||
|
||||
_scrollLine -= _linesPerPage - 1;
|
||||
if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
|
||||
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
case Event::MoveHome:
|
||||
_currentPos = _promptStartPos;
|
||||
break;
|
||||
|
||||
case KBDK_PAGEDOWN:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
// Don't scroll down when at bottom of buffer
|
||||
if(_scrollLine >= _promptEndPos / _lineWidth)
|
||||
break;
|
||||
|
||||
_scrollLine += _linesPerPage - 1;
|
||||
if (_scrollLine > _promptEndPos / _lineWidth)
|
||||
_scrollLine = _promptEndPos / _lineWidth;
|
||||
updateScrollBuffer();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
case Event::MoveEnd:
|
||||
_currentPos = _promptEndPos;
|
||||
break;
|
||||
|
||||
case KBDK_HOME:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
}
|
||||
else
|
||||
_currentPos = _promptStartPos;
|
||||
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case KBDK_END:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
_scrollLine = _promptEndPos / _lineWidth;
|
||||
if (_scrollLine < _linesPerPage - 1)
|
||||
_scrollLine = _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
}
|
||||
else
|
||||
_currentPos = _promptEndPos;
|
||||
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case KBDK_UP:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1)
|
||||
break;
|
||||
|
||||
_scrollLine -= 1;
|
||||
updateScrollBuffer();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
else
|
||||
historyScroll(+1);
|
||||
break;
|
||||
|
||||
case KBDK_DOWN:
|
||||
if (StellaModTest::isShift(mod))
|
||||
{
|
||||
// Don't scroll down when at bottom of buffer
|
||||
if(_scrollLine >= _promptEndPos / _lineWidth)
|
||||
break;
|
||||
|
||||
_scrollLine += 1;
|
||||
updateScrollBuffer();
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
else
|
||||
historyScroll(-1);
|
||||
break;
|
||||
|
||||
case KBDK_RIGHT:
|
||||
if (_currentPos < _promptEndPos)
|
||||
case Event::MoveRightChar:
|
||||
if(_currentPos < _promptEndPos)
|
||||
_currentPos++;
|
||||
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case KBDK_LEFT:
|
||||
if (_currentPos > _promptStartPos)
|
||||
case Event::MoveLeftChar:
|
||||
if(_currentPos > _promptStartPos)
|
||||
_currentPos--;
|
||||
|
||||
dirty = true;
|
||||
break;
|
||||
|
||||
case KBDK_INSERT:
|
||||
if(StellaModTest::isShift(mod))
|
||||
{
|
||||
textPaste();
|
||||
dirty = true;
|
||||
}
|
||||
else if(StellaModTest::isControl(mod))
|
||||
{
|
||||
textCopy();
|
||||
dirty = true;
|
||||
}
|
||||
else
|
||||
handled = false;
|
||||
case Event::DeleteRightWord:
|
||||
killChar(+1);
|
||||
break;
|
||||
|
||||
case Event::DeleteEnd:
|
||||
killLine(+1);
|
||||
break;
|
||||
|
||||
case Event::DeleteHome:
|
||||
killLine(-1);
|
||||
break;
|
||||
|
||||
case Event::DeleteLeftWord:
|
||||
killWord();
|
||||
break;
|
||||
|
||||
case Event::UIUp:
|
||||
if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1)
|
||||
break;
|
||||
|
||||
_scrollLine -= 1;
|
||||
updateScrollBuffer();
|
||||
break;
|
||||
|
||||
case Event::UIDown:
|
||||
// Don't scroll down when at bottom of buffer
|
||||
if(_scrollLine >= _promptEndPos / _lineWidth)
|
||||
break;
|
||||
|
||||
_scrollLine += 1;
|
||||
updateScrollBuffer();
|
||||
break;
|
||||
|
||||
case Event::UIPgUp:
|
||||
// Don't scroll up when at top of buffer
|
||||
if(_scrollLine < _linesPerPage)
|
||||
break;
|
||||
|
||||
_scrollLine -= _linesPerPage - 1;
|
||||
if(_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
|
||||
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
break;
|
||||
|
||||
case Event::UIPgDown:
|
||||
// Don't scroll down when at bottom of buffer
|
||||
if(_scrollLine >= _promptEndPos / _lineWidth)
|
||||
break;
|
||||
|
||||
_scrollLine += _linesPerPage - 1;
|
||||
if(_scrollLine > _promptEndPos / _lineWidth)
|
||||
_scrollLine = _promptEndPos / _lineWidth;
|
||||
updateScrollBuffer();
|
||||
break;
|
||||
|
||||
case Event::UIHome:
|
||||
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
break;
|
||||
|
||||
case Event::UIEnd:
|
||||
_scrollLine = _promptEndPos / _lineWidth;
|
||||
if(_scrollLine < _linesPerPage - 1)
|
||||
_scrollLine = _linesPerPage - 1;
|
||||
updateScrollBuffer();
|
||||
break;
|
||||
|
||||
//case Event::SelectAll:
|
||||
// textSelectAll();
|
||||
// break;
|
||||
|
||||
case Event::Cut:
|
||||
textCut();
|
||||
break;
|
||||
|
||||
case Event::Copy:
|
||||
textCopy();
|
||||
break;
|
||||
|
||||
case Event::Paste:
|
||||
textPaste();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (StellaModTest::isControl(mod))
|
||||
{
|
||||
specialKeys(key);
|
||||
}
|
||||
else if (StellaModTest::isAlt(mod))
|
||||
{
|
||||
// Placeholder only - this will never be reached
|
||||
}
|
||||
else
|
||||
handled = false;
|
||||
handled = false;
|
||||
dirty = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -546,46 +413,6 @@ int PromptWidget::getWidth() const
|
|||
return _w + ScrollBarWidget::scrollBarWidth(_font);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PromptWidget::specialKeys(StellaKey key)
|
||||
{
|
||||
bool handled = true;
|
||||
|
||||
switch(key)
|
||||
{
|
||||
case KBDK_D:
|
||||
killChar(+1);
|
||||
break;
|
||||
case KBDK_K:
|
||||
killLine(+1);
|
||||
break;
|
||||
case KBDK_U:
|
||||
killLine(-1);
|
||||
break;
|
||||
case KBDK_W:
|
||||
killWord();
|
||||
break;
|
||||
case KBDK_A:
|
||||
textSelectAll();
|
||||
break;
|
||||
case KBDK_X:
|
||||
textCut();
|
||||
break;
|
||||
case KBDK_C:
|
||||
textCopy();
|
||||
break;
|
||||
case KBDK_V:
|
||||
textPaste();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(handled)
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PromptWidget::killChar(int direction)
|
||||
{
|
||||
|
@ -807,6 +634,135 @@ void PromptWidget::historyScroll(int direction)
|
|||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PromptWidget::execute()
|
||||
{
|
||||
nextLine();
|
||||
|
||||
assert(_promptEndPos >= _promptStartPos);
|
||||
int len = _promptEndPos - _promptStartPos;
|
||||
|
||||
if(len > 0)
|
||||
{
|
||||
// Copy the user input to command
|
||||
string command;
|
||||
for(int i = 0; i < len; i++)
|
||||
command += buffer(_promptStartPos + i) & 0x7f;
|
||||
|
||||
// Add the input to the history
|
||||
addToHistory(command.c_str());
|
||||
|
||||
// Pass the command to the debugger, and print the result
|
||||
string result = instance().debugger().run(command);
|
||||
|
||||
// This is a bit of a hack
|
||||
// Certain commands remove the debugger dialog from underneath us,
|
||||
// so we shouldn't print any messages
|
||||
// Those commands will return '_EXIT_DEBUGGER' as their result
|
||||
if(result == "_EXIT_DEBUGGER")
|
||||
{
|
||||
_exitedEarly = true;
|
||||
return true;
|
||||
}
|
||||
else if(result == "_NO_PROMPT")
|
||||
return true;
|
||||
else if(result != "")
|
||||
print(result + "\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PromptWidget::autoComplete(int direction)
|
||||
{
|
||||
// Tab completion: we complete either commands or labels, but not
|
||||
// both at once.
|
||||
|
||||
if(_currentPos <= _promptStartPos)
|
||||
return false; // no input
|
||||
|
||||
scrollToCurrent();
|
||||
|
||||
int len = _promptEndPos - _promptStartPos;
|
||||
|
||||
if(_tabCount != -1)
|
||||
len = int(strlen(_inputStr));
|
||||
if(len > 255)
|
||||
len = 255;
|
||||
|
||||
int lastDelimPos = -1;
|
||||
char delimiter = '\0';
|
||||
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
// copy the input at first tab press only
|
||||
if(_tabCount == -1)
|
||||
_inputStr[i] = buffer(_promptStartPos + i) & 0x7f;
|
||||
// whitespace characters
|
||||
if(strchr("{*@<> =[]()+-/&|!^~%", _inputStr[i]))
|
||||
{
|
||||
lastDelimPos = i;
|
||||
delimiter = _inputStr[i];
|
||||
}
|
||||
}
|
||||
if(_tabCount == -1)
|
||||
_inputStr[len] = '\0';
|
||||
|
||||
StringList list;
|
||||
|
||||
if(lastDelimPos == -1)
|
||||
// no delimiters, do only command completion:
|
||||
instance().debugger().parser().getCompletions(_inputStr, list);
|
||||
else
|
||||
{
|
||||
size_t strLen = len - lastDelimPos - 1;
|
||||
// do not show ALL commands/labels without any filter as it makes no sense
|
||||
if(strLen > 0)
|
||||
{
|
||||
// Special case for 'help' command
|
||||
if(BSPF::startsWithIgnoreCase(_inputStr, "help"))
|
||||
instance().debugger().parser().getCompletions(_inputStr + lastDelimPos + 1, list);
|
||||
else
|
||||
{
|
||||
// we got a delimiter, so this must be a label or a function
|
||||
const Debugger& dbg = instance().debugger();
|
||||
|
||||
dbg.cartDebug().getCompletions(_inputStr + lastDelimPos + 1, list);
|
||||
dbg.getCompletions(_inputStr + lastDelimPos + 1, list);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(list.size() < 1)
|
||||
return false;
|
||||
sort(list.begin(), list.end());
|
||||
|
||||
if(direction < 0)
|
||||
{
|
||||
if(--_tabCount < 0)
|
||||
_tabCount = int(list.size()) - 1;
|
||||
}
|
||||
else
|
||||
_tabCount = (++_tabCount) % list.size();
|
||||
|
||||
nextLine();
|
||||
_currentPos = _promptStartPos;
|
||||
killLine(1); // kill whole line
|
||||
|
||||
// start with-autocompleted, fixed string...
|
||||
for(int i = 0; i < lastDelimPos; i++)
|
||||
putcharIntern(_inputStr[i]);
|
||||
if(lastDelimPos > 0)
|
||||
putcharIntern(delimiter);
|
||||
|
||||
// ...and add current autocompletion string
|
||||
print(list[_tabCount]);
|
||||
putcharIntern(' ');
|
||||
_promptEndPos = _currentPos;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PromptWidget::nextLine()
|
||||
{
|
||||
|
@ -971,29 +927,6 @@ string PromptWidget::saveBuffer(const FilesystemNode& file)
|
|||
return "unable to save session";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string PromptWidget::getCompletionPrefix(const StringList& completions)
|
||||
{
|
||||
// Find the number of characters matching for each of the completions provided
|
||||
for(uInt32 len = 1;; ++len)
|
||||
{
|
||||
for(uInt32 i = 0; i < completions.size(); ++i)
|
||||
{
|
||||
string s1 = completions[i];
|
||||
if(s1.length() < len)
|
||||
{
|
||||
return s1.substr(0, len - 1);
|
||||
}
|
||||
string find = s1.substr(0, len);
|
||||
|
||||
for(uInt32 j = i + 1; j < completions.size(); ++j)
|
||||
{
|
||||
if(!BSPF::startsWithIgnoreCase(completions[j], find))
|
||||
return s1.substr(0, len - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PromptWidget::clearScreen()
|
||||
|
|
|
@ -64,7 +64,6 @@ class PromptWidget : public Widget, public CommandSender
|
|||
void scrollToCurrent();
|
||||
|
||||
// Line editing
|
||||
void specialKeys(StellaKey key);
|
||||
void nextLine();
|
||||
void killChar(int direction);
|
||||
void killLine(int direction);
|
||||
|
@ -80,6 +79,9 @@ class PromptWidget : public Widget, public CommandSender
|
|||
// History
|
||||
void historyScroll(int direction);
|
||||
|
||||
bool execute();
|
||||
bool autoComplete(int direction);
|
||||
|
||||
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseWheel(int x, int y, int direction) override;
|
||||
bool handleText(char text) override;
|
||||
|
@ -92,10 +94,6 @@ class PromptWidget : public Widget, public CommandSender
|
|||
bool wantsFocus() const override { return true; }
|
||||
void loadConfig() override;
|
||||
|
||||
private:
|
||||
// Get the longest prefix (initially 's') that is in every string in the list
|
||||
string getCompletionPrefix(const StringList& completions);
|
||||
|
||||
private:
|
||||
enum {
|
||||
kBufferSize = 32768,
|
||||
|
|
|
@ -84,6 +84,7 @@ enum class EventMode {
|
|||
kCompuMateMode, // cannot be remapped
|
||||
kCommonMode, // mapping common between controllers
|
||||
kEditMode, // mapping used in editable widgets
|
||||
kPromptMode, // extra mappings used in debugger's prompt widget
|
||||
kNumModes
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue