[frameworks/ktexteditor] /: vi-mode: Fix synchronization of the view block selection

Ismael Asensio <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 184676ad6502e819cba2462990dd0cc1a4cd2415 by Ismael Asensio.
Committed on 27/07/2026 at 16:36.
Pushed by iasensio into branch 'master'.

vi-mode: Fix synchronization of the view block selection

When in vi-mode, the view's block selection property needs to be always
in sync with the visual block mode.

Ensure this condition is met on every codepath and add specific test
cases for switching:
- between Vi visual modes
- between normal input mode and Vi input mode

M  +28   -0    autotests/src/vimode/modes.cpp
M  +3    -1    src/inputmode/kateviinputmode.cpp
M  +2    -0    src/vimode/inputmodemanager.cpp
M  +0    -1    src/vimode/modes/normalvimode.cpp
M  +2    -10   src/vimode/modes/visualvimode.cpp

https://invent.kde.org/frameworks/ktexteditor/-/commit/184676ad6502e819cba2462990dd0cc1a4cd2415

diff --git a/autotests/src/vimode/modes.cpp b/autotests/src/vimode/modes.cpp
index 7b4100207..5ea0156de 100644
--- a/autotests/src/vimode/modes.cpp
+++ b/autotests/src/vimode/modes.cpp
@@ -1467,6 +1467,16 @@ void ModesTest::VisualCommandsTests()
         TestPressKey(QStringLiteral("v")); // Press "v" again. Exit visual mode
         QCOMPARE(kate_view->selectionText(), QString());
     }
+
+    // Check synchornization of block selection with block visual mode
+    {
+        BeginTest(QStringLiteral("aaaa\nbbbb\ncccc\ndddd"));
+        QCOMPARE(kate_view->blockSelection(), false);
+        TestPressKey(QStringLiteral("\\ctrl-v"));
+        QCOMPARE(kate_view->blockSelection(), true);
+        TestPressKey(QStringLiteral("\\ctrl-v"));
+        QCOMPARE(kate_view->blockSelection(), false);
+    }
 }
 
 void ModesTest::VisualExternalTests()
@@ -1522,6 +1532,24 @@ void ModesTest::VisualExternalTests()
     TestPressKey(QStringLiteral("d"));
     QCOMPARE(kate_document->text(), QStringLiteral("far"));
 
+    // Test switching from normal input mode with an active block selection
+    // It should get into Vi Visual Block Mode and keep the selected range
+    kate_view->setInputMode(View::NormalInputMode);
+    kate_document->setText(QStringLiteral("abcd\nefgh"));
+    kate_view->setBlockSelection(true);
+    kate_view->setSelection(Range(Cursor(0, 1), Cursor(1, 3)));
+    QCOMPARE(kate_document->text(kate_view->selectionRange(), true), QStringLiteral("bc\nfg"));
+    kate_view->setInputMode(View::ViInputMode);
+    QVERIFY(kate_view->currentInputMode()->viewInputMode() == View::ViInputMode);
+    vi_input_mode = static_cast<KateViInputMode *>(kate_view->currentInputMode());
+    vi_input_mode_manager = vi_input_mode->viInputModeManager();
+    QCOMPARE(kate_view->blockSelection(), true);
+    QTRY_COMPARE(vi_input_mode_manager->getCurrentViMode(), KateVi::VisualBlockMode);
+    TestPressKey(QStringLiteral("l"));
+    QCOMPARE(kate_document->text(kate_view->selectionRange(), true), QStringLiteral("bcd\nfgh"));
+    TestPressKey(QStringLiteral("d"));
+    QCOMPARE(kate_document->text(), QStringLiteral("a\ne"));
+
     // Test returning to correct mode when selecting ranges with mouse
     BeginTest(QStringLiteral("foo bar\nbar baz"));
     TestPressKey(QStringLiteral("i")); // get me into insert mode
diff --git a/src/inputmode/kateviinputmode.cpp b/src/inputmode/kateviinputmode.cpp
index ddfd0f086..417584df6 100644
--- a/src/inputmode/kateviinputmode.cpp
+++ b/src/inputmode/kateviinputmode.cpp
@@ -70,8 +70,10 @@ void KateViInputMode::activate()
     reset(); // TODO: is this necessary? (well, not anymore I guess)
 
     if (view()->selection()) {
-        m_viModeManager->changeViMode(KateVi::VisualMode);
+        const KateVi::ViMode mode = view()->blockSelection() ? KateVi::VisualBlockMode : KateVi::VisualMode;
+        m_viModeManager->changeViMode(mode);
         view()->setCursorPosition(KTextEditor::Cursor(view()->selectionRange().end().line(), view()->selectionRange().end().column() - 1));
+        m_viModeManager->m_viVisualMode->setVisualModeType(mode);
         m_viModeManager->m_viVisualMode->updateSelection();
     }
     viewInternal()->iconBorder()->setRelLineNumbersOn(m_relLineNumbers);
diff --git a/src/vimode/inputmodemanager.cpp b/src/vimode/inputmodemanager.cpp
index 92819a77a..c8948399d 100644
--- a/src/vimode/inputmodemanager.cpp
+++ b/src/vimode/inputmodemanager.cpp
@@ -263,6 +263,8 @@ void InputModeManager::changeViMode(ViMode newMode)
 {
     m_previousViMode = m_currentViMode;
     m_currentViMode = newMode;
+
+    m_view->setBlockSelection(newMode == ViMode::VisualBlockMode);
 }
 
 ViMode InputModeManager::getCurrentViMode() const
diff --git a/src/vimode/modes/normalvimode.cpp b/src/vimode/modes/normalvimode.cpp
index b391c2f2d..6e8f4c0f0 100644
--- a/src/vimode/modes/normalvimode.cpp
+++ b/src/vimode/modes/normalvimode.cpp
@@ -381,7 +381,6 @@ bool NormalViMode::handleKeypress(const QKeyEvent *e)
             // check if reset() should be called. some commands in visual mode should not end visual mode
             if (cmd.shouldReset()) {
                 reset();
-                m_view->setBlockSelection(false);
             }
             resetParser();
 
diff --git a/src/vimode/modes/visualvimode.cpp b/src/vimode/modes/visualvimode.cpp
index 6d95c45d3..3d377323b 100644
--- a/src/vimode/modes/visualvimode.cpp
+++ b/src/vimode/modes/visualvimode.cpp
@@ -29,8 +29,6 @@ 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 {
@@ -40,8 +38,6 @@ void VisualViMode::selectInclusive(const KTextEditor::Cursor c1, const KTextEdit
 
 void VisualViMode::selectBlockInclusive(const KTextEditor::Cursor c1, const KTextEditor::Cursor c2)
 {
-    m_view->setBlockSelection(true);
-
     if (c1.column() >= c2.column()) {
         m_view->setSelection(KTextEditor::Range(c1.line(), c1.column() + 1, c2.line(), c2.column()));
     } else {
@@ -55,7 +51,6 @@ 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)));
 }
 
@@ -217,9 +212,6 @@ void VisualViMode::updateSelection()
         return;
     }
 
-    // If we are there it's already not VisualBlock mode.
-    m_view->setBlockSelection(false);
-
     // If not valid going back to normal mode
     KTextEditor::Range r = m_view->selectionRange();
     if (!r.isValid()) {
@@ -229,8 +221,8 @@ void VisualViMode::updateSelection()
         return;
     }
 
-    // If already not in visual mode, it's time to go there.
-    if (m_viInputModeManager->getCurrentViMode() != ViMode::VisualMode) {
+    // If already not in any visual mode, it's time to go there.
+    if (!m_viInputModeManager->isAnyVisualMode()) {
         commandEnterVisualMode();
     }
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.