11/*
2- * Copyright 2003-2023 The IdeaVim authors
2+ * Copyright 2003-2026 The IdeaVim authors
33 *
44 * Use of this source code is governed by an MIT-style
55 * license that can be found in the LICENSE.txt file or at
@@ -17,6 +17,7 @@ import com.maddyhome.idea.vim.api.VimEditor
1717import com.maddyhome.idea.vim.api.getLineEndForOffset
1818import com.maddyhome.idea.vim.api.getLineStartForOffset
1919import com.maddyhome.idea.vim.api.injector
20+ import com.maddyhome.idea.vim.group.visual.VimVisualTimer
2021import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
2122import com.maddyhome.idea.vim.newapi.IjEditorExecutionContext
2223import com.maddyhome.idea.vim.newapi.IjVimCaret
@@ -28,6 +29,9 @@ import com.maddyhome.idea.vim.state.mode.inSelectMode
2829internal fun VimEditor.exitSelectMode (adjustCaretPosition : Boolean ) {
2930 if (! this .inSelectMode) return
3031
32+ // Cancel any pending visual timer mode change. When the user explicitly exits SELECT mode,
33+ // we don't want a delayed selection change handler to override their intent.
34+ VimVisualTimer .drop()
3135 mode = mode.returnTo
3236 SelectionVimListenerSuppressor .lock().use {
3337 carets().forEach { vimCaret ->
@@ -47,5 +51,8 @@ internal fun VimEditor.exitSelectMode(adjustCaretPosition: Boolean) {
4751}
4852
4953internal fun Editor.exitInsertMode (context : DataContext ) {
54+ // Cancel any pending visual timer mode change. When the user explicitly presses Escape to exit INSERT mode,
55+ // we don't want a delayed selection change handler to override their intent and switch back to INSERT.
56+ VimVisualTimer .drop()
5057 VimPlugin .getChange().processEscape(IjVimEditor (this ), IjEditorExecutionContext (context))
5158}
0 commit comments