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.c198
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;