aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Anders <8965202+gpanders@users.noreply.github.com>2022-03-06 12:35:14 -0700
committerGitHub <noreply@github.com>2022-03-06 12:35:14 -0700
commit92349b1db0039aac3a43089d0aade2437164505c (patch)
tree8917d542e9fb66f95118d472997419c8ed0a2f1c
parent3800615da9eaf9e8b26d9040c882c74084d688e4 (diff)
downloadrneovim-92349b1db0039aac3a43089d0aade2437164505c.tar.gz
rneovim-92349b1db0039aac3a43089d0aade2437164505c.tar.bz2
rneovim-92349b1db0039aac3a43089d0aade2437164505c.zip
feat(api): add 'buffer' argument to nvim_get_autocmds (#17594)
This enables retrieving autocommands defined in the given buffers. Under the hood this simply translates the buffer numbers into '<buffer=%d>' patterns.
-rw-r--r--runtime/doc/api.txt6
-rw-r--r--src/nvim/api/autocmd.c66
-rw-r--r--src/nvim/api/keysets.lua1
-rw-r--r--test/functional/api/autocmd_spec.lua56
4 files changed, 123 insertions, 6 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index fe5f9eaf35..73536d174a 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -3226,7 +3226,11 @@ nvim_get_autocmds({*opts}) *nvim_get_autocmds()*
against
• group (string): Name of group to match against
• pattern: Pattern or list of patterns to match
- against
+ against. Cannot be used with {buffer}
+ • buffer: Buffer number or list of buffer numbers
+ for buffer local autocommands
+ |autocmd-buflocal|. Cannot be used with
+ {pattern}
Return: ~
A list of autocmds that match
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 0ad7b320d0..685667ac64 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -41,7 +41,9 @@ static int64_t next_autocmd_id = 1;
/// @param opts Optional Parameters:
/// - event : Name or list of name of events to match against
/// - group (string): Name of group to match against
-/// - pattern: Pattern or list of patterns to match against
+/// - pattern: Pattern or list of patterns to match against. Cannot be used with {buffer}
+/// - buffer: Buffer number or list of buffer numbers for buffer local autocommands
+/// |autocmd-buflocal|. Cannot be used with {pattern}
///
/// @return A list of autocmds that match
Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
@@ -53,6 +55,8 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
char_u *pattern_filters[AUCMD_MAX_PATTERNS];
char_u pattern_buflocal[BUFLOCAL_PAT_LEN];
+ Array buffers = ARRAY_DICT_INIT;
+
bool event_set[NUM_EVENTS] = { false };
bool check_event = false;
@@ -100,6 +104,12 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
}
}
+ if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) {
+ api_set_error(err, kErrorTypeValidation,
+ "Cannot use both 'pattern' and 'buffer'");
+ goto cleanup;
+ }
+
int pattern_filter_count = 0;
if (opts->pattern.type != kObjectTypeNil) {
Object v = opts->pattern;
@@ -107,25 +117,70 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
pattern_filters[pattern_filter_count] = (char_u *)v.data.string.data;
pattern_filter_count += 1;
} else if (v.type == kObjectTypeArray) {
+ if (v.data.array.size > AUCMD_MAX_PATTERNS) {
+ api_set_error(err, kErrorTypeValidation,
+ "Too many patterns. Please limit yourself to %d or fewer",
+ AUCMD_MAX_PATTERNS);
+ goto cleanup;
+ }
+
FOREACH_ITEM(v.data.array, item, {
+ if (item.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'pattern': must be a string");
+ goto cleanup;
+ }
+
pattern_filters[pattern_filter_count] = (char_u *)item.data.string.data;
pattern_filter_count += 1;
});
} else {
- api_set_error(err,
- kErrorTypeValidation,
+ api_set_error(err, kErrorTypeValidation,
"Not a valid 'pattern' value. Must be a string or an array");
goto cleanup;
}
+ }
+
+ if (opts->buffer.type == kObjectTypeInteger || opts->buffer.type == kObjectTypeBuffer) {
+ buf_T *buf = find_buffer_by_handle((Buffer)opts->buffer.data.integer, err);
+ if (ERROR_SET(err)) {
+ goto cleanup;
+ }
- if (pattern_filter_count >= AUCMD_MAX_PATTERNS) {
+ snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
+ ADD(buffers, CSTR_TO_OBJ((char *)pattern_buflocal));
+ } else if (opts->buffer.type == kObjectTypeArray) {
+ if (opts->buffer.data.array.size > AUCMD_MAX_PATTERNS) {
api_set_error(err,
kErrorTypeValidation,
- "Too many patterns. Please limit yourself to less");
+ "Too many buffers. Please limit yourself to %d or fewer", AUCMD_MAX_PATTERNS);
goto cleanup;
}
+
+ FOREACH_ITEM(opts->buffer.data.array, bufnr, {
+ if (bufnr.type != kObjectTypeInteger && bufnr.type != kObjectTypeBuffer) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'buffer': must be an integer");
+ goto cleanup;
+ }
+
+ buf_T *buf = find_buffer_by_handle((Buffer)bufnr.data.integer, err);
+ if (ERROR_SET(err)) {
+ goto cleanup;
+ }
+
+ snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
+ ADD(buffers, CSTR_TO_OBJ((char *)pattern_buflocal));
+ });
+ } else if (opts->buffer.type != kObjectTypeNil) {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value for 'buffer': must be an integer or array of integers");
+ goto cleanup;
}
+ FOREACH_ITEM(buffers, bufnr, {
+ pattern_filters[pattern_filter_count] = (char_u *)bufnr.data.string.data;
+ pattern_filter_count += 1;
+ });
+
FOR_ALL_AUEVENTS(event) {
if (check_event && !event_set[event]) {
continue;
@@ -234,6 +289,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
}
cleanup:
+ api_free_array(buffers);
return autocmd_list;
}
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 32d4e98822..435e8195dd 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -142,6 +142,7 @@ return {
"event";
"group";
"pattern";
+ "buffer";
};
create_augroup = {
"clear";
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index e50e812b4b..e8dc284925 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -8,6 +8,7 @@ local exec_lua = helpers.exec_lua
local matches = helpers.matches
local meths = helpers.meths
local source = helpers.source
+local pcall_err = helpers.pcall_err
before_each(clear)
@@ -225,6 +226,61 @@ describe('autocmd api', function()
local aus = meths.get_autocmds { event = "InsertEnter" }
eq({ { buflocal = false, command = ':echo "1"', event = "InsertEnter", once = false, pattern = "*" } }, aus)
end)
+
+ it('should work with buffer numbers', function()
+ command [[new]]
+ command [[au! InsertEnter]]
+ command [[au InsertEnter <buffer=1> :echo "1"]]
+ command [[au InsertEnter <buffer=2> :echo "2"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter", buffer = 0 }
+ eq({{
+ buffer = 2,
+ buflocal = true,
+ command = ':echo "2"',
+ event = 'InsertEnter',
+ once = false,
+ pattern = '<buffer=2>',
+ }}, aus)
+
+ aus = meths.get_autocmds { event = "InsertEnter", buffer = 1 }
+ eq({{
+ buffer = 1,
+ buflocal = true,
+ command = ':echo "1"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=1>",
+ }}, aus)
+
+ aus = meths.get_autocmds { event = "InsertEnter", buffer = { 1, 2 } }
+ eq({{
+ buffer = 1,
+ buflocal = true,
+ command = ':echo "1"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=1>",
+ }, {
+ buffer = 2,
+ buflocal = true,
+ command = ':echo "2"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=2>",
+ }}, aus)
+
+ eq("Invalid value for 'buffer': must be an integer or array of integers", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" }))
+ eq("Invalid value for 'buffer': must be an integer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } }))
+ eq("Invalid buffer id: 42", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { 42 } }))
+
+ local bufs = {}
+ for _ = 1, 257 do
+ table.insert(bufs, meths.create_buf(true, false))
+ end
+
+ eq("Too many buffers. Please limit yourself to 256 or fewer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs }))
+ end)
end)
describe('groups', function()