commit 1d57374c41e6c46c41d537c342ce30ad96cdb85b
parent c2ecc9ca41a95b1644cae183fd19ce49ce10f980
Author: luukvbaal <luukvbaal@gmail.com>
Date: Tue, 27 Jan 2026 15:30:37 +0100
fix(ui): textlock still causes issues for UI callbacks #37513
Problem: There are still ways to run into textlock errors with
vim.ui_attach callbacks trying to display a UI event.
Solution: Disregard textlock again during vim.ui_attach() callbacks
(also when scheduled). Partially revert 3277dc3b; avoiding
to flush while textlock is set is still helpful.
Diffstat:
3 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
@@ -382,10 +382,18 @@ static void nlua_schedule_event(void **argv)
lua_State *const lstate = global_lstate;
nlua_pushref(lstate, cb);
nlua_unref_global(lstate, cb);
+
+ // Don't impose textlock restrictions upon UI event handlers.
+ int save_expr_map_lock = expr_map_lock;
+ int save_textlock = textlock;
+ expr_map_lock = ns_id > 0 ? 0 : expr_map_lock;
+ textlock = ns_id > 0 ? 0 : textlock;
if (nlua_pcall(lstate, 0, 0)) {
nlua_error(lstate, _("vim.schedule callback: %.*s"));
ui_remove_cb(ns_id, true);
}
+ expr_map_lock = save_expr_map_lock;
+ textlock = save_textlock;
}
/// Schedule Lua callback on main loop's event queue
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
@@ -550,7 +550,7 @@ void ui_flush(void)
win_ui_flush(false);
// Avoid flushing callbacks expected to change text during textlock.
- if (textlock == 0) {
+ if (textlock == 0 && expr_map_lock == 0) {
cmdline_ui_flush();
msg_ext_ui_flush();
}
@@ -761,9 +761,14 @@ void ui_call_event(char *name, Array args)
fast = !strequal(not_fast[i], args.items[0].data.string.data);
}
+ // Don't impose textlock restrictions upon UI event handlers.
+ int save_expr_map_lock = expr_map_lock;
+ int save_textlock = textlock;
+ expr_map_lock = 0;
+ textlock = 0;
+
bool handled = false;
UIEventCallback *event_cb;
-
map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, {
Error err = ERROR_INIT;
uint32_t ns_id = ui_event_ns_id;
@@ -778,6 +783,8 @@ void ui_call_event(char *name, Array args)
}
api_clear_error(&err);
})
+ expr_map_lock = save_expr_map_lock;
+ textlock = save_textlock;
if (!handled) {
UI_CALL(true, event, ui, name, args);
diff --git a/test/functional/ui/messages2_spec.lua b/test/functional/ui/messages2_spec.lua
@@ -429,8 +429,7 @@ describe('messages2', function()
exec_lua(function()
vim.schedule(function()
print('foo')
- vim.uv.sleep(100)
- print('bar')
+ vim.fn.getchar()
end)
end)
screen:expect([[
@@ -438,13 +437,6 @@ describe('messages2', function()
{1:~ }|*12
foo |
]])
- screen:expect([[
- ^ |
- {1:~ }|*10
- {3: }|
- foo |
- bar |
- ]])
end)
it('properly formatted carriage return messages', function()
@@ -477,4 +469,46 @@ describe('messages2', function()
{15:bar}{9:baz} |
]])
end)
+
+ it('can show message during textlock', function()
+ exec_lua(function()
+ _G.omnifunc = function()
+ print('x!')
+ vim.cmd.sleep('100m')
+ end
+ vim.bo.omnifunc = 'v:lua.omnifunc'
+ end)
+ feed('i<C-X>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*12
+ {5:-- ^X mode (^]^D^E^F^I^K^L^N^O^P^Rs^U^V^Y)} |
+ ]])
+ feed('<C-O>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*12
+ x! |
+ ]])
+ screen:expect([[
+ ^ |
+ {1:~ }|*12
+ {5:-- Omni completion (^O^N^P) }{9:Pattern not found} |
+ ]])
+ exec_lua(function()
+ vim.keymap.set('n', '<F1>', function()
+ print('i hate locks so much!!!!')
+ vim.cmd.messages()
+ end, { expr = true })
+ end)
+ feed('<Esc><F1>')
+ screen:expect([[
+ |
+ {1:~ }|*8
+ {3: }|
+ x^! |
+ x! |
+ i hate locks so much!!!! |*2
+ ]])
+ end)
end)