[frameworks/ktexteditor] /: vi-mode: Update view selection when switching modes

Christoph Cullmann <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit ad3d4a782afc9e8c69dd5a28213bd6a48bb24c63 by Christoph Cullmann, on behalf of Ismael Asensio.
Committed on 20/07/2026 at 21:22.
Pushed by cullmann into branch 'master'.

vi-mode: Update view selection when switching modes

When entering a visual mode, or switching between them, the properties
of the underlying view need to be kept in sync with the expected vi mode
behavior.

Extract the code into a separate method to trigger this update when
switching or entering a visual mode and not only after a cursor
movement.

M  +25   -4    autotests/src/vimode/modes.cpp
M  +1    -0    src/vimode/modes/modebase.cpp
M  +15   -14   src/vimode/modes/visualvimode.cpp
M  +4    -0    src/vimode/modes/visualvimode.h

https://invent.kde.org/frameworks/ktexteditor/-/commit/ad3d4a782afc9e8c69dd5a28213bd6a48bb24c63

diff --git a/autotests/src/vimode/modes.cpp b/autotests/src/vimode/modes.cpp
index 2a56b270f..b871ea5e8 100644
--- a/autotests/src/vimode/modes.cpp
+++ b/autotests/src/vimode/modes.cpp
@@ -1427,10 +1427,31 @@ void ModesTest::VisualCommandsTests()
     }
 
     // BUG #328277 - make sure kate doesn't crash
-    BeginTest(QStringLiteral("aaa\nbbb"));
-    TestPressKey(QStringLiteral("Vj>u>."));
-    QCOMPARE(kate_view->renderer()->caretStyle(), KTextEditor::caretStyles::Block);
-    FinishTest("aaa\nbbb");
+    {
+        BeginTest(QStringLiteral("aaa\nbbb"));
+        TestPressKey(QStringLiteral("Vj>u>."));
+        QCOMPARE(kate_view->renderer()->caretStyle(), KTextEditor::caretStyles::Block);
+        FinishTest("aaa\nbbb");
+    }
+
+    // Switch between different visual modes
+    {
+        BeginTest(QStringLiteral("aaaa\nbbbb\ncccc\ndddd"));
+        TestPressKey(QStringLiteral("3lv2j2h")); // Start charwise Visual mode
+        QCOMPARE(kate_view->selectionText(), QStringLiteral("a\nbbbb\ncc"));
+        QCOMPARE(kate_view->blockSelection(), false);
+        TestPressKey(QStringLiteral("V")); // Visual Line
+        QCOMPARE(kate_view->selectionText(), QStringLiteral("aaaa\nbbbb\ncccc"));
+        QCOMPARE(kate_view->blockSelection(), false);
+        TestPressKey(QStringLiteral("\\ctrl-v")); // Visual Block
+        QCOMPARE(kate_view->selectionText(), QStringLiteral("aaa\nbbb\nccc"));
+        QCOMPARE(kate_view->blockSelection(), true);
+        TestPressKey(QStringLiteral("v")); // Back to Visual
+        QCOMPARE(kate_view->selectionText(), QStringLiteral("a\nbbbb\ncc"));
+        QCOMPARE(kate_view->blockSelection(), false);
+        TestPressKey(QStringLiteral("v")); // Press "v" again. Exit visual mode
+        QCOMPARE(kate_view->selectionText(), QString());
+    }
 }
 
 void ModesTest::VisualExternalTests()
diff --git a/src/vimode/modes/modebase.cpp b/src/vimode/modes/modebase.cpp
index cc8fe93ee..9f8623d16 100644
--- a/src/vimode/modes/modebase.cpp
+++ b/src/vimode/modes/modebase.cpp
@@ -1058,6 +1058,7 @@ bool ModeBase::startVisualMode(ViMode mode)
     if (m_viInputModeManager->isAnyVisualMode()) {
         m_viInputModeManager->changeViMode(mode);
         m_viInputModeManager->getViVisualMode()->setVisualModeType(mode);
+        m_viInputModeManager->getViVisualMode()->updateViewSelection();
     } else {
         m_viInputModeManager->viEnterVisualMode(mode);
     }
diff --git a/src/vimode/modes/visualvimode.cpp b/src/vimode/modes/visualvimode.cpp
index 4b1c71c91..6c601c597 100644
--- a/src/vimode/modes/visualvimode.cpp
+++ b/src/vimode/modes/visualvimode.cpp
@@ -29,6 +29,8 @@ VisualViMode::VisualViMode(InputModeManager *viInputModeManager, KTextEditor::Vi
 
 void VisualViMode::selectInclusive(const KTextEditor::Cursor c1, const KTextEditor::Cursor c2)
 {
+    m_view->setBlockSelection(false);
+
     if (c1 >= c2) {
         m_view->setSelection(KTextEditor::Range(c1.line(), c1.column() + 1, c2.line(), c2.column()));
     } else {
@@ -53,6 +55,7 @@ void VisualViMode::selectLines(KTextEditor::Range range)
     int eline = qMax(range.start().line(), range.end().line());
     int ecol = m_view->doc()->lineLength(eline) + 1;
 
+    m_view->setBlockSelection(false);
     m_view->setSelection(KTextEditor::Range(KTextEditor::Cursor(sline, 0), KTextEditor::Cursor(eline, ecol)));
 }
 
@@ -87,27 +90,24 @@ void VisualViMode::goToPos(const Range &r)
     // Setting range for a command
     m_commandRange = Range(m_start, c, m_commandRange.motionType);
 
-    // If visual mode is blockwise
+    updateViewSelection();
+}
+
+void VisualViMode::updateViewSelection()
+{
+    KTextEditor::Cursor c = m_view->cursorPosition();
+
     if (isVisualBlock()) {
         selectBlockInclusive(m_start, c);
-
         // Need to correct command range to make it inclusive.
-        if ((c.line() < m_start.line() && c.column() > m_start.column()) || (c.line() > m_start.line() && c.column() < m_start.column())) {
+        if ((c.line() < m_start.line()) != (c.column() < m_start.column())) {
             qSwap(m_commandRange.endColumn, m_commandRange.startColumn);
         }
-        return;
-    } else {
-        m_view->setBlockSelection(false);
-    }
-
-    // If visual mode is linewise
-    if (isVisualLine()) {
+    } else if (isVisualLine()) {
         selectLines(KTextEditor::Range(m_start, c));
-        return;
+    } else { // If visual mode is charwise
+        selectInclusive(m_start, c);
     }
-
-    // If visual mode is charwise
-    selectInclusive(m_start, c);
 }
 
 void VisualViMode::reset()
@@ -176,6 +176,7 @@ void VisualViMode::init()
     }
 
     m_commandRange = Range(m_start, m_start, m_commandRange.motionType);
+    updateViewSelection();
 }
 
 void VisualViMode::setVisualModeType(ViMode mode)
diff --git a/src/vimode/modes/visualvimode.h b/src/vimode/modes/visualvimode.h
index e2c4c1caf..dc9086b3a 100644
--- a/src/vimode/modes/visualvimode.h
+++ b/src/vimode/modes/visualvimode.h
@@ -98,6 +98,10 @@ public:
      * via mouse selection.
      */
     void updateSelection();
+    /**
+     * Updates the selection of the view when an internal change happens
+     */
+    void updateViewSelection();
 
 private:
     KTextEditor::Cursor m_start;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.