diff --git a/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java b/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java
index 3a24c0fce..45c4ad08b 100644
--- a/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java
+++ b/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java
@@ -308,6 +308,9 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
     protected void textChanged(@NotNull DocumentEvent e) {
       try {
         final Editor editor = entry.getEditor();
+        if (editor == null) {
+          return;
+        }
 
         final String labelText = label.getText(); // Either '/', '?' or ':'boolean searchCommand = false;
 
@@ -351,8 +354,8 @@ public class ExEntryPanel extends JPanel implements VimCommandLine {
 
         if (labelText.equals("/") || labelText.equals("?") || searchCommand) {
           final boolean forwards = !labelText.equals("?");  // :s, :g, :v are treated as forwards
-          int pattenEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
-          final String pattern = searchText.substring(0, pattenEnd);
+          int patternEnd = injector.getSearchGroup().findEndOfPattern(searchText, separator, 0);
+          final String pattern = searchText.substring(0, patternEnd);
 
           VimPlugin.getEditor().closeEditorSearchSession(editor);
           final int matchOffset =
diff --git a/src/test/java/org/jetbrains/plugins/ideavim/group/search/IncsearchTests.kt b/src/test/java/org/jetbrains/plugins/ideavim/group/search/IncsearchTests.kt
index a628154b6..e45ceb62a 100644
--- a/src/test/java/org/jetbrains/plugins/ideavim/group/search/IncsearchTests.kt
+++ b/src/test/java/org/jetbrains/plugins/ideavim/group/search/IncsearchTests.kt
@@ -563,7 +563,67 @@ class IncsearchTests : VimTestCase() {
   }
 
   @Test
-  fun `test incsearch updates selection when started in Visual mode`() {
+  fun `test incsearch updates Visual selection`() {
+    doTest(
+      listOf("ve", "/dolor"),
+      """
+        |Lorem ipsum dolor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas. 
+      """.trimMargin(),
+      """
+        |${s}Lorem ipsum ${c}d${se}olor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas. 
+      """.trimMargin(),
+      Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
+    ) {
+      enterCommand("set hlsearch incsearch")
+    }
+    assertSearchHighlights("dolor",
+      """
+        |Lorem ipsum ‷dolor‴ sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas. 
+      """.trimMargin()
+    )
+  }
+
+  @Test
+  fun `test incsearch updates empty Visual selection`() {
+    doTest(
+      "v/ipsum",
+      """
+        |Lorem ipsum dolor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas.
+      """.trimMargin(),
+      """
+        |${s}Lorem ${c}i${se}psum dolor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas.
+      """.trimMargin(),
+      Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
+    ) {
+      enterCommand("set hlsearch incsearch")
+    }
+    assertSearchHighlights("ipsum",
+      """
+        |Lorem ‷ipsum‴ dolor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas.
+      """.trimMargin()
+    )
+  }
+
+  @Test
+  fun `test incsearch updates exclusive Visual selection`() {
     doTest(
       listOf("ve", "/dolor"),
       """
@@ -580,8 +640,48 @@ class IncsearchTests : VimTestCase() {
       """.trimMargin(),
       Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
     ) {
+      enterCommand("set selection=exclusive")
       enterCommand("set hlsearch incsearch")
     }
+    assertSearchHighlights("dolor",
+      """
+        |Lorem ipsum ‷dolor‴ sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas. 
+      """.trimMargin()
+    )
+  }
+
+  @Test
+  fun `test incsearch updates empty exclusive Visual selection`() {
+    doTest(
+      "v/ipsum",
+      """
+        |Lorem ipsum dolor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas.
+      """.trimMargin(),
+      """
+        |${s}Lorem ${c}${se}ipsum dolor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas.
+      """.trimMargin(),
+      Mode.CMD_LINE(Mode.VISUAL(SelectionType.CHARACTER_WISE))
+    ) {
+      enterCommand("set selection=exclusive")
+      enterCommand("set hlsearch incsearch")
+    }
+    assertSearchHighlights("ipsum",
+      """
+        |Lorem ‷ipsum‴ dolor sit amet,
+        |consectetur adipiscing elit
+        |Sed in orci mauris.
+        |Cras id tellus in ex imperdiet egestas.
+      """.trimMargin()
+    )
   }
 
   @Test
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt
index 2874a642a..999577a74 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt
@@ -20,7 +20,7 @@ import com.maddyhome.idea.vim.helper.exitVisualMode
 import com.maddyhome.idea.vim.register.Register
 import com.maddyhome.idea.vim.state.mode.SelectionType
 import com.maddyhome.idea.vim.state.mode.inBlockSelection
-import com.maddyhome.idea.vim.state.mode.inCommandLineMode
+import com.maddyhome.idea.vim.state.mode.inCommandLineModeWithVisual
 import com.maddyhome.idea.vim.state.mode.inSelectMode
 import com.maddyhome.idea.vim.state.mode.inVisualMode
 import javax.swing.KeyStroke
@@ -98,27 +98,26 @@ per-caret marks.
     // Make sure to always reposition the caret, even if the offset hasn't changed. We might need to reposition due to
     // changes in surrounding text, especially with inline inlays.
     val oldOffset = this.offset
-    var caretAfterMove = moveToInlayAwareOffset(offset)
+    var updatedCaret = moveToInlayAwareOffset(offset)
 
     // Similarly, always make sure the caret is positioned within the view. Adding or removing text could move the caret
     // position relative to the view, without changing offset.
     if (this == editor.primaryCaret()) {
       injector.scroll.scrollCaretIntoView(editor)
     }
-    caretAfterMove = if (editor.inVisualMode || editor.inSelectMode) {
+
+    // If we're in Visual or Select mode, update the selection. We also need to handle Command-line mode, with Visual
+    // pending, e.g. `v/foo` or `v:<C-U>normal 3j`
+    updatedCaret = if (editor.inVisualMode || editor.inSelectMode || editor.inCommandLineModeWithVisual) {
       // Another inconsistency with immutable caret. This method should be called on the new caret instance.
-      caretAfterMove.vimMoveSelectionToCaret(this.vimSelectionStart)
-      editor.findLastVersionOfCaret(caretAfterMove) ?: caretAfterMove
-    } else if (editor.inCommandLineMode && caretAfterMove.hasSelection()) {
-      // If we're updating the caret in Command-line mode, it's most likely due to incsearch
-      caretAfterMove.setSelection(caretAfterMove.selectionStart, offset)
-      editor.findLastVersionOfCaret(caretAfterMove) ?: caretAfterMove
+      updatedCaret.vimMoveSelectionToCaret(this.vimSelectionStart)
+      editor.findLastVersionOfCaret(updatedCaret) ?: updatedCaret
     } else {
       editor.exitVisualMode()
-      caretAfterMove
+      updatedCaret
     }
     injector.motion.onAppCodeMovement(editor, this, offset, oldOffset)
-    return caretAfterMove
+    return updatedCaret
   }
 
   fun moveToOffsetNative(offset: Int)
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/group/visual/EngineVisualGroup.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/group/visual/EngineVisualGroup.kt
index a7dccc907..fb5c738a4 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/group/visual/EngineVisualGroup.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/group/visual/EngineVisualGroup.kt
@@ -20,6 +20,7 @@ import com.maddyhome.idea.vim.helper.RWLockLabel
 import com.maddyhome.idea.vim.state.mode.Mode
 import com.maddyhome.idea.vim.state.mode.SelectionType
 import com.maddyhome.idea.vim.state.mode.inBlockSelection
+import com.maddyhome.idea.vim.state.mode.inCommandLineModeWithVisual
 import com.maddyhome.idea.vim.state.mode.inSelectMode
 import com.maddyhome.idea.vim.state.mode.inVisualMode
 import com.maddyhome.idea.vim.state.mode.selectionType
@@ -122,7 +123,7 @@ fun vimMoveBlockSelectionToOffset(editor: VimEditor, offset: Int) {
  * @see vimMoveBlockSelectionToOffset for blockwise selection
  */
 fun VimCaret.vimMoveSelectionToCaret(vimSelectionStart: Int = this.vimSelectionStart) {
-  if (!editor.inVisualMode && !editor.inSelectMode) error("Attempt to extent selection in non-visual mode")
+  if (!editor.inVisualMode && !editor.inSelectMode && !editor.inCommandLineModeWithVisual) error("Attempt to extent selection in non-visual mode")
   if (editor.inBlockSelection) error("Move caret with [vimMoveBlockSelectionToOffset]")
 
   val startOffsetMark = vimSelectionStart
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/Mode.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/Mode.kt
index 444fc1051..f647abf34 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/Mode.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/Mode.kt
@@ -156,6 +156,13 @@ sealed interface Mode {
         "CMD_LINE mode can be active only in NORMAL, OP_PENDING, VISUAL or INSERT modes, not ${returnTo.javaClass.simpleName}"
       }
     }
+
+    /**
+     * Returns true if Visual mode is pending, by starting Command-line with a Visual selection
+     *
+     * For example, `v/foo` or `v:<C-U>normal 3j`
+     */
+    val isVisualPending = returnTo is VISUAL
   }
 }
 
diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/editorExtensions.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/editorExtensions.kt
index 8389b4f33..538e7704f 100644
--- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/editorExtensions.kt
+++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/state/mode/editorExtensions.kt
@@ -26,6 +26,9 @@ val VimEditor.inSelectMode: Boolean
 val VimEditor.inCommandLineMode: Boolean
   get() = this.mode is Mode.CMD_LINE
 
+val VimEditor.inCommandLineModeWithVisual: Boolean
+  get() = (this.mode as? Mode.CMD_LINE)?.isVisualPending == true
+
 val VimEditor.singleModeActive: Boolean
   get() = this.mode.isSingleModeActive