diff options
Diffstat (limited to 'src/nvim/autocmd.c')
-rw-r--r-- | src/nvim/autocmd.c | 198 |
1 files changed, 121 insertions, 77 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 5b5ea43d86..01ebdfdafe 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -2,9 +2,13 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // autocmd.c: Autocommand related functions -#include <signal.h> -#include "lauxlib.h" +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" @@ -12,26 +16,43 @@ #include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" -#include "nvim/edit.h" #include "nvim/eval.h" +#include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" +#include "nvim/event/defs.h" +#include "nvim/event/loop.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/fileio.h" +#include "nvim/garray.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" #include "nvim/grid.h" +#include "nvim/hashtab.h" +#include "nvim/highlight_defs.h" #include "nvim/insexpand.h" #include "nvim/lua/executor.h" +#include "nvim/main.h" #include "nvim/map.h" +#include "nvim/memline_defs.h" +#include "nvim/memory.h" +#include "nvim/message.h" +#include "nvim/option_defs.h" #include "nvim/optionstr.h" #include "nvim/os/input.h" +#include "nvim/os/os.h" +#include "nvim/os/time.h" +#include "nvim/path.h" #include "nvim/profile.h" #include "nvim/regexp.h" #include "nvim/runtime.h" +#include "nvim/screen.h" #include "nvim/search.h" #include "nvim/state.h" +#include "nvim/strings.h" +#include "nvim/ui.h" #include "nvim/ui_compositor.h" #include "nvim/vim.h" #include "nvim/window.h" @@ -283,7 +304,7 @@ static void au_show_for_event(int group, event_T event, char *pat) // all buffer-local patterns. if ((group == AUGROUP_ALL || ap->group == group) && ap->patlen == patlen - && STRNCMP(pat, ap->pat, patlen) == 0) { + && strncmp(pat, ap->pat, (size_t)patlen) == 0) { // Show autocmd's for this autopat, or buflocals <buffer=X> aupat_show(ap, event, previous_group); previous_group = ap->group; @@ -638,9 +659,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". @@ -779,7 +813,7 @@ void au_event_restore(char *old_ei) // :autocmd * *.c show all autocommands for *.c files. // // Mostly a {group} argument can optionally appear before <event>. -void do_autocmd(char *arg_in, int forceit) +void do_autocmd(exarg_T *eap, char *arg_in, int forceit) { char *arg = arg_in; char *envpat = NULL; @@ -790,6 +824,7 @@ void do_autocmd(char *arg_in, int forceit) int group; if (*arg == '|') { + eap->nextcmd = arg + 1; arg = ""; group = AUGROUP_ALL; // no argument, use all groups } else { @@ -806,6 +841,7 @@ void do_autocmd(char *arg_in, int forceit) pat = skipwhite(pat); if (*pat == '|') { + eap->nextcmd = pat + 1; pat = ""; cmd = ""; } else { @@ -979,7 +1015,7 @@ int do_autocmd_event(event_T event, char *pat, bool once, int nested, char *cmd, // all buffer-local patterns. if (ap->group == findgroup && ap->patlen == patlen - && STRNCMP(pat, ap->pat, patlen) == 0) { + && strncmp(pat, ap->pat, (size_t)patlen) == 0) { // Remove existing autocommands. // If adding any new autocmd's for this AutoPat, don't // delete the pattern from the autopat list, append to @@ -1063,7 +1099,7 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group // all buffer-local patterns. if (ap->group == findgroup && ap->patlen == patlen - && STRNCMP(pat, ap->pat, patlen) == 0) { + && strncmp(pat, ap->pat, (size_t)patlen) == 0) { if (ap->next == NULL) { // Add autocmd to this autopat, if it's the last one. break; @@ -1118,14 +1154,19 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group curwin->w_last_cursormoved = curwin->w_cursor; } - // Initialize the fields checked by the WinScrolled trigger to - // stop it from firing right after the first autocmd is defined. - if (event == EVENT_WINSCROLLED && !has_event(EVENT_WINSCROLLED)) { - curwin->w_last_topline = curwin->w_topline; - curwin->w_last_leftcol = curwin->w_leftcol; - curwin->w_last_skipcol = curwin->w_skipcol; - curwin->w_last_width = curwin->w_width; - curwin->w_last_height = curwin->w_height; + // Initialize the fields checked by the WinScrolled and + // WinResized trigger to prevent them from firing right after + // the first autocmd is defined. + if ((event == EVENT_WINSCROLLED || event == EVENT_WINRESIZED) + && !(has_event(EVENT_WINSCROLLED) || has_event(EVENT_WINRESIZED))) { + tabpage_T *save_curtab = curtab; + FOR_ALL_TABS(tp) { + unuse_tabpage(curtab); + use_tabpage(tp); + snapshot_windows_scroll_size(); + } + unuse_tabpage(curtab); + use_tabpage(save_curtab); } ap->cmds = NULL; @@ -1291,7 +1332,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 @@ -1321,7 +1362,7 @@ void ex_doautoall(exarg_T *eap) bool check_nomodeline(char **argp) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - if (STRNCMP(*argp, "<nomodeline>", 12) == 0) { + if (strncmp(*argp, "<nomodeline>", 12) == 0) { *argp = skipwhite(*argp + 12); return false; } @@ -1330,7 +1371,7 @@ 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`. /// /// @param aco structure to save values in @@ -1353,15 +1394,29 @@ 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) { + break; + } + } + + if (auc_idx == AUCMD_WIN_COUNT) { + kv_push(aucmd_win_vec, ((aucmdwin_T){ + .auc_win = NULL, + .auc_win_used = false, + })); + } + + 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; } aco->save_curwin_handle = curwin->handle; @@ -1371,42 +1426,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; @@ -1423,18 +1477,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; } } @@ -1449,7 +1505,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 @@ -1470,8 +1528,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; @@ -1754,7 +1812,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force || event == EVENT_SIGNAL || event == EVENT_SPELLFILEMISSING || event == EVENT_SYNTAX || event == EVENT_TABCLOSED || event == EVENT_USER || event == EVENT_WINCLOSED - || event == EVENT_WINSCROLLED) { + || event == EVENT_WINRESIZED || event == EVENT_WINSCROLLED) { fname = xstrdup(fname); } else { fname = FullName_save(fname, false); @@ -2431,7 +2489,7 @@ bool aupat_is_buflocal(char *pat, int patlen) FUNC_ATTR_PURE { return patlen >= 8 - && STRNCMP(pat, "<buffer", 7) == 0 + && strncmp(pat, "<buffer", 7) == 0 && (pat)[patlen - 1] == '>'; } @@ -2618,26 +2676,27 @@ static int arg_augroup_get(char **argp) { char *p; char *arg = *argp; - int group = AUGROUP_ALL; for (p = arg; *p && !ascii_iswhite(*p) && *p != '|'; p++) {} - if (p > arg) { - char *group_name = xstrnsave(arg, (size_t)(p - arg)); - group = augroup_find(group_name); - if (group == AUGROUP_ERROR) { - group = AUGROUP_ALL; // no match, use all groups - } else { - *argp = skipwhite(p); // match, skip over group name - } - xfree(group_name); + if (p <= arg) { + return AUGROUP_ALL; + } + + char *group_name = xstrnsave(arg, (size_t)(p - arg)); + int group = augroup_find(group_name); + if (group == AUGROUP_ERROR) { + group = AUGROUP_ALL; // no match, use all groups + } else { + *argp = skipwhite(p); // match, skip over group name } + xfree(group_name); return group; } /// Handles grabbing arguments from `:autocmd` such as ++once and ++nested static bool arg_autocmd_flag_get(bool *flag, char **cmd_ptr, char *pattern, int len) { - if (STRNCMP(*cmd_ptr, pattern, len) == 0 && ascii_iswhite((*cmd_ptr)[len])) { + if (strncmp(*cmd_ptr, pattern, (size_t)len) == 0 && ascii_iswhite((*cmd_ptr)[len])) { if (*flag) { semsg(_(e_duparg2), pattern); return true; @@ -2674,22 +2733,7 @@ void do_autocmd_uienter(uint64_t chanid, bool attached) // FocusGained -static void focusgained_event(void **argv) -{ - bool *gainedp = argv[0]; - do_autocmd_focusgained(*gainedp); - xfree(gainedp); -} - -void autocmd_schedule_focusgained(bool gained) -{ - bool *gainedp = xmalloc(sizeof(*gainedp)); - *gainedp = gained; - loop_schedule_deferred(&main_loop, - event_create(focusgained_event, 1, gainedp)); -} - -static void do_autocmd_focusgained(bool gained) +void do_autocmd_focusgained(bool gained) { static bool recursive = false; static Timestamp last_time = (time_t)0; |