diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index 2ea7fec5b8a..94fff499b33 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -2948,3 +2948,357 @@ void FakeVimPlugin::test_macros() KEYS("gg@x", "abc" N X "def"); data.doCommand("unmap "); } + +void FakeVimPlugin::test_vim_qtcreator() +{ + TestData data; + setup(&data); + + // Pass input keys in insert mode to underlying editor widget. + data.doCommand("set passkeys"); + + data.setText("" N ""); + KEYS("i" "void f(int arg1) {// TODO;", + "void f(int arg1) {" N + " // TODO" N + " ;" X N + "}" N + ""); + KEYS("cc" "assert(arg1 != 0", + "void f(int arg1) {" N + " // TODO" N + " assert(arg1 != 0" X ")" N + "}" N + ""); + KEYS("k" "." "A;", + "void f(int arg1) {" N + " assert(arg1 != 0);" X N + " assert(arg1 != 0)" N + "}" N + ""); + KEYS("j.", + "void f(int arg1) {" N + " assert(arg1 != 0);" N + " assert(arg1 != 0)" X ";" N + "}" N + ""); + KEYS("4b2#", + "void f(int " X "arg1) {" N + " assert(arg1 != 0);" N + " assert(arg1 != 0);" N + "}" N + ""); + KEYS("e" "a, int arg2 = 0" "n", + "void f(int " X "arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(arg1 != 0);" N + "}" N + ""); + + // Record macro. + KEYS("2j" "qa" "" "f!" "2s>=" "q", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(arg2 >" X "= 0);" N + "}" N + ""); + // Replay macro. + KEYS("n" "@a", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg2 >" X "= 0);" N + " assert(arg2 >= 0);" N + "}" N + ""); + + // Undo. + KEYS("u", + "void f(int arg1, int arg2 = 0) {" N + " assert(" X "arg1 != 0);" N + " assert(arg2 >= 0);" N + "}" N + ""); + KEYS("u", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(arg2 " X "!= 0);" N + "}" N + ""); + KEYS("u", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(" X "arg1 != 0);" N + "}" N + ""); + KEYS("u", + "void f(int arg1" X ") {" N + " assert(arg1 != 0);" N + " assert(arg1 != 0);" N + "}" N + ""); + KEYS("u", + "void f(int arg1) {" N + " assert(arg1 != 0);" N + " assert(arg1 != 0" X ")" N + "}" N + ""); + KEYS("u", + "void f(int arg1) {" N + " assert(arg1 != 0" X ")" N + " assert(arg1 != 0)" N + "}" N + ""); + KEYS("u", + "void f(int arg1) {" N + " " X "// TODO" N + " assert(arg1 != 0)" N + "}" N + ""); + KEYS("u", + "void f(int arg1) {" N + " // TODO" N + " " X ";" N + "}" N + ""); + + // Redo and occasional undo. + KEYS("", + "void f(int arg1) {" N + " // TODO" N + " " X "assert(arg1 != 0)" N + "}" N + ""); + KEYS("", + "void f(int arg1) {" N + " " X "assert(arg1 != 0)" N + " assert(arg1 != 0)" N + "}" N + ""); + KEYS("", + "void f(int arg1) {" N + " assert(arg1 != 0)" X ";" N + " assert(arg1 != 0)" N + "}" N + ""); + KEYS("u", + "void f(int arg1) {" N + " assert(arg1 != 0" X ")" N + " assert(arg1 != 0)" N + "}" N + ""); + KEYS("", + "void f(int arg1) {" N + " assert(arg1 != 0)" X ";" N + " assert(arg1 != 0)" N + "}" N + ""); + KEYS("", + "void f(int arg1) {" N + " assert(arg1 != 0);" N + " assert(arg1 != 0)" X ";" N + "}" N + ""); + KEYS("", + "void f(int arg1" X ", int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(arg1 != 0);" N + "}" N + ""); + KEYS("", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(" X "arg2 != 0);" N + "}" N + ""); + KEYS("", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(arg2 " X ">= 0);" N + "}" N + ""); + KEYS("", + "void f(int arg1, int arg2 = 0) {" N + " assert(" X "arg2 >= 0);" N + " assert(arg2 >= 0);" N + "}" N + ""); + KEYS("3u", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(" X "arg1 != 0);" N + "}" N + ""); + + // Repeat last command. + KEYS("w.", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 != 0);" N + " assert(arg1 >" X "= 0);" N + "}" N + ""); + + KEYS("kdd", + "void f(int arg1, int arg2 = 0) {" N + " " X "assert(arg1 >= 0);" N + "}" N + ""); + + // Make mistakes. + KEYS("43" "2oif (arg321 > 0) return true;", + "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return true" X ";" N + "}" N + ""); + + // Jumps around and change stuff. + KEYS("gg" "ciw" "bool", + "bool" X " f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return true;" N + "}" N + ""); + KEYS("`'", + "bool f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return true" X ";" N + "}" N + ""); + KEYS("caW" " false;", + "bool f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return false;" X N + "}" N + ""); + KEYS("k.", + "bool f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return false" X ";" N + " if (arg1 > 0) return false;" N + "}" N + ""); + + // Undo/redo again. + KEYS("u", + "bool f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return" X " true;" N + " if (arg1 > 0) return false;" N + "}" N + ""); + KEYS("u", + "bool f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return" X " true;" N + "}" N + ""); + KEYS("", + "bool f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return" X " false;" N + "}" N + ""); + KEYS("u", + "bool f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return" X " true;" N + "}" N + ""); + KEYS("u", + X "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return true;" N + "}" N + ""); + + // Record long insert mode. + KEYS("qb" "4s" "bool" "" "Q_ASSERT" "" "2" + "2w1" ":s/true/false" "q", + "bool f(int arg1, int arg2 = 0) {" N + " Q_ASSERT(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " " X " if (arg2 > 1) return false;" N + "}" N + ""); + + KEYS("u", + "bool f(int arg1, int arg2 = 0) {" N + " Q_ASSERT(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + X " if (arg2 > 1) return true;" N + "}" N + ""); + KEYS("u", + "bool f(int arg1, int arg2 = 0) {" N + " Q_ASSERT(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg2 > " X "0) return true;" N + "}" N + ""); + KEYS("u", + "bool f(int arg1, int arg2 = 0) {" N + " Q_ASSERT(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1" X " > 0) return true;" N + "}" N + ""); + KEYS("u", + "bool f(int arg1, int arg2 = 0) {" N + " " X "assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return true;" N + "}" N + ""); + KEYS("u", + X "void f(int arg1, int arg2 = 0) {" N + " assert(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg1 > 0) return true;" N + "}" N + ""); + + // Replay. + KEYS("@b", + "bool f(int arg1, int arg2 = 0) {" N + " Q_ASSERT(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " " X " if (arg2 > 1) return false;" N + "}" N + ""); + + // Return to the first change. + KEYS("99u" "", + X "void f(int arg1) {" N + " // TODO" N + " ;" N + "}" N + ""); + KEYS("", + "void f(int arg1) {" N + " // TODO" N + " " X "assert(arg1 != 0)" N + "}" N + ""); + KEYS("", + "void f(int arg1) {" N + " " X "assert(arg1 != 0)" N + " assert(arg1 != 0)" N + "}" N + ""); + + // Return to the last change. + KEYS("99", + "bool f(int arg1, int arg2 = 0) {" N + " Q_ASSERT(arg1 >= 0);" N + " if (arg1 > 0) return true;" N + " if (arg2 > 1) return false;" N + "}" N + ""); +} diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index d9852305cc3..30d2533a4d4 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1499,14 +1499,14 @@ public: int mvCount() const { return m_mvcount.isEmpty() ? 1 : m_mvcount.toInt(); } int opCount() const { return m_opcount.isEmpty() ? 1 : m_opcount.toInt(); } int count() const { return mvCount() * opCount(); } - QTextBlock block() const { return cursor().block(); } + QTextBlock block() const { return m_cursor.block(); } int leftDist() const { return position() - block().position(); } int rightDist() const { return block().length() - leftDist() - 1; } - bool atBlockStart() const { return cursor().atBlockStart(); } - bool atBlockEnd() const { return cursor().atBlockEnd(); } + bool atBlockStart() const { return m_cursor.atBlockStart(); } + bool atBlockEnd() const { return m_cursor.atBlockEnd(); } bool atEndOfLine() const { return atBlockEnd() && block().length() > 1; } bool atDocumentEnd() const { return position() >= lastPositionInDocument(); } - bool atDocumentStart() const { return cursor().atStart(); } + bool atDocumentStart() const { return m_cursor.atStart(); } bool atEmptyLine(const QTextCursor &tc = QTextCursor()) const; bool atBoundary(bool end, bool simple, bool onlyWords = false, @@ -1540,8 +1540,11 @@ public: int logicalToPhysicalColumn(int logical, const QString &text) const; int windowScrollOffset() const; // return scrolloffset but max half the current window height Column cursorColumn() const; // as visible on screen + void updateFirstVisibleLine(); int firstVisibleLine() const; - void setScrollBarValue(int line); + int lastVisibleLine() const; + int lineOnTop(int count = 1) const; // [count]-th line from top reachable without scrolling + int lineOnBottom(int count = 1) const; // [count]-th line from bottom reachable without scrolling void scrollToLine(int line); void scrollUp(int count); void scrollDown(int count) { scrollUp(-count); } @@ -1549,6 +1552,8 @@ public: void alignViewportToCursor(Qt::AlignmentFlag align, int line = -1, bool moveToNonBlank = false); + int lineToBlockNumber(int line) const; + void setCursorPosition(const CursorPosition &p); void setCursorPosition(QTextCursor *tc, const CursorPosition &p); @@ -1596,56 +1601,38 @@ public: } void moveRight(int n = 1) { //dump("RIGHT 1"); - QTextCursor tc = cursor(); - tc.movePosition(Right, KeepAnchor, n); - setCursor(tc); + m_cursor.movePosition(Right, KeepAnchor, n); if (atEndOfLine()) emit q->fold(1, false); //dump("RIGHT 2"); } void moveLeft(int n = 1) { - QTextCursor tc = cursor(); - tc.movePosition(Left, KeepAnchor, n); - setCursor(tc); + m_cursor.movePosition(Left, KeepAnchor, n); } void setAnchor() { - QTextCursor tc = cursor(); - tc.setPosition(tc.position(), MoveAnchor); - setCursor(tc); + m_cursor.setPosition(position(), MoveAnchor); } void setAnchor(int position) { - QTextCursor tc = cursor(); - tc.setPosition(tc.anchor(), MoveAnchor); - tc.setPosition(position, KeepAnchor); - setCursor(tc); + m_cursor.setPosition(position, KeepAnchor); } void setPosition(int position) { - QTextCursor tc = cursor(); - tc.setPosition(position, KeepAnchor); - setCursor(tc); + m_cursor.setPosition(position, KeepAnchor); } void setAnchorAndPosition(int anchor, int position) { - QTextCursor tc = cursor(); - tc.setPosition(anchor, MoveAnchor); - tc.setPosition(position, KeepAnchor); - setCursor(tc); + m_cursor.setPosition(anchor, MoveAnchor); + m_cursor.setPosition(position, KeepAnchor); + } + // Set cursor in text editor widget. + void commitCursor() { + if (editor()) + EDITOR(setTextCursor(m_cursor)); } - // Workaround for occational crash when setting text cursor while in edit block. + // Values to save when starting FakeVim processing. + bool m_inFakeVim; + int m_firstVisibleLine; QTextCursor m_cursor; - QTextCursor cursor() const { - if (m_editBlockLevel > 0) - return m_cursor; - return EDITOR(textCursor()); - } - - void setCursor(const QTextCursor &tc) { - m_cursor = tc; - if (m_editBlockLevel == 0) - EDITOR(setTextCursor(tc)); - } - bool moveToPreviousParagraph(int count) { return moveToNextParagraph(-count); } bool moveToNextParagraph(int count); @@ -1747,8 +1734,8 @@ public: bool m_breakEditBlock; - int anchor() const { return cursor().anchor(); } - int position() const { return cursor().position(); } + int anchor() const { return m_cursor.anchor(); } + int position() const { return m_cursor.position(); } struct TransformationData { @@ -2009,6 +1996,8 @@ void FakeVimHandler::Private::init() m_searchStartPosition = 0; m_searchFromScreenLine = 0; m_editBlockLevel = 0; + m_inFakeVim = false; + m_firstVisibleLine = 0; setupCharClass(); } @@ -2026,29 +2015,32 @@ void FakeVimHandler::Private::focus() void FakeVimHandler::Private::enterFakeVim() { + QTC_ASSERT(!m_inFakeVim, qDebug() << "enterFakeVim() shouldn't be called recursively!"); + + m_cursor = EDITOR(textCursor()); + m_inFakeVim = true; + + updateFirstVisibleLine(); importSelection(); - QTextCursor tc = cursor(); - // Position changed externally, e.g. by code completion. - if (tc.position() != m_oldPosition) { + if (position() != m_oldPosition) { // record external jump to different line - if (m_oldPosition != -1 && lineForPosition(m_oldPosition) != lineForPosition(tc.position())) + if (m_oldPosition != -1 && lineForPosition(m_oldPosition) != lineForPosition(position())) recordJump(m_oldPosition); setTargetColumn(); if (atEndOfLine() && !isVisualMode() && !isInsertMode()) moveLeft(); } - tc.setVisualNavigation(true); - setCursor(tc); - if (m_fakeEnd) moveRight(); } void FakeVimHandler::Private::leaveFakeVim() { + QTC_ASSERT(m_inFakeVim, qDebug() << "enterFakeVim() not called before leaveFakeVim()!"); + // The command might have destroyed the editor. if (m_textedit || m_plaintextedit) { // We fake vi-style end-of-line behaviour @@ -2066,7 +2058,18 @@ void FakeVimHandler::Private::leaveFakeVim() exportSelection(); updateCursorShape(); + commitCursor(); + + // Move cursor line to middle of screen if it's not visible. + const int line = cursorLine(); + if (line < firstVisibleLine() || line >= firstVisibleLine() + linesOnScreen()) + scrollToLine(qMax(0, line - linesOnScreen() / 2)); + else + scrollToLine(firstVisibleLine()); + updateScrollOffset(); } + + m_inFakeVim = false; } bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev) @@ -2144,7 +2147,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev) #endif // Fake "End of line" - //m_tc = cursor(); + //m_tc = m_cursor; //bool hasBlock = false; //emit q->requestHasBlockSelection(&hasBlock); @@ -2257,7 +2260,7 @@ void FakeVimHandler::Private::exportSelection() setMark(QLatin1Char('>'), mark(QLatin1Char('>')).position); } else { if (m_subsubmode == SearchSubSubMode && !m_searchCursor.isNull()) - setCursor(m_searchCursor); + m_cursor = m_searchCursor; else setAnchorAndPosition(pos, pos); } @@ -2339,7 +2342,7 @@ void FakeVimHandler::Private::importSelection() } else { // Import new selection. Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); - if (cursor().hasSelection()) { + if (m_cursor.hasSelection()) { if (mods & HostOsInfo::controlModifier()) m_visualMode = VisualBlockMode; else if (mods & Qt::AltModifier) @@ -2587,8 +2590,7 @@ void FakeVimHandler::Private::stopIncrementalFind() { if (g.findPending) { g.findPending = false; - QTextCursor tc = cursor(); - setAnchorAndPosition(m_findStartPosition, tc.selectionStart()); + setAnchorAndPosition(m_findStartPosition, m_cursor.selectionStart()); finishMovement(); setAnchor(); } @@ -2621,7 +2623,7 @@ bool FakeVimHandler::Private::isInputCount(const Input &input) const bool FakeVimHandler::Private::atEmptyLine(const QTextCursor &tc) const { if (tc.isNull()) - return atEmptyLine(cursor()); + return atEmptyLine(m_cursor); return tc.block().length() == 1; } @@ -2629,7 +2631,7 @@ bool FakeVimHandler::Private::atBoundary(bool end, bool simple, bool onlyWords, const QTextCursor &tc) const { if (tc.isNull()) - return atBoundary(end, simple, onlyWords, cursor()); + return atBoundary(end, simple, onlyWords, m_cursor); if (atEmptyLine(tc)) return true; int pos = tc.position(); @@ -2674,12 +2676,13 @@ void FakeVimHandler::Private::pushUndoState(bool overwrite) int pos = position(); if (!isInsertMode()) { - if (isVisualMode() || m_submode == DeleteSubMode) { + if (isVisualMode() || m_submode == DeleteSubMode + || (m_submode == ChangeSubMode && m_movetype != MoveLineWise)) { pos = qMin(pos, anchor()); if (isVisualLineMode()) pos = firstPositionInLine(lineForPosition(pos)); } else if (m_movetype == MoveLineWise && hasConfig(ConfigStartOfLine)) { - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; if (m_submode == ShiftLeftSubMode || m_submode == ShiftRightSubMode || m_submode == IndentSubMode) { pos = qMin(pos, anchor()); @@ -2702,7 +2705,7 @@ void FakeVimHandler::Private::pushUndoState(bool overwrite) void FakeVimHandler::Private::moveDown(int n) { - QTextBlock block = cursor().block(); + QTextBlock block = m_cursor.block(); const int col = position() - block.position(); const int targetLine = qMax(0, lineNumber(block) + n); @@ -2711,8 +2714,6 @@ void FakeVimHandler::Private::moveDown(int n) block = document()->lastBlock(); setPosition(block.position() + qMax(0, qMin(block.length() - 2, col))); moveToTargetColumn(); - - updateScrollOffset(); } void FakeVimHandler::Private::movePageDown(int count) @@ -2726,7 +2727,7 @@ void FakeVimHandler::Private::movePageDown(int count) if (count > 0) scrollToLine(cursorLine()); else - scrollToLine(qMax(0, cursorLine() - screenLines)); + scrollToLine(qMax(0, cursorLine() - screenLines + 1)); } bool FakeVimHandler::Private::moveToNextParagraph(int count) @@ -2891,7 +2892,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) QString dotCommand; if (m_submode == ChangeSubMode) { - pushUndoState(); + pushUndoState(false); beginEditBlock(); removeText(currentRange()); dotCommand = _("c"); @@ -2902,7 +2903,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) m_lastInsertion.clear(); g.returnToMode = InsertMode; } else if (m_submode == DeleteSubMode) { - pushUndoState(); + pushUndoState(false); beginEditBlock(); const int pos = position(); // Always delete something (e.g. 'dw' on an empty line deletes the line). @@ -2919,7 +2920,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) setTargetColumn(); endEditBlock(); } else if (m_submode == YankSubMode) { - const QTextCursor tc = cursor(); + const QTextCursor tc = m_cursor; if (m_rangemode == RangeBlockMode) { const int pos1 = tc.block().position(); const int pos2 = document()->findBlock(tc.anchor()).position(); @@ -2955,7 +2956,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement) || m_submode == ShiftRightSubMode || m_submode == ShiftLeftSubMode) { recordJump(); - pushUndoState(); + pushUndoState(false); if (m_submode == IndentSubMode) { indentSelectedText(); dotCommand = _("="); @@ -3010,11 +3011,11 @@ void FakeVimHandler::Private::updateSelection() for (MarksIterator it(m_marks); it.hasNext(); ) { it.next(); QTextEdit::ExtraSelection sel; - sel.cursor = cursor(); + sel.cursor = m_cursor; setCursorPosition(&sel.cursor, it.value().position); sel.cursor.setPosition(sel.cursor.position(), MoveAnchor); sel.cursor.movePosition(Right, KeepAnchor); - sel.format = cursor().blockCharFormat(); + sel.format = m_cursor.blockCharFormat(); sel.format.setForeground(Qt::blue); sel.format.setBackground(Qt::green); selections.append(sel); @@ -3181,7 +3182,7 @@ bool FakeVimHandler::Private::handleCommandSubSubMode(const Input &input) handled = false; } } else if (m_subsubmode == MarkSubSubMode) { - setMark(input.asChar(), CursorPosition(cursor())); + setMark(input.asChar(), CursorPosition(m_cursor)); m_subsubmode = NoSubSubMode; } else if (m_subsubmode == BackTickSubSubMode || m_subsubmode == TickSubSubMode) { @@ -3295,7 +3296,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) } else if (input.is('#') || input.is('*')) { // FIXME: That's not proper vim behaviour QString needle; - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; tc.select(QTextCursor::WordUnderCursor); needle = QRegExp::escape(tc.selection().toPlainText()); if (!m_gflag) @@ -3420,6 +3421,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) setPosition(firstPositionInLine(n, false)); } setTargetColumn(); + updateScrollOffset(); } else if (input.is('h') || input.isKey(Key_Left) || input.isBackspace()) { m_movetype = MoveExclusive; int n = qMin(count, leftDist()); @@ -3429,8 +3431,8 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) setTargetColumn(); movement = _("h"); } else if (input.is('H')) { - setCursor(EDITOR(cursorForPosition(QPoint(0, 0)))); - moveDown(qMax(count - 1, 0)); + const CursorPosition pos(lineToBlockNumber(lineOnTop(count)), 0); + setCursorPosition(&m_cursor, pos); handleStartOfLine(); } else if (input.is('j') || input.isKey(Key_Down) || input.isControl('j') || input.isControl('n')) { @@ -3449,28 +3451,26 @@ bool FakeVimHandler::Private::handleMovement(const Input &input) if (pastEnd && isVisualMode()) m_visualTargetColumn = -1; } else if (input.is('L')) { - QTextCursor tc = EDITOR(cursorForPosition(QPoint(0, EDITOR(height())))); - setCursor(tc); - moveUp(qMax(count, 1)); + const CursorPosition pos(lineToBlockNumber(lineOnBottom(count)), 0); + setCursorPosition(&m_cursor, pos); handleStartOfLine(); } else if (m_gflag && input.is('m')) { moveToStartOfLine(); moveRight(qMin(columnsOnScreen() / 2, rightDist()) - 1); setTargetColumn(); } else if (input.is('M')) { - QTextCursor tc = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2))); - setCursor(tc); + m_cursor = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2))); handleStartOfLine(); } else if (input.is('n') || input.is('N')) { if (hasConfig(ConfigUseCoreSearch)) { bool forward = (input.is('n')) ? g.lastSearchForward : !g.lastSearchForward; int pos = position(); emit q->findNextRequested(!forward); - if (forward && pos == cursor().selectionStart()) { + if (forward && pos == m_cursor.selectionStart()) { // if cursor is already positioned at the start of a find result, this is returned emit q->findNextRequested(false); } - setPosition(cursor().selectionStart()); + setPosition(m_cursor.selectionStart()); } else { searchNext(input.is('n')); } @@ -3647,7 +3647,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input) // << input; QString savedCommand = g.dotCommand; g.dotCommand.clear(); - beginEditBlock(); + beginLargeEditBlock(); replay(savedCommand); endEditBlock(); resetCommandMode(); @@ -3765,7 +3765,8 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input) removeText(currentRange()); setPosition(qMin(position(), anchor())); } else if (input.isControl('d')) { - int sline = cursorLineOnScreen(); + const int scrollOffset = windowScrollOffset(); + int sline = cursorLine() < scrollOffset ? scrollOffset : cursorLineOnScreen(); // FIXME: this should use the "scroll" option, and "count" moveDown(linesOnScreen() / 2); handleStartOfLine(); @@ -4382,11 +4383,11 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) pos.column = qMax(lastPosition.column, lastAnchor.column) + 1; while (pos.line < lastPosition.line) { ++pos.line; - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; setCursorPosition(&tc, pos); if (pos.line != tc.blockNumber()) break; - setCursor(tc); + m_cursor = tc; if (tc.positionInBlock() == pos.column) replay(text.repeated(repeat)); } @@ -4417,10 +4418,10 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) m_ctrlVActive = true; insert = _(""); } else if (input.isControl('w')) { - const int blockNumber = cursor().blockNumber(); + const int blockNumber = m_cursor.blockNumber(); const int endPos = position(); moveToNextWordStart(count(), false, false); - if (blockNumber != cursor().blockNumber()) + if (blockNumber != m_cursor.blockNumber()) moveToEndOfLine(); const int beginPos = position(); Range range(beginPos, endPos, RangeCharMode); @@ -4488,7 +4489,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) moveRight(prefix.size()); } else { setAnchor(); - cursor().deletePreviousChar(); + m_cursor.deletePreviousChar(); } } insert = _(""); @@ -4497,7 +4498,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) } else if (input.isKey(Key_Delete)) { if (!handleInsertInEditor(input, &insert)) { joinPreviousEditBlock(); - cursor().deleteChar(); + m_cursor.deleteChar(); insert = _(""); endEditBlock(); } @@ -4541,10 +4542,10 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) //} else if (key >= control('a') && key <= control('z')) { // // ignore these } else if (input.isControl('p') || input.isControl('n')) { - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; moveToNextWordStart(count(), false, false); QString str = selectText(Range(position(), tc.position())); - setCursor(tc); + m_cursor = tc; emit q->simpleCompletionRequested(str, input.isControl('n')); if (input.isControl('p')) insert = _(""); @@ -4997,7 +4998,7 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd) lastBlock = block; beginEditBlock(); } - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; const int pos = block.position(); const int anchor = pos + block.length() - 1; tc.setPosition(anchor); @@ -5779,7 +5780,7 @@ void FakeVimHandler::Private::search(const SearchData &sd, bool showMessages) QTextCursor tc = search(sd, m_searchStartPosition, count(), showMessages); if (tc.isNull()) { - tc = cursor(); + tc = m_cursor; tc.setPosition(m_searchStartPosition); } @@ -5796,7 +5797,7 @@ void FakeVimHandler::Private::search(const SearchData &sd, bool showMessages) if (oldLine != cursorLine() - cursorLineOnScreen()) scrollToLine(cursorLine() - linesOnScreen() / 2); - m_searchCursor = cursor(); + m_searchCursor = m_cursor; setTargetColumn(); } @@ -5824,9 +5825,7 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle) void FakeVimHandler::Private::moveToFirstNonBlankOnLine() { - QTextCursor tc2 = cursor(); - moveToFirstNonBlankOnLine(&tc2); - setPosition(tc2.position()); + moveToFirstNonBlankOnLine(&m_cursor); } void FakeVimHandler::Private::moveToFirstNonBlankOnLine(QTextCursor *tc) @@ -5835,11 +5834,11 @@ void FakeVimHandler::Private::moveToFirstNonBlankOnLine(QTextCursor *tc) int firstPos = tc->block().position(); for (int i = firstPos, n = firstPos + block().length(); i < n; ++i) { if (!doc->characterAt(i).isSpace() || i == n - 1) { - tc->setPosition(i); + tc->setPosition(i, KeepAnchor); return; } } - tc->setPosition(block().position()); + tc->setPosition(block().position(), KeepAnchor); } void FakeVimHandler::Private::indentSelectedText(QChar typedChar) @@ -5897,7 +5896,7 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat) QTextBlock block = document()->findBlockByLineNumber(beginLine - 1); while (block.isValid() && lineNumber(block) <= endLine) { const Column col = indentation(block.text()); - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; tc.setPosition(block.position()); if (col.physical > 0) tc.setPosition(tc.position() + col.physical, KeepAnchor); @@ -6042,7 +6041,7 @@ void FakeVimHandler::Private::moveToBoundary(bool simple, bool forward) c = doc->characterAt(tc.position()); int thisClass = charClass(c, simple); if (thisClass != lastClass || (forward ? tc.atBlockEnd() : tc.atBlockStart())) { - if (tc != cursor()) + if (tc != m_cursor) tc.movePosition(forward ? Left : Right); break; } @@ -6162,7 +6161,7 @@ void FakeVimHandler::Private::moveToMatchingParanthesis() bool forward = false; const int anc = anchor(); - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; emit q->moveToMatchingParenthesis(&moved, &forward, &tc); if (moved && forward) tc.movePosition(Left, KeepAnchor, 1); @@ -6265,39 +6264,62 @@ Column FakeVimHandler::Private::cursorColumn() const int FakeVimHandler::Private::linesInDocument() const { - if (cursor().isNull()) + if (m_cursor.isNull()) return 0; return document()->blockCount(); } -void FakeVimHandler::Private::setScrollBarValue(int line) +void FakeVimHandler::Private::scrollToLine(int line) { QScrollBar *scrollBar = EDITOR(verticalScrollBar()); // Convert line number to scroll bar value. const int maxValue = scrollBar->maximum(); - const int scrollLines = qMax(1, linesInDocument() - linesOnScreen()); + const int scrollLines = qMax(1, linesInDocument() - linesOnScreen() + 1); const int value = maxValue >= scrollLines ? line * maxValue / scrollLines : line; scrollBar->setValue(value); + + updateFirstVisibleLine(); } -void FakeVimHandler::Private::scrollToLine(int line) +void FakeVimHandler::Private::updateFirstVisibleLine() { - setScrollBarValue(line); - updateScrollOffset(); + QScrollBar *scrollBar = EDITOR(verticalScrollBar()); + + // Convert scroll bar value to line number. + const int maxValue = qMax(1, scrollBar->maximum()); + const int scrollLines = qMax(1, linesInDocument() - linesOnScreen() + 1); + const int value = scrollBar->value(); + + m_firstVisibleLine = maxValue >= scrollLines ? value * scrollLines / maxValue : value; } int FakeVimHandler::Private::firstVisibleLine() const { - QScrollBar *scrollBar = EDITOR(verticalScrollBar()); - if (0 && scrollBar->value() != cursorLine() - cursorLineOnScreen()) { - qDebug() << "SCROLLBAR: " << scrollBar->value() - << "CURSORLINE IN DOC" << cursorLine() - << "CURSORLINE ON SCREEN" << cursorLineOnScreen(); - } - //return scrollBar->value(); - return cursorLine() - cursorLineOnScreen(); + return m_firstVisibleLine; +} + +int FakeVimHandler::Private::lastVisibleLine() const +{ + const int blockNumber = lineToBlockNumber(m_firstVisibleLine + linesOnScreen()); + const QTextBlock block = document()->findBlockByNumber(blockNumber); + return block.isValid() ? block.firstLineNumber() : document()->lastBlock().firstLineNumber(); +} + +int FakeVimHandler::Private::lineOnTop(int count) const +{ + const int scrollOffset = qMax(count - 1, windowScrollOffset()); + const int line = firstVisibleLine(); + return line == 0 ? count - 1 : scrollOffset + line; +} + +int FakeVimHandler::Private::lineOnBottom(int count) const +{ + const int scrollOffset = qMax(count - 1, windowScrollOffset()); + const int line = lastVisibleLine(); + return line >= document()->lastBlock().firstLineNumber() ? line - count + 1 + : line - scrollOffset - 1; } void FakeVimHandler::Private::scrollUp(int count) @@ -6307,18 +6329,11 @@ void FakeVimHandler::Private::scrollUp(int count) void FakeVimHandler::Private::updateScrollOffset() { - // Precision of scroll offset depends on singleStep property of vertical scroll bar. - const int offset = windowScrollOffset(); const int line = cursorLine(); - const int scrollLine = firstVisibleLine(); - int d = line - scrollLine; - if (d <= offset) { - setScrollBarValue(scrollLine - offset + d); - } else { - d = linesOnScreen() - d; - if (d <= offset) - setScrollBarValue(scrollLine + offset - d + 1); - } + if (line < lineOnTop()) + scrollToLine(qMax(0, line - windowScrollOffset())); + else if (line > lineOnBottom()) + scrollToLine(line - linesOnScreen() + windowScrollOffset() + 1); } void FakeVimHandler::Private::alignViewportToCursor(AlignmentFlag align, int line, @@ -6337,16 +6352,18 @@ void FakeVimHandler::Private::alignViewportToCursor(AlignmentFlag align, int lin scrollUp(linesOnScreen() - cursorLineOnScreen()); } +int FakeVimHandler::Private::lineToBlockNumber(int line) const +{ + return document()->findBlockByLineNumber(line).blockNumber(); +} + void FakeVimHandler::Private::setCursorPosition(const CursorPosition &p) { const int firstLine = firstVisibleLine(); - const int firstBlock = document()->findBlockByLineNumber(firstLine).blockNumber(); - const int lastBlock = - document()->findBlockByLineNumber(firstLine + linesOnScreen() - 2).blockNumber(); + const int firstBlock = lineToBlockNumber(firstLine); + const int lastBlock = lineToBlockNumber(firstLine + linesOnScreen() - 2); bool isLineVisible = firstBlock <= p.line && p.line <= lastBlock; - QTextCursor tc = cursor(); - setCursorPosition(&tc, p); - setCursor(tc); + setCursorPosition(&m_cursor, p); if (!isLineVisible) alignViewportToCursor(Qt::AlignVCenter); } @@ -6426,7 +6443,7 @@ void FakeVimHandler::Private::yankText(const Range &range, int reg) void FakeVimHandler::Private::transformText(const Range &range, Transformation transformFunc, const QVariant &extra) { - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; int posAfter = range.beginPos; switch (range.rangemode) { case RangeCharMode: { @@ -6505,9 +6522,8 @@ void FakeVimHandler::Private::transformText(const Range &range, void FakeVimHandler::Private::insertText(QTextCursor &tc, const QString &text) { if (hasConfig(ConfigPassKeys)) { - QTextCursor oldTc = cursor(); - setCursor(tc); - EDITOR(setOverwriteMode(false)); + QTextCursor oldTc = m_cursor; + m_cursor = tc; if (tc.hasSelection() && text.isEmpty()) { QKeyEvent event(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier, QString()); @@ -6520,7 +6536,7 @@ void FakeVimHandler::Private::insertText(QTextCursor &tc, const QString &text) } updateCursorShape(); - setCursor(oldTc); + m_cursor = oldTc; } else { tc.insertText(text); } @@ -6531,7 +6547,7 @@ void FakeVimHandler::Private::insertText(const Register ®) QTC_ASSERT(reg.rangemode == RangeCharMode, qDebug() << "WRONG INSERT MODE: " << reg.rangemode; return); setAnchor(); - cursor().insertText(reg.contents); + m_cursor.insertText(reg.contents); //dump("AFTER INSERT"); } @@ -6649,7 +6665,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor) } case RangeLineMode: case RangeLineModeExclusive: { - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; if (visualCharMode) tc.insertBlock(); else @@ -6678,7 +6694,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor) const int pos = position(); if (pasteAfter && rightDist() > 0) moveRight(); - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; const int col = tc.columnNumber(); QTextBlock block = tc.block(); const QStringList lines = text.split(QLatin1Char('\n')); @@ -6719,7 +6735,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor) void FakeVimHandler::Private::joinLines(int count, bool preserveSpace) { int pos = position(); - const int blockNumber = cursor().blockNumber(); + const int blockNumber = m_cursor.blockNumber(); for (int i = qMax(count - 2, 0); i >= 0 && blockNumber < document()->blockCount(); --i) { moveBehindEndOfLine(); pos = position(); @@ -6730,7 +6746,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace) } else { while (characterAtCursor() == QLatin1Char(' ') || characterAtCursor() == QLatin1Char('\t')) moveRight(); - cursor().insertText(QString(QLatin1Char(' '))); + m_cursor.insertText(QString(QLatin1Char(' '))); } } setPosition(pos); @@ -6760,6 +6776,7 @@ bool FakeVimHandler::Private::handleInsertInEditor(const Input &input, QString * QKeyEvent event(QEvent::KeyPress, input.key(), static_cast(input.modifiers()), input.text()); + setAnchor(); if (!passEventToEditor(event)) return false; @@ -6777,14 +6794,14 @@ bool FakeVimHandler::Private::passEventToEditor(QEvent &event) { removeEventFilter(); - QTextCursor tc = m_cursor; - EDITOR(setTextCursor(tc)); + commitCursor(); + EDITOR(setOverwriteMode(false)); bool accepted = QApplication::sendEvent(editor(), &event); installEventFilter(); if (accepted) - setPosition(EDITOR(textCursor()).position()); + m_cursor = EDITOR(textCursor()); return accepted; } @@ -6811,7 +6828,7 @@ QString FakeVimHandler::Private::guessInsertCommand(int pos1, int pos2, int len1 } else if (len1 < len2) { // Text inserted. if (pos1 < pos2) { - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; tc.setPosition(pos1); tc.setPosition(pos2, KeepAnchor); insert = QString(tc.selectedText()).replace(_("<"), _("")); @@ -6861,7 +6878,7 @@ QString FakeVimHandler::Private::lineContents(int line) const void FakeVimHandler::Private::setLineContents(int line, const QString &contents) { QTextBlock block = document()->findBlockByLineNumber(line - 1); - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; const int begin = block.position(); const int len = block.length(); tc.setPosition(begin); @@ -6876,7 +6893,7 @@ int FakeVimHandler::Private::blockBoundary(const QString &left, const QString &end = closing ? right : left; // shift cursor if it is already on opening/closing string - QTextCursor tc1 = cursor(); + QTextCursor tc1 = m_cursor; int pos = tc1.position(); int max = document()->characterCount(); int sz = left.size(); @@ -6899,7 +6916,7 @@ int FakeVimHandler::Private::blockBoundary(const QString &left, // - on closing string: tc1.setPosition(from + i); } else { - tc1 = cursor(); + tc1 = m_cursor; } } @@ -7035,7 +7052,7 @@ void FakeVimHandler::Private::joinPreviousEditBlock() UNDO_DEBUG("JOIN"); if (m_breakEditBlock && m_editBlockLevel == 0) { beginEditBlock(); - QTextCursor tc(cursor()); + QTextCursor tc(m_cursor); tc.setPosition(tc.position()); tc.beginEditBlock(); tc.insertText(_("X")); @@ -7051,9 +7068,6 @@ void FakeVimHandler::Private::joinPreviousEditBlock() void FakeVimHandler::Private::beginEditBlock(bool largeEditBlock) { UNDO_DEBUG("BEGIN EDIT BLOCK"); - if (m_editBlockLevel == 0) - m_cursor = cursor(); - if (!largeEditBlock && !m_undoState.isValid()) pushUndoState(false); ++m_editBlockLevel; @@ -7066,14 +7080,9 @@ void FakeVimHandler::Private::endEditBlock() QTC_ASSERT(m_editBlockLevel > 0, qDebug() << "beginEditBlock() not called before endEditBlock()!"; return); --m_editBlockLevel; - if (m_editBlockLevel == 0) { - setCursor(m_cursor); - if (m_undoState.isValid()) { - if (m_undoState.revisions > 0) { - m_undo.push(m_undoState); - m_undoState = State(); - } - } + if (m_editBlockLevel == 0 && m_undoState.isValid() && m_undoState.revisions > 0) { + m_undo.push(m_undoState); + m_undoState = State(); } } @@ -7118,9 +7127,7 @@ void FakeVimHandler::Private::undoRedo(bool undo) State state = !stack.empty() ? stack.pop() : State(); - const int firstLine = firstVisibleLine(); - - CursorPosition lastPos(cursor()); + CursorPosition lastPos(m_cursor); const int current = revision(); ++m_editBlockLevel; @@ -7137,8 +7144,6 @@ void FakeVimHandler::Private::undoRedo(bool undo) --m_editBlockLevel; - scrollToLine(firstLine); - if (current == revision()) { const QString msg = undo ? FakeVimHandler::tr("Already at oldest change.") : FakeVimHandler::tr("Already at newest change."); @@ -7160,6 +7165,9 @@ void FakeVimHandler::Private::undoRedo(bool undo) setCursorPosition(m_lastChangePosition); setAnchor(); stack2.push(state); + } else { + updateFirstVisibleLine(); + m_cursor = EDITOR(textCursor()); } setTargetColumn(); @@ -7183,7 +7191,7 @@ void FakeVimHandler::Private::updateCursorShape() || m_subsubmode == SearchSubSubMode || m_mode == InsertMode || isVisualMode() - || cursor().hasSelection(); + || m_cursor.hasSelection(); EDITOR(setOverwriteMode(!thinCursor)); } @@ -7259,7 +7267,7 @@ void FakeVimHandler::Private::enterExMode(const QString &contents) void FakeVimHandler::Private::recordJump(int position) { CursorPosition pos = position >= 0 ? CursorPosition(document(), position) - : CursorPosition(cursor()); + : CursorPosition(m_cursor); setMark(QLatin1Char('\''), pos); setMark(QLatin1Char('`'), pos); if (m_jumpListUndo.isEmpty() || m_jumpListUndo.top() != pos) @@ -7273,7 +7281,7 @@ void FakeVimHandler::Private::jump(int distance) QStack &from = (distance > 0) ? m_jumpListRedo : m_jumpListUndo; QStack &to = (distance > 0) ? m_jumpListUndo : m_jumpListRedo; int len = qMin(qAbs(distance), from.size()); - CursorPosition m(cursor()); + CursorPosition m(m_cursor); setMark(QLatin1Char('\''), m); setMark(QLatin1Char('`'), m); for (int i = 0; i < len; ++i) { @@ -7358,6 +7366,7 @@ void FakeVimHandler::Private::handleStartOfLine() void FakeVimHandler::Private::replay(const QString &command) { //qDebug() << "REPLAY: " << quoteUnprintable(command); + clearCommandMode(); Inputs inputs(command); foreach (const Input &in, inputs) { if (handleDefaultKey(in) != EventHandled) @@ -7367,7 +7376,7 @@ void FakeVimHandler::Private::replay(const QString &command) QString FakeVimHandler::Private::visualDotCommand() const { - QTextCursor start(cursor()); + QTextCursor start(m_cursor); QTextCursor end(start); end.setPosition(end.anchor()); @@ -7443,7 +7452,8 @@ void FakeVimHandler::Private::selectTextObject(bool simple, bool inner) moveToWordStart(1, simple, false); // select trailing spaces if no leading space - if (!leadingSpace && document()->characterAt(position() + direction).isSpace() + QChar afterCursor = document()->characterAt(position() + direction); + if (!leadingSpace && afterCursor.isSpace() && afterCursor != ParagraphSeparator && !atBlockStart()) { if (forward) moveToNextBoundaryEnd(1, simple); @@ -7543,7 +7553,7 @@ bool FakeVimHandler::Private::changeNumberTextObject(int count) { const QTextBlock block = this->block(); const QString lineText = block.text(); - const int posMin = cursor().positionInBlock() + 1; + const int posMin = m_cursor.positionInBlock() + 1; // find first decimal, hexadecimal or octal number under or after cursor position QRegExp re(_("(0[xX])(0*[0-9a-fA-F]+)|(0)(0*[0-7]+)(?=\\D|$)|(\\d+)")); @@ -7607,7 +7617,7 @@ bool FakeVimHandler::Private::changeNumberTextObject(int count) bool FakeVimHandler::Private::selectQuotedStringTextObject(bool inner, const QString "e) { - QTextCursor tc = cursor(); + QTextCursor tc = m_cursor; int sz = quote.size(); QTextCursor tc1; @@ -7983,6 +7993,19 @@ void FakeVimHandler::setTextCursorPosition(int position) d->setAnchorAndPosition(pos, pos); d->m_fakeEnd = false; d->setTargetColumn(); + + if (!d->m_inFakeVim) + d->commitCursor(); +} + +QTextCursor FakeVimHandler::textCursor() const +{ + return d->m_cursor; +} + +void FakeVimHandler::setTextCursor(const QTextCursor &cursor) +{ + d->m_cursor = cursor; } bool FakeVimHandler::jumpToLocalMark(QChar mark, bool backTickMode) diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index 6e742915d42..0ef854d489b 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -125,6 +125,9 @@ public slots: // Set text cursor position. Keeps anchor if in visual mode. void setTextCursorPosition(int position); + QTextCursor textCursor() const; + void setTextCursor(const QTextCursor &cursor); + bool jumpToLocalMark(QChar mark, bool backTickMode); signals: diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index c2d1c507e5f..18b27d0e34e 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1406,10 +1406,10 @@ void FakeVimPluginPrivate::findNext(bool reverse) void FakeVimPluginPrivate::foldToggle(int depth) { IEditor *ieditor = EditorManager::currentEditor(); - BaseTextEditorWidget *editor = qobject_cast(ieditor->widget()); - QTC_ASSERT(editor != 0, return); + FakeVimHandler *handler = m_editorToHandler.value(ieditor, 0); + QTC_ASSERT(handler != 0, return); - QTextBlock block = editor->textCursor().block(); + QTextBlock block = handler->textCursor().block(); fold(depth, !BaseTextDocumentLayout::isFolded(block)); } @@ -1437,6 +1437,8 @@ void FakeVimPluginPrivate::foldAll(bool fold) void FakeVimPluginPrivate::fold(int depth, bool fold) { IEditor *ieditor = EditorManager::currentEditor(); + FakeVimHandler *handler = m_editorToHandler.value(ieditor, 0); + QTC_ASSERT(handler != 0, return); BaseTextEditorWidget *editor = qobject_cast(ieditor->widget()); QTC_ASSERT(editor != 0, return); @@ -1445,7 +1447,7 @@ void FakeVimPluginPrivate::fold(int depth, bool fold) qobject_cast(doc->documentLayout()); QTC_ASSERT(documentLayout != 0, return); - QTextBlock block = editor->textCursor().block(); + QTextBlock block = handler->textCursor().block(); int indent = BaseTextDocumentLayout::foldingIndent(block); if (fold) { if (BaseTextDocumentLayout::isFolded(block)) { @@ -1496,10 +1498,10 @@ void FakeVimPluginPrivate::fold(int depth, bool fold) void FakeVimPluginPrivate::foldGoTo(int count, bool current) { IEditor *ieditor = EditorManager::currentEditor(); - BaseTextEditorWidget *editor = qobject_cast(ieditor->widget()); - QTC_ASSERT(editor != 0, return); + FakeVimHandler *handler = m_editorToHandler.value(ieditor, 0); + QTC_ASSERT(handler != 0, return); - QTextCursor tc = editor->textCursor(); + QTextCursor tc = handler->textCursor(); QTextBlock block = tc.block(); int pos = -1; @@ -1546,7 +1548,7 @@ void FakeVimPluginPrivate::foldGoTo(int count, bool current) if (pos != -1) { tc.setPosition(pos, QTextCursor::KeepAnchor); - editor->setTextCursor(tc); + handler->setTextCursor(tc); } } diff --git a/src/plugins/fakevim/fakevimplugin.h b/src/plugins/fakevim/fakevimplugin.h index 9078acce4b3..46e4dcd2632 100644 --- a/src/plugins/fakevim/fakevimplugin.h +++ b/src/plugins/fakevim/fakevimplugin.h @@ -142,6 +142,8 @@ private slots: void test_macros(); + void test_vim_qtcreator(); + // special tests void test_i_cw_i();