aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluukvbaal <luukvbaal@gmail.com>2025-01-15 15:55:21 +0100
committerGitHub <noreply@github.com>2025-01-15 06:55:21 -0800
commitbbf36ef8ef86534e317e4e0153730a40ae4c936e (patch)
treef42051d012c32af4fb6847dd975498a01585486e
parent5cc93ef4729c65d6a539c8d0a8a2bf767cf17ced (diff)
downloadrneovim-bbf36ef8ef86534e317e4e0153730a40ae4c936e.tar.gz
rneovim-bbf36ef8ef86534e317e4e0153730a40ae4c936e.tar.bz2
rneovim-bbf36ef8ef86534e317e4e0153730a40ae4c936e.zip
fix(cmdline): prevent cmdline_show events after exiting cmdline #32033
Problem: If a (vim.ui_attach) cmdline_hide callback triggers a redraw, it may cause cmdline_show events for an already exited cmdline. Solution: Avoid emitting cmdline_show event when ccline.cmdbuff is already NULL. Unset ccline.cmdbuff before emitting cmdline_hide.
-rw-r--r--src/nvim/ex_getln.c8
-rw-r--r--test/functional/lua/ui_event_spec.lua63
2 files changed, 62 insertions, 9 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 0b5d0864e5..baff795e71 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -951,6 +951,8 @@ theend:
kv_destroy(ccline.last_colors.colors);
char *p = ccline.cmdbuff;
+ // Prevent show events triggered by a (vim.ui_attach) hide callback.
+ ccline.cmdbuff = NULL;
if (ui_has(kUICmdline)) {
ui_call_cmdline_hide(ccline.level, s->gotesc);
@@ -965,8 +967,6 @@ theend:
if (did_save_ccline) {
restore_cmdline(&save_ccline);
- } else {
- ccline.cmdbuff = NULL;
}
return (uint8_t *)p;
@@ -3415,6 +3415,10 @@ static void draw_cmdline(int start, int len)
static void ui_ext_cmdline_show(CmdlineInfo *line)
{
+ if (line->cmdbuff == NULL) {
+ return;
+ }
+
Arena arena = ARENA_EMPTY;
Array content;
if (cmdline_star) {
diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua
index af6b2ceac3..c6f98c8640 100644
--- a/test/functional/lua/ui_event_spec.lua
+++ b/test/functional/lua/ui_event_spec.lua
@@ -168,18 +168,67 @@ describe('vim.ui_attach', function()
vim.ui_attach(ns, { ext_messages = true }, function(ev)
if ev == 'msg_show' then
vim.schedule(function() vim.cmd.redraw() end)
- else
- vim.cmd.redraw()
+ elseif ev:find('cmdline') then
+ _G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0)
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, { tostring(_G.cmdline) })
+ vim.cmd('redraw')
end
- _G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0)
end
)]])
+ screen:expect([[
+ ^ |
+ {1:~ }|*4
+ ]])
feed(':')
- n.assert_alive()
- eq(2, exec_lua('return _G.cmdline'))
- n.assert_alive()
+ screen:expect({
+ grid = [[
+ ^1 |
+ {1:~ }|*4
+ ]],
+ cmdline = { {
+ content = { { '' } },
+ firstc = ':',
+ pos = 0,
+ } },
+ })
feed('version<CR><CR>v<Esc>')
- n.assert_alive()
+ screen:expect({
+ grid = [[
+ ^2 |
+ {1:~ }|*4
+ ]],
+ cmdline = { { abort = false } },
+ })
+ feed([[:call confirm("Save changes?", "&Yes\n&No\n&Cancel")<CR>]])
+ screen:expect({
+ grid = [[
+ ^5 |
+ {1:~ }|*4
+ ]],
+ cmdline = {
+ {
+ content = { { '' } },
+ hl_id = 10,
+ pos = 0,
+ prompt = '[Y]es, (N)o, (C)ancel: ',
+ },
+ },
+ messages = {
+ {
+ content = { { '\nSave changes?\n', 6, 10 } },
+ history = false,
+ kind = 'confirm',
+ },
+ },
+ })
+ feed('n')
+ screen:expect({
+ grid = [[
+ ^5 |
+ {1:~ }|*4
+ ]],
+ cmdline = { { abort = false } },
+ })
end)
it("preserved 'incsearch/command' screen state after :redraw from ext_cmdline", function()