Merge pull request #19091 from clason/do-aucmd-pats

feat(api): support pattern array for exec_autocmds
This commit is contained in:
Christian Clason
2022-06-26 23:05:52 +02:00
committed by GitHub
2 changed files with 46 additions and 34 deletions

View File

@@ -549,9 +549,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
int retval; int retval;
for (size_t i = 0; i < patterns.size; i++) { FOREACH_ITEM(patterns, pat, {
Object pat = patterns.items[i];
// See: TODO(sctx) // See: TODO(sctx)
WITH_SCRIPT_CONTEXT(channel_id, { WITH_SCRIPT_CONTEXT(channel_id, {
retval = autocmd_register(autocmd_id, retval = autocmd_register(autocmd_id,
@@ -569,7 +567,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
api_set_error(err, kErrorTypeException, "Failed to set autocmd"); api_set_error(err, kErrorTypeException, "Failed to set autocmd");
goto cleanup; goto cleanup;
} }
} })
}); });
cleanup: cleanup:
@@ -781,14 +779,12 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
bool modeline = true; bool modeline = true;
buf_T *buf = curbuf; buf_T *buf = curbuf;
bool set_buf = false;
char *pattern = NULL;
Object *data = NULL;
bool set_pattern = false;
Array patterns = ARRAY_DICT_INIT;
Array event_array = ARRAY_DICT_INIT; Array event_array = ARRAY_DICT_INIT;
Object *data = NULL;
if (!unpack_string_or_array(&event_array, &event, "event", true, err)) { if (!unpack_string_or_array(&event_array, &event, "event", true, err)) {
goto cleanup; goto cleanup;
} }
@@ -826,21 +822,18 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
} }
buf = find_buffer_by_handle((Buffer)buf_obj.data.integer, err); buf = find_buffer_by_handle((Buffer)buf_obj.data.integer, err);
set_buf = true;
if (ERROR_SET(err)) { if (ERROR_SET(err)) {
goto cleanup; goto cleanup;
} }
} }
if (opts->pattern.type != kObjectTypeNil) { if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) {
if (opts->pattern.type != kObjectTypeString) { goto cleanup;
api_set_error(err, kErrorTypeValidation, "'pattern' must be a string"); }
goto cleanup;
}
pattern = string_to_cstr(opts->pattern.data.string); if (patterns.size == 0) {
set_pattern = true; ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("*")));
} }
if (opts->data.type != kObjectTypeNil) { if (opts->data.type != kObjectTypeNil) {
@@ -849,16 +842,15 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
modeline = api_object_to_bool(opts->modeline, "modeline", true, err); modeline = api_object_to_bool(opts->modeline, "modeline", true, err);
if (set_pattern && set_buf) {
api_set_error(err, kErrorTypeValidation, "must not set 'buffer' and 'pattern'");
goto cleanup;
}
bool did_aucmd = false; bool did_aucmd = false;
FOREACH_ITEM(event_array, event_str, { FOREACH_ITEM(event_array, event_str, {
GET_ONE_EVENT(event_nr, event_str, cleanup) GET_ONE_EVENT(event_nr, event_str, cleanup)
did_aucmd |= apply_autocmds_group(event_nr, pattern, NULL, true, au_group, buf, NULL, data); FOREACH_ITEM(patterns, pat, {
char *fname = opts->buffer.type == kObjectTypeNil ? pat.data.string.data : NULL;
did_aucmd |=
apply_autocmds_group(event_nr, fname, NULL, true, au_group, buf, NULL, data);
})
}) })
if (did_aucmd && modeline) { if (did_aucmd && modeline) {
@@ -867,13 +859,13 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
cleanup: cleanup:
api_free_array(event_array); api_free_array(event_array);
XFREE_CLEAR(pattern); api_free_array(patterns);
} }
static bool check_autocmd_string_array(Array arr, char *k, Error *err) static bool check_autocmd_string_array(Array arr, char *k, Error *err)
{ {
for (size_t i = 0; i < arr.size; i++) { FOREACH_ITEM(arr, entry, {
if (arr.items[i].type != kObjectTypeString) { if (entry.type != kObjectTypeString) {
api_set_error(err, api_set_error(err,
kErrorTypeValidation, kErrorTypeValidation,
"All entries in '%s' must be strings", "All entries in '%s' must be strings",
@@ -882,13 +874,13 @@ static bool check_autocmd_string_array(Array arr, char *k, Error *err)
} }
// Disallow newlines in the middle of the line. // Disallow newlines in the middle of the line.
const String l = arr.items[i].data.string; const String l = entry.data.string;
if (memchr(l.data, NL, l.size)) { if (memchr(l.data, NL, l.size)) {
api_set_error(err, kErrorTypeValidation, api_set_error(err, kErrorTypeValidation,
"String cannot contain newlines"); "String cannot contain newlines");
return false; return false;
} }
} })
return true; return true;
} }
@@ -975,8 +967,8 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob
} }
Array array = v->data.array; Array array = v->data.array;
for (size_t i = 0; i < array.size; i++) { FOREACH_ITEM(array, entry, {
char *pat = array.items[i].data.string.data; char *pat = entry.data.string.data;
size_t patlen = aucmd_pattern_length(pat); size_t patlen = aucmd_pattern_length(pat);
while (patlen) { while (patlen) {
ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen))); ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen)));
@@ -984,15 +976,15 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob
pat = aucmd_next_pattern(pat, patlen); pat = aucmd_next_pattern(pat, patlen);
patlen = aucmd_pattern_length(pat); patlen = aucmd_pattern_length(pat);
} }
} })
} else { } else {
api_set_error(err, api_set_error(err,
kErrorTypeValidation, kErrorTypeValidation,
"'pattern' must be a string"); "'pattern' must be a string or table");
return false; return false;
} }
} else if (buffer.type != kObjectTypeNil) { } else if (buffer.type != kObjectTypeNil) {
if (buffer.type != kObjectTypeInteger) { if (buffer.type != kObjectTypeInteger && buffer.type != kObjectTypeBuffer) {
api_set_error(err, api_set_error(err,
kErrorTypeValidation, kErrorTypeValidation,
"'buffer' must be an integer"); "'buffer' must be an integer");

View File

@@ -686,6 +686,26 @@ describe('autocmd api', function()
eq(true, meths.get_var("autocmd_executed")) eq(true, meths.get_var("autocmd_executed"))
end) end)
it("can trigger multiple patterns", function()
meths.set_var("autocmd_executed", 0)
meths.create_autocmd("BufReadPost", {
pattern = "*",
command = "let g:autocmd_executed += 1",
})
meths.exec_autocmds("BufReadPost", { pattern = { "*.lua", "*.vim" } })
eq(2, meths.get_var("autocmd_executed"))
meths.create_autocmd("BufReadPre", {
pattern = { "bar", "foo" },
command = "let g:autocmd_executed += 10",
})
meths.exec_autocmds("BufReadPre", { pattern = { "foo", "bar", "baz", "frederick" }})
eq(22, meths.get_var("autocmd_executed"))
end)
it("can pass the buffer", function() it("can pass the buffer", function()
meths.set_var("buffer_executed", -1) meths.set_var("buffer_executed", -1)
eq(-1, meths.get_var("buffer_executed")) eq(-1, meths.get_var("buffer_executed"))
@@ -742,7 +762,7 @@ describe('autocmd api', function()
meths.exec_autocmds("CursorHoldI", { buffer = 1 }) meths.exec_autocmds("CursorHoldI", { buffer = 1 })
eq('none', meths.get_var("filename_executed")) eq('none', meths.get_var("filename_executed"))
meths.exec_autocmds("CursorHoldI", { buffer = tonumber(meths.get_current_buf()) }) meths.exec_autocmds("CursorHoldI", { buffer = meths.get_current_buf() })
eq('__init__.py', meths.get_var("filename_executed")) eq('__init__.py', meths.get_var("filename_executed"))
-- Reset filename -- Reset filename