blob: a10be9b9283c144920ce1dd60d7c024a9bf1768e [file] [log] [blame]
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * autocmd.c: Autocommand related functions
12 */
13
14#include "vim.h"
15
16/*
17 * The autocommands are stored in a list for each event.
18 * Autocommands for the same pattern, that are consecutive, are joined
19 * together, to avoid having to match the pattern too often.
20 * The result is an array of Autopat lists, which point to AutoCmd lists:
21 *
22 * last_autopat[0] -----------------------------+
23 * V
24 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
25 * Autopat.cmds Autopat.cmds
26 * | |
27 * V V
28 * AutoCmd.next AutoCmd.next
29 * | |
30 * V V
31 * AutoCmd.next NULL
32 * |
33 * V
34 * NULL
35 *
36 * last_autopat[1] --------+
37 * V
38 * first_autopat[1] --> Autopat.next --> NULL
39 * Autopat.cmds
40 * |
41 * V
42 * AutoCmd.next
43 * |
44 * V
45 * NULL
46 * etc.
47 *
48 * The order of AutoCmds is important, this is the order in which they were
49 * defined and will have to be executed.
50 */
51typedef struct AutoCmd
52{
53 char_u *cmd; // The command to be executed (NULL
54 // when command has been removed).
Bram Moolenaareb93f3f2019-04-04 15:04:56 +020055 char once; // "One shot": removed after execution
Bram Moolenaar3e460fd2019-01-26 16:21:07 +010056 char nested; // If autocommands nest here.
57 char last; // last command in list
Bram Moolenaar3e460fd2019-01-26 16:21:07 +010058 sctx_T script_ctx; // script context where defined
Bram Moolenaar3e460fd2019-01-26 16:21:07 +010059 struct AutoCmd *next; // next AutoCmd in list
60} AutoCmd;
61
62typedef struct AutoPat
63{
64 struct AutoPat *next; // Next AutoPat in AutoPat list; MUST
65 // be the first entry.
66 char_u *pat; // pattern as typed (NULL when pattern
67 // has been removed)
68 regprog_T *reg_prog; // compiled regprog for pattern
69 AutoCmd *cmds; // list of commands to do
70 int group; // group ID
71 int patlen; // strlen() of pat
72 int buflocal_nr; // !=0 for buffer-local AutoPat
73 char allow_dirs; // Pattern may match whole path
74 char last; // last pattern for apply_autocmds()
75} AutoPat;
76
77static struct event_name
78{
79 char *name; // event name
80 event_T event; // event number
81} event_names[] =
82{
83 {"BufAdd", EVENT_BUFADD},
84 {"BufCreate", EVENT_BUFADD},
85 {"BufDelete", EVENT_BUFDELETE},
86 {"BufEnter", EVENT_BUFENTER},
87 {"BufFilePost", EVENT_BUFFILEPOST},
88 {"BufFilePre", EVENT_BUFFILEPRE},
89 {"BufHidden", EVENT_BUFHIDDEN},
90 {"BufLeave", EVENT_BUFLEAVE},
91 {"BufNew", EVENT_BUFNEW},
92 {"BufNewFile", EVENT_BUFNEWFILE},
93 {"BufRead", EVENT_BUFREADPOST},
94 {"BufReadCmd", EVENT_BUFREADCMD},
95 {"BufReadPost", EVENT_BUFREADPOST},
96 {"BufReadPre", EVENT_BUFREADPRE},
97 {"BufUnload", EVENT_BUFUNLOAD},
98 {"BufWinEnter", EVENT_BUFWINENTER},
99 {"BufWinLeave", EVENT_BUFWINLEAVE},
100 {"BufWipeout", EVENT_BUFWIPEOUT},
101 {"BufWrite", EVENT_BUFWRITEPRE},
102 {"BufWritePost", EVENT_BUFWRITEPOST},
103 {"BufWritePre", EVENT_BUFWRITEPRE},
104 {"BufWriteCmd", EVENT_BUFWRITECMD},
105 {"CmdlineChanged", EVENT_CMDLINECHANGED},
106 {"CmdlineEnter", EVENT_CMDLINEENTER},
107 {"CmdlineLeave", EVENT_CMDLINELEAVE},
108 {"CmdwinEnter", EVENT_CMDWINENTER},
109 {"CmdwinLeave", EVENT_CMDWINLEAVE},
110 {"CmdUndefined", EVENT_CMDUNDEFINED},
111 {"ColorScheme", EVENT_COLORSCHEME},
112 {"ColorSchemePre", EVENT_COLORSCHEMEPRE},
Bram Moolenaard7f246c2019-04-08 18:15:41 +0200113 {"CompleteChanged", EVENT_COMPLETECHANGED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100114 {"CompleteDone", EVENT_COMPLETEDONE},
Bram Moolenaar3f169ce2020-01-26 22:43:31 +0100115 {"CompleteDonePre", EVENT_COMPLETEDONEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100116 {"CursorHold", EVENT_CURSORHOLD},
117 {"CursorHoldI", EVENT_CURSORHOLDI},
118 {"CursorMoved", EVENT_CURSORMOVED},
119 {"CursorMovedI", EVENT_CURSORMOVEDI},
120 {"DiffUpdated", EVENT_DIFFUPDATED},
121 {"DirChanged", EVENT_DIRCHANGED},
122 {"EncodingChanged", EVENT_ENCODINGCHANGED},
123 {"ExitPre", EVENT_EXITPRE},
124 {"FileEncoding", EVENT_ENCODINGCHANGED},
125 {"FileAppendPost", EVENT_FILEAPPENDPOST},
126 {"FileAppendPre", EVENT_FILEAPPENDPRE},
127 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
128 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
129 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
130 {"FileChangedRO", EVENT_FILECHANGEDRO},
131 {"FileReadPost", EVENT_FILEREADPOST},
132 {"FileReadPre", EVENT_FILEREADPRE},
133 {"FileReadCmd", EVENT_FILEREADCMD},
134 {"FileType", EVENT_FILETYPE},
135 {"FileWritePost", EVENT_FILEWRITEPOST},
136 {"FileWritePre", EVENT_FILEWRITEPRE},
137 {"FileWriteCmd", EVENT_FILEWRITECMD},
138 {"FilterReadPost", EVENT_FILTERREADPOST},
139 {"FilterReadPre", EVENT_FILTERREADPRE},
140 {"FilterWritePost", EVENT_FILTERWRITEPOST},
141 {"FilterWritePre", EVENT_FILTERWRITEPRE},
142 {"FocusGained", EVENT_FOCUSGAINED},
143 {"FocusLost", EVENT_FOCUSLOST},
144 {"FuncUndefined", EVENT_FUNCUNDEFINED},
145 {"GUIEnter", EVENT_GUIENTER},
146 {"GUIFailed", EVENT_GUIFAILED},
147 {"InsertChange", EVENT_INSERTCHANGE},
148 {"InsertEnter", EVENT_INSERTENTER},
149 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaarb53e13a2020-10-21 12:19:53 +0200150 {"InsertLeavePre", EVENT_INSERTLEAVEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100151 {"InsertCharPre", EVENT_INSERTCHARPRE},
152 {"MenuPopup", EVENT_MENUPOPUP},
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +0200153 {"ModeChanged", EVENT_MODECHANGED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100154 {"OptionSet", EVENT_OPTIONSET},
155 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
156 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
157 {"QuitPre", EVENT_QUITPRE},
158 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar8aeec402019-09-15 23:02:04 +0200159 {"SafeState", EVENT_SAFESTATE},
Bram Moolenaar69198cb2019-09-16 21:58:13 +0200160 {"SafeStateAgain", EVENT_SAFESTATEAGAIN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100161 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
162 {"ShellCmdPost", EVENT_SHELLCMDPOST},
163 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200164 {"SigUSR1", EVENT_SIGUSR1},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100165 {"SourceCmd", EVENT_SOURCECMD},
166 {"SourcePre", EVENT_SOURCEPRE},
167 {"SourcePost", EVENT_SOURCEPOST},
168 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
169 {"StdinReadPost", EVENT_STDINREADPOST},
170 {"StdinReadPre", EVENT_STDINREADPRE},
171 {"SwapExists", EVENT_SWAPEXISTS},
172 {"Syntax", EVENT_SYNTAX},
173 {"TabNew", EVENT_TABNEW},
174 {"TabClosed", EVENT_TABCLOSED},
175 {"TabEnter", EVENT_TABENTER},
176 {"TabLeave", EVENT_TABLEAVE},
177 {"TermChanged", EVENT_TERMCHANGED},
178 {"TerminalOpen", EVENT_TERMINALOPEN},
Bram Moolenaar28ed4df2019-10-26 16:21:40 +0200179 {"TerminalWinOpen", EVENT_TERMINALWINOPEN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100180 {"TermResponse", EVENT_TERMRESPONSE},
181 {"TextChanged", EVENT_TEXTCHANGED},
182 {"TextChangedI", EVENT_TEXTCHANGEDI},
183 {"TextChangedP", EVENT_TEXTCHANGEDP},
184 {"User", EVENT_USER},
185 {"VimEnter", EVENT_VIMENTER},
186 {"VimLeave", EVENT_VIMLEAVE},
187 {"VimLeavePre", EVENT_VIMLEAVEPRE},
188 {"WinNew", EVENT_WINNEW},
naohiro ono23beefe2021-11-13 12:38:49 +0000189 {"WinClosed", EVENT_WINCLOSED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100190 {"WinEnter", EVENT_WINENTER},
191 {"WinLeave", EVENT_WINLEAVE},
192 {"VimResized", EVENT_VIMRESIZED},
193 {"TextYankPost", EVENT_TEXTYANKPOST},
Bram Moolenaar100118c2020-12-11 19:30:34 +0100194 {"VimSuspend", EVENT_VIMSUSPEND},
195 {"VimResume", EVENT_VIMRESUME},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100196 {NULL, (event_T)0}
197};
198
199static AutoPat *first_autopat[NUM_EVENTS] =
200{
201 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
202 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
204 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
205 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
206 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
207};
208
209static AutoPat *last_autopat[NUM_EVENTS] =
210{
211 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
212 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
213 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
214 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
215 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
216 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
217};
218
219#define AUGROUP_DEFAULT -1 // default autocmd group
220#define AUGROUP_ERROR -2 // erroneous autocmd group
221#define AUGROUP_ALL -3 // all autocmd groups
222
223/*
224 * struct used to keep status while executing autocommands for an event.
225 */
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100226struct AutoPatCmd_S
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100227{
228 AutoPat *curpat; // next AutoPat to examine
229 AutoCmd *nextcmd; // next AutoCmd to execute
230 int group; // group being used
231 char_u *fname; // fname to match with
232 char_u *sfname; // sfname to match with
233 char_u *tail; // tail of fname
234 event_T event; // current event
235 int arg_bufnr; // Initially equal to <abuf>, set to zero when
236 // buf is deleted.
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100237 AutoPatCmd *next; // chain of active apc-s for auto-invalidation
238};
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100239
Bram Moolenaarc667da52019-11-30 20:52:27 +0100240static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100241
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200242// Macro to loop over all the patterns for an autocmd event
243#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \
244 for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next)
245
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100246/*
247 * augroups stores a list of autocmd group names.
248 */
249static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
250#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
Bram Moolenaarc667da52019-11-30 20:52:27 +0100251// use get_deleted_augroup() to get this
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100252static char_u *deleted_augroup = NULL;
253
254/*
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100255 * The ID of the current group. Group 0 is the default one.
256 */
257static int current_augroup = AUGROUP_DEFAULT;
258
Bram Moolenaarc667da52019-11-30 20:52:27 +0100259static int au_need_clean = FALSE; // need to delete marked patterns
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100260
261static char_u *event_nr2name(event_T event);
262static int au_get_grouparg(char_u **argp);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200263static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group, int flags);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100264static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
265static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
266static int au_find_group(char_u *name);
267
268static event_T last_event;
269static int last_group;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100270static int autocmd_blocked = 0; // block all autocmds
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100271
272 static char_u *
273get_deleted_augroup(void)
274{
275 if (deleted_augroup == NULL)
276 deleted_augroup = (char_u *)_("--Deleted--");
277 return deleted_augroup;
278}
279
280/*
281 * Show the autocommands for one AutoPat.
282 */
283 static void
284show_autocmd(AutoPat *ap, event_T event)
285{
286 AutoCmd *ac;
287
288 // Check for "got_int" (here and at various places below), which is set
289 // when "q" has been hit for the "--more--" prompt
290 if (got_int)
291 return;
292 if (ap->pat == NULL) // pattern has been removed
293 return;
294
295 msg_putchar('\n');
296 if (got_int)
297 return;
298 if (event != last_event || ap->group != last_group)
299 {
300 if (ap->group != AUGROUP_DEFAULT)
301 {
302 if (AUGROUP_NAME(ap->group) == NULL)
303 msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
304 else
305 msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
306 msg_puts(" ");
307 }
308 msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
309 last_event = event;
310 last_group = ap->group;
311 msg_putchar('\n');
312 if (got_int)
313 return;
314 }
315 msg_col = 4;
316 msg_outtrans(ap->pat);
317
318 for (ac = ap->cmds; ac != NULL; ac = ac->next)
319 {
320 if (ac->cmd != NULL) // skip removed commands
321 {
322 if (msg_col >= 14)
323 msg_putchar('\n');
324 msg_col = 14;
325 if (got_int)
326 return;
327 msg_outtrans(ac->cmd);
328#ifdef FEAT_EVAL
329 if (p_verbose > 0)
330 last_set_msg(ac->script_ctx);
331#endif
332 if (got_int)
333 return;
334 if (ac->next != NULL)
335 {
336 msg_putchar('\n');
337 if (got_int)
338 return;
339 }
340 }
341 }
342}
343
344/*
345 * Mark an autocommand pattern for deletion.
346 */
347 static void
348au_remove_pat(AutoPat *ap)
349{
350 VIM_CLEAR(ap->pat);
351 ap->buflocal_nr = -1;
352 au_need_clean = TRUE;
353}
354
355/*
356 * Mark all commands for a pattern for deletion.
357 */
358 static void
359au_remove_cmds(AutoPat *ap)
360{
361 AutoCmd *ac;
362
363 for (ac = ap->cmds; ac != NULL; ac = ac->next)
364 VIM_CLEAR(ac->cmd);
365 au_need_clean = TRUE;
366}
367
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200368// Delete one command from an autocmd pattern.
369static void au_del_cmd(AutoCmd *ac)
370{
371 VIM_CLEAR(ac->cmd);
372 au_need_clean = TRUE;
373}
374
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100375/*
376 * Cleanup autocommands and patterns that have been deleted.
377 * This is only done when not executing autocommands.
378 */
379 static void
380au_cleanup(void)
381{
382 AutoPat *ap, **prev_ap;
383 AutoCmd *ac, **prev_ac;
384 event_T event;
385
386 if (autocmd_busy || !au_need_clean)
387 return;
388
389 // loop over all events
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100390 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100391 event = (event_T)((int)event + 1))
392 {
393 // loop over all autocommand patterns
394 prev_ap = &(first_autopat[(int)event]);
395 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
396 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200397 int has_cmd = FALSE;
398
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200399 // loop over all commands for this pattern
400 prev_ac = &(ap->cmds);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100401 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
402 {
403 // remove the command if the pattern is to be deleted or when
404 // the command has been marked for deletion
405 if (ap->pat == NULL || ac->cmd == NULL)
406 {
407 *prev_ac = ac->next;
408 vim_free(ac->cmd);
409 vim_free(ac);
410 }
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200411 else
412 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200413 has_cmd = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100414 prev_ac = &(ac->next);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200415 }
416 }
417
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200418 if (ap->pat != NULL && !has_cmd)
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200419 // Pattern was not marked for deletion, but all of its
420 // commands were. So mark the pattern for deletion.
421 au_remove_pat(ap);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100422
423 // remove the pattern if it has been marked for deletion
424 if (ap->pat == NULL)
425 {
426 if (ap->next == NULL)
427 {
428 if (prev_ap == &(first_autopat[(int)event]))
429 last_autopat[(int)event] = NULL;
430 else
431 // this depends on the "next" field being the first in
432 // the struct
433 last_autopat[(int)event] = (AutoPat *)prev_ap;
434 }
435 *prev_ap = ap->next;
436 vim_regfree(ap->reg_prog);
437 vim_free(ap);
438 }
439 else
440 prev_ap = &(ap->next);
441 }
442 }
443
444 au_need_clean = FALSE;
445}
446
447/*
448 * Called when buffer is freed, to remove/invalidate related buffer-local
449 * autocmds.
450 */
451 void
452aubuflocal_remove(buf_T *buf)
453{
454 AutoPat *ap;
455 event_T event;
456 AutoPatCmd *apc;
457
458 // invalidate currently executing autocommands
459 for (apc = active_apc_list; apc; apc = apc->next)
460 if (buf->b_fnum == apc->arg_bufnr)
461 apc->arg_bufnr = 0;
462
463 // invalidate buflocals looping through events
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100464 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100465 event = (event_T)((int)event + 1))
466 // loop over all autocommand patterns
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200467 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100468 if (ap->buflocal_nr == buf->b_fnum)
469 {
470 au_remove_pat(ap);
471 if (p_verbose >= 6)
472 {
473 verbose_enter();
474 smsg(_("auto-removing autocommand: %s <buffer=%d>"),
475 event_nr2name(event), buf->b_fnum);
476 verbose_leave();
477 }
478 }
479 au_cleanup();
480}
481
482/*
483 * Add an autocmd group name.
484 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
485 */
486 static int
487au_new_group(char_u *name)
488{
489 int i;
490
491 i = au_find_group(name);
492 if (i == AUGROUP_ERROR) // the group doesn't exist yet, add it
493 {
494 // First try using a free entry.
495 for (i = 0; i < augroups.ga_len; ++i)
496 if (AUGROUP_NAME(i) == NULL)
497 break;
498 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
499 return AUGROUP_ERROR;
500
501 AUGROUP_NAME(i) = vim_strsave(name);
502 if (AUGROUP_NAME(i) == NULL)
503 return AUGROUP_ERROR;
504 if (i == augroups.ga_len)
505 ++augroups.ga_len;
506 }
507
508 return i;
509}
510
511 static void
512au_del_group(char_u *name)
513{
514 int i;
515
516 i = au_find_group(name);
517 if (i == AUGROUP_ERROR) // the group doesn't exist
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000518 semsg(_(e_no_such_group_str), name);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100519 else if (i == current_augroup)
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000520 emsg(_(e_cannot_delete_current_group));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100521 else
522 {
523 event_T event;
524 AutoPat *ap;
525 int in_use = FALSE;
526
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100527 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100528 event = (event_T)((int)event + 1))
529 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200530 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100531 if (ap->group == i && ap->pat != NULL)
532 {
533 give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
534 in_use = TRUE;
535 event = NUM_EVENTS;
536 break;
537 }
538 }
539 vim_free(AUGROUP_NAME(i));
540 if (in_use)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100541 AUGROUP_NAME(i) = get_deleted_augroup();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100542 else
543 AUGROUP_NAME(i) = NULL;
544 }
545}
546
547/*
548 * Find the ID of an autocmd group name.
549 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
550 */
551 static int
552au_find_group(char_u *name)
553{
554 int i;
555
556 for (i = 0; i < augroups.ga_len; ++i)
557 if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
558 && STRCMP(AUGROUP_NAME(i), name) == 0)
559 return i;
560 return AUGROUP_ERROR;
561}
562
563/*
564 * Return TRUE if augroup "name" exists.
565 */
566 int
567au_has_group(char_u *name)
568{
569 return au_find_group(name) != AUGROUP_ERROR;
570}
571
572/*
573 * ":augroup {name}".
574 */
575 void
576do_augroup(char_u *arg, int del_group)
577{
578 int i;
579
580 if (del_group)
581 {
582 if (*arg == NUL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000583 emsg(_(e_argument_required));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100584 else
585 au_del_group(arg);
586 }
587 else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0
588 current_augroup = AUGROUP_DEFAULT;
589 else if (*arg) // ":aug xxx": switch to group xxx
590 {
591 i = au_new_group(arg);
592 if (i != AUGROUP_ERROR)
593 current_augroup = i;
594 }
595 else // ":aug": list the group names
596 {
597 msg_start();
598 for (i = 0; i < augroups.ga_len; ++i)
599 {
600 if (AUGROUP_NAME(i) != NULL)
601 {
602 msg_puts((char *)AUGROUP_NAME(i));
603 msg_puts(" ");
604 }
605 }
606 msg_clr_eos();
607 msg_end();
608 }
609}
610
611#if defined(EXITFREE) || defined(PROTO)
612 void
613free_all_autocmds(void)
614{
615 int i;
616 char_u *s;
617
618 for (current_augroup = -1; current_augroup < augroups.ga_len;
619 ++current_augroup)
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200620 do_autocmd(NULL, (char_u *)"", TRUE);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100621
622 for (i = 0; i < augroups.ga_len; ++i)
623 {
624 s = ((char_u **)(augroups.ga_data))[i];
625 if (s != get_deleted_augroup())
626 vim_free(s);
627 }
628 ga_clear(&augroups);
629}
630#endif
631
632/*
633 * Return the event number for event name "start".
634 * Return NUM_EVENTS if the event name was not found.
635 * Return a pointer to the next event name in "end".
636 */
637 static event_T
638event_name2nr(char_u *start, char_u **end)
639{
640 char_u *p;
641 int i;
642 int len;
643
644 // the event name ends with end of line, '|', a blank or a comma
645 for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
646 ;
647 for (i = 0; event_names[i].name != NULL; ++i)
648 {
649 len = (int)STRLEN(event_names[i].name);
650 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
651 break;
652 }
653 if (*p == ',')
654 ++p;
655 *end = p;
656 if (event_names[i].name == NULL)
657 return NUM_EVENTS;
658 return event_names[i].event;
659}
660
661/*
662 * Return the name for event "event".
663 */
664 static char_u *
665event_nr2name(event_T event)
666{
667 int i;
668
669 for (i = 0; event_names[i].name != NULL; ++i)
670 if (event_names[i].event == event)
671 return (char_u *)event_names[i].name;
672 return (char_u *)"Unknown";
673}
674
675/*
676 * Scan over the events. "*" stands for all events.
677 */
678 static char_u *
679find_end_event(
680 char_u *arg,
681 int have_group) // TRUE when group name was found
682{
683 char_u *pat;
684 char_u *p;
685
686 if (*arg == '*')
687 {
688 if (arg[1] && !VIM_ISWHITE(arg[1]))
689 {
Bram Moolenaar6d057012021-12-31 18:49:43 +0000690 semsg(_(e_illegal_character_after_star_str), arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100691 return NULL;
692 }
693 pat = arg + 1;
694 }
695 else
696 {
697 for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
698 {
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100699 if ((int)event_name2nr(pat, &p) >= NUM_EVENTS)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100700 {
701 if (have_group)
Bram Moolenaar6d057012021-12-31 18:49:43 +0000702 semsg(_(e_no_such_event_str), pat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100703 else
Bram Moolenaar6d057012021-12-31 18:49:43 +0000704 semsg(_(e_no_such_group_or_event_str), pat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100705 return NULL;
706 }
707 }
708 }
709 return pat;
710}
711
712/*
713 * Return TRUE if "event" is included in 'eventignore'.
714 */
715 static int
716event_ignored(event_T event)
717{
718 char_u *p = p_ei;
719
720 while (*p != NUL)
721 {
722 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
723 return TRUE;
724 if (event_name2nr(p, &p) == event)
725 return TRUE;
726 }
727
728 return FALSE;
729}
730
731/*
732 * Return OK when the contents of p_ei is valid, FAIL otherwise.
733 */
734 int
735check_ei(void)
736{
737 char_u *p = p_ei;
738
739 while (*p)
740 {
741 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
742 {
743 p += 3;
744 if (*p == ',')
745 ++p;
746 }
747 else if (event_name2nr(p, &p) == NUM_EVENTS)
748 return FAIL;
749 }
750
751 return OK;
752}
753
754# if defined(FEAT_SYN_HL) || defined(PROTO)
755
756/*
757 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
758 * buffer loaded into the window. "what" must start with a comma.
759 * Returns the old value of 'eventignore' in allocated memory.
760 */
761 char_u *
762au_event_disable(char *what)
763{
764 char_u *new_ei;
765 char_u *save_ei;
766
767 save_ei = vim_strsave(p_ei);
768 if (save_ei != NULL)
769 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200770 new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100771 if (new_ei != NULL)
772 {
773 if (*what == ',' && *p_ei == NUL)
774 STRCPY(new_ei, what + 1);
775 else
776 STRCAT(new_ei, what);
777 set_string_option_direct((char_u *)"ei", -1, new_ei,
778 OPT_FREE, SID_NONE);
779 vim_free(new_ei);
780 }
781 }
782 return save_ei;
783}
784
785 void
786au_event_restore(char_u *old_ei)
787{
788 if (old_ei != NULL)
789 {
790 set_string_option_direct((char_u *)"ei", -1, old_ei,
791 OPT_FREE, SID_NONE);
792 vim_free(old_ei);
793 }
794}
Bram Moolenaarc667da52019-11-30 20:52:27 +0100795# endif // FEAT_SYN_HL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100796
797/*
798 * do_autocmd() -- implements the :autocmd command. Can be used in the
799 * following ways:
800 *
801 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
802 * will be automatically executed for <event>
803 * when editing a file matching <pat>, in
804 * the current group.
805 * :autocmd <event> <pat> Show the autocommands associated with
806 * <event> and <pat>.
807 * :autocmd <event> Show the autocommands associated with
808 * <event>.
809 * :autocmd Show all autocommands.
810 * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
811 * <event> and <pat>, and add the command
812 * <cmd>, for the current group.
813 * :autocmd! <event> <pat> Remove all autocommands associated with
814 * <event> and <pat> for the current group.
815 * :autocmd! <event> Remove all autocommands associated with
816 * <event> for the current group.
817 * :autocmd! Remove ALL autocommands for the current
818 * group.
819 *
820 * Multiple events and patterns may be given separated by commas. Here are
821 * some examples:
822 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
823 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
824 *
825 * :autocmd * *.c show all autocommands for *.c files.
826 *
827 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200828 * "eap" can be NULL.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100829 */
830 void
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200831do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100832{
833 char_u *arg = arg_in;
834 char_u *pat;
835 char_u *envpat = NULL;
836 char_u *cmd;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200837 int cmd_need_free = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100838 event_T event;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200839 char_u *tofree = NULL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100840 int nested = FALSE;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200841 int once = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100842 int group;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200843 int i;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200844 int flags = 0;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100845
846 if (*arg == '|')
847 {
Bram Moolenaarb8e642f2021-11-20 10:38:25 +0000848 eap->nextcmd = arg + 1;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100849 arg = (char_u *)"";
850 group = AUGROUP_ALL; // no argument, use all groups
851 }
852 else
853 {
854 /*
855 * Check for a legal group name. If not, use AUGROUP_ALL.
856 */
857 group = au_get_grouparg(&arg);
858 if (arg == NULL) // out of memory
859 return;
860 }
861
862 /*
863 * Scan over the events.
864 * If we find an illegal name, return here, don't do anything.
865 */
866 pat = find_end_event(arg, group != AUGROUP_ALL);
867 if (pat == NULL)
868 return;
869
870 pat = skipwhite(pat);
871 if (*pat == '|')
872 {
Bram Moolenaarb8e642f2021-11-20 10:38:25 +0000873 eap->nextcmd = pat + 1;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100874 pat = (char_u *)"";
875 cmd = (char_u *)"";
876 }
877 else
878 {
879 /*
880 * Scan over the pattern. Put a NUL at the end.
881 */
882 cmd = pat;
883 while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
884 cmd++;
885 if (*cmd)
886 *cmd++ = NUL;
887
888 // Expand environment variables in the pattern. Set 'shellslash', we
889 // want forward slashes here.
890 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
891 {
892#ifdef BACKSLASH_IN_FILENAME
893 int p_ssl_save = p_ssl;
894
895 p_ssl = TRUE;
896#endif
897 envpat = expand_env_save(pat);
898#ifdef BACKSLASH_IN_FILENAME
899 p_ssl = p_ssl_save;
900#endif
901 if (envpat != NULL)
902 pat = envpat;
903 }
904
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100905 cmd = skipwhite(cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200906 for (i = 0; i < 2; i++)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100907 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200908 if (*cmd != NUL)
909 {
910 // Check for "++once" flag.
911 if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
912 {
913 if (once)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000914 semsg(_(e_duplicate_argument_str), "++once");
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200915 once = TRUE;
916 cmd = skipwhite(cmd + 6);
917 }
918
919 // Check for "++nested" flag.
920 if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
921 {
922 if (nested)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000923 semsg(_(e_duplicate_argument_str), "++nested");
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200924 nested = TRUE;
925 cmd = skipwhite(cmd + 8);
926 }
927
928 // Check for the old "nested" flag.
929 if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
930 {
931 if (nested)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000932 semsg(_(e_duplicate_argument_str), "nested");
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200933 nested = TRUE;
934 cmd = skipwhite(cmd + 6);
935 }
936 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100937 }
938
939 /*
940 * Find the start of the commands.
941 * Expand <sfile> in it.
942 */
943 if (*cmd != NUL)
944 {
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200945 if (eap != NULL)
946 // Read a {} block if it follows.
947 cmd = may_get_cmd_block(eap, cmd, &tofree, &flags);
948
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100949 cmd = expand_sfile(cmd);
950 if (cmd == NULL) // some error
951 return;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200952 cmd_need_free = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100953 }
954 }
955
956 /*
957 * Print header when showing autocommands.
958 */
959 if (!forceit && *cmd == NUL)
960 // Highlight title
961 msg_puts_title(_("\n--- Autocommands ---"));
962
963 /*
964 * Loop over the events.
965 */
966 last_event = (event_T)-1; // for listing the event name
967 last_group = AUGROUP_ERROR; // for listing the group name
968 if (*arg == '*' || *arg == NUL || *arg == '|')
969 {
Bram Moolenaarb6db1462021-12-24 19:24:47 +0000970 if (*cmd != NUL)
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100971 emsg(_(e_cannot_define_autocommands_for_all_events));
972 else
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100973 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100974 event = (event_T)((int)event + 1))
975 if (do_autocmd_event(event, pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200976 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100977 break;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100978 }
979 else
980 {
981 while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
982 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200983 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100984 break;
985 }
986
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200987 if (cmd_need_free)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100988 vim_free(cmd);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200989 vim_free(tofree);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100990 vim_free(envpat);
991}
992
993/*
994 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
995 * The "argp" argument is advanced to the following argument.
996 *
997 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
998 */
999 static int
1000au_get_grouparg(char_u **argp)
1001{
1002 char_u *group_name;
1003 char_u *p;
1004 char_u *arg = *argp;
1005 int group = AUGROUP_ALL;
1006
1007 for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
1008 ;
1009 if (p > arg)
1010 {
Bram Moolenaardf44a272020-06-07 20:49:05 +02001011 group_name = vim_strnsave(arg, p - arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001012 if (group_name == NULL) // out of memory
1013 return AUGROUP_ERROR;
1014 group = au_find_group(group_name);
1015 if (group == AUGROUP_ERROR)
1016 group = AUGROUP_ALL; // no match, use all groups
1017 else
1018 *argp = skipwhite(p); // match, skip over group name
1019 vim_free(group_name);
1020 }
1021 return group;
1022}
1023
1024/*
1025 * do_autocmd() for one event.
1026 * If *pat == NUL do for all patterns.
1027 * If *cmd == NUL show entries.
1028 * If forceit == TRUE delete entries.
1029 * If group is not AUGROUP_ALL, only use this group.
1030 */
1031 static int
1032do_autocmd_event(
1033 event_T event,
1034 char_u *pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001035 int once,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001036 int nested,
1037 char_u *cmd,
1038 int forceit,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001039 int group,
1040 int flags)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001041{
1042 AutoPat *ap;
1043 AutoPat **prev_ap;
1044 AutoCmd *ac;
1045 AutoCmd **prev_ac;
1046 int brace_level;
1047 char_u *endpat;
1048 int findgroup;
1049 int allgroups;
1050 int patlen;
1051 int is_buflocal;
1052 int buflocal_nr;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001053 char_u buflocal_pat[25]; // for "<buffer=X>"
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001054
1055 if (group == AUGROUP_ALL)
1056 findgroup = current_augroup;
1057 else
1058 findgroup = group;
1059 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
1060
1061 /*
1062 * Show or delete all patterns for an event.
1063 */
1064 if (*pat == NUL)
1065 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001066 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001067 {
1068 if (forceit) // delete the AutoPat, if it's in the current group
1069 {
1070 if (ap->group == findgroup)
1071 au_remove_pat(ap);
1072 }
1073 else if (group == AUGROUP_ALL || ap->group == group)
1074 show_autocmd(ap, event);
1075 }
1076 }
1077
1078 /*
1079 * Loop through all the specified patterns.
1080 */
1081 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
1082 {
1083 /*
1084 * Find end of the pattern.
1085 * Watch out for a comma in braces, like "*.\{obj,o\}".
1086 */
1087 brace_level = 0;
1088 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
1089 || (endpat > pat && endpat[-1] == '\\')); ++endpat)
1090 {
1091 if (*endpat == '{')
1092 brace_level++;
1093 else if (*endpat == '}')
1094 brace_level--;
1095 }
1096 if (pat == endpat) // ignore single comma
1097 continue;
1098 patlen = (int)(endpat - pat);
1099
1100 /*
1101 * detect special <buflocal[=X]> buffer-local patterns
1102 */
1103 is_buflocal = FALSE;
1104 buflocal_nr = 0;
1105
1106 if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
1107 && pat[patlen - 1] == '>')
1108 {
1109 // "<buffer...>": Error will be printed only for addition.
1110 // printing and removing will proceed silently.
1111 is_buflocal = TRUE;
1112 if (patlen == 8)
1113 // "<buffer>"
1114 buflocal_nr = curbuf->b_fnum;
1115 else if (patlen > 9 && pat[7] == '=')
1116 {
1117 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
1118 // "<buffer=abuf>"
1119 buflocal_nr = autocmd_bufnr;
1120 else if (skipdigits(pat + 8) == pat + patlen - 1)
1121 // "<buffer=123>"
1122 buflocal_nr = atoi((char *)pat + 8);
1123 }
1124 }
1125
1126 if (is_buflocal)
1127 {
1128 // normalize pat into standard "<buffer>#N" form
1129 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
1130 pat = buflocal_pat; // can modify pat and patlen
1131 patlen = (int)STRLEN(buflocal_pat); // but not endpat
1132 }
1133
1134 /*
1135 * Find AutoPat entries with this pattern. When adding a command it
1136 * always goes at or after the last one, so start at the end.
1137 */
1138 if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
1139 prev_ap = &last_autopat[(int)event];
1140 else
1141 prev_ap = &first_autopat[(int)event];
1142 while ((ap = *prev_ap) != NULL)
1143 {
1144 if (ap->pat != NULL)
1145 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001146 /*
1147 * Accept a pattern when:
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001148 * - a group was specified and it's that group, or a group was
1149 * not specified and it's the current group, or a group was
1150 * not specified and we are listing
1151 * - the length of the pattern matches
1152 * - the pattern matches.
1153 * For <buffer[=X]>, this condition works because we normalize
1154 * all buffer-local patterns.
1155 */
1156 if ((allgroups || ap->group == findgroup)
1157 && ap->patlen == patlen
1158 && STRNCMP(pat, ap->pat, patlen) == 0)
1159 {
1160 /*
1161 * Remove existing autocommands.
1162 * If adding any new autocmd's for this AutoPat, don't
1163 * delete the pattern from the autopat list, append to
1164 * this list.
1165 */
1166 if (forceit)
1167 {
1168 if (*cmd != NUL && ap->next == NULL)
1169 {
1170 au_remove_cmds(ap);
1171 break;
1172 }
1173 au_remove_pat(ap);
1174 }
1175
1176 /*
1177 * Show autocmd's for this autopat, or buflocals <buffer=X>
1178 */
1179 else if (*cmd == NUL)
1180 show_autocmd(ap, event);
1181
1182 /*
1183 * Add autocmd to this autopat, if it's the last one.
1184 */
1185 else if (ap->next == NULL)
1186 break;
1187 }
1188 }
1189 prev_ap = &ap->next;
1190 }
1191
1192 /*
1193 * Add a new command.
1194 */
1195 if (*cmd != NUL)
1196 {
1197 /*
1198 * If the pattern we want to add a command to does appear at the
1199 * end of the list (or not is not in the list at all), add the
1200 * pattern at the end of the list.
1201 */
1202 if (ap == NULL)
1203 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001204 // refuse to add buffer-local ap if buffer number is invalid
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001205 if (is_buflocal && (buflocal_nr == 0
1206 || buflist_findnr(buflocal_nr) == NULL))
1207 {
Bram Moolenaarf1474d82021-12-31 19:59:55 +00001208 semsg(_(e_buffer_nr_invalid_buffer_number), buflocal_nr);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001209 return FAIL;
1210 }
1211
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001212 ap = ALLOC_ONE(AutoPat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001213 if (ap == NULL)
1214 return FAIL;
1215 ap->pat = vim_strnsave(pat, patlen);
1216 ap->patlen = patlen;
1217 if (ap->pat == NULL)
1218 {
1219 vim_free(ap);
1220 return FAIL;
1221 }
1222
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01001223#ifdef FEAT_EVAL
1224 // need to initialize last_mode for the first ModeChanged
1225 // autocmd
1226 if (event == EVENT_MODECHANGED && !has_modechanged())
1227 {
1228 typval_T rettv;
1229 typval_T tv[2];
1230
1231 tv[0].v_type = VAR_NUMBER;
1232 tv[0].vval.v_number = 1;
1233 tv[1].v_type = VAR_UNKNOWN;
1234 f_mode(tv, &rettv);
1235 STRCPY(last_mode, rettv.vval.v_string);
1236 vim_free(rettv.vval.v_string);
1237 }
1238#endif
1239
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001240 if (is_buflocal)
1241 {
1242 ap->buflocal_nr = buflocal_nr;
1243 ap->reg_prog = NULL;
1244 }
1245 else
1246 {
1247 char_u *reg_pat;
1248
1249 ap->buflocal_nr = 0;
1250 reg_pat = file_pat_to_reg_pat(pat, endpat,
1251 &ap->allow_dirs, TRUE);
1252 if (reg_pat != NULL)
1253 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1254 vim_free(reg_pat);
1255 if (reg_pat == NULL || ap->reg_prog == NULL)
1256 {
1257 vim_free(ap->pat);
1258 vim_free(ap);
1259 return FAIL;
1260 }
1261 }
1262 ap->cmds = NULL;
1263 *prev_ap = ap;
1264 last_autopat[(int)event] = ap;
1265 ap->next = NULL;
1266 if (group == AUGROUP_ALL)
1267 ap->group = current_augroup;
1268 else
1269 ap->group = group;
1270 }
1271
1272 /*
1273 * Add the autocmd at the end of the AutoCmd list.
1274 */
1275 prev_ac = &(ap->cmds);
1276 while ((ac = *prev_ac) != NULL)
1277 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001278 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001279 if (ac == NULL)
1280 return FAIL;
1281 ac->cmd = vim_strsave(cmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001282 ac->script_ctx = current_sctx;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001283 if (flags & UC_VIM9)
1284 ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001285#ifdef FEAT_EVAL
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001286 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001287#endif
1288 if (ac->cmd == NULL)
1289 {
1290 vim_free(ac);
1291 return FAIL;
1292 }
1293 ac->next = NULL;
1294 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001295 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001296 ac->nested = nested;
1297 }
1298 }
1299
1300 au_cleanup(); // may really delete removed patterns/commands now
1301 return OK;
1302}
1303
1304/*
1305 * Implementation of ":doautocmd [group] event [fname]".
1306 * Return OK for success, FAIL for failure;
1307 */
1308 int
1309do_doautocmd(
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001310 char_u *arg_start,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001311 int do_msg, // give message for no matching autocmds?
1312 int *did_something)
1313{
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001314 char_u *arg = arg_start;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001315 char_u *fname;
1316 int nothing_done = TRUE;
1317 int group;
1318
1319 if (did_something != NULL)
1320 *did_something = FALSE;
1321
1322 /*
1323 * Check for a legal group name. If not, use AUGROUP_ALL.
1324 */
1325 group = au_get_grouparg(&arg);
1326 if (arg == NULL) // out of memory
1327 return FAIL;
1328
1329 if (*arg == '*')
1330 {
Bram Moolenaar6d057012021-12-31 18:49:43 +00001331 emsg(_(e_cant_execute_autocommands_for_all_events));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001332 return FAIL;
1333 }
1334
1335 /*
1336 * Scan over the events.
1337 * If we find an illegal name, return here, don't do anything.
1338 */
1339 fname = find_end_event(arg, group != AUGROUP_ALL);
1340 if (fname == NULL)
1341 return FAIL;
1342
1343 fname = skipwhite(fname);
1344
1345 /*
1346 * Loop over the events.
1347 */
1348 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1349 if (apply_autocmds_group(event_name2nr(arg, &arg),
1350 fname, NULL, TRUE, group, curbuf, NULL))
1351 nothing_done = FALSE;
1352
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001353 if (nothing_done && do_msg
1354#ifdef FEAT_EVAL
1355 && !aborting()
1356#endif
1357 )
1358 smsg(_("No matching autocommands: %s"), arg_start);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001359 if (did_something != NULL)
1360 *did_something = !nothing_done;
1361
1362#ifdef FEAT_EVAL
1363 return aborting() ? FAIL : OK;
1364#else
1365 return OK;
1366#endif
1367}
1368
1369/*
1370 * ":doautoall": execute autocommands for each loaded buffer.
1371 */
1372 void
1373ex_doautoall(exarg_T *eap)
1374{
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001375 int retval = OK;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001376 aco_save_T aco;
1377 buf_T *buf;
1378 bufref_T bufref;
1379 char_u *arg = eap->arg;
1380 int call_do_modelines = check_nomodeline(&arg);
1381 int did_aucmd;
1382
1383 /*
1384 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1385 * equal to curbuf, but for some buffers there may not be a window.
1386 * So we change the buffer for the current window for a moment. This
1387 * gives problems when the autocommands make changes to the list of
1388 * buffers or windows...
1389 */
1390 FOR_ALL_BUFFERS(buf)
1391 {
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001392 // Only do loaded buffers and skip the current buffer, it's done last.
1393 if (buf->b_ml.ml_mfp != NULL && buf != curbuf)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001394 {
1395 // find a window for this buffer and save some values
1396 aucmd_prepbuf(&aco, buf);
1397 set_bufref(&bufref, buf);
1398
1399 // execute the autocommands for this buffer
1400 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1401
1402 if (call_do_modelines && did_aucmd)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001403 // Execute the modeline settings, but don't set window-local
1404 // options if we are using the current window for another
1405 // buffer.
1406 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001407
1408 // restore the current window
1409 aucmd_restbuf(&aco);
1410
1411 // stop if there is some error or buffer was deleted
1412 if (retval == FAIL || !bufref_valid(&bufref))
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001413 {
1414 retval = FAIL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001415 break;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001416 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001417 }
1418 }
1419
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001420 // Execute autocommands for the current buffer last.
1421 if (retval == OK)
1422 {
1423 do_doautocmd(arg, FALSE, &did_aucmd);
1424 if (call_do_modelines && did_aucmd)
1425 do_modelines(0);
1426 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001427}
1428
1429/*
1430 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1431 * return TRUE and advance *argp to after it.
1432 * Thus return TRUE when do_modelines() should be called.
1433 */
1434 int
1435check_nomodeline(char_u **argp)
1436{
1437 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1438 {
1439 *argp = skipwhite(*argp + 12);
1440 return FALSE;
1441 }
1442 return TRUE;
1443}
1444
1445/*
1446 * Prepare for executing autocommands for (hidden) buffer "buf".
1447 * Search for a visible window containing the current buffer. If there isn't
1448 * one then use "aucmd_win".
1449 * Set "curbuf" and "curwin" to match "buf".
1450 */
1451 void
1452aucmd_prepbuf(
1453 aco_save_T *aco, // structure to save values in
1454 buf_T *buf) // new curbuf
1455{
1456 win_T *win;
1457 int save_ea;
1458#ifdef FEAT_AUTOCHDIR
1459 int save_acd;
1460#endif
1461
1462 // Find a window that is for the new buffer
1463 if (buf == curbuf) // be quick when buf is curbuf
1464 win = curwin;
1465 else
1466 FOR_ALL_WINDOWS(win)
1467 if (win->w_buffer == buf)
1468 break;
1469
1470 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1471 // back to using the current window.
1472 if (win == NULL && aucmd_win == NULL)
1473 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001474 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001475 if (aucmd_win == NULL)
1476 win = curwin;
1477 }
1478 if (win == NULL && aucmd_win_used)
1479 // Strange recursive autocommand, fall back to using the current
1480 // window. Expect a few side effects...
1481 win = curwin;
1482
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001483 aco->save_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001484 aco->save_curbuf = curbuf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001485 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001486 if (win != NULL)
1487 {
1488 // There is a window for "buf" in the current tab page, make it the
1489 // curwin. This is preferred, it has the least side effects (esp. if
1490 // "buf" is curbuf).
1491 aco->use_aucmd_win = FALSE;
1492 curwin = win;
1493 }
1494 else
1495 {
1496 // There is no window for "buf", use "aucmd_win". To minimize the side
1497 // effects, insert it in the current tab page.
1498 // Anything related to a window (e.g., setting folds) may have
1499 // unexpected results.
1500 aco->use_aucmd_win = TRUE;
1501 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001502
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001503 win_init_popup_win(aucmd_win, buf);
1504
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001505 aco->globaldir = globaldir;
1506 globaldir = NULL;
1507
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001508 // Split the current window, put the aucmd_win in the upper half.
1509 // We don't want the BufEnter or WinEnter autocommands.
1510 block_autocmds();
1511 make_snapshot(SNAP_AUCMD_IDX);
1512 save_ea = p_ea;
1513 p_ea = FALSE;
1514
1515#ifdef FEAT_AUTOCHDIR
1516 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1517 save_acd = p_acd;
1518 p_acd = FALSE;
1519#endif
1520
Bram Moolenaardff97e62022-01-24 20:00:55 +00001521 // no redrawing and don't set the window title
1522 ++RedrawingDisabled;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001523 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
Bram Moolenaardff97e62022-01-24 20:00:55 +00001524 --RedrawingDisabled;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001525 (void)win_comp_pos(); // recompute window positions
1526 p_ea = save_ea;
1527#ifdef FEAT_AUTOCHDIR
1528 p_acd = save_acd;
1529#endif
1530 unblock_autocmds();
1531 curwin = aucmd_win;
1532 }
1533 curbuf = buf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001534 aco->new_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001535 set_bufref(&aco->new_curbuf, curbuf);
Bram Moolenaarcb1956d2022-01-07 15:45:18 +00001536
1537 // disable the Visual area, the position may be invalid in another buffer
1538 aco->save_VIsual_active = VIsual_active;
1539 VIsual_active = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001540}
1541
1542/*
1543 * Cleanup after executing autocommands for a (hidden) buffer.
1544 * Restore the window as it was (if possible).
1545 */
1546 void
1547aucmd_restbuf(
1548 aco_save_T *aco) // structure holding saved values
1549{
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001550 int dummy;
1551 win_T *save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001552
1553 if (aco->use_aucmd_win)
1554 {
1555 --curbuf->b_nwindows;
1556 // Find "aucmd_win", it can't be closed, but it may be in another tab
1557 // page. Do not trigger autocommands here.
1558 block_autocmds();
1559 if (curwin != aucmd_win)
1560 {
1561 tabpage_T *tp;
1562 win_T *wp;
1563
1564 FOR_ALL_TAB_WINDOWS(tp, wp)
1565 {
1566 if (wp == aucmd_win)
1567 {
1568 if (tp != curtab)
1569 goto_tabpage_tp(tp, TRUE, TRUE);
1570 win_goto(aucmd_win);
1571 goto win_found;
1572 }
1573 }
1574 }
1575win_found:
1576
1577 // Remove the window and frame from the tree of frames.
1578 (void)winframe_remove(curwin, &dummy, NULL);
1579 win_remove(curwin, NULL);
1580 aucmd_win_used = FALSE;
1581 last_status(FALSE); // may need to remove last status line
1582
1583 if (!valid_tabpage_win(curtab))
1584 // no valid window in current tabpage
1585 close_tabpage(curtab);
1586
1587 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1588 (void)win_comp_pos(); // recompute window positions
1589 unblock_autocmds();
1590
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001591 save_curwin = win_find_by_id(aco->save_curwin_id);
1592 if (save_curwin != NULL)
1593 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001594 else
1595 // Hmm, original window disappeared. Just use the first one.
1596 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001597 curbuf = curwin->w_buffer;
1598#ifdef FEAT_JOB_CHANNEL
1599 // May need to restore insert mode for a prompt buffer.
1600 entering_window(curwin);
1601#endif
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001602 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001603#ifdef FEAT_EVAL
1604 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1605 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1606#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001607 vim_free(globaldir);
1608 globaldir = aco->globaldir;
1609
1610 // the buffer contents may have changed
1611 check_cursor();
1612 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1613 {
1614 curwin->w_topline = curbuf->b_ml.ml_line_count;
1615#ifdef FEAT_DIFF
1616 curwin->w_topfill = 0;
1617#endif
1618 }
1619#if defined(FEAT_GUI)
Bram Moolenaard2ff7052021-12-17 16:00:04 +00001620 if (gui.in_use)
1621 {
1622 // Hide the scrollbars from the aucmd_win and update.
1623 gui_mch_enable_scrollbar(
1624 &aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1625 gui_mch_enable_scrollbar(
1626 &aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1627 gui_may_update_scrollbars();
1628 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001629#endif
1630 }
1631 else
1632 {
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001633 // Restore curwin. Use the window ID, a window may have been closed
1634 // and the memory re-used for another one.
1635 save_curwin = win_find_by_id(aco->save_curwin_id);
1636 if (save_curwin != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001637 {
1638 // Restore the buffer which was previously edited by curwin, if
1639 // it was changed, we are still the same window and the buffer is
1640 // valid.
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001641 if (curwin->w_id == aco->new_curwin_id
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001642 && curbuf != aco->new_curbuf.br_buf
1643 && bufref_valid(&aco->new_curbuf)
1644 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1645 {
1646# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1647 if (curwin->w_s == &curbuf->b_s)
1648 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1649# endif
1650 --curbuf->b_nwindows;
1651 curbuf = aco->new_curbuf.br_buf;
1652 curwin->w_buffer = curbuf;
1653 ++curbuf->b_nwindows;
1654 }
1655
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001656 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001657 curbuf = curwin->w_buffer;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001658 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001659 // In case the autocommand moves the cursor to a position that
1660 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001661 check_cursor();
1662 }
1663 }
Bram Moolenaarcb1956d2022-01-07 15:45:18 +00001664
1665 check_cursor(); // just in case lines got deleted
1666 VIsual_active = aco->save_VIsual_active;
1667 if (VIsual_active)
1668 check_pos(curbuf, &VIsual);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001669}
1670
1671static int autocmd_nested = FALSE;
1672
1673/*
1674 * Execute autocommands for "event" and file name "fname".
1675 * Return TRUE if some commands were executed.
1676 */
1677 int
1678apply_autocmds(
1679 event_T event,
1680 char_u *fname, // NULL or empty means use actual file name
1681 char_u *fname_io, // fname to use for <afile> on cmdline
1682 int force, // when TRUE, ignore autocmd_busy
1683 buf_T *buf) // buffer for <abuf>
1684{
1685 return apply_autocmds_group(event, fname, fname_io, force,
1686 AUGROUP_ALL, buf, NULL);
1687}
1688
1689/*
1690 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1691 * setting v:filearg.
1692 */
1693 int
1694apply_autocmds_exarg(
1695 event_T event,
1696 char_u *fname,
1697 char_u *fname_io,
1698 int force,
1699 buf_T *buf,
1700 exarg_T *eap)
1701{
1702 return apply_autocmds_group(event, fname, fname_io, force,
1703 AUGROUP_ALL, buf, eap);
1704}
1705
1706/*
1707 * Like apply_autocmds(), but handles the caller's retval. If the script
1708 * processing is being aborted or if retval is FAIL when inside a try
1709 * conditional, no autocommands are executed. If otherwise the autocommands
1710 * cause the script to be aborted, retval is set to FAIL.
1711 */
1712 int
1713apply_autocmds_retval(
1714 event_T event,
1715 char_u *fname, // NULL or empty means use actual file name
1716 char_u *fname_io, // fname to use for <afile> on cmdline
1717 int force, // when TRUE, ignore autocmd_busy
1718 buf_T *buf, // buffer for <abuf>
1719 int *retval) // pointer to caller's retval
1720{
1721 int did_cmd;
1722
1723#ifdef FEAT_EVAL
1724 if (should_abort(*retval))
1725 return FALSE;
1726#endif
1727
1728 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1729 AUGROUP_ALL, buf, NULL);
1730 if (did_cmd
1731#ifdef FEAT_EVAL
1732 && aborting()
1733#endif
1734 )
1735 *retval = FAIL;
1736 return did_cmd;
1737}
1738
1739/*
1740 * Return TRUE when there is a CursorHold autocommand defined.
1741 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001742 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001743has_cursorhold(void)
1744{
1745 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1746 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1747}
1748
1749/*
1750 * Return TRUE if the CursorHold event can be triggered.
1751 */
1752 int
1753trigger_cursorhold(void)
1754{
1755 int state;
1756
1757 if (!did_cursorhold
1758 && has_cursorhold()
1759 && reg_recording == 0
1760 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001761 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001762 {
1763 state = get_real_state();
1764 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1765 return TRUE;
1766 }
1767 return FALSE;
1768}
1769
1770/*
1771 * Return TRUE when there is a CursorMoved autocommand defined.
1772 */
1773 int
1774has_cursormoved(void)
1775{
1776 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1777}
1778
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001779/*
1780 * Return TRUE when there is a CursorMovedI autocommand defined.
1781 */
1782 int
1783has_cursormovedI(void)
1784{
1785 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1786}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001787
1788/*
1789 * Return TRUE when there is a TextChanged autocommand defined.
1790 */
1791 int
1792has_textchanged(void)
1793{
1794 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1795}
1796
1797/*
1798 * Return TRUE when there is a TextChangedI autocommand defined.
1799 */
1800 int
1801has_textchangedI(void)
1802{
1803 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1804}
1805
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001806/*
1807 * Return TRUE when there is a TextChangedP autocommand defined.
1808 */
1809 int
1810has_textchangedP(void)
1811{
1812 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1813}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001814
1815/*
1816 * Return TRUE when there is an InsertCharPre autocommand defined.
1817 */
1818 int
1819has_insertcharpre(void)
1820{
1821 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1822}
1823
1824/*
1825 * Return TRUE when there is an CmdUndefined autocommand defined.
1826 */
1827 int
1828has_cmdundefined(void)
1829{
1830 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1831}
1832
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001833#if defined(FEAT_EVAL) || defined(PROTO)
1834/*
1835 * Return TRUE when there is a TextYankPost autocommand defined.
1836 */
1837 int
1838has_textyankpost(void)
1839{
1840 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1841}
1842#endif
1843
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001844#if defined(FEAT_EVAL) || defined(PROTO)
1845/*
1846 * Return TRUE when there is a CompleteChanged autocommand defined.
1847 */
1848 int
1849has_completechanged(void)
1850{
1851 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1852}
1853#endif
1854
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001855#if defined(FEAT_EVAL) || defined(PROTO)
1856/*
1857 * Return TRUE when there is a ModeChanged autocommand defined.
1858 */
1859 int
1860has_modechanged(void)
1861{
1862 return (first_autopat[(int)EVENT_MODECHANGED] != NULL);
1863}
1864#endif
1865
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001866/*
1867 * Execute autocommands for "event" and file name "fname".
1868 * Return TRUE if some commands were executed.
1869 */
1870 static int
1871apply_autocmds_group(
1872 event_T event,
1873 char_u *fname, // NULL or empty means use actual file name
1874 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1875 // use fname
1876 int force, // when TRUE, ignore autocmd_busy
1877 int group, // group ID, or AUGROUP_ALL
1878 buf_T *buf, // buffer for <abuf>
1879 exarg_T *eap UNUSED) // command arguments
1880{
1881 char_u *sfname = NULL; // short file name
1882 char_u *tail;
1883 int save_changed;
1884 buf_T *old_curbuf;
1885 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001886 char_u *save_autocmd_fname;
1887 int save_autocmd_fname_full;
1888 int save_autocmd_bufnr;
1889 char_u *save_autocmd_match;
1890 int save_autocmd_busy;
1891 int save_autocmd_nested;
1892 static int nesting = 0;
1893 AutoPatCmd patcmd;
1894 AutoPat *ap;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001895 sctx_T save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001896#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001897 funccal_entry_T funccal_entry;
1898 char_u *save_cmdarg;
1899 long save_cmdbang;
1900#endif
1901 static int filechangeshell_busy = FALSE;
1902#ifdef FEAT_PROFILE
1903 proftime_T wait_time;
1904#endif
1905 int did_save_redobuff = FALSE;
1906 save_redo_T save_redo;
1907 int save_KeyTyped = KeyTyped;
ichizokc3f91c02021-12-17 09:44:33 +00001908 int save_did_emsg;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001909 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001910
1911 /*
1912 * Quickly return if there are no autocommands for this event or
1913 * autocommands are blocked.
1914 */
1915 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1916 || autocmd_blocked > 0)
1917 goto BYPASS_AU;
1918
1919 /*
1920 * When autocommands are busy, new autocommands are only executed when
1921 * explicitly enabled with the "nested" flag.
1922 */
1923 if (autocmd_busy && !(force || autocmd_nested))
1924 goto BYPASS_AU;
1925
1926#ifdef FEAT_EVAL
1927 /*
1928 * Quickly return when immediately aborting on error, or when an interrupt
1929 * occurred or an exception was thrown but not caught.
1930 */
1931 if (aborting())
1932 goto BYPASS_AU;
1933#endif
1934
1935 /*
1936 * FileChangedShell never nests, because it can create an endless loop.
1937 */
1938 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1939 || event == EVENT_FILECHANGEDSHELLPOST))
1940 goto BYPASS_AU;
1941
1942 /*
1943 * Ignore events in 'eventignore'.
1944 */
1945 if (event_ignored(event))
1946 goto BYPASS_AU;
1947
1948 /*
1949 * Allow nesting of autocommands, but restrict the depth, because it's
1950 * possible to create an endless loop.
1951 */
1952 if (nesting == 10)
1953 {
Bram Moolenaar6d057012021-12-31 18:49:43 +00001954 emsg(_(e_autocommand_nesting_too_deep));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001955 goto BYPASS_AU;
1956 }
1957
1958 /*
1959 * Check if these autocommands are disabled. Used when doing ":all" or
1960 * ":ball".
1961 */
1962 if ( (autocmd_no_enter
1963 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1964 || (autocmd_no_leave
1965 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1966 goto BYPASS_AU;
1967
1968 /*
1969 * Save the autocmd_* variables and info about the current buffer.
1970 */
1971 save_autocmd_fname = autocmd_fname;
1972 save_autocmd_fname_full = autocmd_fname_full;
1973 save_autocmd_bufnr = autocmd_bufnr;
1974 save_autocmd_match = autocmd_match;
1975 save_autocmd_busy = autocmd_busy;
1976 save_autocmd_nested = autocmd_nested;
1977 save_changed = curbuf->b_changed;
1978 old_curbuf = curbuf;
1979
1980 /*
1981 * Set the file name to be used for <afile>.
1982 * Make a copy to avoid that changing a buffer name or directory makes it
1983 * invalid.
1984 */
1985 if (fname_io == NULL)
1986 {
1987 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001988 || event == EVENT_OPTIONSET
1989 || event == EVENT_MODECHANGED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001990 autocmd_fname = NULL;
1991 else if (fname != NULL && !ends_excmd(*fname))
1992 autocmd_fname = fname;
1993 else if (buf != NULL)
1994 autocmd_fname = buf->b_ffname;
1995 else
1996 autocmd_fname = NULL;
1997 }
1998 else
1999 autocmd_fname = fname_io;
2000 if (autocmd_fname != NULL)
2001 autocmd_fname = vim_strsave(autocmd_fname);
2002 autocmd_fname_full = FALSE; // call FullName_save() later
2003
2004 /*
2005 * Set the buffer number to be used for <abuf>.
2006 */
2007 if (buf == NULL)
2008 autocmd_bufnr = 0;
2009 else
2010 autocmd_bufnr = buf->b_fnum;
2011
2012 /*
2013 * When the file name is NULL or empty, use the file name of buffer "buf".
2014 * Always use the full path of the file name to match with, in case
2015 * "allow_dirs" is set.
2016 */
2017 if (fname == NULL || *fname == NUL)
2018 {
2019 if (buf == NULL)
2020 fname = NULL;
2021 else
2022 {
2023#ifdef FEAT_SYN_HL
2024 if (event == EVENT_SYNTAX)
2025 fname = buf->b_p_syn;
2026 else
2027#endif
2028 if (event == EVENT_FILETYPE)
2029 fname = buf->b_p_ft;
2030 else
2031 {
2032 if (buf->b_sfname != NULL)
2033 sfname = vim_strsave(buf->b_sfname);
2034 fname = buf->b_ffname;
2035 }
2036 }
2037 if (fname == NULL)
2038 fname = (char_u *)"";
2039 fname = vim_strsave(fname); // make a copy, so we can change it
2040 }
2041 else
2042 {
2043 sfname = vim_strsave(fname);
2044 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
2045 // ColorScheme, QuickFixCmd* or DirChanged
2046 if (event == EVENT_FILETYPE
2047 || event == EVENT_SYNTAX
2048 || event == EVENT_CMDLINECHANGED
2049 || event == EVENT_CMDLINEENTER
2050 || event == EVENT_CMDLINELEAVE
2051 || event == EVENT_CMDWINENTER
2052 || event == EVENT_CMDWINLEAVE
2053 || event == EVENT_CMDUNDEFINED
2054 || event == EVENT_FUNCUNDEFINED
2055 || event == EVENT_REMOTEREPLY
2056 || event == EVENT_SPELLFILEMISSING
2057 || event == EVENT_QUICKFIXCMDPRE
2058 || event == EVENT_COLORSCHEME
2059 || event == EVENT_COLORSCHEMEPRE
2060 || event == EVENT_OPTIONSET
2061 || event == EVENT_QUICKFIXCMDPOST
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02002062 || event == EVENT_DIRCHANGED
naohiro ono23beefe2021-11-13 12:38:49 +00002063 || event == EVENT_MODECHANGED
2064 || event == EVENT_WINCLOSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002065 {
2066 fname = vim_strsave(fname);
2067 autocmd_fname_full = TRUE; // don't expand it later
2068 }
2069 else
2070 fname = FullName_save(fname, FALSE);
2071 }
2072 if (fname == NULL) // out of memory
2073 {
2074 vim_free(sfname);
2075 retval = FALSE;
2076 goto BYPASS_AU;
2077 }
2078
2079#ifdef BACKSLASH_IN_FILENAME
2080 /*
2081 * Replace all backslashes with forward slashes. This makes the
2082 * autocommand patterns portable between Unix and MS-DOS.
2083 */
2084 if (sfname != NULL)
2085 forward_slash(sfname);
2086 forward_slash(fname);
2087#endif
2088
2089#ifdef VMS
2090 // remove version for correct match
2091 if (sfname != NULL)
2092 vms_remove_version(sfname);
2093 vms_remove_version(fname);
2094#endif
2095
2096 /*
2097 * Set the name to be used for <amatch>.
2098 */
2099 autocmd_match = fname;
2100
2101
2102 // Don't redraw while doing autocommands.
2103 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002104
2105 // name and lnum are filled in later
2106 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002107 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002108
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002109 save_current_sctx = current_sctx;
2110
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002111#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002112# ifdef FEAT_PROFILE
2113 if (do_profiling == PROF_YES)
2114 prof_child_enter(&wait_time); // doesn't count for the caller itself
2115# endif
2116
2117 // Don't use local function variables, if called from a function.
2118 save_funccal(&funccal_entry);
2119#endif
2120
2121 /*
2122 * When starting to execute autocommands, save the search patterns.
2123 */
2124 if (!autocmd_busy)
2125 {
2126 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002127 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002128 {
2129 saveRedobuff(&save_redo);
2130 did_save_redobuff = TRUE;
2131 }
2132 did_filetype = keep_filetype;
2133 }
2134
2135 /*
2136 * Note that we are applying autocmds. Some commands need to know.
2137 */
2138 autocmd_busy = TRUE;
2139 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2140 ++nesting; // see matching decrement below
2141
2142 // Remember that FileType was triggered. Used for did_filetype().
2143 if (event == EVENT_FILETYPE)
2144 did_filetype = TRUE;
2145
2146 tail = gettail(fname);
2147
2148 // Find first autocommand that matches
2149 patcmd.curpat = first_autopat[(int)event];
2150 patcmd.nextcmd = NULL;
2151 patcmd.group = group;
2152 patcmd.fname = fname;
2153 patcmd.sfname = sfname;
2154 patcmd.tail = tail;
2155 patcmd.event = event;
2156 patcmd.arg_bufnr = autocmd_bufnr;
2157 patcmd.next = NULL;
2158 auto_next_pat(&patcmd, FALSE);
2159
2160 // found one, start executing the autocommands
2161 if (patcmd.curpat != NULL)
2162 {
2163 // add to active_apc_list
2164 patcmd.next = active_apc_list;
2165 active_apc_list = &patcmd;
2166
2167#ifdef FEAT_EVAL
2168 // set v:cmdarg (only when there is a matching pattern)
2169 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2170 if (eap != NULL)
2171 {
2172 save_cmdarg = set_cmdarg(eap, NULL);
2173 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2174 }
2175 else
2176 save_cmdarg = NULL; // avoid gcc warning
2177#endif
2178 retval = TRUE;
2179 // mark the last pattern, to avoid an endless loop when more patterns
2180 // are added when executing autocommands
2181 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2182 ap->last = FALSE;
2183 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002184
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002185 if (nesting == 1)
2186 // make sure cursor and topline are valid
2187 check_lnums(TRUE);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002188
ichizokc3f91c02021-12-17 09:44:33 +00002189 save_did_emsg = did_emsg;
2190
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002191 do_cmdline(NULL, getnextac, (void *)&patcmd,
2192 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002193
ichizokc3f91c02021-12-17 09:44:33 +00002194 did_emsg += save_did_emsg;
2195
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002196 if (nesting == 1)
2197 // restore cursor and topline, unless they were changed
2198 reset_lnums();
Bram Moolenaara68e5952019-04-25 22:22:01 +02002199
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002200#ifdef FEAT_EVAL
2201 if (eap != NULL)
2202 {
2203 (void)set_cmdarg(NULL, save_cmdarg);
2204 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2205 }
2206#endif
2207 // delete from active_apc_list
2208 if (active_apc_list == &patcmd) // just in case
2209 active_apc_list = patcmd.next;
2210 }
2211
2212 --RedrawingDisabled;
2213 autocmd_busy = save_autocmd_busy;
2214 filechangeshell_busy = FALSE;
2215 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002216 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002217 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002218 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002219 vim_free(autocmd_fname);
2220 autocmd_fname = save_autocmd_fname;
2221 autocmd_fname_full = save_autocmd_fname_full;
2222 autocmd_bufnr = save_autocmd_bufnr;
2223 autocmd_match = save_autocmd_match;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002224 current_sctx = save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002225#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002226 restore_funccal();
2227# ifdef FEAT_PROFILE
2228 if (do_profiling == PROF_YES)
2229 prof_child_exit(&wait_time);
2230# endif
2231#endif
2232 KeyTyped = save_KeyTyped;
2233 vim_free(fname);
2234 vim_free(sfname);
2235 --nesting; // see matching increment above
2236
2237 /*
2238 * When stopping to execute autocommands, restore the search patterns and
2239 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2240 * free any windows in the au_pending_free_win list.
2241 */
2242 if (!autocmd_busy)
2243 {
2244 restore_search_patterns();
2245 if (did_save_redobuff)
2246 restoreRedobuff(&save_redo);
2247 did_filetype = FALSE;
2248 while (au_pending_free_buf != NULL)
2249 {
2250 buf_T *b = au_pending_free_buf->b_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002251
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002252 vim_free(au_pending_free_buf);
2253 au_pending_free_buf = b;
2254 }
2255 while (au_pending_free_win != NULL)
2256 {
2257 win_T *w = au_pending_free_win->w_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002258
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002259 vim_free(au_pending_free_win);
2260 au_pending_free_win = w;
2261 }
2262 }
2263
2264 /*
2265 * Some events don't set or reset the Changed flag.
2266 * Check if still in the same buffer!
2267 */
2268 if (curbuf == old_curbuf
2269 && (event == EVENT_BUFREADPOST
2270 || event == EVENT_BUFWRITEPOST
2271 || event == EVENT_FILEAPPENDPOST
2272 || event == EVENT_VIMLEAVE
2273 || event == EVENT_VIMLEAVEPRE))
2274 {
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002275 if (curbuf->b_changed != save_changed)
2276 need_maketitle = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002277 curbuf->b_changed = save_changed;
2278 }
2279
2280 au_cleanup(); // may really delete removed patterns/commands now
2281
2282BYPASS_AU:
2283 // When wiping out a buffer make sure all its buffer-local autocommands
2284 // are deleted.
2285 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2286 aubuflocal_remove(buf);
2287
2288 if (retval == OK && event == EVENT_FILETYPE)
2289 au_did_filetype = TRUE;
2290
2291 return retval;
2292}
2293
2294# ifdef FEAT_EVAL
2295static char_u *old_termresponse = NULL;
2296# endif
2297
2298/*
2299 * Block triggering autocommands until unblock_autocmd() is called.
2300 * Can be used recursively, so long as it's symmetric.
2301 */
2302 void
2303block_autocmds(void)
2304{
2305# ifdef FEAT_EVAL
2306 // Remember the value of v:termresponse.
2307 if (autocmd_blocked == 0)
2308 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2309# endif
2310 ++autocmd_blocked;
2311}
2312
2313 void
2314unblock_autocmds(void)
2315{
2316 --autocmd_blocked;
2317
2318# ifdef FEAT_EVAL
2319 // When v:termresponse was set while autocommands were blocked, trigger
2320 // the autocommands now. Esp. useful when executing a shell command
2321 // during startup (vimdiff).
2322 if (autocmd_blocked == 0
2323 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2324 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2325# endif
2326}
2327
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002328 int
2329is_autocmd_blocked(void)
2330{
2331 return autocmd_blocked != 0;
2332}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002333
2334/*
2335 * Find next autocommand pattern that matches.
2336 */
2337 static void
2338auto_next_pat(
2339 AutoPatCmd *apc,
2340 int stop_at_last) // stop when 'last' flag is set
2341{
2342 AutoPat *ap;
2343 AutoCmd *cp;
2344 char_u *name;
2345 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002346 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002347
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002348 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002349
2350 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2351 {
2352 apc->curpat = NULL;
2353
2354 // Only use a pattern when it has not been removed, has commands and
2355 // the group matches. For buffer-local autocommands only check the
2356 // buffer number.
2357 if (ap->pat != NULL && ap->cmds != NULL
2358 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2359 {
2360 // execution-condition
2361 if (ap->buflocal_nr == 0
2362 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2363 apc->sfname, apc->tail, ap->allow_dirs))
2364 : ap->buflocal_nr == apc->arg_bufnr)
2365 {
2366 name = event_nr2name(apc->event);
2367 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002368 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002369 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002370 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002371 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002372 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002373 (char *)name, (char *)ap->pat);
2374 if (p_verbose >= 8)
2375 {
2376 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002377 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002378 verbose_leave();
2379 }
2380 }
2381
2382 apc->curpat = ap;
2383 apc->nextcmd = ap->cmds;
2384 // mark last command
2385 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2386 cp->last = FALSE;
2387 cp->last = TRUE;
2388 }
2389 line_breakcheck();
2390 if (apc->curpat != NULL) // found a match
2391 break;
2392 }
2393 if (stop_at_last && ap->last)
2394 break;
2395 }
2396}
2397
2398/*
2399 * Get next autocommand command.
2400 * Called by do_cmdline() to get the next line for ":if".
2401 * Returns allocated string, or NULL for end of autocommands.
2402 */
2403 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002404getnextac(
2405 int c UNUSED,
2406 void *cookie,
2407 int indent UNUSED,
2408 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002409{
2410 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2411 char_u *retval;
2412 AutoCmd *ac;
2413
2414 // Can be called again after returning the last line.
2415 if (acp->curpat == NULL)
2416 return NULL;
2417
2418 // repeat until we find an autocommand to execute
2419 for (;;)
2420 {
2421 // skip removed commands
2422 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2423 if (acp->nextcmd->last)
2424 acp->nextcmd = NULL;
2425 else
2426 acp->nextcmd = acp->nextcmd->next;
2427
2428 if (acp->nextcmd != NULL)
2429 break;
2430
2431 // at end of commands, find next pattern that matches
2432 if (acp->curpat->last)
2433 acp->curpat = NULL;
2434 else
2435 acp->curpat = acp->curpat->next;
2436 if (acp->curpat != NULL)
2437 auto_next_pat(acp, TRUE);
2438 if (acp->curpat == NULL)
2439 return NULL;
2440 }
2441
2442 ac = acp->nextcmd;
2443
2444 if (p_verbose >= 9)
2445 {
2446 verbose_enter_scroll();
2447 smsg(_("autocommand %s"), ac->cmd);
2448 msg_puts("\n"); // don't overwrite this either
2449 verbose_leave_scroll();
2450 }
2451 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002452 // Remove one-shot ("once") autocmd in anticipation of its execution.
2453 if (ac->once)
2454 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002455 autocmd_nested = ac->nested;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002456 current_sctx = ac->script_ctx;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002457 if (ac->last)
2458 acp->nextcmd = NULL;
2459 else
2460 acp->nextcmd = ac->next;
2461 return retval;
2462}
2463
2464/*
2465 * Return TRUE if there is a matching autocommand for "fname".
2466 * To account for buffer-local autocommands, function needs to know
2467 * in which buffer the file will be opened.
2468 */
2469 int
2470has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2471{
2472 AutoPat *ap;
2473 char_u *fname;
2474 char_u *tail = gettail(sfname);
2475 int retval = FALSE;
2476
2477 fname = FullName_save(sfname, FALSE);
2478 if (fname == NULL)
2479 return FALSE;
2480
2481#ifdef BACKSLASH_IN_FILENAME
2482 /*
2483 * Replace all backslashes with forward slashes. This makes the
2484 * autocommand patterns portable between Unix and MS-DOS.
2485 */
2486 sfname = vim_strsave(sfname);
2487 if (sfname != NULL)
2488 forward_slash(sfname);
2489 forward_slash(fname);
2490#endif
2491
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002492 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002493 if (ap->pat != NULL && ap->cmds != NULL
2494 && (ap->buflocal_nr == 0
2495 ? match_file_pat(NULL, &ap->reg_prog,
2496 fname, sfname, tail, ap->allow_dirs)
2497 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2498 ))
2499 {
2500 retval = TRUE;
2501 break;
2502 }
2503
2504 vim_free(fname);
2505#ifdef BACKSLASH_IN_FILENAME
2506 vim_free(sfname);
2507#endif
2508
2509 return retval;
2510}
2511
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002512/*
2513 * Function given to ExpandGeneric() to obtain the list of autocommand group
2514 * names.
2515 */
2516 char_u *
2517get_augroup_name(expand_T *xp UNUSED, int idx)
2518{
2519 if (idx == augroups.ga_len) // add "END" add the end
2520 return (char_u *)"END";
2521 if (idx >= augroups.ga_len) // end of list
2522 return NULL;
2523 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2524 // skip deleted entries
2525 return (char_u *)"";
2526 return AUGROUP_NAME(idx); // return a name
2527}
2528
2529static int include_groups = FALSE;
2530
2531 char_u *
2532set_context_in_autocmd(
2533 expand_T *xp,
2534 char_u *arg,
2535 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2536{
2537 char_u *p;
2538 int group;
2539
2540 // check for a group name, skip it if present
2541 include_groups = FALSE;
2542 p = arg;
2543 group = au_get_grouparg(&arg);
2544 if (group == AUGROUP_ERROR)
2545 return NULL;
2546 // If there only is a group name that's what we expand.
2547 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2548 {
2549 arg = p;
2550 group = AUGROUP_ALL;
2551 }
2552
2553 // skip over event name
2554 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2555 if (*p == ',')
2556 arg = p + 1;
2557 if (*p == NUL)
2558 {
2559 if (group == AUGROUP_ALL)
2560 include_groups = TRUE;
2561 xp->xp_context = EXPAND_EVENTS; // expand event name
2562 xp->xp_pattern = arg;
2563 return NULL;
2564 }
2565
2566 // skip over pattern
2567 arg = skipwhite(p);
2568 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2569 arg++;
2570 if (*arg)
2571 return arg; // expand (next) command
2572
2573 if (doautocmd)
2574 xp->xp_context = EXPAND_FILES; // expand file names
2575 else
2576 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2577 return NULL;
2578}
2579
2580/*
2581 * Function given to ExpandGeneric() to obtain the list of event names.
2582 */
2583 char_u *
2584get_event_name(expand_T *xp UNUSED, int idx)
2585{
2586 if (idx < augroups.ga_len) // First list group names, if wanted
2587 {
2588 if (!include_groups || AUGROUP_NAME(idx) == NULL
2589 || AUGROUP_NAME(idx) == get_deleted_augroup())
2590 return (char_u *)""; // skip deleted entries
2591 return AUGROUP_NAME(idx); // return a name
2592 }
2593 return (char_u *)event_names[idx - augroups.ga_len].name;
2594}
2595
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002596
2597#if defined(FEAT_EVAL) || defined(PROTO)
2598/*
2599 * Return TRUE if autocmd is supported.
2600 */
2601 int
2602autocmd_supported(char_u *name)
2603{
2604 char_u *p;
2605
2606 return (event_name2nr(name, &p) != NUM_EVENTS);
2607}
2608
2609/*
2610 * Return TRUE if an autocommand is defined for a group, event and
2611 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2612 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2613 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2614 * Used for:
2615 * exists("#Group") or
2616 * exists("#Group#Event") or
2617 * exists("#Group#Event#pat") or
2618 * exists("#Event") or
2619 * exists("#Event#pat")
2620 */
2621 int
2622au_exists(char_u *arg)
2623{
2624 char_u *arg_save;
2625 char_u *pattern = NULL;
2626 char_u *event_name;
2627 char_u *p;
2628 event_T event;
2629 AutoPat *ap;
2630 buf_T *buflocal_buf = NULL;
2631 int group;
2632 int retval = FALSE;
2633
2634 // Make a copy so that we can change the '#' chars to a NUL.
2635 arg_save = vim_strsave(arg);
2636 if (arg_save == NULL)
2637 return FALSE;
2638 p = vim_strchr(arg_save, '#');
2639 if (p != NULL)
2640 *p++ = NUL;
2641
2642 // First, look for an autocmd group name
2643 group = au_find_group(arg_save);
2644 if (group == AUGROUP_ERROR)
2645 {
2646 // Didn't match a group name, assume the first argument is an event.
2647 group = AUGROUP_ALL;
2648 event_name = arg_save;
2649 }
2650 else
2651 {
2652 if (p == NULL)
2653 {
2654 // "Group": group name is present and it's recognized
2655 retval = TRUE;
2656 goto theend;
2657 }
2658
2659 // Must be "Group#Event" or "Group#Event#pat".
2660 event_name = p;
2661 p = vim_strchr(event_name, '#');
2662 if (p != NULL)
2663 *p++ = NUL; // "Group#Event#pat"
2664 }
2665
2666 pattern = p; // "pattern" is NULL when there is no pattern
2667
2668 // find the index (enum) for the event name
2669 event = event_name2nr(event_name, &p);
2670
2671 // return FALSE if the event name is not recognized
2672 if (event == NUM_EVENTS)
2673 goto theend;
2674
2675 // Find the first autocommand for this event.
2676 // If there isn't any, return FALSE;
2677 // If there is one and no pattern given, return TRUE;
2678 ap = first_autopat[(int)event];
2679 if (ap == NULL)
2680 goto theend;
2681
2682 // if pattern is "<buffer>", special handling is needed which uses curbuf
2683 // for pattern "<buffer=N>, fnamecmp() will work fine
2684 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2685 buflocal_buf = curbuf;
2686
2687 // Check if there is an autocommand with the given pattern.
2688 for ( ; ap != NULL; ap = ap->next)
2689 // only use a pattern when it has not been removed and has commands.
2690 // For buffer-local autocommands, fnamecmp() works fine.
2691 if (ap->pat != NULL && ap->cmds != NULL
2692 && (group == AUGROUP_ALL || ap->group == group)
2693 && (pattern == NULL
2694 || (buflocal_buf == NULL
2695 ? fnamecmp(ap->pat, pattern) == 0
2696 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2697 {
2698 retval = TRUE;
2699 break;
2700 }
2701
2702theend:
2703 vim_free(arg_save);
2704 return retval;
2705}
2706#endif