diff options
-rw-r--r-- | runtime/doc/api.txt | 25 | ||||
-rw-r--r-- | src/nvim/api/autocmd.c | 16 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 55 | ||||
-rw-r--r-- | test/functional/api/autocmd_spec.lua | 48 |
4 files changed, 129 insertions, 15 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index b383c5eaef..095f74b65d 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -3240,7 +3240,7 @@ nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()* < Parameters: ~ - {event} (String|Array) The event or events to register + {event} (string|array) The event or events to register this autocommand {opts} Dictionary of autocommand options: • group (string|integer) optional: the @@ -3252,9 +3252,26 @@ nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()* Cannot be used with {pattern}. • desc (string) optional: description of the autocommand. - • callback (function|string) optional: Lua - function or Vim function (as string) to execute - on event. Cannot be used with {command} + • callback (function|string) optional: if a + string, the name of a Vimscript function to + call when this autocommand is triggered. + Otherwise, a Lua function which is called when + this autocommand is triggered. Cannot be used + with {command}. Lua callbacks can return true + to delete the autocommand; in addition, they + accept a single table argument with the + following keys: + • id: (number) the autocommand id + • event: (string) the name of the event that + triggered the autocommand |autocmd-events| + • group: (number|nil) the autocommand group id, + if it exists + • match: (string) the expanded value of + |<amatch>| + • buf: (number) the expanded value of |<abuf>| + • file: (string) the expanded value of + |<afile>| + • 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 57f392f98e..ccf4ae3d02 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -366,7 +366,7 @@ cleanup: /// {"CursorHold", "BufPreWrite", "BufPostWrite"} /// </pre> /// -/// @param event (String|Array) The event or events to register this autocommand +/// @param event (string|array) The event or events to register this autocommand /// @param opts Dictionary of autocommand options: /// - group (string|integer) optional: the autocommand group name or /// id to match against. @@ -375,8 +375,18 @@ cleanup: /// - buffer (integer) optional: buffer number for buffer local autocommands /// |autocmd-buflocal|. Cannot be used with {pattern}. /// - desc (string) optional: description of the autocommand. -/// - callback (function|string) optional: Lua function or Vim function (as string) to -/// execute on event. Cannot be used with {command} +/// - callback (function|string) optional: if a string, the name of a Vimscript function +/// to call when this autocommand is triggered. Otherwise, a Lua function which is +/// called when this autocommand is triggered. Cannot be used with {command}. Lua +/// callbacks can return true to delete the autocommand; in addition, they accept a +/// single table argument with the following keys: +/// - id: (number) the autocommand id +/// - event: (string) the name of the event that triggered the autocommand +/// |autocmd-events| +/// - group: (number|nil) the autocommand group id, if it exists +/// - match: (string) the expanded value of |<amatch>| +/// - buf: (number) the expanded value of |<abuf>| +/// - file: (string) the expanded value of |<afile>| /// - command (string) optional: Vim command to execute on event. Cannot be used with /// {callback} /// - once (boolean) optional: defaults to false. Run the autocommand diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 5fc36a8412..48c1bb740d 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -2005,6 +2005,50 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last) } } +static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc) +{ + bool ret = false; + Callback callback = ac->exec.callable.cb; + if (callback.type == kCallbackLua) { + Dictionary data = ARRAY_DICT_INIT; + PUT(data, "id", INTEGER_OBJ(ac->id)); + PUT(data, "event", CSTR_TO_OBJ(event_nr2name(apc->event))); + PUT(data, "match", CSTR_TO_OBJ((char *)autocmd_match)); + PUT(data, "file", CSTR_TO_OBJ((char *)autocmd_fname)); + PUT(data, "buf", INTEGER_OBJ(autocmd_bufnr)); + + int group = apc->curpat->group; + switch (group) { + case AUGROUP_ERROR: + abort(); // unreachable + case AUGROUP_DEFAULT: + case AUGROUP_ALL: + case AUGROUP_DELETED: + // omit group in these cases + break; + default: + PUT(data, "group", INTEGER_OBJ(group)); + break; + } + + FIXED_TEMP_ARRAY(args, 1); + args.items[0] = DICTIONARY_OBJ(data); + + Object result = nlua_call_ref(callback.data.luaref, NULL, args, true, NULL); + if (result.type == kObjectTypeBoolean) { + ret = result.data.boolean; + } + api_free_dictionary(data); + api_free_object(result); + } else { + typval_T argsin = TV_INITIAL_VALUE; + typval_T rettv = TV_INITIAL_VALUE; + callback_call(&callback, 0, &argsin, &rettv); + } + + return ret; +} + /// Get next autocommand command. /// Called by do_cmdline() to get the next line for ":if". /// @return allocated string, or NULL for end of autocommands. @@ -2069,16 +2113,11 @@ char_u *getnextac(int c, void *cookie, int indent, bool do_concat) current_sctx = ac->script_ctx; if (ac->exec.type == CALLABLE_CB) { - typval_T argsin = TV_INITIAL_VALUE; - typval_T rettv = TV_INITIAL_VALUE; - if (callback_call(&ac->exec.callable.cb, 0, &argsin, &rettv)) { - if (ac->exec.callable.cb.type == kCallbackLua) { - // If a Lua callback returns 'true' then the autocommand is removed - oneshot = true; - } + if (call_autocmd_callback(ac, acp)) { + // If an autocommand callback returns true, delete the autocommand + oneshot = true; } - // TODO(tjdevries): // // Major Hack Alert: diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index b4a9a4f01f..377b4fecf0 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -182,6 +182,54 @@ describe('autocmd api', function() meths.exec_autocmds("User", {pattern = "Test"}) eq({}, meths.get_autocmds({event = "User", pattern = "Test"})) end) + + it('receives an args table', function() + local res = exec_lua [[ + local group_id = vim.api.nvim_create_augroup("TestGroup", {}) + local autocmd_id = vim.api.nvim_create_autocmd("User", { + group = "TestGroup", + pattern = "Te*", + callback = function(args) + vim.g.autocmd_args = args + end, + }) + + return {group_id, autocmd_id} + ]] + + meths.exec_autocmds("User", {pattern = "Test pattern"}) + eq({ + id = res[2], + group = res[1], + event = "User", + match = "Test pattern", + file = "Test pattern", + buf = 1, + }, meths.get_var("autocmd_args")) + + -- Test without a group + res = exec_lua [[ + local autocmd_id = vim.api.nvim_create_autocmd("User", { + pattern = "*", + callback = function(args) + vim.g.autocmd_args = args + end, + }) + + return {autocmd_id} + ]] + + meths.exec_autocmds("User", {pattern = "some_pat"}) + eq({ + id = res[1], + group = nil, + event = "User", + match = "some_pat", + file = "some_pat", + buf = 1, + }, meths.get_var("autocmd_args")) + + end) end) describe('nvim_get_autocmds', function() |