aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluukvbaal <luukvbaal@gmail.com>2024-06-04 15:09:12 +0200
committerGitHub <noreply@github.com>2024-06-04 06:09:12 -0700
commitb66106a46c5c6180c7f80852a8c822b400e73100 (patch)
tree3ea46b835fbbd014a719fdab42487385843b5225
parent8cbb1f20e557461c8417583a7f69d53aaaef920b (diff)
downloadrneovim-b66106a46c5c6180c7f80852a8c822b400e73100.tar.gz
rneovim-b66106a46c5c6180c7f80852a8c822b400e73100.tar.bz2
rneovim-b66106a46c5c6180c7f80852a8c822b400e73100.zip
fix(ui): superfluous showmode / excessive grid_cursor_goto #29089
Problem: Unsetting global variables earlier in #28578 to avoid recursiveness, caused superfluous or even unlimited showmode(). Solution: Partly revert #28578 so that the globals are unset at the end of showmode(), and avoid recursiveness for ext UI by adding a recursive function guard to each generated UI call that may call a Lua callback.
-rw-r--r--src/nvim/drawscreen.c22
-rw-r--r--src/nvim/ex_getln.c5
-rw-r--r--src/nvim/generators/gen_api_ui_events.lua8
-rw-r--r--test/functional/ui/messages_spec.lua16
4 files changed, 35 insertions, 16 deletions
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index bd9a834869..88e1f302da 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -931,13 +931,7 @@ int showmode(void)
msg_ext_clear(true);
}
- // Don't make non-flushed message part of the showmode and reset global
- // variables before flushing to to avoid recursiveness.
- bool draw_mode = redraw_mode;
- bool clear_cmd = clear_cmdline;
- redraw_cmdline = false;
- redraw_mode = false;
- clear_cmdline = false;
+ // Don't make non-flushed message part of the showmode.
msg_ext_ui_flush();
msg_grid_validate();
@@ -960,8 +954,8 @@ int showmode(void)
msg_check_for_delay(false);
// if the cmdline is more than one line high, erase top lines
- bool need_clear = clear_cmd;
- if (clear_cmd && cmdline_row < Rows - 1) {
+ bool need_clear = clear_cmdline;
+ if (clear_cmdline && cmdline_row < Rows - 1) {
msg_clr_cmdline(); // will reset clear_cmdline
}
@@ -1083,7 +1077,7 @@ int showmode(void)
}
mode_displayed = true;
- if (need_clear || clear_cmd || draw_mode) {
+ if (need_clear || clear_cmdline || redraw_mode) {
msg_clr_eos();
}
msg_didout = false; // overwrite this message
@@ -1092,10 +1086,10 @@ int showmode(void)
msg_no_more = false;
lines_left = save_lines_left;
need_wait_return = nwr_save; // never ask for hit-return for this
- } else if (clear_cmd && msg_silent == 0) {
+ } else if (clear_cmdline && msg_silent == 0) {
// Clear the whole command line. Will reset "clear_cmdline".
msg_clr_cmdline();
- } else if (draw_mode) {
+ } else if (redraw_mode) {
msg_pos_mode();
msg_clr_eos();
}
@@ -1118,6 +1112,10 @@ int showmode(void)
grid_line_flush();
}
+ redraw_cmdline = false;
+ redraw_mode = false;
+ clear_cmdline = false;
+
return length;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 4323a9d221..cef1868fc8 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -3455,11 +3455,9 @@ void cmdline_screen_cleared(void)
/// called by ui_flush, do what redraws necessary to keep cmdline updated.
void cmdline_ui_flush(void)
{
- static bool flushing = false;
- if (!ui_has(kUICmdline) || flushing) {
+ if (!ui_has(kUICmdline)) {
return;
}
- flushing = true;
int level = ccline.level;
CmdlineInfo *line = &ccline;
while (level > 0 && line) {
@@ -3474,7 +3472,6 @@ void cmdline_ui_flush(void)
}
line = line->prev_ccline;
}
- flushing = false;
}
// Put a character on the command line. Shifts the following text to the
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index 516b5ad5ae..c5b37672bf 100644
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -128,8 +128,16 @@ for i = 1, #events do
write_signature(call_output, ev, '')
call_output:write('\n{\n')
if ev.remote_only then
+ -- Lua callbacks may emit other events or the same event again. Avoid the latter
+ -- by adding a recursion guard to each generated function that may call a Lua callback.
+ call_output:write(' static bool entered = false;\n')
+ call_output:write(' if (entered) {\n')
+ call_output:write(' return;\n')
+ call_output:write(' }\n')
+ call_output:write(' entered = true;\n')
write_arglist(call_output, ev)
call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n')
+ call_output:write(' entered = false;\n')
elseif ev.compositor_impl then
call_output:write(' ui_comp_' .. ev.name)
write_signature(call_output, ev, '', true)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index ca52a265fa..07192800e5 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1081,6 +1081,22 @@ stack traceback:
},
})
end)
+
+ it('does not do showmode unnecessarily #29086', function()
+ local screen_showmode = screen._handle_msg_showmode
+ local showmode = 0
+ screen._handle_msg_showmode = function(...)
+ screen_showmode(...)
+ showmode = showmode + 1
+ end
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ })
+ eq(showmode, 1)
+ end)
end)
describe('ui/builtin messages', function()