diff options
-rw-r--r-- | runtime/doc/api.txt | 6 | ||||
-rw-r--r-- | src/nvim/api/autocmd.c | 66 | ||||
-rw-r--r-- | src/nvim/api/keysets.lua | 1 | ||||
-rw-r--r-- | test/functional/api/autocmd_spec.lua | 56 |
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() |