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

Code before:
      prevwin = win_find_by_handle(aco->save_prevwin_handle);

      // In case the autocommand moves the cursor to a position that does not
      // exist in curbuf
      VIsual_active = aco->save_VIsual_active;
      check_cursor(curwin);
    }
  }

  VIsual_active = aco->save_VIsual_active;
  check_cursor(curwin);  // just in case lines got deleted
  if (VIsual_active) {
    check_pos(curbuf, &VIsual);
  }
}

/// Put a safe autocommand event on the queue, to be triggered at a safe time.
///
/// @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,
///                 NULL means use `fname`.
/// @param group autocmd group ID or AUGROUP_ALL
/// @param buf Buffer for <abuf>
/// @param eap Ex command arguments
void queue_safe_autocommand(event_T event, char *fname, char *fname_io, int group, buf_T *buf,
                            exarg_T *eap, Object *data)
{
  SafeAutocommandEvent *evdata = xmalloc(sizeof(SafeAutocommandEvent));
  evdata->event = event;
  evdata->fname = fname;
  evdata->fname_io = fname_io;
  evdata->group = group;
  evdata->buf = buf->handle;
  evdata->eap = eap;
  if (data) {
    evdata->data = xmalloc(sizeof(Object));
    *evdata->data = copy_object(*data, NULL);
  } else {
    evdata->data = NULL;
  }

  multiqueue_put(safe_autocmd_events, safe_autocmd_event, evdata);
}

/// Execute a safe autocommand event
void safe_autocmd_event(void **argv)
{
  SafeAutocommandEvent *e = argv[0];
  event_T event = e->event;
  char *fname = e->fname;

Review comment (suggestion):
let's drop mentioning "safe" (everywhere in this PR), it's confusing given the existence of SafeState. and it's not really necessary.

```suggestion
void aucmd_defer(event_T event, char *fname, char *fname_io, int group, buf_T *buf,
```

Code after:
          && bufref_valid(&aco->new_curbuf)
          && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL) {
        if (curwin->w_s == &curbuf->b_s) {
          curwin->w_s = &aco->new_curbuf.br_buf->b_s;
        }
        curbuf->b_nwindows--;
        curbuf = aco->new_curbuf.br_buf;
        curwin->w_buffer = curbuf;
        curbuf->b_nwindows++;
      }

      curwin = save_curwin;
      curbuf = curwin->w_buffer;
      prevwin = win_find_by_handle(aco->save_prevwin_handle);

      // In case the autocommand moves the cursor to a position that does not
      // exist in curbuf
      VIsual_active = aco->save_VIsual_active;
      check_cursor(curwin);
    }
  }

  VIsual_active = aco->save_VIsual_active;
  check_cursor(curwin);  // just in case lines got deleted
  if (VIsual_active) {
    check_pos(curbuf, &VIsual);
  }
}

/// Schedules an autocommand event, to be executed at the next event-loop tick.
///
/// @param event Event to schedule
/// @param fname Name to use as `<amatch>` (the "pattern"). NULL/empty means use actual filename.
/// @param fname_io Filename to use for <afile> on cmdline, NULL means use `fname`.
/// @param group Group ID or AUGROUP_ALL
/// @param buf Buffer for <abuf>
/// @param eap Ex command arguments
/// @param data Event-specific data. Will be copied, caller must free `data`.
/// The `data` items will also be copied to `v:event`.
void aucmd_defer(event_T event, char *fname, char *fname_io, int group, buf_T *buf, exarg_T *eap,
                 Object *data)
{
  AutoCmdEvent *evdata = xmalloc(sizeof(AutoCmdEvent));
  evdata->event = event;
  evdata->fname = fname != NULL ? xstrdup(fname) : NULL;
  evdata->fname_io = fname_io != NULL ? xstrdup(fname_io) : NULL;
  evdata->group = group;
  evdata->buf = buf->handle;
  evdata->eap = eap;
  if (data) {
    evdata->data = xmalloc(sizeof(Object));