summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorluukvbaal <luukvbaal@gmail.com>2026-04-22 15:04:20 +0200
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>2026-04-22 13:58:56 +0000
commit9e1c542b558d3fb6b85b1dd1dbf788d05d9fe2df (patch)
tree921edb9ab2fd0c369d64e689d97fa8fe1c1e5e49
parentb6a3ad3979cc187fe59d57091c0434a7d3a937c1 (diff)
fix(cmdline): avoid 'incsearch' recursion after redraw #39303
Problem: A vim.ui_attach() callback that redraws to show a 'verbose' regex message during 'incsearch' results in recusive redrawing. Solution: Check that curwin was redrawn instead of just any window when determining if 'incsearch' highlighting was cleared. (cherry picked from commit 61fb88992d34d16b3058dcd8b1664f575449d964)
-rw-r--r--src/nvim/buffer_defs.h1
-rw-r--r--src/nvim/drawscreen.c2
-rw-r--r--src/nvim/ex_getln.c4
-rw-r--r--test/functional/ui/cmdline2_spec.lua12
4 files changed, 17 insertions, 2 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 24d2b677f1..e02ccbb6ca 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1290,6 +1290,7 @@ struct window_S {
bool w_redr_status; // if true statusline/winbar must be redrawn
bool w_redr_border; // if true border must be redrawn
bool w_redr_statuscol; // if true 'statuscolumn' must be redrawn
+ disptick_T w_display_tick; // when window was last drawn.
// remember what is shown in the 'statusline'-format elements
pos_T w_stl_cursor; // cursor position when last redrawn
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 35bc71787c..275bbb0e73 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -2328,6 +2328,8 @@ redr_statuscol:
wp->w_lines_valid = MAX(wp->w_lines_valid, idx);
+ wp->w_display_tick = display_tick;
+
// Let the syntax stuff know we stop parsing here.
if (syntax_last_parsed != 0 && syntax_present(wp)) {
syntax_end_parsing(wp, syntax_last_parsed + 1);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 5d15a9cde0..a59e7791c4 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1291,7 +1291,7 @@ static int command_line_execute(VimState *state, int key)
return -1; // get another key
}
- disptick_T display_tick_saved = display_tick;
+ disptick_T display_tick_saved = curwin->w_display_tick;
CommandLineState *s = (CommandLineState *)state;
s->c = key;
@@ -1322,7 +1322,7 @@ static int command_line_execute(VimState *state, int key)
init_incsearch_state(&s->is_state);
}
// Re-apply 'incsearch' highlighting in case it was cleared.
- if (display_tick > display_tick_saved && s->is_state.did_incsearch) {
+ if (curwin->w_display_tick > display_tick_saved && s->is_state.did_incsearch) {
may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state);
}
// If f_setcmdline() changed the cmdline treat it as such.
diff --git a/test/functional/ui/cmdline2_spec.lua b/test/functional/ui/cmdline2_spec.lua
index 00d56fd504..e6569dc2a3 100644
--- a/test/functional/ui/cmdline2_spec.lua
+++ b/test/functional/ui/cmdline2_spec.lua
@@ -263,6 +263,18 @@ describe('cmdline2', function()
]])
t.eq({ CmdlineChanged = 1, CursorMovedC = 1 }, exec_lua('return _G.events'))
end)
+
+ it("no 'incsearch' recursion with 'verbose' regex message", function()
+ exec('set verbose=1')
+ feed([[:%s/.\{//}]])
+ screen:expect([[
+ |
+ {1:~ }|*9
+ {3: }|
+ Switching to backtracking RE engine for pattern: .\{ |*2
+ {16::}%{15:s}{16:/.\{//}^ } |
+ ]])
+ end)
end)
describe('cmdline2', function()