Repository: neovim/neovim
File: src/nvim/autocmd.c (C)

Code before:
{
  DeferredEvent *e = argv[0];
  event_T event = e->event;
  char *fname = e->fname;
  char *fname_io = e->fname_io;
  int group = e->group;
  exarg_T *eap = e->eap;
  Object *data = e->data;

  Error err = ERROR_INIT;
  buf_T *buf = find_buffer_by_handle(e->buf, &err);
  if (buf) {
    // set v:event with event data (if any)
    save_v_event_T save_v_event;
    dict_T *v_event = get_v_event(&save_v_event);
    if (data && data->type == kObjectTypeDict) {
      for (size_t i = 0; i < data->data.dict.size; i++) {
        KeyValuePair item = data->data.dict.items[i];
        typval_T tv;
        object_to_vim(item.value, &tv, &err);
        if (ERROR_SET(&err)) {
          api_clear_error(&err);
          continue;
        }
        tv_dict_add_tv(v_event, item.key.data, item.key.size, &tv);
      }
    }
    tv_dict_set_keys_readonly(v_event);

    apply_autocmds_group(event, fname, fname_io, false, group, buf, eap, data);
    restore_v_event(v_event, &save_v_event);
  }

  if (data) {
    api_free_object(*data);
    xfree(data);
  }
  xfree(e);
}

/// Execute autocommands for "event" and file name "fname".
///
/// @param event event that occurred
/// @param fname filename, NULL or empty means use actual file name
/// @param fname_io filename to use for <afile> on cmdline
/// @param force When true, ignore autocmd_busy
/// @param buf Buffer for <abuf>
///
/// @return true if some commands were executed.
bool apply_autocmds(event_T event, char *fname, char *fname_io, bool force, buf_T *buf)
{

Review comment (suggestion):
Although `v:event` is unofficially deprecated, there is a benefit to this: it avoids the autocmd impl needing to manually set `v_event` fields. Instead, all new autocmds can focus on `data`, which is the "preferred" way.

We could consider migrating all the old autocmds to this, so that `data` is a superset of `v:event`.

Code after:
static void deferred_event(void **argv)
{
  AutoCmdEvent *e = argv[0];
  event_T event = e->event;
  char *fname = e->fname;
  char *fname_io = e->fname_io;
  int group = e->group;
  exarg_T *eap = e->eap;
  Object *data = e->data;

  Error err = ERROR_INIT;
  buf_T *buf = find_buffer_by_handle(e->buf, &err);
  if (buf) {
    // Copy `data` to `v:event`.
    save_v_event_T save_v_event;
    dict_T *v_event = get_v_event(&save_v_event);
    if (data && data->type == kObjectTypeDict) {
      for (size_t i = 0; i < data->data.dict.size; i++) {
        KeyValuePair item = data->data.dict.items[i];
        typval_T tv;
        object_to_vim(item.value, &tv, &err);
        if (ERROR_SET(&err)) {
          api_clear_error(&err);
          continue;
        }
        tv_dict_add_tv(v_event, item.key.data, item.key.size, &tv);
        tv_clear(&tv);
      }
    }
    tv_dict_set_keys_readonly(v_event);

    aco_save_T aco;
    aucmd_prepbuf(&aco, buf);
    apply_autocmds_group(event, fname, fname_io, false, group, buf, eap, data);
    aucmd_restbuf(&aco);

    restore_v_event(v_event, &save_v_event);
  }

  xfree(fname);
  xfree(fname_io);
  if (data) {
    api_free_object(*data);
    xfree(data);
  }
  xfree(e);
}

/// Execute autocommands for "event" and file name "fname".
///
/// @param event event that occurred