From 07f6d299374595a2bc1a10ccd859ab7a14d09adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Aum=C3=BCller?= <aumuell@reserv.at> Date: Thu, 21 Jan 2010 17:38:28 +0100 Subject: [PATCH] fakevim: ensure that cursor is never at EOL - previously, if the visible vi cursor is on the last character of a line, the corresponding QTextCursor might have been positioned before and after the character - code becomes simpler if the QTextCursor is always positioned before the vi cursor Merge-request: 99 Reviewed-by: hjk <qtc-committer@nokia.com> --- src/plugins/fakevim/fakevimhandler.cpp | 146 +++++++++++-------------- 1 file changed, 63 insertions(+), 83 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index ae4d3fd6b84..c150b3b18d3 100755 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -49,10 +49,15 @@ // Do not pass QTextCursor etc around unless really needed. Convert // early to line/column. // +// A QTextCursor is always between characters, whereas vi's cursor is always +// over a character. FakeVim interprets the QTextCursor to be over the character +// to the right of the QTextCursor's position(). +// // There is always a "current" cursor (m_tc). A current "region of interest" -// spans between m_anchor (== anchor()) and m_tc.position() (== position()) +// spans between m_anchor (== anchor()), i.e. the character below anchor()), and +// m_tc.position() (== position()). The character below position() is not included +// if the last movement command was exclusive (MoveExclusive). // The value of m_tc.anchor() is not used. -// #include <utils/qtcassert.h> @@ -355,8 +360,8 @@ public: void moveDown(int n = 1); // { m_tc.movePosition(Down, MoveAnchor, n); } void moveRight(int n = 1) { m_tc.movePosition(Right, MoveAnchor, n); } void moveLeft(int n = 1) { m_tc.movePosition(Left, MoveAnchor, n); } - void setAnchor() { m_anchor = m_tc.position(); } - void setAnchor(int position) { m_anchor = position; } + void setAnchor() { if (!isVisualMode()) m_anchor = m_tc.position(); } + void setAnchor(int position) { if (!isVisualMode()) m_anchor = position; } void setPosition(int position) { m_tc.setPosition(position, MoveAnchor); } void handleFfTt(int key); @@ -641,6 +646,9 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev) key += 32; } + QTC_ASSERT(!(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1), + qDebug() << "Cursor at EOL before key handler"); + //if (m_mode == InsertMode) // joinPreviousEditBlock(); //else @@ -651,6 +659,9 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev) // We fake vi-style end-of-line behaviour m_fakeEnd = atEndOfLine() && m_mode == CommandMode && !isVisualBlockMode(); + QTC_ASSERT(!(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1), + qDebug() << "Cursor at EOL after key handler"); + if (m_fakeEnd) moveLeft(); @@ -764,7 +775,7 @@ void FakeVimHandler::Private::moveDown(int n) const int targetLine = qMax(0, qMin(lastLine, m_tc.block().blockNumber() + n)); const QTextBlock &block = m_tc.document()->findBlockByNumber(targetLine); const int pos = block.position(); - setPosition(pos + qMin(block.length() - 1, col)); + setPosition(pos + qMax(0, qMin(block.length() - 2, col))); moveToTargetColumn(); #endif } @@ -776,14 +787,15 @@ void FakeVimHandler::Private::moveToEndOfLine() m_tc.movePosition(EndOfLine, MoveAnchor); #else const QTextBlock &block = m_tc.block(); - setPosition(block.position() + block.length() - 1); + const int pos = block.position() + block.length() - 2; + setPosition(qMax(block.position(), pos)); #endif } void FakeVimHandler::Private::moveBehindEndOfLine() { const QTextBlock &block = m_tc.block(); - int pos = qMin(block.position() + block.length(), lastPositionInDocument()); + int pos = qMin(block.position() + block.length() - 1, lastPositionInDocument()); setPosition(pos); } @@ -822,27 +834,39 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand) if (isVisualMode()) m_marks['>'] = m_tc.position(); - if (m_submode == ChangeSubMode) { - beginEditBlock(); + if (m_submode == ChangeSubMode + || m_submode == DeleteSubMode + || m_submode == YankSubMode + || m_submode == TransformSubMode) { + if (m_submode != YankSubMode) + beginEditBlock(); if (m_movetype == MoveLineWise) - m_rangemode = RangeLineModeExclusive; - if (atEndOfLine()) - moveLeft(); - if (m_rangemode == RangeCharMode) { - if (m_movetype == MoveInclusive) - moveRight(); // correction - if (anchor() >= position()) - m_anchor--; + m_rangemode = (m_submode == ChangeSubMode) + ? RangeLineModeExclusive + : RangeLineMode; + + if (m_movetype == MoveInclusive) { + if (anchor() <= position()) { + if ( !m_tc.atBlockEnd()) + moveRight(); // correction + } else { + m_anchor++; + } + } + + if (m_submode != TransformSubMode) { + if (m_submode == YankSubMode) + m_savedYankPosition = qMin(anchor(), position()); + yankSelectedText(); + if (m_movetype == MoveLineWise) + m_registers[m_register].rangemode = RangeLineMode; } + } + + if (m_submode == ChangeSubMode) { + removeSelectedText(true); if (!dotCommand.isEmpty()) setDotCommand("c" + dotCommand); - //QString text = removeSelectedText(); - //qDebug() << "CHANGING TO INSERT MODE" << text; - //m_registers[m_register] = text; - yankSelectedText(); - if (m_movetype == MoveLineWise) - m_registers[m_register].rangemode = RangeLineMode; - removeSelectedText(true); if (m_movetype == MoveLineWise) { insertAutomaticIndentation(true); } @@ -851,23 +875,9 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand) m_beginEditBlock = false; m_submode = NoSubMode; } else if (m_submode == DeleteSubMode) { - if (m_movetype == MoveLineWise) - m_rangemode = RangeLineMode; - if (atEndOfLine()) - moveLeft(); - if (m_rangemode == RangeCharMode) { - if (m_movetype == MoveInclusive) - moveRight(); // correction - if (m_movetype != MoveLineWise) - if (anchor() >= position()) - m_anchor--; - } + removeSelectedText(); if (!dotCommand.isEmpty()) setDotCommand("d" + dotCommand); - yankSelectedText(); - if (m_movetype == MoveLineWise) - m_registers[m_register].rangemode = RangeLineMode; - removeSelectedText(); if (m_movetype == MoveLineWise) handleStartOfLine(); m_submode = NoSubMode; @@ -875,12 +885,8 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand) moveLeft(); else setTargetColumn(); + endEditBlock(); } else if (m_submode == YankSubMode) { - if (m_movetype == MoveLineWise) - m_rangemode = RangeLineMode; - yankSelectedText(); - if (m_movetype == MoveLineWise) - m_registers[m_register].rangemode = RangeLineMode; m_submode = NoSubMode; if (m_register != '"') { setPosition(m_marks[m_register]); @@ -889,17 +895,6 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand) setPosition(m_savedYankPosition); } } else if (m_submode == TransformSubMode) { - if (m_movetype == MoveLineWise) - m_rangemode = RangeLineMode; - beginEditBlock(); - if (atEndOfLine()) - moveLeft(); - if (m_rangemode == RangeCharMode) { - if (m_movetype == MoveInclusive) - moveRight(); // correction - if (anchor() >= position()) - m_anchor--; - } if (m_subsubmode == InvertCaseSubSubMode) { invertCaseSelectedText(); if (!dotCommand.isEmpty()) @@ -1215,6 +1210,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, m_subsubmode = NoSubSubMode; } else if (key >= '0' && key <= '9') { if (key == '0' && m_mvcount.isEmpty()) { + m_movetype = MoveExclusive; moveToStartOfLine(); setTargetColumn(); finishMovement("0"); @@ -1223,6 +1219,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, } } else if (key == '^') { moveToFirstNonBlankOnLine(); + m_movetype = MoveExclusive; finishMovement("^"); } else if (0 && key == ',') { // FIXME: fakevim uses ',' by itself, so it is incompatible @@ -1357,7 +1354,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, endEditBlock(); leaveVisualMode(); } else if (key == '%') { - m_movetype = MoveExclusive; setAnchor(); moveToMatchingParanthesis(); finishMovement(); @@ -1369,7 +1365,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, updateMiniBuffer(); } else if (key == 'A') { enterInsertMode(); - moveToEndOfLine(); + moveBehindEndOfLine(); setDotCommand("A"); m_lastInsertion.clear(); updateMiniBuffer(); @@ -1397,14 +1393,9 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, m_submode = ChangeSubMode; finishMovement(); } else if (key == 'C') { - if (atEndOfLine()) - moveLeft(); setAnchor(); moveToEndOfLine(); - yankSelectedText(); - removeSelectedText(); - enterInsertMode(); - m_beginEditBlock = false; + m_submode = ChangeSubMode; setDotCommand("C"); finishMovement(); } else if (key == control('c')) { @@ -1419,8 +1410,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, setAnchor(); setPosition(m_savedYankPosition); } else { - if (atEndOfLine()) - moveLeft(); setAnchor(); } m_opcount = m_mvcount; @@ -1518,6 +1507,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, finishMovement(dotCommand); } else if (key == 'h' || key == Key_Left || key == Key_Backspace || key == control('h')) { + m_movetype = MoveExclusive; int n = qMin(count(), leftDist()); if (m_fakeEnd && m_tc.block().length() > 1) ++n; @@ -1559,7 +1549,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, beginEditBlock(); if (m_submode == NoSubMode) { for (int i = qMax(count(), 2) - 1; --i >= 0; ) { - moveToEndOfLine(); + moveBehindEndOfLine(); setAnchor(); moveRight(); if (m_gflag) { @@ -1584,7 +1574,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, finishMovement("%1k", count()); } else if (key == 'l' || key == Key_Right || key == ' ') { m_movetype = MoveExclusive; - moveRight(qMin(count(), rightDist())); + moveRight(qMax(0, qMin(count(), rightDist() - (m_submode==NoSubMode)))); setTargetColumn(); finishMovement("%1l", count()); } else if (key == 'L') { @@ -1629,7 +1619,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, if (key == 'O') moveToStartOfLine(); else - moveToEndOfLine(); + moveBehindEndOfLine(); m_tc.insertText("\n"); if (key == 'O') moveUp(); @@ -1728,8 +1718,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, m_submode = WindowSubMode; } else if (key == 'x' && isNoVisualMode()) { // = "dl" m_movetype = MoveExclusive; - if (atEndOfLine()) - moveLeft(); setAnchor(); m_submode = DeleteSubMode; moveRight(qMin(count(), rightDist())); @@ -1756,16 +1744,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, m_submode = YankSubMode; finishMovement(); } else if (key == 'y' && isNoVisualMode()) { - if (m_rangemode == RangeLineMode) { - m_savedYankPosition = position(); - setAnchor(firstPositionInLine(cursorLineInDocument() + 1)); - } else { - m_savedYankPosition = position(); - if (atEndOfLine()) - moveLeft(); - setAnchor(); - m_rangemode = RangeCharMode; - } + m_savedYankPosition = position(); + setAnchor(); m_submode = YankSubMode; } else if (key == 'y' && isVisualCharMode()) { Range range(position(), anchor(), RangeCharMode); @@ -2669,11 +2649,11 @@ void FakeVimHandler::Private::moveToTargetColumn() { const QTextBlock &block = m_tc.block(); int col = m_tc.position() - block.position(); - if (col == m_targetColumn) + if (col == m_targetColumn && m_targetColumn < block.length() - 2) return; //qDebug() << "CORRECTING COLUMN FROM: " << col << "TO" << m_targetColumn; - if (m_targetColumn == -1 || block.length() <= m_targetColumn) - m_tc.setPosition(block.position() + block.length() - 1, MoveAnchor); + if (m_targetColumn == -1 || m_targetColumn >= block.length() - 2) + m_tc.setPosition(block.position() + qMax(0, block.length() - 2), MoveAnchor); else m_tc.setPosition(block.position() + m_targetColumn, MoveAnchor); } -- GitLab