diff options
author | Gregory Anders <8965202+gpanders@users.noreply.github.com> | 2022-03-19 18:57:58 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-19 18:57:58 -0600 |
commit | be35d3c5ad501abb029279f8e1812d0e4525284f (patch) | |
tree | 22f0371d83adcf5f2a97809c8a573562bd7fd129 | |
parent | 77eb6f9dc75ebe00aa835441ad623ba46d7108bb (diff) | |
download | rneovim-be35d3c5ad501abb029279f8e1812d0e4525284f.tar.gz rneovim-be35d3c5ad501abb029279f8e1812d0e4525284f.tar.bz2 rneovim-be35d3c5ad501abb029279f8e1812d0e4525284f.zip |
feat(api): remove Lua autocommand callbacks when they return true (#17784)
This copies the semantics of nvim_buf_attach callbacks, and is a
convenient way to create oneshot autocommands gated by some condition.
-rw-r--r-- | src/nvim/autocmd.c | 11 | ||||
-rw-r--r-- | src/nvim/eval.c | 12 | ||||
-rw-r--r-- | test/functional/api/autocmd_spec.lua | 28 |
3 files changed, 45 insertions, 6 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index df336d8703..a36f2c97b5 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -2013,6 +2013,7 @@ char_u *getnextac(int c, void *cookie, int indent, bool do_concat) } AutoCmd *ac = acp->nextcmd; + bool oneshot = ac->once; if (p_verbose >= 9) { verbose_enter_scroll(); @@ -2024,7 +2025,13 @@ char_u *getnextac(int c, void *cookie, int indent, bool do_concat) if (ac->exec.type == CALLABLE_CB) { typval_T argsin = TV_INITIAL_VALUE; typval_T rettv = TV_INITIAL_VALUE; - callback_call(&ac->exec.callable.cb, 0, &argsin, &rettv); + 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; + } + } + // TODO(tjdevries): // @@ -2042,7 +2049,7 @@ char_u *getnextac(int c, void *cookie, int indent, bool do_concat) } // Remove one-shot ("once") autocmd in anticipation of its execution. - if (ac->once) { + if (oneshot) { aucmd_del(ac); } autocmd_nested = ac->nested; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index af7c3d4985..33e8469768 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7730,6 +7730,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co partial_T *partial; char_u *name; Array args = ARRAY_DICT_INIT; + Object rv; switch (callback->type) { case kCallbackFuncref: name = callback->data.funcref; @@ -7742,10 +7743,13 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co break; case kCallbackLua: - nlua_call_ref(callback->data.luaref, NULL, args, false, NULL); - - return false; - break; + rv = nlua_call_ref(callback->data.luaref, NULL, args, true, NULL); + switch (rv.type) { + case kObjectTypeBoolean: + return rv.data.boolean; + default: + return false; + } case kCallbackNone: return false; diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index 372cbf2c30..a58ca00a75 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -154,6 +154,34 @@ describe('autocmd api', function() eq(1, #aus, aus) end) end) + + it('removes an autocommand if the callback returns true', function() + meths.set_var("some_condition", false) + + exec_lua [[ + vim.api.nvim_create_autocmd("User", { + pattern = "Test", + desc = "A test autocommand", + callback = function() + return vim.g.some_condition + end, + }) + ]] + + meths.do_autocmd("User", {pattern = "Test"}) + eq({{ + buflocal = false, + command = 'A test autocommand', + desc = 'A test autocommand', + event = 'User', + id = 1, + once = false, + pattern = 'Test', + }}, meths.get_autocmds({event = "User", pattern = "Test"})) + meths.set_var("some_condition", true) + meths.do_autocmd("User", {pattern = "Test"}) + eq({}, meths.get_autocmds({event = "User", pattern = "Test"})) + end) end) describe('nvim_get_autocmds', function() |