mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-03 17:24:29 +00:00 
			
		
		
		
	Merge pull request #19091 from clason/do-aucmd-pats
feat(api): support pattern array for exec_autocmds
This commit is contained in:
		@@ -549,9 +549,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
 | 
			
		||||
 | 
			
		||||
    int retval;
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < patterns.size; i++) {
 | 
			
		||||
      Object pat = patterns.items[i];
 | 
			
		||||
 | 
			
		||||
    FOREACH_ITEM(patterns, pat, {
 | 
			
		||||
      // See: TODO(sctx)
 | 
			
		||||
      WITH_SCRIPT_CONTEXT(channel_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");
 | 
			
		||||
        goto cleanup;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    })
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
cleanup:
 | 
			
		||||
@@ -781,14 +779,12 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
 | 
			
		||||
  bool modeline = true;
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
  Object *data = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!unpack_string_or_array(&event_array, &event, "event", true, err)) {
 | 
			
		||||
    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);
 | 
			
		||||
    set_buf = true;
 | 
			
		||||
 | 
			
		||||
    if (ERROR_SET(err)) {
 | 
			
		||||
      goto cleanup;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (opts->pattern.type != kObjectTypeNil) {
 | 
			
		||||
    if (opts->pattern.type != kObjectTypeString) {
 | 
			
		||||
      api_set_error(err, kErrorTypeValidation, "'pattern' must be a string");
 | 
			
		||||
      goto cleanup;
 | 
			
		||||
    }
 | 
			
		||||
  if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) {
 | 
			
		||||
    goto cleanup;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    pattern = string_to_cstr(opts->pattern.data.string);
 | 
			
		||||
    set_pattern = true;
 | 
			
		||||
  if (patterns.size == 0) {
 | 
			
		||||
    ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("*")));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  if (set_pattern && set_buf) {
 | 
			
		||||
    api_set_error(err, kErrorTypeValidation, "must not set 'buffer' and 'pattern'");
 | 
			
		||||
    goto cleanup;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool did_aucmd = false;
 | 
			
		||||
  FOREACH_ITEM(event_array, event_str, {
 | 
			
		||||
    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) {
 | 
			
		||||
@@ -867,13 +859,13 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
 | 
			
		||||
 | 
			
		||||
cleanup:
 | 
			
		||||
  api_free_array(event_array);
 | 
			
		||||
  XFREE_CLEAR(pattern);
 | 
			
		||||
  api_free_array(patterns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool check_autocmd_string_array(Array arr, char *k, Error *err)
 | 
			
		||||
{
 | 
			
		||||
  for (size_t i = 0; i < arr.size; i++) {
 | 
			
		||||
    if (arr.items[i].type != kObjectTypeString) {
 | 
			
		||||
  FOREACH_ITEM(arr, entry, {
 | 
			
		||||
    if (entry.type != kObjectTypeString) {
 | 
			
		||||
      api_set_error(err,
 | 
			
		||||
                    kErrorTypeValidation,
 | 
			
		||||
                    "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.
 | 
			
		||||
    const String l = arr.items[i].data.string;
 | 
			
		||||
    const String l = entry.data.string;
 | 
			
		||||
    if (memchr(l.data, NL, l.size)) {
 | 
			
		||||
      api_set_error(err, kErrorTypeValidation,
 | 
			
		||||
                    "String cannot contain newlines");
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  })
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -975,8 +967,8 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      Array array = v->data.array;
 | 
			
		||||
      for (size_t i = 0; i < array.size; i++) {
 | 
			
		||||
        char *pat = array.items[i].data.string.data;
 | 
			
		||||
      FOREACH_ITEM(array, entry, {
 | 
			
		||||
        char *pat = entry.data.string.data;
 | 
			
		||||
        size_t patlen = aucmd_pattern_length(pat);
 | 
			
		||||
        while (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);
 | 
			
		||||
          patlen = aucmd_pattern_length(pat);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      })
 | 
			
		||||
    } else {
 | 
			
		||||
      api_set_error(err,
 | 
			
		||||
                    kErrorTypeValidation,
 | 
			
		||||
                    "'pattern' must be a string");
 | 
			
		||||
                    "'pattern' must be a string or table");
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  } else if (buffer.type != kObjectTypeNil) {
 | 
			
		||||
    if (buffer.type != kObjectTypeInteger) {
 | 
			
		||||
    if (buffer.type != kObjectTypeInteger && buffer.type != kObjectTypeBuffer) {
 | 
			
		||||
      api_set_error(err,
 | 
			
		||||
                    kErrorTypeValidation,
 | 
			
		||||
                    "'buffer' must be an integer");
 | 
			
		||||
 
 | 
			
		||||
@@ -686,6 +686,26 @@ describe('autocmd api', function()
 | 
			
		||||
      eq(true, meths.get_var("autocmd_executed"))
 | 
			
		||||
    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()
 | 
			
		||||
      meths.set_var("buffer_executed", -1)
 | 
			
		||||
      eq(-1, meths.get_var("buffer_executed"))
 | 
			
		||||
@@ -742,7 +762,7 @@ describe('autocmd api', function()
 | 
			
		||||
      meths.exec_autocmds("CursorHoldI", { buffer = 1 })
 | 
			
		||||
      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"))
 | 
			
		||||
 | 
			
		||||
      -- Reset filename
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user