blob: 341cf837293f0c023d9c635d4f612c9e07afe2c5 [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},
Bram Moolenaar28e8f732022-02-09 12:58:20 +0000122 {"DirChangedPre", EVENT_DIRCHANGEDPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100123 {"EncodingChanged", EVENT_ENCODINGCHANGED},
124 {"ExitPre", EVENT_EXITPRE},
125 {"FileEncoding", EVENT_ENCODINGCHANGED},
126 {"FileAppendPost", EVENT_FILEAPPENDPOST},
127 {"FileAppendPre", EVENT_FILEAPPENDPRE},
128 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
129 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
130 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
131 {"FileChangedRO", EVENT_FILECHANGEDRO},
132 {"FileReadPost", EVENT_FILEREADPOST},
133 {"FileReadPre", EVENT_FILEREADPRE},
134 {"FileReadCmd", EVENT_FILEREADCMD},
135 {"FileType", EVENT_FILETYPE},
136 {"FileWritePost", EVENT_FILEWRITEPOST},
137 {"FileWritePre", EVENT_FILEWRITEPRE},
138 {"FileWriteCmd", EVENT_FILEWRITECMD},
139 {"FilterReadPost", EVENT_FILTERREADPOST},
140 {"FilterReadPre", EVENT_FILTERREADPRE},
141 {"FilterWritePost", EVENT_FILTERWRITEPOST},
142 {"FilterWritePre", EVENT_FILTERWRITEPRE},
143 {"FocusGained", EVENT_FOCUSGAINED},
144 {"FocusLost", EVENT_FOCUSLOST},
145 {"FuncUndefined", EVENT_FUNCUNDEFINED},
146 {"GUIEnter", EVENT_GUIENTER},
147 {"GUIFailed", EVENT_GUIFAILED},
148 {"InsertChange", EVENT_INSERTCHANGE},
149 {"InsertEnter", EVENT_INSERTENTER},
150 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaarb53e13a2020-10-21 12:19:53 +0200151 {"InsertLeavePre", EVENT_INSERTLEAVEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100152 {"InsertCharPre", EVENT_INSERTCHARPRE},
153 {"MenuPopup", EVENT_MENUPOPUP},
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +0200154 {"ModeChanged", EVENT_MODECHANGED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100155 {"OptionSet", EVENT_OPTIONSET},
156 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
157 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
158 {"QuitPre", EVENT_QUITPRE},
159 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar8aeec402019-09-15 23:02:04 +0200160 {"SafeState", EVENT_SAFESTATE},
Bram Moolenaar69198cb2019-09-16 21:58:13 +0200161 {"SafeStateAgain", EVENT_SAFESTATEAGAIN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100162 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
163 {"ShellCmdPost", EVENT_SHELLCMDPOST},
164 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200165 {"SigUSR1", EVENT_SIGUSR1},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100166 {"SourceCmd", EVENT_SOURCECMD},
167 {"SourcePre", EVENT_SOURCEPRE},
168 {"SourcePost", EVENT_SOURCEPOST},
169 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
170 {"StdinReadPost", EVENT_STDINREADPOST},
171 {"StdinReadPre", EVENT_STDINREADPRE},
172 {"SwapExists", EVENT_SWAPEXISTS},
173 {"Syntax", EVENT_SYNTAX},
174 {"TabNew", EVENT_TABNEW},
175 {"TabClosed", EVENT_TABCLOSED},
176 {"TabEnter", EVENT_TABENTER},
177 {"TabLeave", EVENT_TABLEAVE},
178 {"TermChanged", EVENT_TERMCHANGED},
179 {"TerminalOpen", EVENT_TERMINALOPEN},
Bram Moolenaar28ed4df2019-10-26 16:21:40 +0200180 {"TerminalWinOpen", EVENT_TERMINALWINOPEN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100181 {"TermResponse", EVENT_TERMRESPONSE},
182 {"TextChanged", EVENT_TEXTCHANGED},
183 {"TextChangedI", EVENT_TEXTCHANGEDI},
184 {"TextChangedP", EVENT_TEXTCHANGEDP},
185 {"User", EVENT_USER},
186 {"VimEnter", EVENT_VIMENTER},
187 {"VimLeave", EVENT_VIMLEAVE},
188 {"VimLeavePre", EVENT_VIMLEAVEPRE},
189 {"WinNew", EVENT_WINNEW},
naohiro ono23beefe2021-11-13 12:38:49 +0000190 {"WinClosed", EVENT_WINCLOSED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100191 {"WinEnter", EVENT_WINENTER},
192 {"WinLeave", EVENT_WINLEAVE},
193 {"VimResized", EVENT_VIMRESIZED},
194 {"TextYankPost", EVENT_TEXTYANKPOST},
Bram Moolenaar100118c2020-12-11 19:30:34 +0100195 {"VimSuspend", EVENT_VIMSUSPEND},
196 {"VimResume", EVENT_VIMRESUME},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100197 {NULL, (event_T)0}
198};
199
200static AutoPat *first_autopat[NUM_EVENTS] =
201{
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 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
208};
209
210static AutoPat *last_autopat[NUM_EVENTS] =
211{
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 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
218};
219
kylo252ae6f1d82022-02-16 19:24:07 +0000220#define AUGROUP_DEFAULT (-1) // default autocmd group
221#define AUGROUP_ERROR (-2) // erroneous autocmd group
222#define AUGROUP_ALL (-3) // all autocmd groups
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100223
224/*
225 * struct used to keep status while executing autocommands for an event.
226 */
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100227struct AutoPatCmd_S
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100228{
229 AutoPat *curpat; // next AutoPat to examine
230 AutoCmd *nextcmd; // next AutoCmd to execute
231 int group; // group being used
232 char_u *fname; // fname to match with
233 char_u *sfname; // sfname to match with
234 char_u *tail; // tail of fname
235 event_T event; // current event
236 int arg_bufnr; // Initially equal to <abuf>, set to zero when
237 // buf is deleted.
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100238 AutoPatCmd *next; // chain of active apc-s for auto-invalidation
239};
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100240
Bram Moolenaarc667da52019-11-30 20:52:27 +0100241static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100242
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200243// Macro to loop over all the patterns for an autocmd event
244#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \
245 for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next)
246
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100247/*
248 * augroups stores a list of autocmd group names.
249 */
250static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
251#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
Bram Moolenaarc667da52019-11-30 20:52:27 +0100252// use get_deleted_augroup() to get this
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100253static char_u *deleted_augroup = NULL;
254
255/*
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100256 * The ID of the current group. Group 0 is the default one.
257 */
258static int current_augroup = AUGROUP_DEFAULT;
259
Bram Moolenaarc667da52019-11-30 20:52:27 +0100260static int au_need_clean = FALSE; // need to delete marked patterns
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100261
262static char_u *event_nr2name(event_T event);
263static int au_get_grouparg(char_u **argp);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200264static 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 +0100265static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
266static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
267static int au_find_group(char_u *name);
268
269static event_T last_event;
270static int last_group;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100271static int autocmd_blocked = 0; // block all autocmds
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100272
273 static char_u *
274get_deleted_augroup(void)
275{
276 if (deleted_augroup == NULL)
277 deleted_augroup = (char_u *)_("--Deleted--");
278 return deleted_augroup;
279}
280
281/*
282 * Show the autocommands for one AutoPat.
283 */
284 static void
285show_autocmd(AutoPat *ap, event_T event)
286{
287 AutoCmd *ac;
288
289 // Check for "got_int" (here and at various places below), which is set
290 // when "q" has been hit for the "--more--" prompt
291 if (got_int)
292 return;
293 if (ap->pat == NULL) // pattern has been removed
294 return;
295
296 msg_putchar('\n');
297 if (got_int)
298 return;
299 if (event != last_event || ap->group != last_group)
300 {
301 if (ap->group != AUGROUP_DEFAULT)
302 {
303 if (AUGROUP_NAME(ap->group) == NULL)
304 msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
305 else
306 msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
307 msg_puts(" ");
308 }
309 msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
310 last_event = event;
311 last_group = ap->group;
312 msg_putchar('\n');
313 if (got_int)
314 return;
315 }
316 msg_col = 4;
317 msg_outtrans(ap->pat);
318
319 for (ac = ap->cmds; ac != NULL; ac = ac->next)
320 {
321 if (ac->cmd != NULL) // skip removed commands
322 {
323 if (msg_col >= 14)
324 msg_putchar('\n');
325 msg_col = 14;
326 if (got_int)
327 return;
328 msg_outtrans(ac->cmd);
329#ifdef FEAT_EVAL
330 if (p_verbose > 0)
331 last_set_msg(ac->script_ctx);
332#endif
333 if (got_int)
334 return;
335 if (ac->next != NULL)
336 {
337 msg_putchar('\n');
338 if (got_int)
339 return;
340 }
341 }
342 }
343}
344
345/*
346 * Mark an autocommand pattern for deletion.
347 */
348 static void
349au_remove_pat(AutoPat *ap)
350{
351 VIM_CLEAR(ap->pat);
352 ap->buflocal_nr = -1;
353 au_need_clean = TRUE;
354}
355
356/*
357 * Mark all commands for a pattern for deletion.
358 */
359 static void
360au_remove_cmds(AutoPat *ap)
361{
362 AutoCmd *ac;
363
364 for (ac = ap->cmds; ac != NULL; ac = ac->next)
365 VIM_CLEAR(ac->cmd);
366 au_need_clean = TRUE;
367}
368
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200369// Delete one command from an autocmd pattern.
370static void au_del_cmd(AutoCmd *ac)
371{
372 VIM_CLEAR(ac->cmd);
373 au_need_clean = TRUE;
374}
375
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100376/*
377 * Cleanup autocommands and patterns that have been deleted.
378 * This is only done when not executing autocommands.
379 */
380 static void
381au_cleanup(void)
382{
383 AutoPat *ap, **prev_ap;
384 AutoCmd *ac, **prev_ac;
385 event_T event;
386
387 if (autocmd_busy || !au_need_clean)
388 return;
389
390 // loop over all events
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100391 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100392 event = (event_T)((int)event + 1))
393 {
394 // loop over all autocommand patterns
395 prev_ap = &(first_autopat[(int)event]);
396 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
397 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200398 int has_cmd = FALSE;
399
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200400 // loop over all commands for this pattern
401 prev_ac = &(ap->cmds);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100402 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
403 {
404 // remove the command if the pattern is to be deleted or when
405 // the command has been marked for deletion
406 if (ap->pat == NULL || ac->cmd == NULL)
407 {
408 *prev_ac = ac->next;
409 vim_free(ac->cmd);
410 vim_free(ac);
411 }
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200412 else
413 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200414 has_cmd = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100415 prev_ac = &(ac->next);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200416 }
417 }
418
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200419 if (ap->pat != NULL && !has_cmd)
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200420 // Pattern was not marked for deletion, but all of its
421 // commands were. So mark the pattern for deletion.
422 au_remove_pat(ap);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100423
424 // remove the pattern if it has been marked for deletion
425 if (ap->pat == NULL)
426 {
427 if (ap->next == NULL)
428 {
429 if (prev_ap == &(first_autopat[(int)event]))
430 last_autopat[(int)event] = NULL;
431 else
432 // this depends on the "next" field being the first in
433 // the struct
434 last_autopat[(int)event] = (AutoPat *)prev_ap;
435 }
436 *prev_ap = ap->next;
437 vim_regfree(ap->reg_prog);
438 vim_free(ap);
439 }
440 else
441 prev_ap = &(ap->next);
442 }
443 }
444
445 au_need_clean = FALSE;
446}
447
448/*
449 * Called when buffer is freed, to remove/invalidate related buffer-local
450 * autocmds.
451 */
452 void
453aubuflocal_remove(buf_T *buf)
454{
455 AutoPat *ap;
456 event_T event;
457 AutoPatCmd *apc;
458
459 // invalidate currently executing autocommands
460 for (apc = active_apc_list; apc; apc = apc->next)
461 if (buf->b_fnum == apc->arg_bufnr)
462 apc->arg_bufnr = 0;
463
464 // invalidate buflocals looping through events
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100465 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100466 event = (event_T)((int)event + 1))
467 // loop over all autocommand patterns
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200468 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100469 if (ap->buflocal_nr == buf->b_fnum)
470 {
471 au_remove_pat(ap);
472 if (p_verbose >= 6)
473 {
474 verbose_enter();
475 smsg(_("auto-removing autocommand: %s <buffer=%d>"),
476 event_nr2name(event), buf->b_fnum);
477 verbose_leave();
478 }
479 }
480 au_cleanup();
481}
482
483/*
484 * Add an autocmd group name.
485 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
486 */
487 static int
488au_new_group(char_u *name)
489{
490 int i;
491
492 i = au_find_group(name);
493 if (i == AUGROUP_ERROR) // the group doesn't exist yet, add it
494 {
495 // First try using a free entry.
496 for (i = 0; i < augroups.ga_len; ++i)
497 if (AUGROUP_NAME(i) == NULL)
498 break;
499 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
500 return AUGROUP_ERROR;
501
502 AUGROUP_NAME(i) = vim_strsave(name);
503 if (AUGROUP_NAME(i) == NULL)
504 return AUGROUP_ERROR;
505 if (i == augroups.ga_len)
506 ++augroups.ga_len;
507 }
508
509 return i;
510}
511
512 static void
513au_del_group(char_u *name)
514{
515 int i;
516
517 i = au_find_group(name);
518 if (i == AUGROUP_ERROR) // the group doesn't exist
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000519 semsg(_(e_no_such_group_str), name);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100520 else if (i == current_augroup)
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000521 emsg(_(e_cannot_delete_current_group));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100522 else
523 {
524 event_T event;
525 AutoPat *ap;
526 int in_use = FALSE;
527
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100528 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100529 event = (event_T)((int)event + 1))
530 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200531 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100532 if (ap->group == i && ap->pat != NULL)
533 {
534 give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
535 in_use = TRUE;
536 event = NUM_EVENTS;
537 break;
538 }
539 }
540 vim_free(AUGROUP_NAME(i));
541 if (in_use)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100542 AUGROUP_NAME(i) = get_deleted_augroup();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100543 else
544 AUGROUP_NAME(i) = NULL;
545 }
546}
547
548/*
549 * Find the ID of an autocmd group name.
550 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
551 */
552 static int
553au_find_group(char_u *name)
554{
555 int i;
556
557 for (i = 0; i < augroups.ga_len; ++i)
558 if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
559 && STRCMP(AUGROUP_NAME(i), name) == 0)
560 return i;
561 return AUGROUP_ERROR;
562}
563
564/*
565 * Return TRUE if augroup "name" exists.
566 */
567 int
568au_has_group(char_u *name)
569{
570 return au_find_group(name) != AUGROUP_ERROR;
571}
572
573/*
574 * ":augroup {name}".
575 */
576 void
577do_augroup(char_u *arg, int del_group)
578{
579 int i;
580
581 if (del_group)
582 {
583 if (*arg == NUL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000584 emsg(_(e_argument_required));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100585 else
586 au_del_group(arg);
587 }
588 else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0
589 current_augroup = AUGROUP_DEFAULT;
590 else if (*arg) // ":aug xxx": switch to group xxx
591 {
592 i = au_new_group(arg);
593 if (i != AUGROUP_ERROR)
594 current_augroup = i;
595 }
596 else // ":aug": list the group names
597 {
598 msg_start();
599 for (i = 0; i < augroups.ga_len; ++i)
600 {
601 if (AUGROUP_NAME(i) != NULL)
602 {
603 msg_puts((char *)AUGROUP_NAME(i));
604 msg_puts(" ");
605 }
606 }
607 msg_clr_eos();
608 msg_end();
609 }
610}
611
612#if defined(EXITFREE) || defined(PROTO)
613 void
614free_all_autocmds(void)
615{
616 int i;
617 char_u *s;
618
619 for (current_augroup = -1; current_augroup < augroups.ga_len;
620 ++current_augroup)
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200621 do_autocmd(NULL, (char_u *)"", TRUE);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100622
623 for (i = 0; i < augroups.ga_len; ++i)
624 {
625 s = ((char_u **)(augroups.ga_data))[i];
626 if (s != get_deleted_augroup())
627 vim_free(s);
628 }
629 ga_clear(&augroups);
630}
631#endif
632
633/*
634 * Return the event number for event name "start".
635 * Return NUM_EVENTS if the event name was not found.
636 * Return a pointer to the next event name in "end".
637 */
638 static event_T
639event_name2nr(char_u *start, char_u **end)
640{
641 char_u *p;
642 int i;
643 int len;
644
645 // the event name ends with end of line, '|', a blank or a comma
646 for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
647 ;
648 for (i = 0; event_names[i].name != NULL; ++i)
649 {
650 len = (int)STRLEN(event_names[i].name);
651 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
652 break;
653 }
654 if (*p == ',')
655 ++p;
656 *end = p;
657 if (event_names[i].name == NULL)
658 return NUM_EVENTS;
659 return event_names[i].event;
660}
661
662/*
663 * Return the name for event "event".
664 */
665 static char_u *
666event_nr2name(event_T event)
667{
668 int i;
669
670 for (i = 0; event_names[i].name != NULL; ++i)
671 if (event_names[i].event == event)
672 return (char_u *)event_names[i].name;
673 return (char_u *)"Unknown";
674}
675
676/*
677 * Scan over the events. "*" stands for all events.
678 */
679 static char_u *
680find_end_event(
681 char_u *arg,
682 int have_group) // TRUE when group name was found
683{
684 char_u *pat;
685 char_u *p;
686
687 if (*arg == '*')
688 {
689 if (arg[1] && !VIM_ISWHITE(arg[1]))
690 {
Bram Moolenaar6d057012021-12-31 18:49:43 +0000691 semsg(_(e_illegal_character_after_star_str), arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100692 return NULL;
693 }
694 pat = arg + 1;
695 }
696 else
697 {
698 for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
699 {
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100700 if ((int)event_name2nr(pat, &p) >= NUM_EVENTS)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100701 {
702 if (have_group)
Bram Moolenaar6d057012021-12-31 18:49:43 +0000703 semsg(_(e_no_such_event_str), pat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100704 else
Bram Moolenaar6d057012021-12-31 18:49:43 +0000705 semsg(_(e_no_such_group_or_event_str), pat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100706 return NULL;
707 }
708 }
709 }
710 return pat;
711}
712
713/*
714 * Return TRUE if "event" is included in 'eventignore'.
715 */
716 static int
717event_ignored(event_T event)
718{
719 char_u *p = p_ei;
720
721 while (*p != NUL)
722 {
723 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
724 return TRUE;
725 if (event_name2nr(p, &p) == event)
726 return TRUE;
727 }
728
729 return FALSE;
730}
731
732/*
733 * Return OK when the contents of p_ei is valid, FAIL otherwise.
734 */
735 int
736check_ei(void)
737{
738 char_u *p = p_ei;
739
740 while (*p)
741 {
742 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
743 {
744 p += 3;
745 if (*p == ',')
746 ++p;
747 }
748 else if (event_name2nr(p, &p) == NUM_EVENTS)
749 return FAIL;
750 }
751
752 return OK;
753}
754
755# if defined(FEAT_SYN_HL) || defined(PROTO)
756
757/*
758 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
759 * buffer loaded into the window. "what" must start with a comma.
760 * Returns the old value of 'eventignore' in allocated memory.
761 */
762 char_u *
763au_event_disable(char *what)
764{
765 char_u *new_ei;
766 char_u *save_ei;
767
768 save_ei = vim_strsave(p_ei);
769 if (save_ei != NULL)
770 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200771 new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100772 if (new_ei != NULL)
773 {
774 if (*what == ',' && *p_ei == NUL)
775 STRCPY(new_ei, what + 1);
776 else
777 STRCAT(new_ei, what);
778 set_string_option_direct((char_u *)"ei", -1, new_ei,
779 OPT_FREE, SID_NONE);
780 vim_free(new_ei);
781 }
782 }
783 return save_ei;
784}
785
786 void
787au_event_restore(char_u *old_ei)
788{
789 if (old_ei != NULL)
790 {
791 set_string_option_direct((char_u *)"ei", -1, old_ei,
792 OPT_FREE, SID_NONE);
793 vim_free(old_ei);
794 }
795}
Bram Moolenaarc667da52019-11-30 20:52:27 +0100796# endif // FEAT_SYN_HL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100797
798/*
799 * do_autocmd() -- implements the :autocmd command. Can be used in the
800 * following ways:
801 *
802 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
803 * will be automatically executed for <event>
804 * when editing a file matching <pat>, in
805 * the current group.
806 * :autocmd <event> <pat> Show the autocommands associated with
807 * <event> and <pat>.
808 * :autocmd <event> Show the autocommands associated with
809 * <event>.
810 * :autocmd Show all autocommands.
811 * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
812 * <event> and <pat>, and add the command
813 * <cmd>, for the current group.
814 * :autocmd! <event> <pat> Remove all autocommands associated with
815 * <event> and <pat> for the current group.
816 * :autocmd! <event> Remove all autocommands associated with
817 * <event> for the current group.
818 * :autocmd! Remove ALL autocommands for the current
819 * group.
820 *
821 * Multiple events and patterns may be given separated by commas. Here are
822 * some examples:
823 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
824 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
825 *
826 * :autocmd * *.c show all autocommands for *.c files.
827 *
828 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200829 * "eap" can be NULL.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100830 */
831 void
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200832do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100833{
834 char_u *arg = arg_in;
835 char_u *pat;
836 char_u *envpat = NULL;
837 char_u *cmd;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200838 int cmd_need_free = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100839 event_T event;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200840 char_u *tofree = NULL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100841 int nested = FALSE;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200842 int once = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100843 int group;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200844 int i;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200845 int flags = 0;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100846
847 if (*arg == '|')
848 {
Bram Moolenaarb8e642f2021-11-20 10:38:25 +0000849 eap->nextcmd = arg + 1;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100850 arg = (char_u *)"";
851 group = AUGROUP_ALL; // no argument, use all groups
852 }
853 else
854 {
855 /*
856 * Check for a legal group name. If not, use AUGROUP_ALL.
857 */
858 group = au_get_grouparg(&arg);
859 if (arg == NULL) // out of memory
860 return;
861 }
862
863 /*
864 * Scan over the events.
865 * If we find an illegal name, return here, don't do anything.
866 */
867 pat = find_end_event(arg, group != AUGROUP_ALL);
868 if (pat == NULL)
869 return;
870
871 pat = skipwhite(pat);
872 if (*pat == '|')
873 {
Bram Moolenaarb8e642f2021-11-20 10:38:25 +0000874 eap->nextcmd = pat + 1;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100875 pat = (char_u *)"";
876 cmd = (char_u *)"";
877 }
878 else
879 {
880 /*
881 * Scan over the pattern. Put a NUL at the end.
882 */
883 cmd = pat;
884 while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
885 cmd++;
886 if (*cmd)
887 *cmd++ = NUL;
888
889 // Expand environment variables in the pattern. Set 'shellslash', we
890 // want forward slashes here.
891 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
892 {
893#ifdef BACKSLASH_IN_FILENAME
894 int p_ssl_save = p_ssl;
895
896 p_ssl = TRUE;
897#endif
898 envpat = expand_env_save(pat);
899#ifdef BACKSLASH_IN_FILENAME
900 p_ssl = p_ssl_save;
901#endif
902 if (envpat != NULL)
903 pat = envpat;
904 }
905
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100906 cmd = skipwhite(cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200907 for (i = 0; i < 2; i++)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100908 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200909 if (*cmd != NUL)
910 {
911 // Check for "++once" flag.
912 if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
913 {
914 if (once)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000915 semsg(_(e_duplicate_argument_str), "++once");
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200916 once = TRUE;
917 cmd = skipwhite(cmd + 6);
918 }
919
920 // Check for "++nested" flag.
921 if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
922 {
923 if (nested)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000924 semsg(_(e_duplicate_argument_str), "++nested");
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200925 nested = TRUE;
926 cmd = skipwhite(cmd + 8);
927 }
928
929 // Check for the old "nested" flag.
930 if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
931 {
932 if (nested)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000933 semsg(_(e_duplicate_argument_str), "nested");
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200934 nested = TRUE;
935 cmd = skipwhite(cmd + 6);
936 }
937 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100938 }
939
940 /*
941 * Find the start of the commands.
942 * Expand <sfile> in it.
943 */
944 if (*cmd != NUL)
945 {
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200946 if (eap != NULL)
947 // Read a {} block if it follows.
948 cmd = may_get_cmd_block(eap, cmd, &tofree, &flags);
949
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100950 cmd = expand_sfile(cmd);
951 if (cmd == NULL) // some error
952 return;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200953 cmd_need_free = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100954 }
955 }
956
957 /*
958 * Print header when showing autocommands.
959 */
960 if (!forceit && *cmd == NUL)
961 // Highlight title
962 msg_puts_title(_("\n--- Autocommands ---"));
963
964 /*
965 * Loop over the events.
966 */
967 last_event = (event_T)-1; // for listing the event name
968 last_group = AUGROUP_ERROR; // for listing the group name
969 if (*arg == '*' || *arg == NUL || *arg == '|')
970 {
Bram Moolenaarb6db1462021-12-24 19:24:47 +0000971 if (*cmd != NUL)
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100972 emsg(_(e_cannot_define_autocommands_for_all_events));
973 else
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100974 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100975 event = (event_T)((int)event + 1))
976 if (do_autocmd_event(event, pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200977 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100978 break;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100979 }
980 else
981 {
982 while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
983 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200984 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100985 break;
986 }
987
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200988 if (cmd_need_free)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100989 vim_free(cmd);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200990 vim_free(tofree);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100991 vim_free(envpat);
992}
993
994/*
995 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
996 * The "argp" argument is advanced to the following argument.
997 *
998 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
999 */
1000 static int
1001au_get_grouparg(char_u **argp)
1002{
1003 char_u *group_name;
1004 char_u *p;
1005 char_u *arg = *argp;
1006 int group = AUGROUP_ALL;
1007
1008 for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
1009 ;
1010 if (p > arg)
1011 {
Bram Moolenaardf44a272020-06-07 20:49:05 +02001012 group_name = vim_strnsave(arg, p - arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001013 if (group_name == NULL) // out of memory
1014 return AUGROUP_ERROR;
1015 group = au_find_group(group_name);
1016 if (group == AUGROUP_ERROR)
1017 group = AUGROUP_ALL; // no match, use all groups
1018 else
1019 *argp = skipwhite(p); // match, skip over group name
1020 vim_free(group_name);
1021 }
1022 return group;
1023}
1024
1025/*
1026 * do_autocmd() for one event.
1027 * If *pat == NUL do for all patterns.
1028 * If *cmd == NUL show entries.
1029 * If forceit == TRUE delete entries.
1030 * If group is not AUGROUP_ALL, only use this group.
1031 */
1032 static int
1033do_autocmd_event(
1034 event_T event,
1035 char_u *pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001036 int once,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001037 int nested,
1038 char_u *cmd,
1039 int forceit,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001040 int group,
1041 int flags)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001042{
1043 AutoPat *ap;
1044 AutoPat **prev_ap;
1045 AutoCmd *ac;
1046 AutoCmd **prev_ac;
1047 int brace_level;
1048 char_u *endpat;
1049 int findgroup;
1050 int allgroups;
1051 int patlen;
1052 int is_buflocal;
1053 int buflocal_nr;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001054 char_u buflocal_pat[25]; // for "<buffer=X>"
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001055
1056 if (group == AUGROUP_ALL)
1057 findgroup = current_augroup;
1058 else
1059 findgroup = group;
1060 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
1061
1062 /*
1063 * Show or delete all patterns for an event.
1064 */
1065 if (*pat == NUL)
1066 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001067 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001068 {
1069 if (forceit) // delete the AutoPat, if it's in the current group
1070 {
1071 if (ap->group == findgroup)
1072 au_remove_pat(ap);
1073 }
1074 else if (group == AUGROUP_ALL || ap->group == group)
1075 show_autocmd(ap, event);
1076 }
1077 }
1078
1079 /*
1080 * Loop through all the specified patterns.
1081 */
1082 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
1083 {
1084 /*
1085 * Find end of the pattern.
1086 * Watch out for a comma in braces, like "*.\{obj,o\}".
1087 */
1088 brace_level = 0;
1089 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
1090 || (endpat > pat && endpat[-1] == '\\')); ++endpat)
1091 {
1092 if (*endpat == '{')
1093 brace_level++;
1094 else if (*endpat == '}')
1095 brace_level--;
1096 }
1097 if (pat == endpat) // ignore single comma
1098 continue;
1099 patlen = (int)(endpat - pat);
1100
1101 /*
1102 * detect special <buflocal[=X]> buffer-local patterns
1103 */
1104 is_buflocal = FALSE;
1105 buflocal_nr = 0;
1106
1107 if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
1108 && pat[patlen - 1] == '>')
1109 {
1110 // "<buffer...>": Error will be printed only for addition.
1111 // printing and removing will proceed silently.
1112 is_buflocal = TRUE;
1113 if (patlen == 8)
1114 // "<buffer>"
1115 buflocal_nr = curbuf->b_fnum;
1116 else if (patlen > 9 && pat[7] == '=')
1117 {
1118 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
1119 // "<buffer=abuf>"
1120 buflocal_nr = autocmd_bufnr;
1121 else if (skipdigits(pat + 8) == pat + patlen - 1)
1122 // "<buffer=123>"
1123 buflocal_nr = atoi((char *)pat + 8);
1124 }
1125 }
1126
1127 if (is_buflocal)
1128 {
1129 // normalize pat into standard "<buffer>#N" form
1130 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
1131 pat = buflocal_pat; // can modify pat and patlen
1132 patlen = (int)STRLEN(buflocal_pat); // but not endpat
1133 }
1134
1135 /*
1136 * Find AutoPat entries with this pattern. When adding a command it
1137 * always goes at or after the last one, so start at the end.
1138 */
1139 if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
1140 prev_ap = &last_autopat[(int)event];
1141 else
1142 prev_ap = &first_autopat[(int)event];
1143 while ((ap = *prev_ap) != NULL)
1144 {
1145 if (ap->pat != NULL)
1146 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001147 /*
1148 * Accept a pattern when:
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001149 * - a group was specified and it's that group, or a group was
1150 * not specified and it's the current group, or a group was
1151 * not specified and we are listing
1152 * - the length of the pattern matches
1153 * - the pattern matches.
1154 * For <buffer[=X]>, this condition works because we normalize
1155 * all buffer-local patterns.
1156 */
1157 if ((allgroups || ap->group == findgroup)
1158 && ap->patlen == patlen
1159 && STRNCMP(pat, ap->pat, patlen) == 0)
1160 {
1161 /*
1162 * Remove existing autocommands.
1163 * If adding any new autocmd's for this AutoPat, don't
1164 * delete the pattern from the autopat list, append to
1165 * this list.
1166 */
1167 if (forceit)
1168 {
1169 if (*cmd != NUL && ap->next == NULL)
1170 {
1171 au_remove_cmds(ap);
1172 break;
1173 }
1174 au_remove_pat(ap);
1175 }
1176
1177 /*
1178 * Show autocmd's for this autopat, or buflocals <buffer=X>
1179 */
1180 else if (*cmd == NUL)
1181 show_autocmd(ap, event);
1182
1183 /*
1184 * Add autocmd to this autopat, if it's the last one.
1185 */
1186 else if (ap->next == NULL)
1187 break;
1188 }
1189 }
1190 prev_ap = &ap->next;
1191 }
1192
1193 /*
1194 * Add a new command.
1195 */
1196 if (*cmd != NUL)
1197 {
1198 /*
1199 * If the pattern we want to add a command to does appear at the
1200 * end of the list (or not is not in the list at all), add the
1201 * pattern at the end of the list.
1202 */
1203 if (ap == NULL)
1204 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001205 // refuse to add buffer-local ap if buffer number is invalid
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001206 if (is_buflocal && (buflocal_nr == 0
1207 || buflist_findnr(buflocal_nr) == NULL))
1208 {
Bram Moolenaarf1474d82021-12-31 19:59:55 +00001209 semsg(_(e_buffer_nr_invalid_buffer_number), buflocal_nr);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001210 return FAIL;
1211 }
1212
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001213 ap = ALLOC_ONE(AutoPat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001214 if (ap == NULL)
1215 return FAIL;
1216 ap->pat = vim_strnsave(pat, patlen);
1217 ap->patlen = patlen;
1218 if (ap->pat == NULL)
1219 {
1220 vim_free(ap);
1221 return FAIL;
1222 }
1223
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01001224#ifdef FEAT_EVAL
1225 // need to initialize last_mode for the first ModeChanged
1226 // autocmd
1227 if (event == EVENT_MODECHANGED && !has_modechanged())
1228 {
1229 typval_T rettv;
1230 typval_T tv[2];
1231
1232 tv[0].v_type = VAR_NUMBER;
1233 tv[0].vval.v_number = 1;
1234 tv[1].v_type = VAR_UNKNOWN;
1235 f_mode(tv, &rettv);
1236 STRCPY(last_mode, rettv.vval.v_string);
1237 vim_free(rettv.vval.v_string);
1238 }
1239#endif
1240
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001241 if (is_buflocal)
1242 {
1243 ap->buflocal_nr = buflocal_nr;
1244 ap->reg_prog = NULL;
1245 }
1246 else
1247 {
1248 char_u *reg_pat;
1249
1250 ap->buflocal_nr = 0;
1251 reg_pat = file_pat_to_reg_pat(pat, endpat,
1252 &ap->allow_dirs, TRUE);
1253 if (reg_pat != NULL)
1254 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1255 vim_free(reg_pat);
1256 if (reg_pat == NULL || ap->reg_prog == NULL)
1257 {
1258 vim_free(ap->pat);
1259 vim_free(ap);
1260 return FAIL;
1261 }
1262 }
1263 ap->cmds = NULL;
1264 *prev_ap = ap;
1265 last_autopat[(int)event] = ap;
1266 ap->next = NULL;
1267 if (group == AUGROUP_ALL)
1268 ap->group = current_augroup;
1269 else
1270 ap->group = group;
1271 }
1272
1273 /*
1274 * Add the autocmd at the end of the AutoCmd list.
1275 */
1276 prev_ac = &(ap->cmds);
1277 while ((ac = *prev_ac) != NULL)
1278 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001279 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001280 if (ac == NULL)
1281 return FAIL;
1282 ac->cmd = vim_strsave(cmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001283 ac->script_ctx = current_sctx;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001284 if (flags & UC_VIM9)
1285 ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001286#ifdef FEAT_EVAL
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001287 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001288#endif
1289 if (ac->cmd == NULL)
1290 {
1291 vim_free(ac);
1292 return FAIL;
1293 }
1294 ac->next = NULL;
1295 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001296 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001297 ac->nested = nested;
1298 }
1299 }
1300
1301 au_cleanup(); // may really delete removed patterns/commands now
1302 return OK;
1303}
1304
1305/*
1306 * Implementation of ":doautocmd [group] event [fname]".
1307 * Return OK for success, FAIL for failure;
1308 */
1309 int
1310do_doautocmd(
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001311 char_u *arg_start,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001312 int do_msg, // give message for no matching autocmds?
1313 int *did_something)
1314{
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001315 char_u *arg = arg_start;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001316 char_u *fname;
1317 int nothing_done = TRUE;
1318 int group;
1319
1320 if (did_something != NULL)
1321 *did_something = FALSE;
1322
1323 /*
1324 * Check for a legal group name. If not, use AUGROUP_ALL.
1325 */
1326 group = au_get_grouparg(&arg);
1327 if (arg == NULL) // out of memory
1328 return FAIL;
1329
1330 if (*arg == '*')
1331 {
Bram Moolenaar6d057012021-12-31 18:49:43 +00001332 emsg(_(e_cant_execute_autocommands_for_all_events));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001333 return FAIL;
1334 }
1335
1336 /*
1337 * Scan over the events.
1338 * If we find an illegal name, return here, don't do anything.
1339 */
1340 fname = find_end_event(arg, group != AUGROUP_ALL);
1341 if (fname == NULL)
1342 return FAIL;
1343
1344 fname = skipwhite(fname);
1345
1346 /*
1347 * Loop over the events.
1348 */
1349 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1350 if (apply_autocmds_group(event_name2nr(arg, &arg),
1351 fname, NULL, TRUE, group, curbuf, NULL))
1352 nothing_done = FALSE;
1353
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001354 if (nothing_done && do_msg
1355#ifdef FEAT_EVAL
1356 && !aborting()
1357#endif
1358 )
1359 smsg(_("No matching autocommands: %s"), arg_start);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001360 if (did_something != NULL)
1361 *did_something = !nothing_done;
1362
1363#ifdef FEAT_EVAL
1364 return aborting() ? FAIL : OK;
1365#else
1366 return OK;
1367#endif
1368}
1369
1370/*
1371 * ":doautoall": execute autocommands for each loaded buffer.
1372 */
1373 void
1374ex_doautoall(exarg_T *eap)
1375{
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001376 int retval = OK;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001377 aco_save_T aco;
1378 buf_T *buf;
1379 bufref_T bufref;
1380 char_u *arg = eap->arg;
1381 int call_do_modelines = check_nomodeline(&arg);
1382 int did_aucmd;
1383
1384 /*
1385 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1386 * equal to curbuf, but for some buffers there may not be a window.
1387 * So we change the buffer for the current window for a moment. This
1388 * gives problems when the autocommands make changes to the list of
1389 * buffers or windows...
1390 */
1391 FOR_ALL_BUFFERS(buf)
1392 {
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001393 // Only do loaded buffers and skip the current buffer, it's done last.
1394 if (buf->b_ml.ml_mfp != NULL && buf != curbuf)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001395 {
1396 // find a window for this buffer and save some values
1397 aucmd_prepbuf(&aco, buf);
1398 set_bufref(&bufref, buf);
1399
1400 // execute the autocommands for this buffer
1401 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1402
1403 if (call_do_modelines && did_aucmd)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001404 // Execute the modeline settings, but don't set window-local
1405 // options if we are using the current window for another
1406 // buffer.
1407 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001408
1409 // restore the current window
1410 aucmd_restbuf(&aco);
1411
1412 // stop if there is some error or buffer was deleted
1413 if (retval == FAIL || !bufref_valid(&bufref))
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001414 {
1415 retval = FAIL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001416 break;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001417 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001418 }
1419 }
1420
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001421 // Execute autocommands for the current buffer last.
1422 if (retval == OK)
1423 {
1424 do_doautocmd(arg, FALSE, &did_aucmd);
1425 if (call_do_modelines && did_aucmd)
1426 do_modelines(0);
1427 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001428}
1429
1430/*
1431 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1432 * return TRUE and advance *argp to after it.
1433 * Thus return TRUE when do_modelines() should be called.
1434 */
1435 int
1436check_nomodeline(char_u **argp)
1437{
1438 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1439 {
1440 *argp = skipwhite(*argp + 12);
1441 return FALSE;
1442 }
1443 return TRUE;
1444}
1445
1446/*
1447 * Prepare for executing autocommands for (hidden) buffer "buf".
1448 * Search for a visible window containing the current buffer. If there isn't
1449 * one then use "aucmd_win".
1450 * Set "curbuf" and "curwin" to match "buf".
1451 */
1452 void
1453aucmd_prepbuf(
1454 aco_save_T *aco, // structure to save values in
1455 buf_T *buf) // new curbuf
1456{
1457 win_T *win;
1458 int save_ea;
1459#ifdef FEAT_AUTOCHDIR
1460 int save_acd;
1461#endif
1462
1463 // Find a window that is for the new buffer
1464 if (buf == curbuf) // be quick when buf is curbuf
1465 win = curwin;
1466 else
1467 FOR_ALL_WINDOWS(win)
1468 if (win->w_buffer == buf)
1469 break;
1470
1471 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1472 // back to using the current window.
1473 if (win == NULL && aucmd_win == NULL)
1474 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001475 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001476 if (aucmd_win == NULL)
1477 win = curwin;
1478 }
1479 if (win == NULL && aucmd_win_used)
1480 // Strange recursive autocommand, fall back to using the current
1481 // window. Expect a few side effects...
1482 win = curwin;
1483
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001484 aco->save_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001485 aco->save_curbuf = curbuf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001486 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001487 if (win != NULL)
1488 {
1489 // There is a window for "buf" in the current tab page, make it the
1490 // curwin. This is preferred, it has the least side effects (esp. if
1491 // "buf" is curbuf).
1492 aco->use_aucmd_win = FALSE;
1493 curwin = win;
1494 }
1495 else
1496 {
1497 // There is no window for "buf", use "aucmd_win". To minimize the side
1498 // effects, insert it in the current tab page.
1499 // Anything related to a window (e.g., setting folds) may have
1500 // unexpected results.
1501 aco->use_aucmd_win = TRUE;
1502 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001503
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001504 win_init_popup_win(aucmd_win, buf);
1505
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001506 aco->globaldir = globaldir;
1507 globaldir = NULL;
1508
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001509 // Split the current window, put the aucmd_win in the upper half.
1510 // We don't want the BufEnter or WinEnter autocommands.
1511 block_autocmds();
1512 make_snapshot(SNAP_AUCMD_IDX);
1513 save_ea = p_ea;
1514 p_ea = FALSE;
1515
1516#ifdef FEAT_AUTOCHDIR
1517 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1518 save_acd = p_acd;
1519 p_acd = FALSE;
1520#endif
1521
Bram Moolenaardff97e62022-01-24 20:00:55 +00001522 // no redrawing and don't set the window title
1523 ++RedrawingDisabled;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001524 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
Bram Moolenaardff97e62022-01-24 20:00:55 +00001525 --RedrawingDisabled;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001526 (void)win_comp_pos(); // recompute window positions
1527 p_ea = save_ea;
1528#ifdef FEAT_AUTOCHDIR
1529 p_acd = save_acd;
1530#endif
1531 unblock_autocmds();
1532 curwin = aucmd_win;
1533 }
1534 curbuf = buf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001535 aco->new_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001536 set_bufref(&aco->new_curbuf, curbuf);
Bram Moolenaarcb1956d2022-01-07 15:45:18 +00001537
1538 // disable the Visual area, the position may be invalid in another buffer
1539 aco->save_VIsual_active = VIsual_active;
1540 VIsual_active = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001541}
1542
1543/*
1544 * Cleanup after executing autocommands for a (hidden) buffer.
1545 * Restore the window as it was (if possible).
1546 */
1547 void
1548aucmd_restbuf(
1549 aco_save_T *aco) // structure holding saved values
1550{
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001551 int dummy;
1552 win_T *save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001553
1554 if (aco->use_aucmd_win)
1555 {
1556 --curbuf->b_nwindows;
1557 // Find "aucmd_win", it can't be closed, but it may be in another tab
1558 // page. Do not trigger autocommands here.
1559 block_autocmds();
1560 if (curwin != aucmd_win)
1561 {
1562 tabpage_T *tp;
1563 win_T *wp;
1564
1565 FOR_ALL_TAB_WINDOWS(tp, wp)
1566 {
1567 if (wp == aucmd_win)
1568 {
1569 if (tp != curtab)
1570 goto_tabpage_tp(tp, TRUE, TRUE);
1571 win_goto(aucmd_win);
1572 goto win_found;
1573 }
1574 }
1575 }
1576win_found:
1577
1578 // Remove the window and frame from the tree of frames.
1579 (void)winframe_remove(curwin, &dummy, NULL);
1580 win_remove(curwin, NULL);
1581 aucmd_win_used = FALSE;
1582 last_status(FALSE); // may need to remove last status line
1583
1584 if (!valid_tabpage_win(curtab))
1585 // no valid window in current tabpage
1586 close_tabpage(curtab);
1587
1588 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1589 (void)win_comp_pos(); // recompute window positions
1590 unblock_autocmds();
1591
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001592 save_curwin = win_find_by_id(aco->save_curwin_id);
1593 if (save_curwin != NULL)
1594 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001595 else
1596 // Hmm, original window disappeared. Just use the first one.
1597 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001598 curbuf = curwin->w_buffer;
1599#ifdef FEAT_JOB_CHANNEL
1600 // May need to restore insert mode for a prompt buffer.
1601 entering_window(curwin);
1602#endif
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001603 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001604#ifdef FEAT_EVAL
1605 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1606 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1607#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001608 vim_free(globaldir);
1609 globaldir = aco->globaldir;
1610
1611 // the buffer contents may have changed
1612 check_cursor();
1613 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1614 {
1615 curwin->w_topline = curbuf->b_ml.ml_line_count;
1616#ifdef FEAT_DIFF
1617 curwin->w_topfill = 0;
1618#endif
1619 }
1620#if defined(FEAT_GUI)
Bram Moolenaard2ff7052021-12-17 16:00:04 +00001621 if (gui.in_use)
1622 {
1623 // Hide the scrollbars from the aucmd_win and update.
1624 gui_mch_enable_scrollbar(
1625 &aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1626 gui_mch_enable_scrollbar(
1627 &aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1628 gui_may_update_scrollbars();
1629 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001630#endif
1631 }
1632 else
1633 {
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001634 // Restore curwin. Use the window ID, a window may have been closed
1635 // and the memory re-used for another one.
1636 save_curwin = win_find_by_id(aco->save_curwin_id);
1637 if (save_curwin != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001638 {
1639 // Restore the buffer which was previously edited by curwin, if
1640 // it was changed, we are still the same window and the buffer is
1641 // valid.
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001642 if (curwin->w_id == aco->new_curwin_id
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001643 && curbuf != aco->new_curbuf.br_buf
1644 && bufref_valid(&aco->new_curbuf)
1645 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1646 {
1647# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1648 if (curwin->w_s == &curbuf->b_s)
1649 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1650# endif
1651 --curbuf->b_nwindows;
1652 curbuf = aco->new_curbuf.br_buf;
1653 curwin->w_buffer = curbuf;
1654 ++curbuf->b_nwindows;
1655 }
1656
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001657 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001658 curbuf = curwin->w_buffer;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001659 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001660 // In case the autocommand moves the cursor to a position that
1661 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001662 check_cursor();
1663 }
1664 }
Bram Moolenaarcb1956d2022-01-07 15:45:18 +00001665
1666 check_cursor(); // just in case lines got deleted
1667 VIsual_active = aco->save_VIsual_active;
1668 if (VIsual_active)
1669 check_pos(curbuf, &VIsual);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001670}
1671
1672static int autocmd_nested = FALSE;
1673
1674/*
1675 * Execute autocommands for "event" and file name "fname".
1676 * Return TRUE if some commands were executed.
1677 */
1678 int
1679apply_autocmds(
1680 event_T event,
1681 char_u *fname, // NULL or empty means use actual file name
1682 char_u *fname_io, // fname to use for <afile> on cmdline
1683 int force, // when TRUE, ignore autocmd_busy
1684 buf_T *buf) // buffer for <abuf>
1685{
1686 return apply_autocmds_group(event, fname, fname_io, force,
1687 AUGROUP_ALL, buf, NULL);
1688}
1689
1690/*
1691 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1692 * setting v:filearg.
1693 */
1694 int
1695apply_autocmds_exarg(
1696 event_T event,
1697 char_u *fname,
1698 char_u *fname_io,
1699 int force,
1700 buf_T *buf,
1701 exarg_T *eap)
1702{
1703 return apply_autocmds_group(event, fname, fname_io, force,
1704 AUGROUP_ALL, buf, eap);
1705}
1706
1707/*
1708 * Like apply_autocmds(), but handles the caller's retval. If the script
1709 * processing is being aborted or if retval is FAIL when inside a try
1710 * conditional, no autocommands are executed. If otherwise the autocommands
1711 * cause the script to be aborted, retval is set to FAIL.
1712 */
1713 int
1714apply_autocmds_retval(
1715 event_T event,
1716 char_u *fname, // NULL or empty means use actual file name
1717 char_u *fname_io, // fname to use for <afile> on cmdline
1718 int force, // when TRUE, ignore autocmd_busy
1719 buf_T *buf, // buffer for <abuf>
1720 int *retval) // pointer to caller's retval
1721{
1722 int did_cmd;
1723
1724#ifdef FEAT_EVAL
1725 if (should_abort(*retval))
1726 return FALSE;
1727#endif
1728
1729 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1730 AUGROUP_ALL, buf, NULL);
1731 if (did_cmd
1732#ifdef FEAT_EVAL
1733 && aborting()
1734#endif
1735 )
1736 *retval = FAIL;
1737 return did_cmd;
1738}
1739
1740/*
1741 * Return TRUE when there is a CursorHold autocommand defined.
1742 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001743 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001744has_cursorhold(void)
1745{
1746 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1747 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1748}
1749
1750/*
1751 * Return TRUE if the CursorHold event can be triggered.
1752 */
1753 int
1754trigger_cursorhold(void)
1755{
1756 int state;
1757
1758 if (!did_cursorhold
1759 && has_cursorhold()
1760 && reg_recording == 0
1761 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001762 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001763 {
1764 state = get_real_state();
1765 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1766 return TRUE;
1767 }
1768 return FALSE;
1769}
1770
1771/*
1772 * Return TRUE when there is a CursorMoved autocommand defined.
1773 */
1774 int
1775has_cursormoved(void)
1776{
1777 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1778}
1779
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001780/*
1781 * Return TRUE when there is a CursorMovedI autocommand defined.
1782 */
1783 int
1784has_cursormovedI(void)
1785{
1786 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1787}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001788
1789/*
1790 * Return TRUE when there is a TextChanged autocommand defined.
1791 */
1792 int
1793has_textchanged(void)
1794{
1795 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1796}
1797
1798/*
1799 * Return TRUE when there is a TextChangedI autocommand defined.
1800 */
1801 int
1802has_textchangedI(void)
1803{
1804 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1805}
1806
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001807/*
1808 * Return TRUE when there is a TextChangedP autocommand defined.
1809 */
1810 int
1811has_textchangedP(void)
1812{
1813 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1814}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001815
1816/*
1817 * Return TRUE when there is an InsertCharPre autocommand defined.
1818 */
1819 int
1820has_insertcharpre(void)
1821{
1822 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1823}
1824
1825/*
1826 * Return TRUE when there is an CmdUndefined autocommand defined.
1827 */
1828 int
1829has_cmdundefined(void)
1830{
1831 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1832}
1833
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001834#if defined(FEAT_EVAL) || defined(PROTO)
1835/*
1836 * Return TRUE when there is a TextYankPost autocommand defined.
1837 */
1838 int
1839has_textyankpost(void)
1840{
1841 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1842}
1843#endif
1844
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001845#if defined(FEAT_EVAL) || defined(PROTO)
1846/*
1847 * Return TRUE when there is a CompleteChanged autocommand defined.
1848 */
1849 int
1850has_completechanged(void)
1851{
1852 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1853}
1854#endif
1855
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001856#if defined(FEAT_EVAL) || defined(PROTO)
1857/*
1858 * Return TRUE when there is a ModeChanged autocommand defined.
1859 */
1860 int
1861has_modechanged(void)
1862{
1863 return (first_autopat[(int)EVENT_MODECHANGED] != NULL);
1864}
1865#endif
1866
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001867/*
1868 * Execute autocommands for "event" and file name "fname".
1869 * Return TRUE if some commands were executed.
1870 */
1871 static int
1872apply_autocmds_group(
1873 event_T event,
1874 char_u *fname, // NULL or empty means use actual file name
1875 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1876 // use fname
1877 int force, // when TRUE, ignore autocmd_busy
1878 int group, // group ID, or AUGROUP_ALL
1879 buf_T *buf, // buffer for <abuf>
1880 exarg_T *eap UNUSED) // command arguments
1881{
1882 char_u *sfname = NULL; // short file name
1883 char_u *tail;
1884 int save_changed;
1885 buf_T *old_curbuf;
1886 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001887 char_u *save_autocmd_fname;
1888 int save_autocmd_fname_full;
1889 int save_autocmd_bufnr;
1890 char_u *save_autocmd_match;
1891 int save_autocmd_busy;
1892 int save_autocmd_nested;
1893 static int nesting = 0;
1894 AutoPatCmd patcmd;
1895 AutoPat *ap;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001896 sctx_T save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001897#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001898 funccal_entry_T funccal_entry;
1899 char_u *save_cmdarg;
1900 long save_cmdbang;
1901#endif
1902 static int filechangeshell_busy = FALSE;
1903#ifdef FEAT_PROFILE
1904 proftime_T wait_time;
1905#endif
1906 int did_save_redobuff = FALSE;
1907 save_redo_T save_redo;
1908 int save_KeyTyped = KeyTyped;
ichizokc3f91c02021-12-17 09:44:33 +00001909 int save_did_emsg;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001910 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001911
1912 /*
1913 * Quickly return if there are no autocommands for this event or
1914 * autocommands are blocked.
1915 */
1916 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1917 || autocmd_blocked > 0)
1918 goto BYPASS_AU;
1919
1920 /*
1921 * When autocommands are busy, new autocommands are only executed when
1922 * explicitly enabled with the "nested" flag.
1923 */
1924 if (autocmd_busy && !(force || autocmd_nested))
1925 goto BYPASS_AU;
1926
1927#ifdef FEAT_EVAL
1928 /*
1929 * Quickly return when immediately aborting on error, or when an interrupt
1930 * occurred or an exception was thrown but not caught.
1931 */
1932 if (aborting())
1933 goto BYPASS_AU;
1934#endif
1935
1936 /*
1937 * FileChangedShell never nests, because it can create an endless loop.
1938 */
1939 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1940 || event == EVENT_FILECHANGEDSHELLPOST))
1941 goto BYPASS_AU;
1942
1943 /*
1944 * Ignore events in 'eventignore'.
1945 */
1946 if (event_ignored(event))
1947 goto BYPASS_AU;
1948
1949 /*
1950 * Allow nesting of autocommands, but restrict the depth, because it's
1951 * possible to create an endless loop.
1952 */
1953 if (nesting == 10)
1954 {
Bram Moolenaar6d057012021-12-31 18:49:43 +00001955 emsg(_(e_autocommand_nesting_too_deep));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001956 goto BYPASS_AU;
1957 }
1958
1959 /*
1960 * Check if these autocommands are disabled. Used when doing ":all" or
1961 * ":ball".
1962 */
1963 if ( (autocmd_no_enter
1964 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1965 || (autocmd_no_leave
1966 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1967 goto BYPASS_AU;
1968
1969 /*
1970 * Save the autocmd_* variables and info about the current buffer.
1971 */
1972 save_autocmd_fname = autocmd_fname;
1973 save_autocmd_fname_full = autocmd_fname_full;
1974 save_autocmd_bufnr = autocmd_bufnr;
1975 save_autocmd_match = autocmd_match;
1976 save_autocmd_busy = autocmd_busy;
1977 save_autocmd_nested = autocmd_nested;
1978 save_changed = curbuf->b_changed;
1979 old_curbuf = curbuf;
1980
1981 /*
1982 * Set the file name to be used for <afile>.
1983 * Make a copy to avoid that changing a buffer name or directory makes it
1984 * invalid.
1985 */
1986 if (fname_io == NULL)
1987 {
1988 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001989 || event == EVENT_OPTIONSET
1990 || event == EVENT_MODECHANGED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001991 autocmd_fname = NULL;
1992 else if (fname != NULL && !ends_excmd(*fname))
1993 autocmd_fname = fname;
1994 else if (buf != NULL)
1995 autocmd_fname = buf->b_ffname;
1996 else
1997 autocmd_fname = NULL;
1998 }
1999 else
2000 autocmd_fname = fname_io;
2001 if (autocmd_fname != NULL)
2002 autocmd_fname = vim_strsave(autocmd_fname);
2003 autocmd_fname_full = FALSE; // call FullName_save() later
2004
2005 /*
2006 * Set the buffer number to be used for <abuf>.
2007 */
2008 if (buf == NULL)
2009 autocmd_bufnr = 0;
2010 else
2011 autocmd_bufnr = buf->b_fnum;
2012
2013 /*
2014 * When the file name is NULL or empty, use the file name of buffer "buf".
2015 * Always use the full path of the file name to match with, in case
2016 * "allow_dirs" is set.
2017 */
2018 if (fname == NULL || *fname == NUL)
2019 {
2020 if (buf == NULL)
2021 fname = NULL;
2022 else
2023 {
2024#ifdef FEAT_SYN_HL
2025 if (event == EVENT_SYNTAX)
2026 fname = buf->b_p_syn;
2027 else
2028#endif
2029 if (event == EVENT_FILETYPE)
2030 fname = buf->b_p_ft;
2031 else
2032 {
2033 if (buf->b_sfname != NULL)
2034 sfname = vim_strsave(buf->b_sfname);
2035 fname = buf->b_ffname;
2036 }
2037 }
2038 if (fname == NULL)
2039 fname = (char_u *)"";
2040 fname = vim_strsave(fname); // make a copy, so we can change it
2041 }
2042 else
2043 {
2044 sfname = vim_strsave(fname);
2045 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
Bram Moolenaarf6246f52022-02-11 16:30:12 +00002046 // ColorScheme, QuickFixCmd*, DirChanged and similar.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002047 if (event == EVENT_FILETYPE
2048 || event == EVENT_SYNTAX
2049 || event == EVENT_CMDLINECHANGED
2050 || event == EVENT_CMDLINEENTER
2051 || event == EVENT_CMDLINELEAVE
2052 || event == EVENT_CMDWINENTER
2053 || event == EVENT_CMDWINLEAVE
2054 || event == EVENT_CMDUNDEFINED
2055 || event == EVENT_FUNCUNDEFINED
2056 || event == EVENT_REMOTEREPLY
2057 || event == EVENT_SPELLFILEMISSING
2058 || event == EVENT_QUICKFIXCMDPRE
2059 || event == EVENT_COLORSCHEME
2060 || event == EVENT_COLORSCHEMEPRE
2061 || event == EVENT_OPTIONSET
2062 || event == EVENT_QUICKFIXCMDPOST
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02002063 || event == EVENT_DIRCHANGED
Bram Moolenaarf6246f52022-02-11 16:30:12 +00002064 || event == EVENT_DIRCHANGEDPRE
naohiro ono23beefe2021-11-13 12:38:49 +00002065 || event == EVENT_MODECHANGED
Bram Moolenaarf6246f52022-02-11 16:30:12 +00002066 || event == EVENT_USER
naohiro ono23beefe2021-11-13 12:38:49 +00002067 || event == EVENT_WINCLOSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002068 {
2069 fname = vim_strsave(fname);
2070 autocmd_fname_full = TRUE; // don't expand it later
2071 }
2072 else
2073 fname = FullName_save(fname, FALSE);
2074 }
2075 if (fname == NULL) // out of memory
2076 {
2077 vim_free(sfname);
2078 retval = FALSE;
2079 goto BYPASS_AU;
2080 }
2081
2082#ifdef BACKSLASH_IN_FILENAME
2083 /*
2084 * Replace all backslashes with forward slashes. This makes the
2085 * autocommand patterns portable between Unix and MS-DOS.
2086 */
2087 if (sfname != NULL)
2088 forward_slash(sfname);
2089 forward_slash(fname);
2090#endif
2091
2092#ifdef VMS
2093 // remove version for correct match
2094 if (sfname != NULL)
2095 vms_remove_version(sfname);
2096 vms_remove_version(fname);
2097#endif
2098
2099 /*
2100 * Set the name to be used for <amatch>.
2101 */
2102 autocmd_match = fname;
2103
2104
2105 // Don't redraw while doing autocommands.
2106 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002107
2108 // name and lnum are filled in later
2109 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002110 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002111
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002112 save_current_sctx = current_sctx;
2113
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002114#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002115# ifdef FEAT_PROFILE
2116 if (do_profiling == PROF_YES)
2117 prof_child_enter(&wait_time); // doesn't count for the caller itself
2118# endif
2119
2120 // Don't use local function variables, if called from a function.
2121 save_funccal(&funccal_entry);
2122#endif
2123
2124 /*
2125 * When starting to execute autocommands, save the search patterns.
2126 */
2127 if (!autocmd_busy)
2128 {
2129 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002130 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002131 {
2132 saveRedobuff(&save_redo);
2133 did_save_redobuff = TRUE;
2134 }
2135 did_filetype = keep_filetype;
2136 }
2137
2138 /*
2139 * Note that we are applying autocmds. Some commands need to know.
2140 */
2141 autocmd_busy = TRUE;
2142 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2143 ++nesting; // see matching decrement below
2144
2145 // Remember that FileType was triggered. Used for did_filetype().
2146 if (event == EVENT_FILETYPE)
2147 did_filetype = TRUE;
2148
2149 tail = gettail(fname);
2150
2151 // Find first autocommand that matches
2152 patcmd.curpat = first_autopat[(int)event];
2153 patcmd.nextcmd = NULL;
2154 patcmd.group = group;
2155 patcmd.fname = fname;
2156 patcmd.sfname = sfname;
2157 patcmd.tail = tail;
2158 patcmd.event = event;
2159 patcmd.arg_bufnr = autocmd_bufnr;
2160 patcmd.next = NULL;
2161 auto_next_pat(&patcmd, FALSE);
2162
2163 // found one, start executing the autocommands
2164 if (patcmd.curpat != NULL)
2165 {
2166 // add to active_apc_list
2167 patcmd.next = active_apc_list;
2168 active_apc_list = &patcmd;
2169
2170#ifdef FEAT_EVAL
2171 // set v:cmdarg (only when there is a matching pattern)
2172 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2173 if (eap != NULL)
2174 {
2175 save_cmdarg = set_cmdarg(eap, NULL);
2176 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2177 }
2178 else
2179 save_cmdarg = NULL; // avoid gcc warning
2180#endif
2181 retval = TRUE;
2182 // mark the last pattern, to avoid an endless loop when more patterns
2183 // are added when executing autocommands
2184 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2185 ap->last = FALSE;
2186 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002187
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002188 if (nesting == 1)
2189 // make sure cursor and topline are valid
2190 check_lnums(TRUE);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002191
ichizokc3f91c02021-12-17 09:44:33 +00002192 save_did_emsg = did_emsg;
2193
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002194 do_cmdline(NULL, getnextac, (void *)&patcmd,
2195 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002196
ichizokc3f91c02021-12-17 09:44:33 +00002197 did_emsg += save_did_emsg;
2198
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002199 if (nesting == 1)
2200 // restore cursor and topline, unless they were changed
2201 reset_lnums();
Bram Moolenaara68e5952019-04-25 22:22:01 +02002202
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002203#ifdef FEAT_EVAL
2204 if (eap != NULL)
2205 {
2206 (void)set_cmdarg(NULL, save_cmdarg);
2207 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2208 }
2209#endif
2210 // delete from active_apc_list
2211 if (active_apc_list == &patcmd) // just in case
2212 active_apc_list = patcmd.next;
2213 }
2214
2215 --RedrawingDisabled;
2216 autocmd_busy = save_autocmd_busy;
2217 filechangeshell_busy = FALSE;
2218 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002219 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002220 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002221 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002222 vim_free(autocmd_fname);
2223 autocmd_fname = save_autocmd_fname;
2224 autocmd_fname_full = save_autocmd_fname_full;
2225 autocmd_bufnr = save_autocmd_bufnr;
2226 autocmd_match = save_autocmd_match;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002227 current_sctx = save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002228#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002229 restore_funccal();
2230# ifdef FEAT_PROFILE
2231 if (do_profiling == PROF_YES)
2232 prof_child_exit(&wait_time);
2233# endif
2234#endif
2235 KeyTyped = save_KeyTyped;
2236 vim_free(fname);
2237 vim_free(sfname);
2238 --nesting; // see matching increment above
2239
2240 /*
2241 * When stopping to execute autocommands, restore the search patterns and
2242 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2243 * free any windows in the au_pending_free_win list.
2244 */
2245 if (!autocmd_busy)
2246 {
2247 restore_search_patterns();
2248 if (did_save_redobuff)
2249 restoreRedobuff(&save_redo);
2250 did_filetype = FALSE;
2251 while (au_pending_free_buf != NULL)
2252 {
2253 buf_T *b = au_pending_free_buf->b_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002254
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002255 vim_free(au_pending_free_buf);
2256 au_pending_free_buf = b;
2257 }
2258 while (au_pending_free_win != NULL)
2259 {
2260 win_T *w = au_pending_free_win->w_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002261
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002262 vim_free(au_pending_free_win);
2263 au_pending_free_win = w;
2264 }
2265 }
2266
2267 /*
2268 * Some events don't set or reset the Changed flag.
2269 * Check if still in the same buffer!
2270 */
2271 if (curbuf == old_curbuf
2272 && (event == EVENT_BUFREADPOST
2273 || event == EVENT_BUFWRITEPOST
2274 || event == EVENT_FILEAPPENDPOST
2275 || event == EVENT_VIMLEAVE
2276 || event == EVENT_VIMLEAVEPRE))
2277 {
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002278 if (curbuf->b_changed != save_changed)
2279 need_maketitle = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002280 curbuf->b_changed = save_changed;
2281 }
2282
2283 au_cleanup(); // may really delete removed patterns/commands now
2284
2285BYPASS_AU:
2286 // When wiping out a buffer make sure all its buffer-local autocommands
2287 // are deleted.
2288 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2289 aubuflocal_remove(buf);
2290
2291 if (retval == OK && event == EVENT_FILETYPE)
2292 au_did_filetype = TRUE;
2293
2294 return retval;
2295}
2296
2297# ifdef FEAT_EVAL
2298static char_u *old_termresponse = NULL;
2299# endif
2300
2301/*
2302 * Block triggering autocommands until unblock_autocmd() is called.
2303 * Can be used recursively, so long as it's symmetric.
2304 */
2305 void
2306block_autocmds(void)
2307{
2308# ifdef FEAT_EVAL
2309 // Remember the value of v:termresponse.
2310 if (autocmd_blocked == 0)
2311 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2312# endif
2313 ++autocmd_blocked;
2314}
2315
2316 void
2317unblock_autocmds(void)
2318{
2319 --autocmd_blocked;
2320
2321# ifdef FEAT_EVAL
2322 // When v:termresponse was set while autocommands were blocked, trigger
2323 // the autocommands now. Esp. useful when executing a shell command
2324 // during startup (vimdiff).
2325 if (autocmd_blocked == 0
2326 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2327 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2328# endif
2329}
2330
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002331 int
2332is_autocmd_blocked(void)
2333{
2334 return autocmd_blocked != 0;
2335}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002336
2337/*
2338 * Find next autocommand pattern that matches.
2339 */
2340 static void
2341auto_next_pat(
2342 AutoPatCmd *apc,
2343 int stop_at_last) // stop when 'last' flag is set
2344{
2345 AutoPat *ap;
2346 AutoCmd *cp;
2347 char_u *name;
2348 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002349 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002350
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002351 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002352
2353 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2354 {
2355 apc->curpat = NULL;
2356
2357 // Only use a pattern when it has not been removed, has commands and
2358 // the group matches. For buffer-local autocommands only check the
2359 // buffer number.
2360 if (ap->pat != NULL && ap->cmds != NULL
2361 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2362 {
2363 // execution-condition
2364 if (ap->buflocal_nr == 0
2365 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2366 apc->sfname, apc->tail, ap->allow_dirs))
2367 : ap->buflocal_nr == apc->arg_bufnr)
2368 {
2369 name = event_nr2name(apc->event);
2370 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002371 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002372 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002373 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002374 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002375 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002376 (char *)name, (char *)ap->pat);
2377 if (p_verbose >= 8)
2378 {
2379 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002380 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002381 verbose_leave();
2382 }
2383 }
2384
2385 apc->curpat = ap;
2386 apc->nextcmd = ap->cmds;
2387 // mark last command
2388 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2389 cp->last = FALSE;
2390 cp->last = TRUE;
2391 }
2392 line_breakcheck();
2393 if (apc->curpat != NULL) // found a match
2394 break;
2395 }
2396 if (stop_at_last && ap->last)
2397 break;
2398 }
2399}
2400
2401/*
2402 * Get next autocommand command.
2403 * Called by do_cmdline() to get the next line for ":if".
2404 * Returns allocated string, or NULL for end of autocommands.
2405 */
2406 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002407getnextac(
2408 int c UNUSED,
2409 void *cookie,
2410 int indent UNUSED,
2411 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002412{
2413 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2414 char_u *retval;
2415 AutoCmd *ac;
2416
2417 // Can be called again after returning the last line.
2418 if (acp->curpat == NULL)
2419 return NULL;
2420
2421 // repeat until we find an autocommand to execute
2422 for (;;)
2423 {
2424 // skip removed commands
2425 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2426 if (acp->nextcmd->last)
2427 acp->nextcmd = NULL;
2428 else
2429 acp->nextcmd = acp->nextcmd->next;
2430
2431 if (acp->nextcmd != NULL)
2432 break;
2433
2434 // at end of commands, find next pattern that matches
2435 if (acp->curpat->last)
2436 acp->curpat = NULL;
2437 else
2438 acp->curpat = acp->curpat->next;
2439 if (acp->curpat != NULL)
2440 auto_next_pat(acp, TRUE);
2441 if (acp->curpat == NULL)
2442 return NULL;
2443 }
2444
2445 ac = acp->nextcmd;
2446
2447 if (p_verbose >= 9)
2448 {
2449 verbose_enter_scroll();
2450 smsg(_("autocommand %s"), ac->cmd);
2451 msg_puts("\n"); // don't overwrite this either
2452 verbose_leave_scroll();
2453 }
2454 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002455 // Remove one-shot ("once") autocmd in anticipation of its execution.
2456 if (ac->once)
2457 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002458 autocmd_nested = ac->nested;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002459 current_sctx = ac->script_ctx;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002460 if (ac->last)
2461 acp->nextcmd = NULL;
2462 else
2463 acp->nextcmd = ac->next;
2464 return retval;
2465}
2466
2467/*
2468 * Return TRUE if there is a matching autocommand for "fname".
2469 * To account for buffer-local autocommands, function needs to know
2470 * in which buffer the file will be opened.
2471 */
2472 int
2473has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2474{
2475 AutoPat *ap;
2476 char_u *fname;
2477 char_u *tail = gettail(sfname);
2478 int retval = FALSE;
2479
2480 fname = FullName_save(sfname, FALSE);
2481 if (fname == NULL)
2482 return FALSE;
2483
2484#ifdef BACKSLASH_IN_FILENAME
2485 /*
2486 * Replace all backslashes with forward slashes. This makes the
2487 * autocommand patterns portable between Unix and MS-DOS.
2488 */
2489 sfname = vim_strsave(sfname);
2490 if (sfname != NULL)
2491 forward_slash(sfname);
2492 forward_slash(fname);
2493#endif
2494
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002495 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002496 if (ap->pat != NULL && ap->cmds != NULL
2497 && (ap->buflocal_nr == 0
2498 ? match_file_pat(NULL, &ap->reg_prog,
2499 fname, sfname, tail, ap->allow_dirs)
2500 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2501 ))
2502 {
2503 retval = TRUE;
2504 break;
2505 }
2506
2507 vim_free(fname);
2508#ifdef BACKSLASH_IN_FILENAME
2509 vim_free(sfname);
2510#endif
2511
2512 return retval;
2513}
2514
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002515/*
2516 * Function given to ExpandGeneric() to obtain the list of autocommand group
2517 * names.
2518 */
2519 char_u *
2520get_augroup_name(expand_T *xp UNUSED, int idx)
2521{
2522 if (idx == augroups.ga_len) // add "END" add the end
2523 return (char_u *)"END";
2524 if (idx >= augroups.ga_len) // end of list
2525 return NULL;
2526 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2527 // skip deleted entries
2528 return (char_u *)"";
2529 return AUGROUP_NAME(idx); // return a name
2530}
2531
2532static int include_groups = FALSE;
2533
2534 char_u *
2535set_context_in_autocmd(
2536 expand_T *xp,
2537 char_u *arg,
2538 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2539{
2540 char_u *p;
2541 int group;
2542
2543 // check for a group name, skip it if present
2544 include_groups = FALSE;
2545 p = arg;
2546 group = au_get_grouparg(&arg);
2547 if (group == AUGROUP_ERROR)
2548 return NULL;
2549 // If there only is a group name that's what we expand.
2550 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2551 {
2552 arg = p;
2553 group = AUGROUP_ALL;
2554 }
2555
2556 // skip over event name
2557 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2558 if (*p == ',')
2559 arg = p + 1;
2560 if (*p == NUL)
2561 {
2562 if (group == AUGROUP_ALL)
2563 include_groups = TRUE;
2564 xp->xp_context = EXPAND_EVENTS; // expand event name
2565 xp->xp_pattern = arg;
2566 return NULL;
2567 }
2568
2569 // skip over pattern
2570 arg = skipwhite(p);
2571 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2572 arg++;
2573 if (*arg)
2574 return arg; // expand (next) command
2575
2576 if (doautocmd)
2577 xp->xp_context = EXPAND_FILES; // expand file names
2578 else
2579 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2580 return NULL;
2581}
2582
2583/*
2584 * Function given to ExpandGeneric() to obtain the list of event names.
2585 */
2586 char_u *
2587get_event_name(expand_T *xp UNUSED, int idx)
2588{
2589 if (idx < augroups.ga_len) // First list group names, if wanted
2590 {
2591 if (!include_groups || AUGROUP_NAME(idx) == NULL
2592 || AUGROUP_NAME(idx) == get_deleted_augroup())
2593 return (char_u *)""; // skip deleted entries
2594 return AUGROUP_NAME(idx); // return a name
2595 }
2596 return (char_u *)event_names[idx - augroups.ga_len].name;
2597}
2598
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002599
2600#if defined(FEAT_EVAL) || defined(PROTO)
2601/*
2602 * Return TRUE if autocmd is supported.
2603 */
2604 int
2605autocmd_supported(char_u *name)
2606{
2607 char_u *p;
2608
2609 return (event_name2nr(name, &p) != NUM_EVENTS);
2610}
2611
2612/*
2613 * Return TRUE if an autocommand is defined for a group, event and
2614 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2615 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2616 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2617 * Used for:
2618 * exists("#Group") or
2619 * exists("#Group#Event") or
2620 * exists("#Group#Event#pat") or
2621 * exists("#Event") or
2622 * exists("#Event#pat")
2623 */
2624 int
2625au_exists(char_u *arg)
2626{
2627 char_u *arg_save;
2628 char_u *pattern = NULL;
2629 char_u *event_name;
2630 char_u *p;
2631 event_T event;
2632 AutoPat *ap;
2633 buf_T *buflocal_buf = NULL;
2634 int group;
2635 int retval = FALSE;
2636
2637 // Make a copy so that we can change the '#' chars to a NUL.
2638 arg_save = vim_strsave(arg);
2639 if (arg_save == NULL)
2640 return FALSE;
2641 p = vim_strchr(arg_save, '#');
2642 if (p != NULL)
2643 *p++ = NUL;
2644
2645 // First, look for an autocmd group name
2646 group = au_find_group(arg_save);
2647 if (group == AUGROUP_ERROR)
2648 {
2649 // Didn't match a group name, assume the first argument is an event.
2650 group = AUGROUP_ALL;
2651 event_name = arg_save;
2652 }
2653 else
2654 {
2655 if (p == NULL)
2656 {
2657 // "Group": group name is present and it's recognized
2658 retval = TRUE;
2659 goto theend;
2660 }
2661
2662 // Must be "Group#Event" or "Group#Event#pat".
2663 event_name = p;
2664 p = vim_strchr(event_name, '#');
2665 if (p != NULL)
2666 *p++ = NUL; // "Group#Event#pat"
2667 }
2668
2669 pattern = p; // "pattern" is NULL when there is no pattern
2670
2671 // find the index (enum) for the event name
2672 event = event_name2nr(event_name, &p);
2673
2674 // return FALSE if the event name is not recognized
2675 if (event == NUM_EVENTS)
2676 goto theend;
2677
2678 // Find the first autocommand for this event.
2679 // If there isn't any, return FALSE;
2680 // If there is one and no pattern given, return TRUE;
2681 ap = first_autopat[(int)event];
2682 if (ap == NULL)
2683 goto theend;
2684
2685 // if pattern is "<buffer>", special handling is needed which uses curbuf
2686 // for pattern "<buffer=N>, fnamecmp() will work fine
2687 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2688 buflocal_buf = curbuf;
2689
2690 // Check if there is an autocommand with the given pattern.
2691 for ( ; ap != NULL; ap = ap->next)
2692 // only use a pattern when it has not been removed and has commands.
2693 // For buffer-local autocommands, fnamecmp() works fine.
2694 if (ap->pat != NULL && ap->cmds != NULL
2695 && (group == AUGROUP_ALL || ap->group == group)
2696 && (pattern == NULL
2697 || (buflocal_buf == NULL
2698 ? fnamecmp(ap->pat, pattern) == 0
2699 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2700 {
2701 retval = TRUE;
2702 break;
2703 }
2704
2705theend:
2706 vim_free(arg_save);
2707 return retval;
2708}
2709#endif