aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/autocmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/autocmd.c')
-rw-r--r--src/nvim/autocmd.c106
1 files changed, 74 insertions, 32 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 57b5adca53..6efb05ab45 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -633,6 +633,11 @@ void do_augroup(char *arg, int del_group)
}
}
+void autocmd_init(void)
+{
+ CLEAR_FIELD(aucmd_win);
+}
+
#if defined(EXITFREE)
void free_all_autocmds(void)
{
@@ -659,9 +664,22 @@ void free_all_autocmds(void)
api_free_string(name);
})
map_destroy(int, String)(&map_augroup_id_to_name);
+
+ // aucmd_win[] is freed in win_free_all()
}
#endif
+/// Return true if "win" is an active entry in aucmd_win[].
+bool is_aucmd_win(win_T *win)
+{
+ for (int i = 0; i < AUCMD_WIN_COUNT; i++) {
+ if (aucmd_win[i].auc_win_used && aucmd_win[i].auc_win == win) {
+ return true;
+ }
+ }
+ return false;
+}
+
// Return the event number for event name "start".
// Return NUM_EVENTS if the event name was not found.
// Return a pointer to the next event name in "end".
@@ -1310,6 +1328,13 @@ void ex_doautoall(exarg_T *eap)
// Find a window for this buffer and save some values.
aucmd_prepbuf(&aco, buf);
+ if (curbuf != buf) {
+ // Failed to find a window for this buffer. Better not execute
+ // autocommands then.
+ retval = FAIL;
+ break;
+ }
+
set_bufref(&bufref, buf);
// execute the autocommands for this buffer
@@ -1319,7 +1344,7 @@ void ex_doautoall(exarg_T *eap)
// Execute the modeline settings, but don't set window-local
// options if we are using the current window for another
// buffer.
- do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
+ do_modelines(is_aucmd_win(curwin) ? OPT_NOWIN : 0);
}
// restore the current window
@@ -1358,8 +1383,9 @@ bool check_nomodeline(char **argp)
/// Prepare for executing autocommands for (hidden) buffer `buf`.
/// If the current buffer is not in any visible window, put it in a temporary
-/// floating window `aucmd_win`.
+/// floating window using an entry in `aucmd_win[]`.
/// Set `curbuf` and `curwin` to match `buf`.
+/// When this fails `curbuf` is not equal `buf`.
///
/// @param aco structure to save values in
/// @param buf new curbuf
@@ -1381,15 +1407,28 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
}
}
- // Allocate the `aucmd_win` dummy floating window.
- if (win == NULL && aucmd_win == NULL) {
- win_alloc_aucmd_win();
- need_append = false;
- }
- if (win == NULL && aucmd_win_used) {
- // Strange recursive autocommand, fall back to using the current
- // window. Expect a few side effects...
- win = curwin;
+ // Allocate a window when needed.
+ win_T *auc_win = NULL;
+ int auc_idx = AUCMD_WIN_COUNT;
+ if (win == NULL) {
+ for (auc_idx = 0; auc_idx < AUCMD_WIN_COUNT; auc_idx++) {
+ if (!aucmd_win[auc_idx].auc_win_used) {
+ if (aucmd_win[auc_idx].auc_win == NULL) {
+ win_alloc_aucmd_win(auc_idx);
+ need_append = false;
+ }
+ auc_win = aucmd_win[auc_idx].auc_win;
+ aucmd_win[auc_idx].auc_win_used = true;
+ break;
+ }
+ }
+
+ // If this fails (using all AUCMD_WIN_COUNT entries)
+ // then we can't reliably execute the autocmd,
+ // return with "curbuf" unequal "buf".
+ if (auc_win == NULL) {
+ return;
+ }
}
aco->save_curwin_handle = curwin->handle;
@@ -1399,42 +1438,41 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
// There is a window for "buf" in the current tab page, make it the
// curwin. This is preferred, it has the least side effects (esp. if
// "buf" is curbuf).
- aco->use_aucmd_win = false;
+ aco->use_aucmd_win_idx = -1;
curwin = win;
} else {
- // There is no window for "buf", use "aucmd_win". To minimize the side
+ // There is no window for "buf", use "auc_win". To minimize the side
// effects, insert it in the current tab page.
// Anything related to a window (e.g., setting folds) may have
// unexpected results.
- aco->use_aucmd_win = true;
- aucmd_win_used = true;
- aucmd_win->w_buffer = buf;
- aucmd_win->w_s = &buf->b_s;
+ aco->use_aucmd_win_idx = auc_idx;
+ auc_win->w_buffer = buf;
+ auc_win->w_s = &buf->b_s;
buf->b_nwindows++;
- win_init_empty(aucmd_win); // set cursor and topline to safe values
+ win_init_empty(auc_win); // set cursor and topline to safe values
// Make sure w_localdir and globaldir are NULL to avoid a chdir() in
// win_enter_ext().
- XFREE_CLEAR(aucmd_win->w_localdir);
+ XFREE_CLEAR(auc_win->w_localdir);
aco->globaldir = globaldir;
globaldir = NULL;
block_autocmds(); // We don't want BufEnter/WinEnter autocommands.
if (need_append) {
- win_append(lastwin, aucmd_win);
- pmap_put(handle_T)(&window_handles, aucmd_win->handle, aucmd_win);
- win_config_float(aucmd_win, aucmd_win->w_float_config);
+ win_append(lastwin, auc_win);
+ pmap_put(handle_T)(&window_handles, auc_win->handle, auc_win);
+ win_config_float(auc_win, auc_win->w_float_config);
}
// Prevent chdir() call in win_enter_ext(), through do_autochdir()
int save_acd = p_acd;
p_acd = false;
// no redrawing and don't set the window title
RedrawingDisabled++;
- win_enter(aucmd_win, false);
+ win_enter(auc_win, false);
RedrawingDisabled--;
p_acd = save_acd;
unblock_autocmds();
- curwin = aucmd_win;
+ curwin = auc_win;
}
curbuf = buf;
aco->new_curwin_handle = curwin->handle;
@@ -1451,18 +1489,20 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
/// @param aco structure holding saved values
void aucmd_restbuf(aco_save_T *aco)
{
- if (aco->use_aucmd_win) {
+ if (aco->use_aucmd_win_idx >= 0) {
+ win_T *awp = aucmd_win[aco->use_aucmd_win_idx].auc_win;
+
curbuf->b_nwindows--;
- // Find "aucmd_win", it can't be closed, but it may be in another tab page.
+ // Find "awp", it can't be closed, but it may be in another tab page.
// Do not trigger autocommands here.
block_autocmds();
- if (curwin != aucmd_win) {
+ if (curwin != awp) {
FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (wp == aucmd_win) {
+ if (wp == awp) {
if (tp != curtab) {
goto_tabpage_tp(tp, true, true);
}
- win_goto(aucmd_win);
+ win_goto(awp);
goto win_found;
}
}
@@ -1477,7 +1517,9 @@ win_found:
grid_free(&curwin->w_grid_alloc);
}
- aucmd_win_used = false;
+ // The window is marked as not used, but it is not freed, it can be
+ // used again.
+ aucmd_win[aco->use_aucmd_win_idx].auc_win_used = false;
if (!valid_tabpage_win(curtab)) {
// no valid window in current tabpage
@@ -1498,8 +1540,8 @@ win_found:
entering_window(curwin);
prevwin = win_find_by_handle(aco->save_prevwin_handle);
- vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
- hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
+ vars_clear(&awp->w_vars->dv_hashtab); // free all w: variables
+ hash_init(&awp->w_vars->dv_hashtab); // re-use the hashtab
xfree(globaldir);
globaldir = aco->globaldir;