commit 103ddaf9ae80a32e50325888b0cde1c4354f8413
parent d3aae6172ad3b553604bf5ecf51fa071e3c077dd
Author: Tommy Guo <tommyguo024@outlook.com>
Date: Tue, 20 Jan 2026 21:18:33 -0500
fix(lua): correct line number reporting for options set in coroutines (#37463)
Diffstat:
4 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/src/gen/gen_api_dispatch.lua b/src/gen/gen_api_dispatch.lua
@@ -840,6 +840,8 @@ local function process_function(fn)
else
cparams = cparams:gsub(', $', '')
end
+
+ write_shifted_output(' ENTER_LUA_ACTIVE_STATE(lstate);\n')
local free_at_exit_code = ''
for i = 1, #free_code do
local rev_i = #free_code - i + 1
@@ -903,6 +905,7 @@ exit_0:
-- NOTE: we currently assume err_throw needs nothing from arena
write_shifted_output(
[[
+ LEAVE_LUA_ACTIVE_STATE();
%s
%s
%s
@@ -916,6 +919,7 @@ exit_0:
write_shifted_output(
[[
%s(%s);
+ LEAVE_LUA_ACTIVE_STATE();
%s
%s
return 0;
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
@@ -81,6 +81,9 @@ static bool in_script = false;
// Initialized in nlua_init().
static lua_State *global_lstate = NULL;
+// Tracks the currently executing Lua thread (main or coroutine).
+lua_State *active_lstate = NULL;
+
static LuaRef require_ref = LUA_REFNIL;
static uv_thread_t main_thread;
@@ -883,6 +886,7 @@ void nlua_init(char **argv, int argc, int lua_arg0)
luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem);
global_lstate = lstate;
+ active_lstate = lstate;
main_thread = uv_thread_self();
nlua_init_argv(lstate, argv, argc, lua_arg0);
}
@@ -1484,6 +1488,7 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, const char *name
}
lua_State *const lstate = global_lstate;
+
if (luaL_loadbuffer(lstate, lcmd, lcmd_len, name)) {
nlua_error(lstate, _("E5107: Lua: %.*s"));
return;
@@ -2131,7 +2136,7 @@ void nlua_set_sctx(sctx_T *current)
if (p_verbose <= 0) {
return;
}
- lua_State *const lstate = global_lstate;
+ lua_State *const lstate = active_lstate;
lua_Debug *info = (lua_Debug *)xmalloc(sizeof(lua_Debug));
// Files where internal wrappers are defined so we can ignore them
diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h
@@ -55,3 +55,13 @@ enum { CB_MAX_ERROR = 3, };
EXTERN nlua_ref_state_t *nlua_global_refs INIT( = NULL);
EXTERN bool nlua_disable_preload INIT( = false);
+
+/// Tracks the active Lua thread
+extern lua_State *active_lstate;
+
+#define ENTER_LUA_ACTIVE_STATE(new_state) \
+ lua_State *const save_active_lstate = active_lstate; \
+ active_lstate = (new_state);
+
+#define LEAVE_LUA_ACTIVE_STATE() \
+ active_lstate = save_active_lstate;
diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua
@@ -80,6 +80,10 @@ local set_list = ([[
vim.api.nvim_exec2(set_list, {})
vim.api.nvim_create_autocmd('User', { pattern = 'set_mouse', callback = cb })
+
+coroutine.wrap(function()
+ vim.o.busy = 2
+end)()
]=]
)
exec(cmd .. ' ' .. script_file)
@@ -281,6 +285,19 @@ TestHL2 xxx guibg=Green
result
)
end)
+
+ it('for option set in coroutine', function()
+ local result = exec_capture(':verbose set busy?')
+ eq(
+ string.format(
+ [[
+ busy=2
+ Last set from %s]],
+ get_last_set_location(59)
+ ),
+ result
+ )
+ end)
end
describe('lua :verbose with -V1', function()