diff --git a/src/debugger/gui/PromptWidget.cxx b/src/debugger/gui/PromptWidget.cxx index f37651837..f8ef7aa24 100644 --- a/src/debugger/gui/PromptWidget.cxx +++ b/src/debugger/gui/PromptWidget.cxx @@ -40,12 +40,7 @@ PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : Widget(boss, font, x, y, w - ScrollBarWidget::scrollBarWidth(font), h), - CommandSender(boss), - _historySize{0}, - _historyIndex{0}, - _historyLine{0}, - _firstTime{true}, - _exitedEarly{false} + CommandSender(boss) { _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS | Widget::FLAG_WANTS_TAB | Widget::FLAG_WANTS_RAWDATA; @@ -67,9 +62,6 @@ PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font, ScrollBarWidget::scrollBarWidth(_font), _h); _scrollBar->setTarget(this); - // Init colors - _inverse = false; - clearScreen(); addFocusWidget(this); @@ -136,6 +128,8 @@ void PromptWidget::printPrompt() print(PROMPT); _promptStartPos = _promptEndPos = _currentPos; + + resetFunctions(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -149,6 +143,8 @@ bool PromptWidget::handleText(char text) _promptEndPos++; putcharIntern(text); scrollToCurrent(); + + resetFunctions(); } return true; } @@ -156,11 +152,11 @@ bool PromptWidget::handleText(char text) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod) { - bool handled = true; - bool dirty = true; - - if(key != KBDK_TAB && !StellaModTest::isShift(mod)) - _tabCount = -1; + bool handled = true, + dirty = true, + changeInput = false, + resetAutoComplete = true, + resetHistoryScroll = true; // Uses normal edit events + special prompt events Event::Type event = instance().eventHandler().eventForKey(EventMode::kEditMode, key, mod); @@ -178,33 +174,72 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod) break; } + // special events (auto complete & history scrolling) case Event::UINavNext: - dirty = autoComplete(+1); + dirty = changeInput = autoComplete(+1); + resetAutoComplete = false; break; case Event::UINavPrev: - dirty = autoComplete(-1); + dirty = changeInput = autoComplete(-1); + resetAutoComplete = false; break; - case Event::UILeft: - historyScroll(-1); + case Event::UILeft: // mapped to KBDK_DOWN by default + dirty = changeInput = historyScroll(-1); + resetHistoryScroll = false; break; - case Event::UIRight: - historyScroll(+1); + case Event::UIRight: // mapped to KBDK_UP by default + dirty = changeInput = historyScroll(+1); + resetHistoryScroll = false; break; + // input modifying events case Event::Backspace: if(_currentPos > _promptStartPos) + { killChar(-1); - + changeInput = true; + } scrollToCurrent(); break; case Event::Delete: killChar(+1); + changeInput = true; break; + case Event::DeleteEnd: + killLine(+1); + changeInput = true; + break; + + case Event::DeleteHome: + killLine(-1); + changeInput = true; + break; + + case Event::DeleteLeftWord: + killWord(); + changeInput = true; + break; + + case Event::Cut: + textCut(); + changeInput = true; + break; + + case Event::Copy: + textCopy(); + break; + + case Event::Paste: + textPaste(); + changeInput = true; + break; + + // cursor events case Event::MoveHome: _currentPos = _promptStartPos; break; @@ -223,22 +258,7 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod) _currentPos--; break; - case Event::DeleteRightWord: - killChar(+1); - break; - - case Event::DeleteEnd: - killLine(+1); - break; - - case Event::DeleteHome: - killLine(-1); - break; - - case Event::DeleteLeftWord: - killWord(); - break; - + // scrolling events case Event::UIUp: if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1) break; @@ -290,22 +310,6 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod) updateScrollBuffer(); break; - //case Event::SelectAll: - // textSelectAll(); - // break; - - case Event::Cut: - textCut(); - break; - - case Event::Copy: - textCopy(); - break; - - case Event::Paste: - textPaste(); - break; - default: handled = false; dirty = false; @@ -316,6 +320,13 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod) if(dirty) setDirty(); + // Reset special event handling if input has changed + // We assume that non-handled events will modify the input too + if(!handled || (resetAutoComplete && changeInput)) + _tabCount = -1; + if(!handled || (resetHistoryScroll && changeInput)) + _historyLine = 0; + return handled; } @@ -472,11 +483,6 @@ void PromptWidget::killWord() _promptEndPos -= cnt; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptWidget::textSelectAll() -{ -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PromptWidget::getLine() { @@ -497,14 +503,14 @@ string PromptWidget::getLine() void PromptWidget::textCut() { #if defined(PSEUDO_CUT_COPY_PASTE) - string text = getLine(); - - instance().eventHandler().copyText(text); + textCopy(); // Remove the current line _currentPos = _promptStartPos; killLine(1); // to end of line _promptEndPos = _currentPos; + + resetFunctions(); #endif } @@ -531,65 +537,101 @@ void PromptWidget::textPaste() instance().eventHandler().pasteText(text); print(text); _promptEndPos = _currentPos; + + resetFunctions(); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::addToHistory(const char* str) { - // TOOD: do not add duplicates, remove oldest + // Do not add duplicates, remove old duplicate + if(_historySize) + { + int i = _historyIndex; + int historyEnd = _historyIndex % _historySize; + + do + { + if(--i < 0) + i =_historySize - 1; + + if(!BSPF::compareIgnoreCase(_history[i], str)) + { + int j = i, prevJ; + + do + { + prevJ = j; + j = (j + 1) % (_historySize); + + #if defined(BSPF_WINDOWS) + strncpy_s(_history[prevJ], kLineBufferSize, _history[j], kLineBufferSize - 1); + #else + strncpy(_history[prevJ], _history[j], kLineBufferSize - 1); + #endif + } while(j != historyEnd); + + if(--_historyIndex < 0) + _historyIndex = _historySize - 1; + _historySize--; + break; + } + } while(i != historyEnd); + } + #if defined(BSPF_WINDOWS) strncpy_s(_history[_historyIndex], kLineBufferSize, str, kLineBufferSize - 1); #else strncpy(_history[_historyIndex], str, kLineBufferSize - 1); #endif _historyIndex = (_historyIndex + 1) % kHistorySize; - _historyLine = 0; + _historyLine = 0; // reset history scroll if (_historySize < kHistorySize) _historySize++; } -#if 0 // FIXME // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int PromptWidget::compareHistory(const char *histLine) +bool PromptWidget::historyScroll(int direction) { - return 1; -} -#endif + if(_historySize == 0) + return false; -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void PromptWidget::historyScroll(int direction) -{ - if (_historySize == 0) - return; - - if (_historyLine == 0 && direction > 0) + if(_historyLine == 0) { int i; - for (i = 0; i < _promptEndPos - _promptStartPos; i++) + + for(i = 0; i < _promptEndPos - _promptStartPos; i++) _history[_historyIndex][i] = buffer(_promptStartPos + i); //FIXME: int to char?? _history[_historyIndex][i] = '\0'; } // Advance to the next line in the history + int histSize = _historySize + (_historySize < kHistorySize ? 1 : 0); int line = _historyLine + direction; + if(line < 0) - line += _historySize + 1; - line %= (_historySize + 1); + line += histSize; + line %= histSize; - // If they press arrow-up with anything in the buffer, search backwards - // in the history. - /* - if(direction < 0 && _currentPos > _promptStartPos) { - for(;line > 0; line--) { - if(compareHistory(_history[line]) == 0) + // If anything in the buffer, search the history. + if(_currentPos > _promptStartPos) { + do + { + int idx = line ? (_historyIndex - line + _historySize) % _historySize + : _historyIndex; + + if(BSPF::startsWithIgnoreCase(_history[idx], _history[_historyIndex])) break; - } - } - */ + line += direction; + if(line < 0) + line += histSize; + line %= histSize; + } while(line); // if line == 0, nothing was found + } _historyLine = line; // Remove the current user text @@ -600,21 +642,17 @@ void PromptWidget::historyScroll(int direction) scrollToCurrent(); // Print the text from the history - int idx; - if (_historyLine > 0) - idx = (_historyIndex - _historyLine + _historySize) % _historySize; - else - idx = _historyIndex; + int idx = _historyLine ? (_historyIndex - _historyLine + _historySize) % _historySize + : _historyIndex; - for (int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++) + for(int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++) putcharIntern(_history[idx][i]); - _promptEndPos = _currentPos; // Ensure once more the caret is visible (in case of very long history entries) scrollToCurrent(); - setDirty(); + return line; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -670,8 +708,8 @@ bool PromptWidget::autoComplete(int direction) if(_tabCount != -1) len = int(strlen(_inputStr)); - if(len > 255) - len = 255; + if(len > kLineBufferSize - 1) + len = kLineBufferSize - 1; int lastDelimPos = -1; char delimiter = '\0'; @@ -910,7 +948,6 @@ string PromptWidget::saveBuffer(const FilesystemNode& file) return "unable to save session"; } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::clearScreen() { @@ -923,4 +960,14 @@ void PromptWidget::clearScreen() if(!_firstTime) updateScrollBuffer(); + + resetFunctions(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void PromptWidget::resetFunctions() +{ + // reset special functions + _tabCount = -1; + _historyLine = 0; } diff --git a/src/debugger/gui/PromptWidget.hxx b/src/debugger/gui/PromptWidget.hxx index 12981938c..a7eb16bee 100644 --- a/src/debugger/gui/PromptWidget.hxx +++ b/src/debugger/gui/PromptWidget.hxx @@ -70,14 +70,13 @@ class PromptWidget : public Widget, public CommandSender void killWord(); // Clipboard - void textSelectAll(); string getLine(); void textCut(); void textCopy(); void textPaste(); // History - void historyScroll(int direction); + bool historyScroll(int direction); bool execute(); bool autoComplete(int direction); @@ -94,11 +93,13 @@ class PromptWidget : public Widget, public CommandSender bool wantsFocus() const override { return true; } void loadConfig() override; + void resetFunctions(); + private: enum { - kBufferSize = 32768, + kBufferSize = 32768, kLineBufferSize = 256, - kHistorySize = 20 + kHistorySize = 50 }; int _buffer[kBufferSize]; // NOLINT (will be rewritten soon) @@ -117,19 +118,17 @@ class PromptWidget : public Widget, public CommandSender ScrollBarWidget* _scrollBar; char _history[kHistorySize][kLineBufferSize]; // NOLINT (will be rewritten soon) - int _historySize; - int _historyIndex; - int _historyLine; + int _historySize{0}; + int _historyIndex{0}; + int _historyLine{0}; int _tabCount{-1}; - char _inputStr[256]; + char _inputStr[kLineBufferSize]; int _kConsoleCharWidth, _kConsoleCharHeight, _kConsoleLineHeight; - bool _inverse; - bool _firstTime; - bool _exitedEarly; - -// int compareHistory(const char *histLine); + bool _inverse{false}; + bool _firstTime{true}; + bool _exitedEarly{false}; private: // Following constructors and assignment operators not supported