From f302f3b8c27c940daf1a8532606edd0d5f16cf75 Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: Sat, 10 Nov 2012 10:36:05 +0100 Subject: [PATCH] fakevim: to execute single command and return to insert mode After Ctrl+O combination in insert or replace mode enter command mode and after a single command (can consist of entering Ex command or can be switch to other buffer) or escape key return to previous insert or replace mode. One exception is that if entering insert mode is part of the command after pressing escape key will exit to command mode (Vim behavior). Change-Id: I37d684b691157001e2cab156687d6771afdec7b9 Reviewed-by: hjk --- src/plugins/fakevim/fakevim_test.cpp | 21 ++++- src/plugins/fakevim/fakevimhandler.cpp | 110 +++++++++++++++++-------- 2 files changed, 94 insertions(+), 37 deletions(-) diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index 43f70570410..a44f630f370 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -217,6 +217,7 @@ struct FakeVimPlugin::TestData void FakeVimPlugin::setup(TestData *data) { setupTest(&data->title, &data->handler, &data->edit); + data->handler->handleInput("gg"); } @@ -426,6 +427,24 @@ void FakeVimPlugin::test_vim_insert() data.setText("abc" N "def"); KEYS("3O 123", " 123" N " 123" N " 12" X "3" N "abc" N "def"); INTEGRITY(false); + + // + data.setText("abc" N "d" X "ef"); + KEYS("ixX", "abc" N "dX" X "f"); + KEYS("i", "abc" N "dXf" X); + data.setText("ab" X "c" N "def"); + KEYS("irX", "ab" X "X" N "def"); + data.setText("abc" N "def"); + KEYS("Ax", "ab" X N "def"); + data.setText("abc" N "de" X "f"); + KEYS("i0x", "abc" N "x" X "def"); + data.setText("abc" N "de" X "f"); + KEYS("iggx", "x" X "abc" N "def"); + + // to toggle between insert and replace mode + data.setText("abc" N "def"); + KEYS("XYZxyz", "XYZxy" X "z" N "def"); + KEYS("" "0j" "XYZ", "XYZxyz" N "XYZ" X "f"); } void FakeVimPlugin::test_vim_fFtT() @@ -1821,8 +1840,6 @@ void FakeVimPlugin::test_map() KEYS("Y", X "abc" N "def"); data.doCommand("unmap X|unmap Y"); - - NOT_IMPLEMENTED // data.setText("abc def"); data.doCommand("imap X :%s/def/xxx/"); diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 1f8d779f8c0..3bce0e8b9a5 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1341,6 +1341,8 @@ public: friend class FakeVimHandler; void init(); + void focus(); + EventResult handleKey(const Input &input); EventResult handleDefaultKey(const Input &input); void handleMappedKeys(); @@ -1532,7 +1534,7 @@ public: void enterInsertMode(); void enterReplaceMode(); - void enterCommandMode(); + void enterCommandMode(Mode returnToMode = CommandMode); void enterExMode(const QString &contents = QString()); void showMessage(MessageLevel level, const QString &msg); void clearMessage() { showMessage(MessageInfo, QString()); } @@ -1761,7 +1763,7 @@ public: { GlobalData() : mappings(), currentMap(&mappings), inputTimer(-1), currentMessageLevel(MessageInfo), - lastSearchForward(false), findPending(false) + lastSearchForward(false), findPending(false), returnToMode(CommandMode) { // default mapping state - shouldn't be removed mapStates << MappingState(); @@ -1803,6 +1805,9 @@ public: // Global marks. Marks marks; + + // Return to insert/replace mode after single command (). + Mode returnToMode; } g; }; @@ -1854,6 +1859,17 @@ void FakeVimHandler::Private::init() setupCharClass(); } +void FakeVimHandler::Private::focus() +{ + stopIncrementalFind(); + if (g.returnToMode != CommandMode && g.currentCommand.isEmpty() && m_mode != ExMode) { + // Return to insert mode. + resetCommandMode(); + updateMiniBuffer(); + updateCursorShape(); + } +} + bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev) { const int key = ev->key(); @@ -1867,7 +1883,8 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev) if (isNoVisualMode() && m_mode == CommandMode && m_submode == NoSubMode - && g.currentCommand.isEmpty()) + && g.currentCommand.isEmpty() + && g.returnToMode == CommandMode) return false; return true; } @@ -2009,7 +2026,7 @@ void FakeVimHandler::Private::installEventFilter() void FakeVimHandler::Private::setupWidget() { - enterCommandMode(); + resetCommandMode(); if (m_textedit) { m_textedit->setLineWrapMode(QTextEdit::NoWrap); } else if (m_plaintextedit) { @@ -2325,8 +2342,9 @@ void FakeVimHandler::Private::updateFind(bool isComplete) g.currentMessage.clear(); + const QString &needle = g.searchBuffer.contents(); SearchData sd; - sd.needle = g.searchBuffer.contents(); + sd.needle = needle; sd.forward = g.lastSearchForward; sd.highlightMatches = isComplete; if (isComplete) { @@ -2573,7 +2591,8 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) if (m_movetype == MoveLineWise) insertAutomaticIndentation(true); endEditBlock(); - enterInsertMode(); + setTargetColumn(); + g.returnToMode = InsertMode; } else if (m_submode == DeleteSubMode) { setUndoPosition(); removeText(currentRange()); @@ -2643,6 +2662,13 @@ void FakeVimHandler::Private::resetCommandMode() if (isNoVisualMode()) setAnchor(); g.currentCommand.clear(); + if (g.returnToMode != CommandMode) { + if (g.returnToMode == InsertMode) + enterInsertMode(); + else + enterReplaceMode(); + moveToTargetColumn(); + } } void FakeVimHandler::Private::updateSelection() @@ -2718,7 +2744,12 @@ void FakeVimHandler::Private::updateMiniBuffer() msg = "REPLACE"; } else { QTC_CHECK(m_mode == CommandMode && m_subsubmode != SearchSubSubMode); - msg = "COMMAND"; + if (g.returnToMode == CommandMode) + msg = "COMMAND"; + else if (g.returnToMode == InsertMode) + msg = "(insert)"; + else + msg = "(replace)"; } emit q->commandBufferChanged(msg, cursorPos, messageLevel, q); @@ -3261,7 +3292,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input) QString savedCommand = g.dotCommand; g.dotCommand.clear(); replay(savedCommand); - enterCommandMode(); + resetCommandMode(); g.dotCommand = savedCommand; } else if (input.is('<') || input.is('>') || input.is('=')) { if (isNoVisualMode()) { @@ -3876,10 +3907,7 @@ EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input) if (input.isEscape()) { moveLeft(qMin(1, leftDist())); setTargetColumn(); - m_submode = NoSubMode; - m_mode = CommandMode; - finishMovement(); - updateMiniBuffer(); + enterCommandMode(); } else if (input.isKey(Key_Left)) { breakEditBlock(); moveLeft(1); @@ -3895,6 +3923,10 @@ EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input) } else if (input.isKey(Key_Down)) { breakEditBlock(); moveDown(1); + } else if (input.isKey(Key_Insert)) { + m_mode = InsertMode; + } else if (input.isControl('o')) { + enterCommandMode(ReplaceMode); } else { joinPreviousEditBlock(); if (!atEndOfLine()) { @@ -3910,6 +3942,8 @@ EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input) endEditBlock(); setTargetColumn(); } + updateMiniBuffer(); + return EventHandled; } @@ -3960,12 +3994,13 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) g.dotCommand += m_lastInsertion; g.dotCommand += QChar(27); enterCommandMode(); - m_submode = NoSubMode; m_ctrlVActive = false; m_opcount.clear(); m_mvcount.clear(); } else if (m_ctrlVActive) { insertInInsertMode(input.raw()); + } else if (input.isControl('o')) { + enterCommandMode(InsertMode); } else if (input.isControl('v')) { m_ctrlVActive = true; } else if (input.isControl('w')) { @@ -3976,10 +4011,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) Range range(beginPos, endPos, RangeCharMode); removeText(range); } else if (input.isKey(Key_Insert)) { - if (m_mode == ReplaceMode) - m_mode = InsertMode; - else - m_mode = ReplaceMode; + m_mode = ReplaceMode; } else if (input.isKey(Key_Left)) { moveLeft(count()); setTargetColumn(); @@ -4145,7 +4177,8 @@ EventResult FakeVimHandler::Private::handleExMode(const Input &input) { if (input.isEscape()) { g.commandBuffer.clear(); - enterCommandMode(); + enterCommandMode(g.returnToMode); + resetCommandMode(); m_ctrlVActive = false; } else if (m_ctrlVActive) { g.commandBuffer.insertChar(input.raw()); @@ -4154,10 +4187,12 @@ EventResult FakeVimHandler::Private::handleExMode(const Input &input) m_ctrlVActive = true; return EventHandled; } else if (input.isBackspace()) { - if (g.commandBuffer.isEmpty()) - enterCommandMode(); - else + if (g.commandBuffer.isEmpty()) { + enterCommandMode(g.returnToMode); + resetCommandMode(); + } else { g.commandBuffer.deleteChar(); + } } else if (input.isKey(Key_Tab)) { // FIXME: Complete actual commands. g.commandBuffer.historyUp(); @@ -4190,10 +4225,11 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input) g.searchBuffer.clear(); setAnchorAndPosition(m_searchStartPosition, m_searchStartPosition); scrollToLine(m_searchFromScreenLine); - enterCommandMode(); + enterCommandMode(g.returnToMode); + resetCommandMode(); } else if (input.isBackspace()) { if (g.searchBuffer.isEmpty()) { - enterCommandMode(); + resetCommandMode(); } else { g.searchBuffer.deleteChar(); } @@ -4217,7 +4253,8 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input) showMessage(MessageCommand, g.searchBuffer.display()); else handled = EventCancelled; - enterCommandMode(); + enterCommandMode(g.returnToMode); + resetCommandMode(); g.searchBuffer.clear(); } else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) { g.searchBuffer.historyUp(); @@ -5122,7 +5159,7 @@ void FakeVimHandler::Private::handleExCommand(const QString &line0) //qDebug() << "CMD: " << cmd; - enterCommandMode(); + enterCommandMode(g.returnToMode); beginLargeEditBlock(); ExCommand cmd; @@ -5135,6 +5172,8 @@ void FakeVimHandler::Private::handleExCommand(const QString &line0) lastCommand = line; } endEditBlock(); + + resetCommandMode(); } bool FakeVimHandler::Private::handleExCommandHelper(ExCommand &cmd) @@ -5420,17 +5459,14 @@ void FakeVimHandler::Private::moveToTargetColumn() const QTextBlock &bl = block(); //Column column = cursorColumn(); //int logical = logical - const int maxcol = bl.length() - 2; + const int pos = lastPositionInLine(bl.blockNumber() + 1, false); if (m_targetColumn == -1) { - setPosition(bl.position() + qMax(0, maxcol)); + setPosition(pos); return; } - const int physical = logicalToPhysicalColumn(m_targetColumn, bl.text()); + const int physical = bl.position() + logicalToPhysicalColumn(m_targetColumn, bl.text()); //qDebug() << "CORRECTING COLUMN FROM: " << logical << "TO" << m_targetColumn; - if (physical >= maxcol) - setPosition(bl.position() + qMax(0, maxcol)); - else - setPosition(bl.position() + physical); + setPosition(qMin(pos, physical)); } /* if simple is given: @@ -6463,6 +6499,7 @@ void FakeVimHandler::Private::enterReplaceMode() m_subsubmode = NoSubSubMode; m_lastInsertion.clear(); m_lastDeletion.clear(); + g.returnToMode = ReplaceMode; } void FakeVimHandler::Private::enterInsertMode() @@ -6472,15 +6509,17 @@ void FakeVimHandler::Private::enterInsertMode() m_subsubmode = NoSubSubMode; m_lastInsertion.clear(); m_lastDeletion.clear(); + g.returnToMode = InsertMode; } -void FakeVimHandler::Private::enterCommandMode() +void FakeVimHandler::Private::enterCommandMode(Mode returnToMode) { if (atEndOfLine()) moveLeft(); m_mode = CommandMode; m_submode = NoSubMode; m_subsubmode = NoSubSubMode; + g.returnToMode = returnToMode; } void FakeVimHandler::Private::enterExMode(const QString &contents) @@ -7012,7 +7051,8 @@ bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev) return res == EventHandled || res == EventCancelled; } - if (active && ev->type() == QEvent::KeyPress) { + if (active && ev->type() == QEvent::KeyPress && + (ob == d->editor() || (d->m_mode == ExMode || d->m_subsubmode == SearchSubSubMode))) { QKeyEvent *kev = static_cast(ev); KEY_DEBUG("KEYPRESS" << kev->key() << kev->text() << QChar(kev->key())); EventResult res = d->handleEvent(kev); @@ -7037,7 +7077,7 @@ bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev) } if (active && ev->type() == QEvent::FocusIn && ob == d->editor()) { - d->stopIncrementalFind(); + d->focus(); } return QObject::eventFilter(ob, ev);