FakeVim: Block Suggestions

Block suggestions when FakeVim is enabled and the mode
is not "Insert" or "Replace".

Change-Id: I778eb25d9570b76e42652f9d938a8c580033c462
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-04-27 11:03:12 +02:00
parent e46a4eba8d
commit 9f0919c4a3
6 changed files with 84 additions and 26 deletions

View File

@@ -92,7 +92,7 @@ void CopilotClient::openDocument(TextDocument *document)
const int cursorPosition = widget->textCursor().position();
if (cursorPosition < position || cursorPosition > position + charsAdded)
return;
scheduleRequest(textEditor->editorWidget());
scheduleRequest(widget);
});
}

View File

@@ -5197,7 +5197,7 @@ void FakeVimHandler::Private::handleReplaceMode(const Input &input)
moveDown();
} else if (input.isKey(Key_Insert)) {
g.mode = InsertMode;
q->modeChanged();
q->modeChanged(isInsertMode());
} else if (input.isControl('o')) {
enterCommandMode(ReplaceMode);
} else {
@@ -5395,7 +5395,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
removeText(range);
} else if (input.isKey(Key_Insert)) {
g.mode = ReplaceMode;
q->modeChanged();
q->modeChanged(isInsertMode());
} else if (input.isKey(Key_Left)) {
moveLeft();
} else if (input.isShift(Key_Left) || input.isControl(Key_Left)) {
@@ -8578,7 +8578,7 @@ void FakeVimHandler::Private::enterInsertOrReplaceMode(Mode mode)
clearLastInsertion();
}
q->modeChanged();
q->modeChanged(isInsertMode());
}
void FakeVimHandler::Private::enterVisualInsertMode(QChar command)
@@ -8655,7 +8655,7 @@ void FakeVimHandler::Private::enterCommandMode(Mode returnToMode)
m_positionPastEnd = false;
m_anchorPastEnd = false;
q->modeChanged();
q->modeChanged(isInsertMode());
}
void FakeVimHandler::Private::enterExMode(const QString &contents)
@@ -8671,7 +8671,7 @@ void FakeVimHandler::Private::enterExMode(const QString &contents)
g.subsubmode = NoSubSubMode;
unfocus();
q->modeChanged();
q->modeChanged(isInsertMode());
}
void FakeVimHandler::Private::recordJump(int position)

View File

@@ -157,7 +157,7 @@ public:
Signal<void()> completionRequested;
Signal<void()> tabPreviousRequested;
Signal<void()> tabNextRequested;
Signal<void()> modeChanged;
Signal<void(bool insertMode)> modeChanged;
public:
class Private;

View File

@@ -539,7 +539,22 @@ signals:
void delayedQuitAllRequested(bool forced);
public:
QHash<IEditor *, FakeVimHandler *> m_editorToHandler;
struct HandlerAndData
{
#ifdef Q_OS_WIN
// We need to declare a constructor here, otherwise the MSVC 17.5.x compiler fails to parse
// the "{nullptr}" initializer in the definition below.
// This seems to be a compiler bug,
// see: https://developercommunity.visualstudio.com/t/10351118
HandlerAndData()
: handler(nullptr)
{}
#endif
FakeVimHandler *handler{nullptr};
TextEditorWidget::SuggestionBlocker suggestionBlocker;
};
QHash<IEditor *, HandlerAndData> m_editorToHandler;
void setActionChecked(Id id, bool check);
@@ -1253,7 +1268,7 @@ void FakeVimPluginPrivate::initialize()
void FakeVimPluginPrivate::userActionTriggered(int key)
{
IEditor *editor = EditorManager::currentEditor();
FakeVimHandler *handler = m_editorToHandler[editor];
FakeVimHandler *handler = m_editorToHandler[editor].handler;
if (handler) {
// If disabled, enable FakeVim mode just for single user command.
bool enableFakeVim = !fakeVimSettings()->useFakeVim.value();
@@ -1569,14 +1584,14 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
// the handler might have triggered the deletion of the editor:
// make sure that it can return before being deleted itself
new DeferredDeleter(widget, handler);
m_editorToHandler[editor] = handler;
m_editorToHandler[editor].handler = handler;
handler->extraInformationChanged.connect([this](const QString &text) {
EditorManager::splitSideBySide();
QString title = "stdout.txt";
IEditor *iedit = EditorManager::openEditorWithContents(Id(), &title, text.toUtf8());
EditorManager::activateEditor(iedit);
FakeVimHandler *handler = m_editorToHandler.value(iedit, nullptr);
FakeVimHandler *handler = m_editorToHandler.value(iedit, {}).handler;
QTC_ASSERT(handler, return);
handler->handleCommand("0");
});
@@ -1591,7 +1606,13 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
tew->setExtraSelections(TextEditorWidget::FakeVimSelection, selection);
});
handler->modeChanged.connect([tew]() {
handler->modeChanged.connect([tew, this, editor](bool insertMode) {
HandlerAndData &handlerAndData = m_editorToHandler[editor];
// We don't want to show suggestions unless we are in insert mode.
if (insertMode != (handlerAndData.suggestionBlocker == nullptr))
handlerAndData.suggestionBlocker = insertMode ? nullptr : tew->blockSuggestions();
if (tew)
tew->clearSuggestion();
});
@@ -1840,7 +1861,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
handler->requestJumpToGlobalMark.connect(
[this](QChar mark, bool backTickMode, const QString &fileName) {
if (IEditor *iedit = EditorManager::openEditor(FilePath::fromString(fileName))) {
if (FakeVimHandler *handler = m_editorToHandler.value(iedit, nullptr))
if (FakeVimHandler *handler = m_editorToHandler.value(iedit, {}).handler)
handler->jumpToLocalMark(mark, backTickMode);
}
});
@@ -1887,7 +1908,7 @@ void FakeVimPluginPrivate::editorAboutToClose(IEditor *editor)
void FakeVimPluginPrivate::currentEditorAboutToChange(IEditor *editor)
{
if (FakeVimHandler *handler = m_editorToHandler.value(editor, 0))
if (FakeVimHandler *handler = m_editorToHandler.value(editor, {}).handler)
handler->enterCommandMode();
}
@@ -1905,9 +1926,9 @@ void FakeVimPluginPrivate::documentRenamed(
void FakeVimPluginPrivate::renameFileNameInEditors(const FilePath &oldPath, const FilePath &newPath)
{
for (FakeVimHandler *handler : m_editorToHandler) {
if (handler->currentFileName() == oldPath.toString())
handler->setCurrentFileName(newPath.toString());
for (const HandlerAndData &handlerAndData : m_editorToHandler) {
if (handlerAndData.handler->currentFileName() == oldPath.toString())
handlerAndData.handler->setCurrentFileName(newPath.toString());
}
}
@@ -1926,16 +1947,19 @@ void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
//ICore *core = ICore::instance();
//core->updateAdditionalContexts(Context(FAKEVIM_CONTEXT),
// Context());
for (FakeVimHandler *handler : m_editorToHandler)
handler->setupWidget();
for (const HandlerAndData &handlerAndData : m_editorToHandler)
handlerAndData.handler->setupWidget();
} else {
//ICore *core = ICore::instance();
//core->updateAdditionalContexts(Context(),
// Context(FAKEVIM_CONTEXT));
resetCommandBuffer();
for (auto it = m_editorToHandler.constBegin(); it != m_editorToHandler.constEnd(); ++it) {
if (auto textDocument = qobject_cast<const TextDocument *>(it.key()->document()))
it.value()->restoreWidget(textDocument->tabSettings().m_tabSize);
for (auto it = m_editorToHandler.begin(); it != m_editorToHandler.end(); ++it) {
if (auto textDocument = qobject_cast<const TextDocument *>(it.key()->document())) {
HandlerAndData &handlerAndData = it.value();
handlerAndData.handler->restoreWidget(textDocument->tabSettings().m_tabSize);
handlerAndData.suggestionBlocker.reset();
}
}
}
}
@@ -1970,11 +1994,22 @@ void FakeVimPluginPrivate::handleExCommand(FakeVimHandler *handler, bool *handle
if (editor)
editor->setFocus();
auto editorFromHandler = [this, handler]() -> Core::IEditor * {
auto itEditor = std::find_if(m_editorToHandler.cbegin(),
m_editorToHandler.cend(),
[handler](const HandlerAndData &handlerAndData) {
return handlerAndData.handler == handler;
});
if (itEditor != m_editorToHandler.cend())
return itEditor.key();
return nullptr;
};
*handled = true;
if ((cmd.matches("w", "write") || cmd.cmd == "wq") && cmd.args.isEmpty()) {
// :w[rite]
bool saved = false;
IEditor *editor = m_editorToHandler.key(handler);
IEditor *editor = editorFromHandler();
const QString fileName = handler->currentFileName();
if (editor && editor->document()->filePath().toString() == fileName) {
triggerAction(Core::Constants::SAVE);
@@ -1986,7 +2021,7 @@ void FakeVimPluginPrivate::handleExCommand(FakeVimHandler *handler, bool *handle
handler->showMessage(MessageInfo, Tr::tr("\"%1\" %2 %3L, %4C written")
.arg(fileName).arg(' ').arg(ba.count('\n')).arg(ba.size()));
if (cmd.cmd == "wq")
emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
emit delayedQuitRequested(cmd.hasBang, editor);
}
}
}
@@ -2005,7 +2040,7 @@ void FakeVimPluginPrivate::handleExCommand(FakeVimHandler *handler, bool *handle
emit delayedQuitAllRequested(cmd.hasBang);
} else if (cmd.matches("q", "quit")) {
// :q[uit]
emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
emit delayedQuitRequested(cmd.hasBang, editorFromHandler());
} else if (cmd.matches("qa", "qall")) {
// :qa[ll]
emit delayedQuitAllRequested(cmd.hasBang);
@@ -2167,7 +2202,7 @@ void FakeVimPlugin::setupTest(QString *title, FakeVimHandler **handler, QWidget
IEditor *iedit = EditorManager::openEditorWithContents(Id(), title);
EditorManager::activateEditor(iedit);
*edit = iedit->widget();
*handler = dd->m_editorToHandler.value(iedit, 0);
*handler = dd->m_editorToHandler.value(iedit, {}).handler;
(*handler)->setupWidget();
(*handler)->handleCommand("set startofline");

View File

@@ -657,6 +657,7 @@ public:
uint m_optionalActionMask = TextEditorActionHandler::None;
bool m_contentsChanged = false;
bool m_lastCursorChangeWasInteresting = false;
std::shared_ptr<void> m_suggestionBlocker;
QSharedPointer<TextDocument> m_document;
QList<QMetaObject::Connection> m_documentConnections;
@@ -905,6 +906,7 @@ void TextEditorWidgetFind::cancelCurrentSelectAll()
TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent)
: q(parent)
, m_suggestionBlocker((void *) this, [](void *) {})
, m_overlay(new TextEditorOverlay(q))
, m_snippetOverlay(new SnippetOverlay(q))
, m_searchResultOverlay(new TextEditorOverlay(q))
@@ -1654,6 +1656,10 @@ void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperatio
void TextEditorWidgetPrivate::insertSuggestion(std::unique_ptr<TextSuggestion> &&suggestion)
{
clearCurrentSuggestion();
if (m_suggestionBlocker.use_count() > 1)
return;
auto cursor = q->textCursor();
cursor.setPosition(suggestion->position());
m_suggestionBlock = cursor.block();
@@ -6017,6 +6023,18 @@ bool TextEditorWidget::suggestionVisible() const
return currentSuggestion();
}
bool TextEditorWidget::suggestionsBlocked() const
{
return d->m_suggestionBlocker.use_count() > 1;
}
TextEditorWidget::SuggestionBlocker TextEditorWidget::blockSuggestions()
{
if (!suggestionsBlocked())
clearSuggestion();
return d->m_suggestionBlocker;
}
#ifdef WITH_TESTS
void TextEditorWidget::processTooltipRequest(const QTextCursor &c)
{

View File

@@ -475,6 +475,11 @@ public:
void clearSuggestion();
TextSuggestion *currentSuggestion() const;
bool suggestionVisible() const;
bool suggestionsBlocked() const;
using SuggestionBlocker = std::shared_ptr<void>;
// Returns an object that blocks suggestions until it is destroyed.
SuggestionBlocker blockSuggestions();
#ifdef WITH_TESTS
void processTooltipRequest(const QTextCursor &c);