diff --git a/src/utils/veditutils.cpp b/src/utils/veditutils.cpp index e683a32a..7dcab885 100644 --- a/src/utils/veditutils.cpp +++ b/src/utils/veditutils.cpp @@ -283,6 +283,7 @@ bool VEditUtils::findTargetWithinBlock(QTextCursor &p_cursor, QChar p_target, bool p_forward, bool p_inclusive, + bool p_leftSideOfCursor, int p_repeat) { if (p_repeat < 1) { @@ -296,6 +297,9 @@ bool VEditUtils::findTargetWithinBlock(QTextCursor &p_cursor, // The index to start searching. int idx = pib + (p_inclusive ? delta : 2 * delta); + if (p_leftSideOfCursor) { + --idx; + } for (; idx < text.size() && idx >= 0; idx += delta) { if (text[idx] == p_target) { @@ -322,9 +326,9 @@ bool VEditUtils::findTargetWithinBlock(QTextCursor &p_cursor, } int VEditUtils::findTargetsWithinBlock(QTextCursor &p_cursor, - QTextCursor::MoveMode p_mode, const QList &p_targets, bool p_forward, + bool p_leftSideOfCursor, bool p_inclusive) { if (p_targets.isEmpty()) { @@ -339,6 +343,9 @@ int VEditUtils::findTargetsWithinBlock(QTextCursor &p_cursor, // The index to start searching. int idx = pib + (p_inclusive ? delta : 2 * delta); + if (p_leftSideOfCursor) { + --idx; + } for (; idx < text.size() && idx >= 0; idx += delta) { int index = p_targets.indexOf(text[idx]); @@ -353,14 +360,11 @@ int VEditUtils::findTargetsWithinBlock(QTextCursor &p_cursor, } // text[idx] is the target character. - if ((p_forward && p_inclusive && p_mode == QTextCursor::KeepAnchor) - || (!p_forward && !p_inclusive)) { - ++idx; - } else if (p_forward && !p_inclusive && p_mode == QTextCursor::MoveAnchor) { + if (p_forward && !p_inclusive) { --idx; } - p_cursor.setPosition(block.position() + idx, p_mode); + p_cursor.setPosition(block.position() + idx); return targetIdx; } diff --git a/src/utils/veditutils.h b/src/utils/veditutils.h index e63c6453..175bac85 100644 --- a/src/utils/veditutils.h +++ b/src/utils/veditutils.h @@ -89,17 +89,18 @@ public: QChar p_target, bool p_forward, bool p_inclusive, + bool p_leftSideOfCursor, int p_repeat); // Find th first occurence of a char in @p_targets within a block. // Returns the index of the found char in @p_targets if found. // Returns -1 if none of the @p_targets is found. - // Please pay attention to the one-step-forward/backward in KeepAnchor mode - // and exclusive case. + // Different from findTargetWithinBlock(), will not modify the ucrsor position + // even in KeepAnchor mode. static int findTargetsWithinBlock(QTextCursor &p_cursor, - QTextCursor::MoveMode p_mode, const QList &p_targets, bool p_forward, + bool p_leftSideOfCursor, bool p_inclusive); // Find a pair target (@p_opening, @p_closing) containing current cursor and diff --git a/src/utils/vvim.cpp b/src/utils/vvim.cpp index 0d424a66..53c11188 100644 --- a/src/utils/vvim.cpp +++ b/src/utils/vvim.cpp @@ -178,7 +178,8 @@ static void findCurrentSpace(const QTextCursor &p_cursor, int &p_start, int &p_e // Backward: wwww|ssssswwww static void moveCursorAcrossSpaces(QTextCursor &p_cursor, QTextCursor::MoveMode p_mode, - bool p_forward) + bool p_forward, + bool p_stopAtBoundary = false) { while (true) { QTextBlock block = p_cursor.block(); @@ -192,7 +193,7 @@ static void moveCursorAcrossSpaces(QTextCursor &p_cursor, } } - if (pib == text.size()) { + if (pib == text.size() && !p_stopAtBoundary) { // Move to next block. p_cursor.movePosition(QTextCursor::Down, p_mode, 1); if (block.blockNumber() == p_cursor.block().blockNumber()) { @@ -218,7 +219,7 @@ static void moveCursorAcrossSpaces(QTextCursor &p_cursor, } } - if (idx == -1) { + if (idx == -1 && !p_stopAtBoundary) { // Move to previous block. p_cursor.movePosition(QTextCursor::Up, p_mode, 1); if (block.blockNumber() == p_cursor.block().blockNumber()) { @@ -2551,6 +2552,13 @@ bool VVim::processMovement(QTextCursor &p_cursor, p_repeat = 1; } + if (checkMode(VimMode::Visual)) { + int pos = p_cursor.position(); + if (pos == p_cursor.anchor() - 1 && pos == m_positionBeforeVisualMode) { + ++p_repeat; + } + } + int pib = p_cursor.positionInBlock(); int length = p_cursor.block().length(); if (length - pib <= p_repeat) { @@ -2730,6 +2738,12 @@ bool VVim::processMovement(QTextCursor &p_cursor, // If all the block is space, just move to the end of block; otherwise, // move to the first non-space character. VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode); + + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + // Move one character forward. + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } + hasMoved = true; break; } @@ -2752,6 +2766,11 @@ bool VVim::processMovement(QTextCursor &p_cursor, } VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode); + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + // Move one character forward. + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } + hasMoved = true; break; } @@ -2766,6 +2785,11 @@ bool VVim::processMovement(QTextCursor &p_cursor, p_cursor.movePosition(QTextCursor::Start, p_moveMode, 1); VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode); + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + // Move one character forward. + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } + hasMoved = true; break; } @@ -2780,6 +2804,11 @@ bool VVim::processMovement(QTextCursor &p_cursor, p_cursor.movePosition(QTextCursor::End, p_moveMode, 1); VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode); + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + // Move one character forward. + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } + hasMoved = true; break; } @@ -2797,7 +2826,17 @@ bool VVim::processMovement(QTextCursor &p_cursor, } p_cursor.movePosition(QTextCursor::NextWord, p_moveMode); - if (p_cursor.atBlockEnd() || VEditUtils::isSpaceBlock(p_cursor.block())) { + if (p_cursor.atBlockEnd()) { + // dw/yw/cw will stop at the end of the line. + if (p_repeat == 1 + && checkMode(VimMode::Normal) + && p_moveMode == QTextCursor::KeepAnchor) { + --p_repeat; + } + + continue; + } else if (doc->characterAt(p_cursor.position()).isSpace() + || VEditUtils::isSpaceBlock(p_cursor.block())) { continue; } @@ -2830,6 +2869,18 @@ bool VVim::processMovement(QTextCursor &p_cursor, VEditUtils::findCurrentWORD(p_cursor, start, end); // Move cursor to end of current WORD. p_cursor.setPosition(end, p_moveMode); + + if (p_repeat == 1 + && checkMode(VimMode::Normal) + && p_moveMode == QTextCursor::KeepAnchor) { + // dW/yW/cW will stop at the end of the line. + moveCursorAcrossSpaces(p_cursor, p_moveMode, true, true); + if (p_cursor.atBlockEnd()) { + --p_repeat; + continue; + } + } + // Skip spaces. moveCursorAcrossSpaces(p_cursor, p_moveMode, true); if (p_cursor.atBlockEnd()) { @@ -3193,6 +3244,7 @@ handle_target: target, forward, inclusive, + useLeftSideOfCursor(p_cursor), p_repeat); } @@ -3227,6 +3279,11 @@ handle_target: VEditUtils::moveCursorFirstNonSpaceCharacter(p_cursor, p_moveMode); } + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + // Move one character forward. + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } + hasMoved = true; } @@ -3251,15 +3308,19 @@ handle_target: } // First check if current char hits the targets. - QChar ch = doc->characterAt(position); + bool useLeftSideBefore = useLeftSideOfCursor(p_cursor); + QChar ch = doc->characterAt(useLeftSideBefore ? position - 1 + : position); int idx = targets.indexOf(ch); if (idx == -1) { - // Use MoveAnchor to avoid the one-step-forward. idx = VEditUtils::findTargetsWithinBlock(p_cursor, - QTextCursor::MoveAnchor, targets, true, + useLeftSideOfCursor(p_cursor), true); + } else if (useLeftSideBefore) { + // Move one character back to let p_cursor position at the pair. + p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode); } if (idx == -1) { @@ -3294,6 +3355,12 @@ handle_target: p_cursor.setPosition(anchor); p_cursor.setPosition(target, p_moveMode); + + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + // Move one character forward. + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } + hasMoved = true; break; } else { @@ -3323,11 +3390,27 @@ handle_target: // Record current location. m_locations.addLocation(p_cursor); + bool useLeftSideBefore = useLeftSideOfCursor(p_cursor); const SearchItem &item = m_searchHistory.lastItem(); while (--p_repeat >= 0) { - hasMoved = m_editor->findText(item.m_text, item.m_options, - forward ? item.m_forward : !item.m_forward, - &p_cursor, p_moveMode); + bool found = m_editor->findText(item.m_text, + item.m_options, + forward ? item.m_forward : !item.m_forward, + &p_cursor, + p_moveMode, + useLeftSideBefore); + if (found) { + hasMoved = true; + useLeftSideBefore = false; + } else { + break; + } + } + + if (hasMoved) { + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } } break; @@ -3396,6 +3479,9 @@ handle_target: } Q_ASSERT(hasMoved); + if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) { + p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode); + } break; } diff --git a/src/veditor.cpp b/src/veditor.cpp index c21047b0..b5dca387 100644 --- a/src/veditor.cpp +++ b/src/veditor.cpp @@ -424,7 +424,8 @@ bool VEditor::findText(const QString &p_text, uint p_options, bool p_forward, QTextCursor *p_cursor, - QTextCursor::MoveMode p_moveMode) + QTextCursor::MoveMode p_moveMode, + bool p_useLeftSideOfCursor) { clearIncrementalSearchedWordHighlight(); @@ -442,6 +443,10 @@ bool VEditor::findText(const QString &p_text, start = p_forward ? p_cursor->position() + 1 : p_cursor->position(); } + if (p_useLeftSideOfCursor) { + --start; + } + bool found = findTextHelper(p_text, p_options, p_forward, start, wrapped, retCursor); if (found) { @@ -541,12 +546,13 @@ bool VEditor::findTextHelper(const QString &p_text, } else if (p_start > m_document->characterCount()) { p_start = m_document->characterCount(); } - - QTextCursor startCursor = cursor; - startCursor.setPosition(p_start); - setTextCursorW(startCursor); } + QTextCursor startCursor = cursor; + // Will clear the selection. + startCursor.setPosition(p_start); + setTextCursorW(startCursor); + while (!found) { if (useRegExp) { found = findW(exp, findFlags); diff --git a/src/veditor.h b/src/veditor.h index f950e414..2e631589 100644 --- a/src/veditor.h +++ b/src/veditor.h @@ -75,7 +75,8 @@ public: uint p_options, bool p_forward, QTextCursor *p_cursor = nullptr, - QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor); + QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor, + bool p_useLeftSideOfCursor = false); void replaceText(const QString &p_text, uint p_options,