diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-12-06 20:01:28 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-06 20:01:28 +0800 |
commit | e9f4ceeb7467364554ecef770fd3380e89457abb (patch) | |
tree | a1a224f25606e50d665dc4c7fee3b6b1b147dd2b | |
parent | 812d02970206d5a65819e076bcddedd92e083a19 (diff) | |
download | rneovim-e9f4ceeb7467364554ecef770fd3380e89457abb.tar.gz rneovim-e9f4ceeb7467364554ecef770fd3380e89457abb.tar.bz2 rneovim-e9f4ceeb7467364554ecef770fd3380e89457abb.zip |
fix(events): don't expand `args.file` for Lua callback (#31473)
Problem: In an autocommand Lua callback whether `args.file` is expanded
depends on whether `expand('<afile>')` has been called.
Solution: Always use the unexpanded file name for `args.file`.
Related to #31306 and vim/vim#16106. This doesn't provide `sfname`, but
at least makes `args.file` have a consistent value.
-rw-r--r-- | runtime/doc/api.txt | 6 | ||||
-rw-r--r-- | runtime/lua/vim/_meta/api.lua | 6 | ||||
-rw-r--r-- | src/nvim/api/autocmd.c | 6 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 6 | ||||
-rw-r--r-- | src/nvim/autocmd_defs.h | 1 | ||||
-rw-r--r-- | test/functional/api/autocmd_spec.lua | 50 |
6 files changed, 49 insertions, 26 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 9cb8f72348..cb3b2a3f77 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -3494,9 +3494,9 @@ nvim_create_autocmd({event}, {opts}) *nvim_create_autocmd()* • event: (string) name of the triggered event |autocmd-events| • group: (number|nil) autocommand group id, if any - • match: (string) expanded value of <amatch> - • buf: (number) expanded value of <abuf> - • file: (string) expanded value of <afile> + • file: (string) <afile> (not expanded to a full path) + • match: (string) <amatch> (expanded to a full path) + • buf: (number) <abuf> • data: (any) arbitrary data passed from |nvim_exec_autocmds()| *event-data* • command (string) optional: Vim command to execute on event. diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index d74ee11b46..b2385197bd 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -963,9 +963,9 @@ function vim.api.nvim_create_augroup(name, opts) end --- - id: (number) autocommand id --- - event: (string) name of the triggered event `autocmd-events` --- - group: (number|nil) autocommand group id, if any ---- - match: (string) expanded value of [<amatch>] ---- - buf: (number) expanded value of [<abuf>] ---- - file: (string) expanded value of [<afile>] +--- - file: (string) [<afile>] (not expanded to a full path) +--- - match: (string) [<amatch>] (expanded to a full path) +--- - buf: (number) [<abuf>] --- - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]() --- - command (string) optional: Vim command to execute on event. Cannot be used with --- {callback} diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index db87500d08..45e2de69e0 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -386,9 +386,9 @@ cleanup: /// - id: (number) autocommand id /// - event: (string) name of the triggered event |autocmd-events| /// - group: (number|nil) autocommand group id, if any -/// - match: (string) expanded value of [<amatch>] -/// - buf: (number) expanded value of [<abuf>] -/// - file: (string) expanded value of [<afile>] +/// - file: (string) [<afile>] (not expanded to a full path) +/// - match: (string) [<amatch>] (expanded to a full path) +/// - buf: (number) [<abuf>] /// - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]() /// - command (string) optional: Vim command to execute on event. Cannot be used with /// {callback} diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index c08ef7a4c1..118a50e15d 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1666,7 +1666,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force } else { autocmd_fname = fname_io; } + char *afile_orig = NULL; ///< Unexpanded <afile> if (autocmd_fname != NULL) { + afile_orig = xstrdup(autocmd_fname); // Allocate MAXPATHL for when eval_vars() resolves the fullpath. autocmd_fname = xstrnsave(autocmd_fname, MAXPATHL); } @@ -1798,6 +1800,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force // save vector size, to avoid an endless loop when more patterns // are added when executing autocommands .ausize = kv_size(autocmds[(int)event]), + .afile_orig = afile_orig, .fname = fname, .sfname = sfname, .tail = tail, @@ -1865,6 +1868,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force autocmd_nested = save_autocmd_nested; xfree(SOURCING_NAME); estack_pop(); + xfree(afile_orig); xfree(autocmd_fname); autocmd_fname = save_autocmd_fname; autocmd_fname_full = save_autocmd_fname_full; @@ -2029,8 +2033,8 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc) MAXSIZE_TEMP_DICT(data, 7); PUT_C(data, "id", INTEGER_OBJ(ac->id)); PUT_C(data, "event", CSTR_AS_OBJ(event_nr2name(apc->event))); + PUT_C(data, "file", CSTR_AS_OBJ(apc->afile_orig)); PUT_C(data, "match", CSTR_AS_OBJ(autocmd_match)); - PUT_C(data, "file", CSTR_AS_OBJ(autocmd_fname)); PUT_C(data, "buf", INTEGER_OBJ(autocmd_bufnr)); if (apc->data) { diff --git a/src/nvim/autocmd_defs.h b/src/nvim/autocmd_defs.h index 490782b209..cba947e85f 100644 --- a/src/nvim/autocmd_defs.h +++ b/src/nvim/autocmd_defs.h @@ -52,6 +52,7 @@ struct AutoPatCmd_S { AutoPat *lastpat; ///< Last matched AutoPat size_t auidx; ///< Current autocmd index to execute size_t ausize; ///< Saved AutoCmd vector size + char *afile_orig; ///< Unexpanded <afile> char *fname; ///< Fname to match with char *sfname; ///< Sfname to match with char *tail; ///< Tail of fname diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index 3f9883f43f..bb6456f45b 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -273,54 +273,72 @@ describe('autocmd api', function() eq({}, api.nvim_get_autocmds({ event = 'User', pattern = 'Test' })) end) - it('receives an args table', function() + local function test_autocmd_args(event) + local function get_amatch(pat) + return event == 'User' and pat or vim.fs.normalize(n.fn.fnamemodify(pat, ':p')) + end + local group_id = api.nvim_create_augroup('TestGroup', {}) -- Having an existing autocmd calling expand("<afile>") shouldn't change args #18964 - api.nvim_create_autocmd('User', { + api.nvim_create_autocmd(event, { group = 'TestGroup', pattern = 'Te*', command = 'call expand("<afile>")', }) - local autocmd_id = exec_lua [[ - return vim.api.nvim_create_autocmd("User", { + local autocmd_id = exec_lua(([[ + return vim.api.nvim_create_autocmd(%q, { group = "TestGroup", pattern = "Te*", callback = function(args) vim.g.autocmd_args = args end, }) - ]] + ]]):format(event)) - api.nvim_exec_autocmds('User', { pattern = 'Test pattern' }) + local exec_pat = 'Test pattern' + local amatch = get_amatch(exec_pat) + api.nvim_exec_autocmds(event, { pattern = exec_pat }) eq({ id = autocmd_id, group = group_id, - event = 'User', - match = 'Test pattern', - file = 'Test pattern', + event = event, + match = amatch, + file = exec_pat, buf = 1, }, api.nvim_get_var('autocmd_args')) -- Test without a group - autocmd_id = exec_lua [[ - return vim.api.nvim_create_autocmd("User", { + autocmd_id = exec_lua(([[ + return vim.api.nvim_create_autocmd(%q, { pattern = "*", callback = function(args) vim.g.autocmd_args = args end, }) - ]] + ]]):format(event)) - api.nvim_exec_autocmds('User', { pattern = 'some_pat' }) + exec_pat = 'some_pat' + amatch = get_amatch(exec_pat) + api.nvim_exec_autocmds(event, { pattern = exec_pat }) eq({ id = autocmd_id, group = nil, - event = 'User', - match = 'some_pat', - file = 'some_pat', + event = event, + match = amatch, + file = exec_pat, buf = 1, }, api.nvim_get_var('autocmd_args')) + end + + describe('receives correct args table', function() + it('for event that takes non-file pattern', function() + test_autocmd_args('User') + end) + + it('for event that takes file pattern', function() + test_autocmd_args('BufEnter') + end) end) it('can receive arbitrary data', function() |