From 015d12ccf317443576c286ef87c09ddb01e4d34c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 27 Apr 2023 12:18:07 +0200 Subject: [PATCH] FakeVim: Accept suggestion with Tab Key * Changed signals to callbacks as only one receiver was ever added * Added "tabPressedInInsertMode" callback to allow accepting a suggestion with the Tab Key Fixes: QTCREATORBUG-28830 Change-Id: Ie70ba595b8802b6100fff495164d8e0471b1354c Reviewed-by: hjk --- src/plugins/fakevim/fakevimhandler.cpp | 20 +++--- src/plugins/fakevim/fakevimhandler.h | 85 ++++++++++++++------------ src/plugins/fakevim/fakevimplugin.cpp | 72 +++++++++++----------- tests/manual/fakevim/main.cpp | 15 +++-- 4 files changed, 103 insertions(+), 89 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 05ea400bbba..bd1e035f48a 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -5459,16 +5459,18 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input) } else if (input.isKey(Key_PageUp) || input.isControl('b')) { movePageUp(); } else if (input.isKey(Key_Tab)) { - m_buffer->insertState.insertingSpaces = true; - if (s.expandTab.value()) { - const int ts = s.tabStop.value(); - const int col = logicalCursorColumn(); - QString str = QString(ts - col % ts, ' '); - insertText(str); - } else { - insertInInsertMode(input.raw()); + if (q->tabPressedInInsertMode()) { + m_buffer->insertState.insertingSpaces = true; + if (s.expandTab.value()) { + const int ts = s.tabStop.value(); + const int col = logicalCursorColumn(); + QString str = QString(ts - col % ts, ' '); + insertText(str); + } else { + insertInInsertMode(input.raw()); + } + m_buffer->insertState.insertingSpaces = false; } - m_buffer->insertState.insertingSpaces = false; } else if (input.isControl('d')) { // remove one level of indentation from the current line const int shift = s.shiftWidth.value(); diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index 30ee5599ef8..b19e2579092 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -61,23 +61,30 @@ enum MessageLevel MessageShowCmd // partial command }; -template -class Signal +template +class Callback; + +template +class Callback { public: - using Callable = std::function; + static constexpr auto IsVoidReturnType = std::is_same_v; + using Function = std::function; + void set(const Function &callable) { m_callable = callable; } - void connect(const Callable &callable) { m_callables.push_back(callable); } - - template - void operator()(Args ...args) const + R operator()(Params... params) { - for (const Callable &callable : m_callables) - callable(args...); - } + if (!m_callable) + return R(); + + if constexpr (IsVoidReturnType) + m_callable(std::forward(params)...); + else + return m_callable(std::forward(params)...); + } private: - std::vector m_callables; + Function m_callable; }; class FakeVimHandler : public QObject @@ -131,33 +138,35 @@ public: bool eventFilter(QObject *ob, QEvent *ev) override; - Signal commandBufferChanged; - Signal statusDataChanged; - Signal extraInformationChanged; - Signal &selection)> selectionChanged; - Signal highlightMatches; - Signal moveToMatchingParenthesis; - Signal checkForElectricCharacter; - Signal indentRegion; - Signal simpleCompletionRequested; - Signal windowCommandRequested; - Signal findRequested; - Signal findNextRequested; - Signal handleExCommandRequested; - Signal requestDisableBlockSelection; - Signal requestSetBlockSelection; - Signal requestBlockSelection; - Signal requestHasBlockSelection; - Signal foldToggle; - Signal foldAll; - Signal fold; - Signal foldGoTo; - Signal requestJumpToLocalMark; - Signal requestJumpToGlobalMark; - Signal completionRequested; - Signal tabPreviousRequested; - Signal tabNextRequested; - Signal modeChanged; + Callback + commandBufferChanged; + Callback statusDataChanged; + Callback extraInformationChanged; + Callback &selection)> selectionChanged; + Callback highlightMatches; + Callback moveToMatchingParenthesis; + Callback checkForElectricCharacter; + Callback indentRegion; + Callback simpleCompletionRequested; + Callback windowCommandRequested; + Callback findRequested; + Callback findNextRequested; + Callback handleExCommandRequested; + Callback requestDisableBlockSelection; + Callback requestSetBlockSelection; + Callback requestBlockSelection; + Callback requestHasBlockSelection; + Callback foldToggle; + Callback foldAll; + Callback fold; + Callback foldGoTo; + Callback requestJumpToLocalMark; + Callback requestJumpToGlobalMark; + Callback completionRequested; + Callback tabPreviousRequested; + Callback tabNextRequested; + Callback modeChanged; + Callback tabPressedInInsertMode; public: class Private; diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index e41d83be2c0..d0c399ac31b 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1586,7 +1586,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) new DeferredDeleter(widget, handler); m_editorToHandler[editor].handler = handler; - handler->extraInformationChanged.connect([this](const QString &text) { + handler->extraInformationChanged.set([this](const QString &text) { EditorManager::splitSideBySide(); QString title = "stdout.txt"; IEditor *iedit = EditorManager::openEditorWithContents(Id(), &title, text.toUtf8()); @@ -1596,17 +1596,27 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) handler->handleCommand("0"); }); - handler->commandBufferChanged - .connect([this, handler](const QString &contents, int cursorPos, int anchorPos, int messageLevel) { - showCommandBuffer(handler, contents, cursorPos, anchorPos, messageLevel); - }); + handler->commandBufferChanged.set( + [this, handler](const QString &contents, int cursorPos, int anchorPos, int messageLevel) { + showCommandBuffer(handler, contents, cursorPos, anchorPos, messageLevel); + }); - handler->selectionChanged.connect([tew](const QList &selection) { + handler->selectionChanged.set([tew](const QList &selection) { if (tew) tew->setExtraSelections(TextEditorWidget::FakeVimSelection, selection); }); - handler->modeChanged.connect([tew, this, editor](bool insertMode) { + handler->tabPressedInInsertMode.set([tew]() { + auto suggestion = tew->currentSuggestion(); + if (suggestion) { + suggestion->apply(); + return false; + } + + return true; + }); + + handler->modeChanged.set([tew, this, editor](bool insertMode) { HandlerAndData &handlerAndData = m_editorToHandler[editor]; // We don't want to show suggestions unless we are in insert mode. @@ -1617,7 +1627,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) tew->clearSuggestion(); }); - handler->highlightMatches.connect([](const QString &needle) { + handler->highlightMatches.set([](const QString &needle) { for (IEditor *editor : EditorManager::visibleEditors()) { QWidget *w = editor->widget(); if (auto find = Aggregation::query(w)) @@ -1625,7 +1635,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->moveToMatchingParenthesis.connect([](bool *moved, bool *forward, QTextCursor *cursor) { + handler->moveToMatchingParenthesis.set([](bool *moved, bool *forward, QTextCursor *cursor) { *moved = false; bool undoFakeEOL = false; @@ -1658,7 +1668,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->indentRegion.connect([tew](int beginBlock, int endBlock, QChar typedChar) { + handler->indentRegion.set([tew](int beginBlock, int endBlock, QChar typedChar) { if (!tew) return; @@ -1691,17 +1701,17 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->checkForElectricCharacter.connect([tew](bool *result, QChar c) { + handler->checkForElectricCharacter.set([tew](bool *result, QChar c) { if (tew) *result = tew->textDocument()->indenter()->isElectricCharacter(c); }); - handler->requestDisableBlockSelection.connect([tew] { + handler->requestDisableBlockSelection.set([tew] { if (tew) tew->setTextCursor(tew->textCursor()); }); - handler->requestSetBlockSelection.connect([tew](const QTextCursor &cursor) { + handler->requestSetBlockSelection.set([tew](const QTextCursor &cursor) { if (tew) { const TabSettings &tabs = tew->textDocument()->tabSettings(); MultiTextCursor mtc; @@ -1725,7 +1735,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->requestBlockSelection.connect([tew](QTextCursor *cursor) { + handler->requestBlockSelection.set([tew](QTextCursor *cursor) { if (tew && cursor) { MultiTextCursor mtc = tew->multiTextCursor(); *cursor = mtc.cursors().first(); @@ -1733,16 +1743,16 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->requestHasBlockSelection.connect([tew](bool *on) { + handler->requestHasBlockSelection.set([tew](bool *on) { if (tew && on) *on = tew->multiTextCursor().hasMultipleCursors(); }); - handler->simpleCompletionRequested.connect([this, handler](const QString &needle, bool forward) { + handler->simpleCompletionRequested.set([this, handler](const QString &needle, bool forward) { runData->wordProvider.setActive(needle, forward, handler); }); - handler->windowCommandRequested.connect([this, handler](const QString &map, int count) { + handler->windowCommandRequested.set([this, handler](const QString &map, int count) { // normalize mapping const QString key = map.toUpper(); @@ -1772,22 +1782,22 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) qDebug() << "UNKNOWN WINDOW COMMAND: " << map; }); - handler->findRequested.connect([](bool reverse) { + handler->findRequested.set([](bool reverse) { Find::setUseFakeVim(true); Find::openFindToolBar(reverse ? Find::FindBackwardDirection : Find::FindForwardDirection); }); - handler->findNextRequested.connect([](bool reverse) { + handler->findNextRequested.set([](bool reverse) { triggerAction(reverse ? Core::Constants::FIND_PREVIOUS : Core::Constants::FIND_NEXT); }); - handler->foldToggle.connect([this, handler](int depth) { + handler->foldToggle.set([this, handler](int depth) { QTextBlock block = handler->textCursor().block(); fold(handler, depth, !TextDocumentLayout::isFolded(block)); }); - handler->foldAll.connect([handler](bool fold) { + handler->foldAll.set([handler](bool fold) { QTextDocument *document = handler->textCursor().document(); auto documentLayout = qobject_cast(document->documentLayout()); QTC_ASSERT(documentLayout, return); @@ -1802,11 +1812,9 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) documentLayout->emitDocumentSizeChanged(); }); - handler->fold.connect([this, handler](int depth, bool dofold) { - fold(handler, depth, dofold); - }); + handler->fold.set([this, handler](int depth, bool dofold) { fold(handler, depth, dofold); }); - handler->foldGoTo.connect([handler](int count, bool current) { + handler->foldGoTo.set([handler](int count, bool current) { QTextCursor tc = handler->textCursor(); QTextBlock block = tc.block(); @@ -1858,7 +1866,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->requestJumpToGlobalMark.connect( + handler->requestJumpToGlobalMark.set( [this](QChar mark, bool backTickMode, const QString &fileName) { if (IEditor *iedit = EditorManager::openEditor(FilePath::fromString(fileName))) { if (FakeVimHandler *handler = m_editorToHandler.value(iedit, {}).handler) @@ -1866,19 +1874,15 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) } }); - handler->handleExCommandRequested.connect([this, handler](bool *handled, const ExCommand &cmd) { + handler->handleExCommandRequested.set([this, handler](bool *handled, const ExCommand &cmd) { handleExCommand(handler, handled, cmd); }); - handler->tabNextRequested.connect([] { - triggerAction(Core::Constants::GOTONEXTINHISTORY); - }); + handler->tabNextRequested.set([] { triggerAction(Core::Constants::GOTONEXTINHISTORY); }); - handler->tabPreviousRequested.connect([] { - triggerAction(Core::Constants::GOTOPREVINHISTORY); - }); + handler->tabPreviousRequested.set([] { triggerAction(Core::Constants::GOTOPREVINHISTORY); }); - handler->completionRequested.connect([this, tew] { + handler->completionRequested.set([this, tew] { if (tew) tew->invokeAssist(Completion, &runData->wordProvider); }); diff --git a/tests/manual/fakevim/main.cpp b/tests/manual/fakevim/main.cpp index c733dd63198..288c244e43c 100644 --- a/tests/manual/fakevim/main.cpp +++ b/tests/manual/fakevim/main.cpp @@ -187,12 +187,12 @@ int main(int argc, char *argv[]) // Create FakeVimHandler instance which will emulate Vim behavior in editor widget. FakeVimHandler handler(editor, nullptr); - handler.commandBufferChanged.connect([&](const QString &msg, int cursorPos, int, int) { + handler.commandBufferChanged.set([&](const QString &msg, int cursorPos, int, int) { statusData.setStatusMessage(msg, cursorPos); mainWindow.statusBar()->showMessage(statusData.currentStatusLine()); }); - handler.selectionChanged.connect([&handler](const QList &s) { + handler.selectionChanged.set([&handler](const QList &s) { QWidget *widget = handler.widget(); if (auto ed = qobject_cast(widget)) ed->setExtraSelections(s); @@ -200,21 +200,20 @@ int main(int argc, char *argv[]) ed->setExtraSelections(s); }); - handler.extraInformationChanged.connect([&](const QString &info) { + handler.extraInformationChanged.set([&](const QString &info) { statusData.setStatusInfo(info); mainWindow.statusBar()->showMessage(statusData.currentStatusLine()); }); - handler.statusDataChanged.connect([&](const QString &info) { + handler.statusDataChanged.set([&](const QString &info) { statusData.setStatusInfo(info); mainWindow.statusBar()->showMessage(statusData.currentStatusLine()); }); - handler.highlightMatches.connect([&](const QString &needle) { - highlightMatches(handler.widget(), needle); - }); + handler.highlightMatches.set( + [&](const QString &needle) { highlightMatches(handler.widget(), needle); }); - handler.handleExCommandRequested.connect([](bool *handled, const ExCommand &cmd) { + handler.handleExCommandRequested.set([](bool *handled, const ExCommand &cmd) { if (cmd.matches("q", "quit") || cmd.matches("qa", "qall")) { QApplication::quit(); *handled = true;