neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit f7c939fa7af9744bcb6d79100a7e126f7e9c8f5c
parent 2f95abddfaf8921555a7e252fc77ed26cbb4de5c
Author: Yochem van Rosmalen <git@yochem.nl>
Date:   Sun, 29 Jun 2025 17:19:10 +0200

fix(exrc): exrc knows its own location (#34638)

fix(exrc): lua exrc files know their location

Problem:
'exrc' files are inherently bound to their location / workspace and
therefore require to "know" their location on the filesystem. However,
currently using `debug.getinfo(1, 'S')` returns `"<nvim>"`.

Solution:
Include the filepath as chunkname in `loadstring()` and `nlua_exec()`.
Diffstat:
Mruntime/doc/options.txt | 2++
Mruntime/doc/vimfn.txt | 3++-
Mruntime/lua/vim/_defaults.lua | 2+-
Mruntime/lua/vim/_meta/options.lua | 2++
Mruntime/lua/vim/_meta/vimfn.lua | 3++-
Msrc/nvim/api/deprecated.c | 2+-
Msrc/nvim/api/vim.c | 2+-
Msrc/nvim/eval.lua | 3++-
Msrc/nvim/lua/executor.c | 7+++++--
Msrc/nvim/lua/executor.h | 2+-
Msrc/nvim/main.c | 5+++--
Msrc/nvim/options.lua | 2++
12 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt @@ -2527,6 +2527,8 @@ A jump table for the options with a short description can be found at |Q_op|. Unset 'exrc' to stop further searching of 'exrc' files in parent directories, similar to |editorconfig.root|. + To get its own location, Lua exrc files can use |debug.getinfo()|. + Compare 'exrc' to |editorconfig|: - 'exrc' can execute any code; editorconfig only specifies settings. - 'exrc' is Nvim-specific; editorconfig works in other editors. diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt @@ -2114,7 +2114,8 @@ expand({string} [, {nosuf} [, {list}]]) *expand()* <SID> "<SNR>123_" where "123" is the current script ID |<SID>| <script> sourced script file, or script file - where the current function was defined + where the current function was defined. + Use |debug.getinfo()| in Lua scripts. <stack> call stack <cword> word under the cursor <cWORD> WORD under the cursor diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua @@ -956,7 +956,7 @@ do local trusted = vim.secure.read(file) --[[@as string|nil]] if trusted then if vim.endswith(file, '.lua') then - assert(loadstring(trusted))() + assert(loadstring(trusted, '@' .. file))() else vim.api.nvim_exec2(trusted, {}) end diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua @@ -2194,6 +2194,8 @@ vim.bo.et = vim.bo.expandtab --- Unset 'exrc' to stop further searching of 'exrc' files in parent --- directories, similar to `editorconfig.root`. --- +--- To get its own location, Lua exrc files can use `debug.getinfo()`. +--- --- Compare 'exrc' to `editorconfig`: --- - 'exrc' can execute any code; editorconfig only specifies settings. --- - 'exrc' is Nvim-specific; editorconfig works in other editors. diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua @@ -1871,7 +1871,8 @@ function vim.fn.exp(expr) end --- <SID> "<SNR>123_" where "123" is the --- current script ID |<SID>| --- <script> sourced script file, or script file ---- where the current function was defined +--- where the current function was defined. +--- Use |debug.getinfo()| in Lua scripts. --- <stack> call stack --- <cword> word under the cursor --- <cWORD> WORD under the cursor diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c @@ -62,7 +62,7 @@ Object nvim_execute_lua(String code, Array args, Arena *arena, Error *err) FUNC_API_DEPRECATED_SINCE(7) FUNC_API_REMOTE_ONLY { - return nlua_exec(code, args, kRetObject, arena, err); + return nlua_exec(code, NULL, args, kRetObject, arena, err); } /// Gets the buffer number diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c @@ -513,7 +513,7 @@ Object nvim_exec_lua(String code, Array args, Arena *arena, Error *err) FUNC_API_REMOTE_ONLY { // TODO(bfredl): convert directly from msgpack to lua and then back again - return nlua_exec(code, args, kRetObject, arena, err); + return nlua_exec(code, NULL, args, kRetObject, arena, err); } /// Calculates the number of display cells occupied by `text`. diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua @@ -2421,7 +2421,8 @@ M.funcs = { <SID> "<SNR>123_" where "123" is the current script ID |<SID>| <script> sourced script file, or script file - where the current function was defined + where the current function was defined. + Use |debug.getinfo()| in Lua scripts. <stack> call stack <cword> word under the cursor <cWORD> WORD under the cursor diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c @@ -1512,17 +1512,20 @@ int typval_exec_lua_callable(LuaRef lua_cb, int argcount, typval_T *argvars, typ /// Used for nvim_exec_lua() and internally to execute a lua string. /// /// @param[in] str String to execute. +/// @param[in] chunkname Chunkname, defaults to "<nvim>". /// @param[in] args array of ... args /// @param[in] mode Whether and how the the return value should be converted to Object /// @param[in] arena can be NULL, then nested allocations are used /// @param[out] err Location where error will be saved. /// /// @return Return value of the execution. -Object nlua_exec(const String str, const Array args, LuaRetMode mode, Arena *arena, Error *err) +Object nlua_exec(const String str, const char *chunkname, const Array args, LuaRetMode mode, + Arena *arena, Error *err) { lua_State *const lstate = global_lstate; - if (luaL_loadbuffer(lstate, str.data, str.size, "<nvim>")) { + const char *name = (chunkname && chunkname[0]) ? chunkname : "<nvim>"; + if (luaL_loadbuffer(lstate, str.data, str.size, name)) { size_t len; const char *errstr = lua_tolstring(lstate, -1, &len); api_set_error(err, kErrorTypeValidation, "Lua: %.*s", (int)len, errstr); diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h @@ -26,7 +26,7 @@ typedef struct { } nlua_ref_state_t; #define NLUA_EXEC_STATIC(cstr, arg, mode, arena, err) \ - nlua_exec(STATIC_CSTR_AS_STRING(cstr), arg, mode, arena, err) + nlua_exec(STATIC_CSTR_AS_STRING(cstr), NULL, arg, mode, arena, err) #define NLUA_CLEAR_REF(x) \ do { \ diff --git a/src/nvim/main.c b/src/nvim/main.c @@ -961,7 +961,7 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr, ADD_C(a, CSTR_AS_OBJ(connect_error)); ADD_C(a, ARRAY_OBJ(args)); String s = STATIC_CSTR_AS_STRING("return vim._cs_remote(...)"); - Object o = nlua_exec(s, a, kRetObject, NULL, &err); + Object o = nlua_exec(s, NULL, a, kRetObject, NULL, &err); kv_destroy(args); if (ERROR_SET(&err)) { fprintf(stderr, "%s\n", err.msg); @@ -2062,7 +2062,8 @@ static void do_exrc_initialization(void) str = nlua_read_secure(VIMRC_LUA_FILE); if (str != NULL) { Error err = ERROR_INIT; - nlua_exec(cstr_as_string(str), (Array)ARRAY_DICT_INIT, kRetNilBool, NULL, &err); + nlua_exec(cstr_as_string(str), "@"VIMRC_LUA_FILE, (Array)ARRAY_DICT_INIT, kRetNilBool, NULL, + &err); xfree(str); if (ERROR_SET(&err)) { semsg("Error in %s:", VIMRC_LUA_FILE); diff --git a/src/nvim/options.lua b/src/nvim/options.lua @@ -2792,6 +2792,8 @@ local options = { Unset 'exrc' to stop further searching of 'exrc' files in parent directories, similar to |editorconfig.root|. + To get its own location, Lua exrc files can use |debug.getinfo()|. + Compare 'exrc' to |editorconfig|: - 'exrc' can execute any code; editorconfig only specifies settings. - 'exrc' is Nvim-specific; editorconfig works in other editors.