blob: 07681bbe5209d286c2f9c4b8f8f85ff0b8c49cf0 [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},
153 {"OptionSet", EVENT_OPTIONSET},
154 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
155 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
156 {"QuitPre", EVENT_QUITPRE},
157 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar8aeec402019-09-15 23:02:04 +0200158 {"SafeState", EVENT_SAFESTATE},
Bram Moolenaar69198cb2019-09-16 21:58:13 +0200159 {"SafeStateAgain", EVENT_SAFESTATEAGAIN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100160 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
161 {"ShellCmdPost", EVENT_SHELLCMDPOST},
162 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200163 {"SigUSR1", EVENT_SIGUSR1},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100164 {"SourceCmd", EVENT_SOURCECMD},
165 {"SourcePre", EVENT_SOURCEPRE},
166 {"SourcePost", EVENT_SOURCEPOST},
167 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
168 {"StdinReadPost", EVENT_STDINREADPOST},
169 {"StdinReadPre", EVENT_STDINREADPRE},
170 {"SwapExists", EVENT_SWAPEXISTS},
171 {"Syntax", EVENT_SYNTAX},
172 {"TabNew", EVENT_TABNEW},
173 {"TabClosed", EVENT_TABCLOSED},
174 {"TabEnter", EVENT_TABENTER},
175 {"TabLeave", EVENT_TABLEAVE},
176 {"TermChanged", EVENT_TERMCHANGED},
177 {"TerminalOpen", EVENT_TERMINALOPEN},
Bram Moolenaar28ed4df2019-10-26 16:21:40 +0200178 {"TerminalWinOpen", EVENT_TERMINALWINOPEN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100179 {"TermResponse", EVENT_TERMRESPONSE},
180 {"TextChanged", EVENT_TEXTCHANGED},
181 {"TextChangedI", EVENT_TEXTCHANGEDI},
182 {"TextChangedP", EVENT_TEXTCHANGEDP},
183 {"User", EVENT_USER},
184 {"VimEnter", EVENT_VIMENTER},
185 {"VimLeave", EVENT_VIMLEAVE},
186 {"VimLeavePre", EVENT_VIMLEAVEPRE},
187 {"WinNew", EVENT_WINNEW},
188 {"WinEnter", EVENT_WINENTER},
189 {"WinLeave", EVENT_WINLEAVE},
190 {"VimResized", EVENT_VIMRESIZED},
191 {"TextYankPost", EVENT_TEXTYANKPOST},
Bram Moolenaar100118c2020-12-11 19:30:34 +0100192 {"VimSuspend", EVENT_VIMSUSPEND},
193 {"VimResume", EVENT_VIMRESUME},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100194 {NULL, (event_T)0}
195};
196
197static AutoPat *first_autopat[NUM_EVENTS] =
198{
199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
200 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
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};
206
207static AutoPat *last_autopat[NUM_EVENTS] =
208{
209 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
210 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
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};
216
217#define AUGROUP_DEFAULT -1 // default autocmd group
218#define AUGROUP_ERROR -2 // erroneous autocmd group
219#define AUGROUP_ALL -3 // all autocmd groups
220
221/*
222 * struct used to keep status while executing autocommands for an event.
223 */
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100224struct AutoPatCmd_S
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100225{
226 AutoPat *curpat; // next AutoPat to examine
227 AutoCmd *nextcmd; // next AutoCmd to execute
228 int group; // group being used
229 char_u *fname; // fname to match with
230 char_u *sfname; // sfname to match with
231 char_u *tail; // tail of fname
232 event_T event; // current event
233 int arg_bufnr; // Initially equal to <abuf>, set to zero when
234 // buf is deleted.
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100235 AutoPatCmd *next; // chain of active apc-s for auto-invalidation
236};
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100237
Bram Moolenaarc667da52019-11-30 20:52:27 +0100238static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100239
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200240// Macro to loop over all the patterns for an autocmd event
241#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \
242 for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next)
243
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100244/*
245 * augroups stores a list of autocmd group names.
246 */
247static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
248#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
Bram Moolenaarc667da52019-11-30 20:52:27 +0100249// use get_deleted_augroup() to get this
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100250static char_u *deleted_augroup = NULL;
251
252/*
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100253 * The ID of the current group. Group 0 is the default one.
254 */
255static int current_augroup = AUGROUP_DEFAULT;
256
Bram Moolenaarc667da52019-11-30 20:52:27 +0100257static int au_need_clean = FALSE; // need to delete marked patterns
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100258
259static char_u *event_nr2name(event_T event);
260static int au_get_grouparg(char_u **argp);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200261static 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 +0100262static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
263static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
264static int au_find_group(char_u *name);
265
266static event_T last_event;
267static int last_group;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100268static int autocmd_blocked = 0; // block all autocmds
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100269
270 static char_u *
271get_deleted_augroup(void)
272{
273 if (deleted_augroup == NULL)
274 deleted_augroup = (char_u *)_("--Deleted--");
275 return deleted_augroup;
276}
277
278/*
279 * Show the autocommands for one AutoPat.
280 */
281 static void
282show_autocmd(AutoPat *ap, event_T event)
283{
284 AutoCmd *ac;
285
286 // Check for "got_int" (here and at various places below), which is set
287 // when "q" has been hit for the "--more--" prompt
288 if (got_int)
289 return;
290 if (ap->pat == NULL) // pattern has been removed
291 return;
292
293 msg_putchar('\n');
294 if (got_int)
295 return;
296 if (event != last_event || ap->group != last_group)
297 {
298 if (ap->group != AUGROUP_DEFAULT)
299 {
300 if (AUGROUP_NAME(ap->group) == NULL)
301 msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
302 else
303 msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
304 msg_puts(" ");
305 }
306 msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
307 last_event = event;
308 last_group = ap->group;
309 msg_putchar('\n');
310 if (got_int)
311 return;
312 }
313 msg_col = 4;
314 msg_outtrans(ap->pat);
315
316 for (ac = ap->cmds; ac != NULL; ac = ac->next)
317 {
318 if (ac->cmd != NULL) // skip removed commands
319 {
320 if (msg_col >= 14)
321 msg_putchar('\n');
322 msg_col = 14;
323 if (got_int)
324 return;
325 msg_outtrans(ac->cmd);
326#ifdef FEAT_EVAL
327 if (p_verbose > 0)
328 last_set_msg(ac->script_ctx);
329#endif
330 if (got_int)
331 return;
332 if (ac->next != NULL)
333 {
334 msg_putchar('\n');
335 if (got_int)
336 return;
337 }
338 }
339 }
340}
341
342/*
343 * Mark an autocommand pattern for deletion.
344 */
345 static void
346au_remove_pat(AutoPat *ap)
347{
348 VIM_CLEAR(ap->pat);
349 ap->buflocal_nr = -1;
350 au_need_clean = TRUE;
351}
352
353/*
354 * Mark all commands for a pattern for deletion.
355 */
356 static void
357au_remove_cmds(AutoPat *ap)
358{
359 AutoCmd *ac;
360
361 for (ac = ap->cmds; ac != NULL; ac = ac->next)
362 VIM_CLEAR(ac->cmd);
363 au_need_clean = TRUE;
364}
365
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200366// Delete one command from an autocmd pattern.
367static void au_del_cmd(AutoCmd *ac)
368{
369 VIM_CLEAR(ac->cmd);
370 au_need_clean = TRUE;
371}
372
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100373/*
374 * Cleanup autocommands and patterns that have been deleted.
375 * This is only done when not executing autocommands.
376 */
377 static void
378au_cleanup(void)
379{
380 AutoPat *ap, **prev_ap;
381 AutoCmd *ac, **prev_ac;
382 event_T event;
383
384 if (autocmd_busy || !au_need_clean)
385 return;
386
387 // loop over all events
388 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
389 event = (event_T)((int)event + 1))
390 {
391 // loop over all autocommand patterns
392 prev_ap = &(first_autopat[(int)event]);
393 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
394 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200395 int has_cmd = FALSE;
396
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200397 // loop over all commands for this pattern
398 prev_ac = &(ap->cmds);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100399 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
400 {
401 // remove the command if the pattern is to be deleted or when
402 // the command has been marked for deletion
403 if (ap->pat == NULL || ac->cmd == NULL)
404 {
405 *prev_ac = ac->next;
406 vim_free(ac->cmd);
407 vim_free(ac);
408 }
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200409 else
410 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200411 has_cmd = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100412 prev_ac = &(ac->next);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200413 }
414 }
415
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200416 if (ap->pat != NULL && !has_cmd)
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200417 // Pattern was not marked for deletion, but all of its
418 // commands were. So mark the pattern for deletion.
419 au_remove_pat(ap);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100420
421 // remove the pattern if it has been marked for deletion
422 if (ap->pat == NULL)
423 {
424 if (ap->next == NULL)
425 {
426 if (prev_ap == &(first_autopat[(int)event]))
427 last_autopat[(int)event] = NULL;
428 else
429 // this depends on the "next" field being the first in
430 // the struct
431 last_autopat[(int)event] = (AutoPat *)prev_ap;
432 }
433 *prev_ap = ap->next;
434 vim_regfree(ap->reg_prog);
435 vim_free(ap);
436 }
437 else
438 prev_ap = &(ap->next);
439 }
440 }
441
442 au_need_clean = FALSE;
443}
444
445/*
446 * Called when buffer is freed, to remove/invalidate related buffer-local
447 * autocmds.
448 */
449 void
450aubuflocal_remove(buf_T *buf)
451{
452 AutoPat *ap;
453 event_T event;
454 AutoPatCmd *apc;
455
456 // invalidate currently executing autocommands
457 for (apc = active_apc_list; apc; apc = apc->next)
458 if (buf->b_fnum == apc->arg_bufnr)
459 apc->arg_bufnr = 0;
460
461 // invalidate buflocals looping through events
462 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
463 event = (event_T)((int)event + 1))
464 // loop over all autocommand patterns
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200465 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100466 if (ap->buflocal_nr == buf->b_fnum)
467 {
468 au_remove_pat(ap);
469 if (p_verbose >= 6)
470 {
471 verbose_enter();
472 smsg(_("auto-removing autocommand: %s <buffer=%d>"),
473 event_nr2name(event), buf->b_fnum);
474 verbose_leave();
475 }
476 }
477 au_cleanup();
478}
479
480/*
481 * Add an autocmd group name.
482 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
483 */
484 static int
485au_new_group(char_u *name)
486{
487 int i;
488
489 i = au_find_group(name);
490 if (i == AUGROUP_ERROR) // the group doesn't exist yet, add it
491 {
492 // First try using a free entry.
493 for (i = 0; i < augroups.ga_len; ++i)
494 if (AUGROUP_NAME(i) == NULL)
495 break;
496 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
497 return AUGROUP_ERROR;
498
499 AUGROUP_NAME(i) = vim_strsave(name);
500 if (AUGROUP_NAME(i) == NULL)
501 return AUGROUP_ERROR;
502 if (i == augroups.ga_len)
503 ++augroups.ga_len;
504 }
505
506 return i;
507}
508
509 static void
510au_del_group(char_u *name)
511{
512 int i;
513
514 i = au_find_group(name);
515 if (i == AUGROUP_ERROR) // the group doesn't exist
516 semsg(_("E367: No such group: \"%s\""), name);
517 else if (i == current_augroup)
518 emsg(_("E936: Cannot delete the current group"));
519 else
520 {
521 event_T event;
522 AutoPat *ap;
523 int in_use = FALSE;
524
525 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
526 event = (event_T)((int)event + 1))
527 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200528 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100529 if (ap->group == i && ap->pat != NULL)
530 {
531 give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
532 in_use = TRUE;
533 event = NUM_EVENTS;
534 break;
535 }
536 }
537 vim_free(AUGROUP_NAME(i));
538 if (in_use)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100539 AUGROUP_NAME(i) = get_deleted_augroup();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100540 else
541 AUGROUP_NAME(i) = NULL;
542 }
543}
544
545/*
546 * Find the ID of an autocmd group name.
547 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
548 */
549 static int
550au_find_group(char_u *name)
551{
552 int i;
553
554 for (i = 0; i < augroups.ga_len; ++i)
555 if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
556 && STRCMP(AUGROUP_NAME(i), name) == 0)
557 return i;
558 return AUGROUP_ERROR;
559}
560
561/*
562 * Return TRUE if augroup "name" exists.
563 */
564 int
565au_has_group(char_u *name)
566{
567 return au_find_group(name) != AUGROUP_ERROR;
568}
569
570/*
571 * ":augroup {name}".
572 */
573 void
574do_augroup(char_u *arg, int del_group)
575{
576 int i;
577
578 if (del_group)
579 {
580 if (*arg == NUL)
581 emsg(_(e_argreq));
582 else
583 au_del_group(arg);
584 }
585 else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0
586 current_augroup = AUGROUP_DEFAULT;
587 else if (*arg) // ":aug xxx": switch to group xxx
588 {
589 i = au_new_group(arg);
590 if (i != AUGROUP_ERROR)
591 current_augroup = i;
592 }
593 else // ":aug": list the group names
594 {
595 msg_start();
596 for (i = 0; i < augroups.ga_len; ++i)
597 {
598 if (AUGROUP_NAME(i) != NULL)
599 {
600 msg_puts((char *)AUGROUP_NAME(i));
601 msg_puts(" ");
602 }
603 }
604 msg_clr_eos();
605 msg_end();
606 }
607}
608
609#if defined(EXITFREE) || defined(PROTO)
610 void
611free_all_autocmds(void)
612{
613 int i;
614 char_u *s;
615
616 for (current_augroup = -1; current_augroup < augroups.ga_len;
617 ++current_augroup)
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200618 do_autocmd(NULL, (char_u *)"", TRUE);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100619
620 for (i = 0; i < augroups.ga_len; ++i)
621 {
622 s = ((char_u **)(augroups.ga_data))[i];
623 if (s != get_deleted_augroup())
624 vim_free(s);
625 }
626 ga_clear(&augroups);
627}
628#endif
629
630/*
631 * Return the event number for event name "start".
632 * Return NUM_EVENTS if the event name was not found.
633 * Return a pointer to the next event name in "end".
634 */
635 static event_T
636event_name2nr(char_u *start, char_u **end)
637{
638 char_u *p;
639 int i;
640 int len;
641
642 // the event name ends with end of line, '|', a blank or a comma
643 for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
644 ;
645 for (i = 0; event_names[i].name != NULL; ++i)
646 {
647 len = (int)STRLEN(event_names[i].name);
648 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
649 break;
650 }
651 if (*p == ',')
652 ++p;
653 *end = p;
654 if (event_names[i].name == NULL)
655 return NUM_EVENTS;
656 return event_names[i].event;
657}
658
659/*
660 * Return the name for event "event".
661 */
662 static char_u *
663event_nr2name(event_T event)
664{
665 int i;
666
667 for (i = 0; event_names[i].name != NULL; ++i)
668 if (event_names[i].event == event)
669 return (char_u *)event_names[i].name;
670 return (char_u *)"Unknown";
671}
672
673/*
674 * Scan over the events. "*" stands for all events.
675 */
676 static char_u *
677find_end_event(
678 char_u *arg,
679 int have_group) // TRUE when group name was found
680{
681 char_u *pat;
682 char_u *p;
683
684 if (*arg == '*')
685 {
686 if (arg[1] && !VIM_ISWHITE(arg[1]))
687 {
688 semsg(_("E215: Illegal character after *: %s"), arg);
689 return NULL;
690 }
691 pat = arg + 1;
692 }
693 else
694 {
695 for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
696 {
697 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
698 {
699 if (have_group)
700 semsg(_("E216: No such event: %s"), pat);
701 else
702 semsg(_("E216: No such group or event: %s"), pat);
703 return NULL;
704 }
705 }
706 }
707 return pat;
708}
709
710/*
711 * Return TRUE if "event" is included in 'eventignore'.
712 */
713 static int
714event_ignored(event_T event)
715{
716 char_u *p = p_ei;
717
718 while (*p != NUL)
719 {
720 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
721 return TRUE;
722 if (event_name2nr(p, &p) == event)
723 return TRUE;
724 }
725
726 return FALSE;
727}
728
729/*
730 * Return OK when the contents of p_ei is valid, FAIL otherwise.
731 */
732 int
733check_ei(void)
734{
735 char_u *p = p_ei;
736
737 while (*p)
738 {
739 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
740 {
741 p += 3;
742 if (*p == ',')
743 ++p;
744 }
745 else if (event_name2nr(p, &p) == NUM_EVENTS)
746 return FAIL;
747 }
748
749 return OK;
750}
751
752# if defined(FEAT_SYN_HL) || defined(PROTO)
753
754/*
755 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
756 * buffer loaded into the window. "what" must start with a comma.
757 * Returns the old value of 'eventignore' in allocated memory.
758 */
759 char_u *
760au_event_disable(char *what)
761{
762 char_u *new_ei;
763 char_u *save_ei;
764
765 save_ei = vim_strsave(p_ei);
766 if (save_ei != NULL)
767 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200768 new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100769 if (new_ei != NULL)
770 {
771 if (*what == ',' && *p_ei == NUL)
772 STRCPY(new_ei, what + 1);
773 else
774 STRCAT(new_ei, what);
775 set_string_option_direct((char_u *)"ei", -1, new_ei,
776 OPT_FREE, SID_NONE);
777 vim_free(new_ei);
778 }
779 }
780 return save_ei;
781}
782
783 void
784au_event_restore(char_u *old_ei)
785{
786 if (old_ei != NULL)
787 {
788 set_string_option_direct((char_u *)"ei", -1, old_ei,
789 OPT_FREE, SID_NONE);
790 vim_free(old_ei);
791 }
792}
Bram Moolenaarc667da52019-11-30 20:52:27 +0100793# endif // FEAT_SYN_HL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100794
795/*
796 * do_autocmd() -- implements the :autocmd command. Can be used in the
797 * following ways:
798 *
799 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
800 * will be automatically executed for <event>
801 * when editing a file matching <pat>, in
802 * the current group.
803 * :autocmd <event> <pat> Show the autocommands associated with
804 * <event> and <pat>.
805 * :autocmd <event> Show the autocommands associated with
806 * <event>.
807 * :autocmd Show all autocommands.
808 * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
809 * <event> and <pat>, and add the command
810 * <cmd>, for the current group.
811 * :autocmd! <event> <pat> Remove all autocommands associated with
812 * <event> and <pat> for the current group.
813 * :autocmd! <event> Remove all autocommands associated with
814 * <event> for the current group.
815 * :autocmd! Remove ALL autocommands for the current
816 * group.
817 *
818 * Multiple events and patterns may be given separated by commas. Here are
819 * some examples:
820 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
821 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
822 *
823 * :autocmd * *.c show all autocommands for *.c files.
824 *
825 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200826 * "eap" can be NULL.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100827 */
828 void
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200829do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100830{
831 char_u *arg = arg_in;
832 char_u *pat;
833 char_u *envpat = NULL;
834 char_u *cmd;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200835 int cmd_need_free = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100836 event_T event;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200837 char_u *tofree = NULL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100838 int nested = FALSE;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200839 int once = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100840 int group;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200841 int i;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200842 int flags = 0;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100843
844 if (*arg == '|')
845 {
846 arg = (char_u *)"";
847 group = AUGROUP_ALL; // no argument, use all groups
848 }
849 else
850 {
851 /*
852 * Check for a legal group name. If not, use AUGROUP_ALL.
853 */
854 group = au_get_grouparg(&arg);
855 if (arg == NULL) // out of memory
856 return;
857 }
858
859 /*
860 * Scan over the events.
861 * If we find an illegal name, return here, don't do anything.
862 */
863 pat = find_end_event(arg, group != AUGROUP_ALL);
864 if (pat == NULL)
865 return;
866
867 pat = skipwhite(pat);
868 if (*pat == '|')
869 {
870 pat = (char_u *)"";
871 cmd = (char_u *)"";
872 }
873 else
874 {
875 /*
876 * Scan over the pattern. Put a NUL at the end.
877 */
878 cmd = pat;
879 while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
880 cmd++;
881 if (*cmd)
882 *cmd++ = NUL;
883
884 // Expand environment variables in the pattern. Set 'shellslash', we
885 // want forward slashes here.
886 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
887 {
888#ifdef BACKSLASH_IN_FILENAME
889 int p_ssl_save = p_ssl;
890
891 p_ssl = TRUE;
892#endif
893 envpat = expand_env_save(pat);
894#ifdef BACKSLASH_IN_FILENAME
895 p_ssl = p_ssl_save;
896#endif
897 if (envpat != NULL)
898 pat = envpat;
899 }
900
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100901 cmd = skipwhite(cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200902 for (i = 0; i < 2; i++)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100903 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200904 if (*cmd != NUL)
905 {
906 // Check for "++once" flag.
907 if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
908 {
909 if (once)
910 semsg(_(e_duparg2), "++once");
911 once = TRUE;
912 cmd = skipwhite(cmd + 6);
913 }
914
915 // Check for "++nested" flag.
916 if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
917 {
918 if (nested)
919 semsg(_(e_duparg2), "++nested");
920 nested = TRUE;
921 cmd = skipwhite(cmd + 8);
922 }
923
924 // Check for the old "nested" flag.
925 if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
926 {
927 if (nested)
928 semsg(_(e_duparg2), "nested");
929 nested = TRUE;
930 cmd = skipwhite(cmd + 6);
931 }
932 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100933 }
934
935 /*
936 * Find the start of the commands.
937 * Expand <sfile> in it.
938 */
939 if (*cmd != NUL)
940 {
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200941 if (eap != NULL)
942 // Read a {} block if it follows.
943 cmd = may_get_cmd_block(eap, cmd, &tofree, &flags);
944
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100945 cmd = expand_sfile(cmd);
946 if (cmd == NULL) // some error
947 return;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200948 cmd_need_free = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100949 }
950 }
951
952 /*
953 * Print header when showing autocommands.
954 */
955 if (!forceit && *cmd == NUL)
956 // Highlight title
957 msg_puts_title(_("\n--- Autocommands ---"));
958
959 /*
960 * Loop over the events.
961 */
962 last_event = (event_T)-1; // for listing the event name
963 last_group = AUGROUP_ERROR; // for listing the group name
964 if (*arg == '*' || *arg == NUL || *arg == '|')
965 {
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100966 if (!forceit && *cmd != NUL)
967 emsg(_(e_cannot_define_autocommands_for_all_events));
968 else
969 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
970 event = (event_T)((int)event + 1))
971 if (do_autocmd_event(event, pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200972 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100973 break;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100974 }
975 else
976 {
977 while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
978 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200979 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100980 break;
981 }
982
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200983 if (cmd_need_free)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100984 vim_free(cmd);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200985 vim_free(tofree);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100986 vim_free(envpat);
987}
988
989/*
990 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
991 * The "argp" argument is advanced to the following argument.
992 *
993 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
994 */
995 static int
996au_get_grouparg(char_u **argp)
997{
998 char_u *group_name;
999 char_u *p;
1000 char_u *arg = *argp;
1001 int group = AUGROUP_ALL;
1002
1003 for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
1004 ;
1005 if (p > arg)
1006 {
Bram Moolenaardf44a272020-06-07 20:49:05 +02001007 group_name = vim_strnsave(arg, p - arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001008 if (group_name == NULL) // out of memory
1009 return AUGROUP_ERROR;
1010 group = au_find_group(group_name);
1011 if (group == AUGROUP_ERROR)
1012 group = AUGROUP_ALL; // no match, use all groups
1013 else
1014 *argp = skipwhite(p); // match, skip over group name
1015 vim_free(group_name);
1016 }
1017 return group;
1018}
1019
1020/*
1021 * do_autocmd() for one event.
1022 * If *pat == NUL do for all patterns.
1023 * If *cmd == NUL show entries.
1024 * If forceit == TRUE delete entries.
1025 * If group is not AUGROUP_ALL, only use this group.
1026 */
1027 static int
1028do_autocmd_event(
1029 event_T event,
1030 char_u *pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001031 int once,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001032 int nested,
1033 char_u *cmd,
1034 int forceit,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001035 int group,
1036 int flags)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001037{
1038 AutoPat *ap;
1039 AutoPat **prev_ap;
1040 AutoCmd *ac;
1041 AutoCmd **prev_ac;
1042 int brace_level;
1043 char_u *endpat;
1044 int findgroup;
1045 int allgroups;
1046 int patlen;
1047 int is_buflocal;
1048 int buflocal_nr;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001049 char_u buflocal_pat[25]; // for "<buffer=X>"
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001050
1051 if (group == AUGROUP_ALL)
1052 findgroup = current_augroup;
1053 else
1054 findgroup = group;
1055 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
1056
1057 /*
1058 * Show or delete all patterns for an event.
1059 */
1060 if (*pat == NUL)
1061 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001062 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001063 {
1064 if (forceit) // delete the AutoPat, if it's in the current group
1065 {
1066 if (ap->group == findgroup)
1067 au_remove_pat(ap);
1068 }
1069 else if (group == AUGROUP_ALL || ap->group == group)
1070 show_autocmd(ap, event);
1071 }
1072 }
1073
1074 /*
1075 * Loop through all the specified patterns.
1076 */
1077 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
1078 {
1079 /*
1080 * Find end of the pattern.
1081 * Watch out for a comma in braces, like "*.\{obj,o\}".
1082 */
1083 brace_level = 0;
1084 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
1085 || (endpat > pat && endpat[-1] == '\\')); ++endpat)
1086 {
1087 if (*endpat == '{')
1088 brace_level++;
1089 else if (*endpat == '}')
1090 brace_level--;
1091 }
1092 if (pat == endpat) // ignore single comma
1093 continue;
1094 patlen = (int)(endpat - pat);
1095
1096 /*
1097 * detect special <buflocal[=X]> buffer-local patterns
1098 */
1099 is_buflocal = FALSE;
1100 buflocal_nr = 0;
1101
1102 if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
1103 && pat[patlen - 1] == '>')
1104 {
1105 // "<buffer...>": Error will be printed only for addition.
1106 // printing and removing will proceed silently.
1107 is_buflocal = TRUE;
1108 if (patlen == 8)
1109 // "<buffer>"
1110 buflocal_nr = curbuf->b_fnum;
1111 else if (patlen > 9 && pat[7] == '=')
1112 {
1113 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
1114 // "<buffer=abuf>"
1115 buflocal_nr = autocmd_bufnr;
1116 else if (skipdigits(pat + 8) == pat + patlen - 1)
1117 // "<buffer=123>"
1118 buflocal_nr = atoi((char *)pat + 8);
1119 }
1120 }
1121
1122 if (is_buflocal)
1123 {
1124 // normalize pat into standard "<buffer>#N" form
1125 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
1126 pat = buflocal_pat; // can modify pat and patlen
1127 patlen = (int)STRLEN(buflocal_pat); // but not endpat
1128 }
1129
1130 /*
1131 * Find AutoPat entries with this pattern. When adding a command it
1132 * always goes at or after the last one, so start at the end.
1133 */
1134 if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
1135 prev_ap = &last_autopat[(int)event];
1136 else
1137 prev_ap = &first_autopat[(int)event];
1138 while ((ap = *prev_ap) != NULL)
1139 {
1140 if (ap->pat != NULL)
1141 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001142 /*
1143 * Accept a pattern when:
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001144 * - a group was specified and it's that group, or a group was
1145 * not specified and it's the current group, or a group was
1146 * not specified and we are listing
1147 * - the length of the pattern matches
1148 * - the pattern matches.
1149 * For <buffer[=X]>, this condition works because we normalize
1150 * all buffer-local patterns.
1151 */
1152 if ((allgroups || ap->group == findgroup)
1153 && ap->patlen == patlen
1154 && STRNCMP(pat, ap->pat, patlen) == 0)
1155 {
1156 /*
1157 * Remove existing autocommands.
1158 * If adding any new autocmd's for this AutoPat, don't
1159 * delete the pattern from the autopat list, append to
1160 * this list.
1161 */
1162 if (forceit)
1163 {
1164 if (*cmd != NUL && ap->next == NULL)
1165 {
1166 au_remove_cmds(ap);
1167 break;
1168 }
1169 au_remove_pat(ap);
1170 }
1171
1172 /*
1173 * Show autocmd's for this autopat, or buflocals <buffer=X>
1174 */
1175 else if (*cmd == NUL)
1176 show_autocmd(ap, event);
1177
1178 /*
1179 * Add autocmd to this autopat, if it's the last one.
1180 */
1181 else if (ap->next == NULL)
1182 break;
1183 }
1184 }
1185 prev_ap = &ap->next;
1186 }
1187
1188 /*
1189 * Add a new command.
1190 */
1191 if (*cmd != NUL)
1192 {
1193 /*
1194 * If the pattern we want to add a command to does appear at the
1195 * end of the list (or not is not in the list at all), add the
1196 * pattern at the end of the list.
1197 */
1198 if (ap == NULL)
1199 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001200 // refuse to add buffer-local ap if buffer number is invalid
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001201 if (is_buflocal && (buflocal_nr == 0
1202 || buflist_findnr(buflocal_nr) == NULL))
1203 {
1204 semsg(_("E680: <buffer=%d>: invalid buffer number "),
1205 buflocal_nr);
1206 return FAIL;
1207 }
1208
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001209 ap = ALLOC_ONE(AutoPat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001210 if (ap == NULL)
1211 return FAIL;
1212 ap->pat = vim_strnsave(pat, patlen);
1213 ap->patlen = patlen;
1214 if (ap->pat == NULL)
1215 {
1216 vim_free(ap);
1217 return FAIL;
1218 }
1219
1220 if (is_buflocal)
1221 {
1222 ap->buflocal_nr = buflocal_nr;
1223 ap->reg_prog = NULL;
1224 }
1225 else
1226 {
1227 char_u *reg_pat;
1228
1229 ap->buflocal_nr = 0;
1230 reg_pat = file_pat_to_reg_pat(pat, endpat,
1231 &ap->allow_dirs, TRUE);
1232 if (reg_pat != NULL)
1233 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1234 vim_free(reg_pat);
1235 if (reg_pat == NULL || ap->reg_prog == NULL)
1236 {
1237 vim_free(ap->pat);
1238 vim_free(ap);
1239 return FAIL;
1240 }
1241 }
1242 ap->cmds = NULL;
1243 *prev_ap = ap;
1244 last_autopat[(int)event] = ap;
1245 ap->next = NULL;
1246 if (group == AUGROUP_ALL)
1247 ap->group = current_augroup;
1248 else
1249 ap->group = group;
1250 }
1251
1252 /*
1253 * Add the autocmd at the end of the AutoCmd list.
1254 */
1255 prev_ac = &(ap->cmds);
1256 while ((ac = *prev_ac) != NULL)
1257 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001258 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001259 if (ac == NULL)
1260 return FAIL;
1261 ac->cmd = vim_strsave(cmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001262 ac->script_ctx = current_sctx;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001263 if (flags & UC_VIM9)
1264 ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001265#ifdef FEAT_EVAL
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001266 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001267#endif
1268 if (ac->cmd == NULL)
1269 {
1270 vim_free(ac);
1271 return FAIL;
1272 }
1273 ac->next = NULL;
1274 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001275 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001276 ac->nested = nested;
1277 }
1278 }
1279
1280 au_cleanup(); // may really delete removed patterns/commands now
1281 return OK;
1282}
1283
1284/*
1285 * Implementation of ":doautocmd [group] event [fname]".
1286 * Return OK for success, FAIL for failure;
1287 */
1288 int
1289do_doautocmd(
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001290 char_u *arg_start,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001291 int do_msg, // give message for no matching autocmds?
1292 int *did_something)
1293{
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001294 char_u *arg = arg_start;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001295 char_u *fname;
1296 int nothing_done = TRUE;
1297 int group;
1298
1299 if (did_something != NULL)
1300 *did_something = FALSE;
1301
1302 /*
1303 * Check for a legal group name. If not, use AUGROUP_ALL.
1304 */
1305 group = au_get_grouparg(&arg);
1306 if (arg == NULL) // out of memory
1307 return FAIL;
1308
1309 if (*arg == '*')
1310 {
1311 emsg(_("E217: Can't execute autocommands for ALL events"));
1312 return FAIL;
1313 }
1314
1315 /*
1316 * Scan over the events.
1317 * If we find an illegal name, return here, don't do anything.
1318 */
1319 fname = find_end_event(arg, group != AUGROUP_ALL);
1320 if (fname == NULL)
1321 return FAIL;
1322
1323 fname = skipwhite(fname);
1324
1325 /*
1326 * Loop over the events.
1327 */
1328 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1329 if (apply_autocmds_group(event_name2nr(arg, &arg),
1330 fname, NULL, TRUE, group, curbuf, NULL))
1331 nothing_done = FALSE;
1332
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001333 if (nothing_done && do_msg
1334#ifdef FEAT_EVAL
1335 && !aborting()
1336#endif
1337 )
1338 smsg(_("No matching autocommands: %s"), arg_start);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001339 if (did_something != NULL)
1340 *did_something = !nothing_done;
1341
1342#ifdef FEAT_EVAL
1343 return aborting() ? FAIL : OK;
1344#else
1345 return OK;
1346#endif
1347}
1348
1349/*
1350 * ":doautoall": execute autocommands for each loaded buffer.
1351 */
1352 void
1353ex_doautoall(exarg_T *eap)
1354{
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001355 int retval = OK;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001356 aco_save_T aco;
1357 buf_T *buf;
1358 bufref_T bufref;
1359 char_u *arg = eap->arg;
1360 int call_do_modelines = check_nomodeline(&arg);
1361 int did_aucmd;
1362
1363 /*
1364 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1365 * equal to curbuf, but for some buffers there may not be a window.
1366 * So we change the buffer for the current window for a moment. This
1367 * gives problems when the autocommands make changes to the list of
1368 * buffers or windows...
1369 */
1370 FOR_ALL_BUFFERS(buf)
1371 {
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001372 // Only do loaded buffers and skip the current buffer, it's done last.
1373 if (buf->b_ml.ml_mfp != NULL && buf != curbuf)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001374 {
1375 // find a window for this buffer and save some values
1376 aucmd_prepbuf(&aco, buf);
1377 set_bufref(&bufref, buf);
1378
1379 // execute the autocommands for this buffer
1380 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1381
1382 if (call_do_modelines && did_aucmd)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001383 // Execute the modeline settings, but don't set window-local
1384 // options if we are using the current window for another
1385 // buffer.
1386 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001387
1388 // restore the current window
1389 aucmd_restbuf(&aco);
1390
1391 // stop if there is some error or buffer was deleted
1392 if (retval == FAIL || !bufref_valid(&bufref))
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001393 {
1394 retval = FAIL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001395 break;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001396 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001397 }
1398 }
1399
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001400 // Execute autocommands for the current buffer last.
1401 if (retval == OK)
1402 {
1403 do_doautocmd(arg, FALSE, &did_aucmd);
1404 if (call_do_modelines && did_aucmd)
1405 do_modelines(0);
1406 }
1407
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001408 check_cursor(); // just in case lines got deleted
1409}
1410
1411/*
1412 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1413 * return TRUE and advance *argp to after it.
1414 * Thus return TRUE when do_modelines() should be called.
1415 */
1416 int
1417check_nomodeline(char_u **argp)
1418{
1419 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1420 {
1421 *argp = skipwhite(*argp + 12);
1422 return FALSE;
1423 }
1424 return TRUE;
1425}
1426
1427/*
1428 * Prepare for executing autocommands for (hidden) buffer "buf".
1429 * Search for a visible window containing the current buffer. If there isn't
1430 * one then use "aucmd_win".
1431 * Set "curbuf" and "curwin" to match "buf".
1432 */
1433 void
1434aucmd_prepbuf(
1435 aco_save_T *aco, // structure to save values in
1436 buf_T *buf) // new curbuf
1437{
1438 win_T *win;
1439 int save_ea;
1440#ifdef FEAT_AUTOCHDIR
1441 int save_acd;
1442#endif
1443
1444 // Find a window that is for the new buffer
1445 if (buf == curbuf) // be quick when buf is curbuf
1446 win = curwin;
1447 else
1448 FOR_ALL_WINDOWS(win)
1449 if (win->w_buffer == buf)
1450 break;
1451
1452 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1453 // back to using the current window.
1454 if (win == NULL && aucmd_win == NULL)
1455 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001456 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001457 if (aucmd_win == NULL)
1458 win = curwin;
1459 }
1460 if (win == NULL && aucmd_win_used)
1461 // Strange recursive autocommand, fall back to using the current
1462 // window. Expect a few side effects...
1463 win = curwin;
1464
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001465 aco->save_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001466 aco->save_curbuf = curbuf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001467 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001468 if (win != NULL)
1469 {
1470 // There is a window for "buf" in the current tab page, make it the
1471 // curwin. This is preferred, it has the least side effects (esp. if
1472 // "buf" is curbuf).
1473 aco->use_aucmd_win = FALSE;
1474 curwin = win;
1475 }
1476 else
1477 {
1478 // There is no window for "buf", use "aucmd_win". To minimize the side
1479 // effects, insert it in the current tab page.
1480 // Anything related to a window (e.g., setting folds) may have
1481 // unexpected results.
1482 aco->use_aucmd_win = TRUE;
1483 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001484
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001485 win_init_popup_win(aucmd_win, buf);
1486
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001487 aco->globaldir = globaldir;
1488 globaldir = NULL;
1489
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001490 // Split the current window, put the aucmd_win in the upper half.
1491 // We don't want the BufEnter or WinEnter autocommands.
1492 block_autocmds();
1493 make_snapshot(SNAP_AUCMD_IDX);
1494 save_ea = p_ea;
1495 p_ea = FALSE;
1496
1497#ifdef FEAT_AUTOCHDIR
1498 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1499 save_acd = p_acd;
1500 p_acd = FALSE;
1501#endif
1502
1503 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
1504 (void)win_comp_pos(); // recompute window positions
1505 p_ea = save_ea;
1506#ifdef FEAT_AUTOCHDIR
1507 p_acd = save_acd;
1508#endif
1509 unblock_autocmds();
1510 curwin = aucmd_win;
1511 }
1512 curbuf = buf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001513 aco->new_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001514 set_bufref(&aco->new_curbuf, curbuf);
1515}
1516
1517/*
1518 * Cleanup after executing autocommands for a (hidden) buffer.
1519 * Restore the window as it was (if possible).
1520 */
1521 void
1522aucmd_restbuf(
1523 aco_save_T *aco) // structure holding saved values
1524{
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001525 int dummy;
1526 win_T *save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001527
1528 if (aco->use_aucmd_win)
1529 {
1530 --curbuf->b_nwindows;
1531 // Find "aucmd_win", it can't be closed, but it may be in another tab
1532 // page. Do not trigger autocommands here.
1533 block_autocmds();
1534 if (curwin != aucmd_win)
1535 {
1536 tabpage_T *tp;
1537 win_T *wp;
1538
1539 FOR_ALL_TAB_WINDOWS(tp, wp)
1540 {
1541 if (wp == aucmd_win)
1542 {
1543 if (tp != curtab)
1544 goto_tabpage_tp(tp, TRUE, TRUE);
1545 win_goto(aucmd_win);
1546 goto win_found;
1547 }
1548 }
1549 }
1550win_found:
1551
1552 // Remove the window and frame from the tree of frames.
1553 (void)winframe_remove(curwin, &dummy, NULL);
1554 win_remove(curwin, NULL);
1555 aucmd_win_used = FALSE;
1556 last_status(FALSE); // may need to remove last status line
1557
1558 if (!valid_tabpage_win(curtab))
1559 // no valid window in current tabpage
1560 close_tabpage(curtab);
1561
1562 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1563 (void)win_comp_pos(); // recompute window positions
1564 unblock_autocmds();
1565
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001566 save_curwin = win_find_by_id(aco->save_curwin_id);
1567 if (save_curwin != NULL)
1568 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001569 else
1570 // Hmm, original window disappeared. Just use the first one.
1571 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001572 curbuf = curwin->w_buffer;
1573#ifdef FEAT_JOB_CHANNEL
1574 // May need to restore insert mode for a prompt buffer.
1575 entering_window(curwin);
1576#endif
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001577 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001578#ifdef FEAT_EVAL
1579 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1580 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1581#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001582 vim_free(globaldir);
1583 globaldir = aco->globaldir;
1584
1585 // the buffer contents may have changed
1586 check_cursor();
1587 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1588 {
1589 curwin->w_topline = curbuf->b_ml.ml_line_count;
1590#ifdef FEAT_DIFF
1591 curwin->w_topfill = 0;
1592#endif
1593 }
1594#if defined(FEAT_GUI)
1595 // Hide the scrollbars from the aucmd_win and update.
1596 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1597 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1598 gui_may_update_scrollbars();
1599#endif
1600 }
1601 else
1602 {
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001603 // Restore curwin. Use the window ID, a window may have been closed
1604 // and the memory re-used for another one.
1605 save_curwin = win_find_by_id(aco->save_curwin_id);
1606 if (save_curwin != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001607 {
1608 // Restore the buffer which was previously edited by curwin, if
1609 // it was changed, we are still the same window and the buffer is
1610 // valid.
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001611 if (curwin->w_id == aco->new_curwin_id
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001612 && curbuf != aco->new_curbuf.br_buf
1613 && bufref_valid(&aco->new_curbuf)
1614 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1615 {
1616# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1617 if (curwin->w_s == &curbuf->b_s)
1618 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1619# endif
1620 --curbuf->b_nwindows;
1621 curbuf = aco->new_curbuf.br_buf;
1622 curwin->w_buffer = curbuf;
1623 ++curbuf->b_nwindows;
1624 }
1625
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001626 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001627 curbuf = curwin->w_buffer;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001628 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001629 // In case the autocommand moves the cursor to a position that
1630 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001631 check_cursor();
1632 }
1633 }
1634}
1635
1636static int autocmd_nested = FALSE;
1637
1638/*
1639 * Execute autocommands for "event" and file name "fname".
1640 * Return TRUE if some commands were executed.
1641 */
1642 int
1643apply_autocmds(
1644 event_T event,
1645 char_u *fname, // NULL or empty means use actual file name
1646 char_u *fname_io, // fname to use for <afile> on cmdline
1647 int force, // when TRUE, ignore autocmd_busy
1648 buf_T *buf) // buffer for <abuf>
1649{
1650 return apply_autocmds_group(event, fname, fname_io, force,
1651 AUGROUP_ALL, buf, NULL);
1652}
1653
1654/*
1655 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1656 * setting v:filearg.
1657 */
1658 int
1659apply_autocmds_exarg(
1660 event_T event,
1661 char_u *fname,
1662 char_u *fname_io,
1663 int force,
1664 buf_T *buf,
1665 exarg_T *eap)
1666{
1667 return apply_autocmds_group(event, fname, fname_io, force,
1668 AUGROUP_ALL, buf, eap);
1669}
1670
1671/*
1672 * Like apply_autocmds(), but handles the caller's retval. If the script
1673 * processing is being aborted or if retval is FAIL when inside a try
1674 * conditional, no autocommands are executed. If otherwise the autocommands
1675 * cause the script to be aborted, retval is set to FAIL.
1676 */
1677 int
1678apply_autocmds_retval(
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 int *retval) // pointer to caller's retval
1685{
1686 int did_cmd;
1687
1688#ifdef FEAT_EVAL
1689 if (should_abort(*retval))
1690 return FALSE;
1691#endif
1692
1693 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1694 AUGROUP_ALL, buf, NULL);
1695 if (did_cmd
1696#ifdef FEAT_EVAL
1697 && aborting()
1698#endif
1699 )
1700 *retval = FAIL;
1701 return did_cmd;
1702}
1703
1704/*
1705 * Return TRUE when there is a CursorHold autocommand defined.
1706 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001707 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001708has_cursorhold(void)
1709{
1710 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1711 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1712}
1713
1714/*
1715 * Return TRUE if the CursorHold event can be triggered.
1716 */
1717 int
1718trigger_cursorhold(void)
1719{
1720 int state;
1721
1722 if (!did_cursorhold
1723 && has_cursorhold()
1724 && reg_recording == 0
1725 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001726 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001727 {
1728 state = get_real_state();
1729 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1730 return TRUE;
1731 }
1732 return FALSE;
1733}
1734
1735/*
1736 * Return TRUE when there is a CursorMoved autocommand defined.
1737 */
1738 int
1739has_cursormoved(void)
1740{
1741 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1742}
1743
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001744/*
1745 * Return TRUE when there is a CursorMovedI autocommand defined.
1746 */
1747 int
1748has_cursormovedI(void)
1749{
1750 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1751}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001752
1753/*
1754 * Return TRUE when there is a TextChanged autocommand defined.
1755 */
1756 int
1757has_textchanged(void)
1758{
1759 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1760}
1761
1762/*
1763 * Return TRUE when there is a TextChangedI autocommand defined.
1764 */
1765 int
1766has_textchangedI(void)
1767{
1768 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1769}
1770
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001771/*
1772 * Return TRUE when there is a TextChangedP autocommand defined.
1773 */
1774 int
1775has_textchangedP(void)
1776{
1777 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1778}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001779
1780/*
1781 * Return TRUE when there is an InsertCharPre autocommand defined.
1782 */
1783 int
1784has_insertcharpre(void)
1785{
1786 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1787}
1788
1789/*
1790 * Return TRUE when there is an CmdUndefined autocommand defined.
1791 */
1792 int
1793has_cmdundefined(void)
1794{
1795 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1796}
1797
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001798#if defined(FEAT_EVAL) || defined(PROTO)
1799/*
1800 * Return TRUE when there is a TextYankPost autocommand defined.
1801 */
1802 int
1803has_textyankpost(void)
1804{
1805 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1806}
1807#endif
1808
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001809#if defined(FEAT_EVAL) || defined(PROTO)
1810/*
1811 * Return TRUE when there is a CompleteChanged autocommand defined.
1812 */
1813 int
1814has_completechanged(void)
1815{
1816 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1817}
1818#endif
1819
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001820/*
1821 * Execute autocommands for "event" and file name "fname".
1822 * Return TRUE if some commands were executed.
1823 */
1824 static int
1825apply_autocmds_group(
1826 event_T event,
1827 char_u *fname, // NULL or empty means use actual file name
1828 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1829 // use fname
1830 int force, // when TRUE, ignore autocmd_busy
1831 int group, // group ID, or AUGROUP_ALL
1832 buf_T *buf, // buffer for <abuf>
1833 exarg_T *eap UNUSED) // command arguments
1834{
1835 char_u *sfname = NULL; // short file name
1836 char_u *tail;
1837 int save_changed;
1838 buf_T *old_curbuf;
1839 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001840 char_u *save_autocmd_fname;
1841 int save_autocmd_fname_full;
1842 int save_autocmd_bufnr;
1843 char_u *save_autocmd_match;
1844 int save_autocmd_busy;
1845 int save_autocmd_nested;
1846 static int nesting = 0;
1847 AutoPatCmd patcmd;
1848 AutoPat *ap;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001849 sctx_T save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001850#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001851 funccal_entry_T funccal_entry;
1852 char_u *save_cmdarg;
1853 long save_cmdbang;
1854#endif
1855 static int filechangeshell_busy = FALSE;
1856#ifdef FEAT_PROFILE
1857 proftime_T wait_time;
1858#endif
1859 int did_save_redobuff = FALSE;
1860 save_redo_T save_redo;
1861 int save_KeyTyped = KeyTyped;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001862 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001863
1864 /*
1865 * Quickly return if there are no autocommands for this event or
1866 * autocommands are blocked.
1867 */
1868 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1869 || autocmd_blocked > 0)
1870 goto BYPASS_AU;
1871
1872 /*
1873 * When autocommands are busy, new autocommands are only executed when
1874 * explicitly enabled with the "nested" flag.
1875 */
1876 if (autocmd_busy && !(force || autocmd_nested))
1877 goto BYPASS_AU;
1878
1879#ifdef FEAT_EVAL
1880 /*
1881 * Quickly return when immediately aborting on error, or when an interrupt
1882 * occurred or an exception was thrown but not caught.
1883 */
1884 if (aborting())
1885 goto BYPASS_AU;
1886#endif
1887
1888 /*
1889 * FileChangedShell never nests, because it can create an endless loop.
1890 */
1891 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1892 || event == EVENT_FILECHANGEDSHELLPOST))
1893 goto BYPASS_AU;
1894
1895 /*
1896 * Ignore events in 'eventignore'.
1897 */
1898 if (event_ignored(event))
1899 goto BYPASS_AU;
1900
1901 /*
1902 * Allow nesting of autocommands, but restrict the depth, because it's
1903 * possible to create an endless loop.
1904 */
1905 if (nesting == 10)
1906 {
1907 emsg(_("E218: autocommand nesting too deep"));
1908 goto BYPASS_AU;
1909 }
1910
1911 /*
1912 * Check if these autocommands are disabled. Used when doing ":all" or
1913 * ":ball".
1914 */
1915 if ( (autocmd_no_enter
1916 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1917 || (autocmd_no_leave
1918 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1919 goto BYPASS_AU;
1920
1921 /*
1922 * Save the autocmd_* variables and info about the current buffer.
1923 */
1924 save_autocmd_fname = autocmd_fname;
1925 save_autocmd_fname_full = autocmd_fname_full;
1926 save_autocmd_bufnr = autocmd_bufnr;
1927 save_autocmd_match = autocmd_match;
1928 save_autocmd_busy = autocmd_busy;
1929 save_autocmd_nested = autocmd_nested;
1930 save_changed = curbuf->b_changed;
1931 old_curbuf = curbuf;
1932
1933 /*
1934 * Set the file name to be used for <afile>.
1935 * Make a copy to avoid that changing a buffer name or directory makes it
1936 * invalid.
1937 */
1938 if (fname_io == NULL)
1939 {
1940 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
1941 || event == EVENT_OPTIONSET)
1942 autocmd_fname = NULL;
1943 else if (fname != NULL && !ends_excmd(*fname))
1944 autocmd_fname = fname;
1945 else if (buf != NULL)
1946 autocmd_fname = buf->b_ffname;
1947 else
1948 autocmd_fname = NULL;
1949 }
1950 else
1951 autocmd_fname = fname_io;
1952 if (autocmd_fname != NULL)
1953 autocmd_fname = vim_strsave(autocmd_fname);
1954 autocmd_fname_full = FALSE; // call FullName_save() later
1955
1956 /*
1957 * Set the buffer number to be used for <abuf>.
1958 */
1959 if (buf == NULL)
1960 autocmd_bufnr = 0;
1961 else
1962 autocmd_bufnr = buf->b_fnum;
1963
1964 /*
1965 * When the file name is NULL or empty, use the file name of buffer "buf".
1966 * Always use the full path of the file name to match with, in case
1967 * "allow_dirs" is set.
1968 */
1969 if (fname == NULL || *fname == NUL)
1970 {
1971 if (buf == NULL)
1972 fname = NULL;
1973 else
1974 {
1975#ifdef FEAT_SYN_HL
1976 if (event == EVENT_SYNTAX)
1977 fname = buf->b_p_syn;
1978 else
1979#endif
1980 if (event == EVENT_FILETYPE)
1981 fname = buf->b_p_ft;
1982 else
1983 {
1984 if (buf->b_sfname != NULL)
1985 sfname = vim_strsave(buf->b_sfname);
1986 fname = buf->b_ffname;
1987 }
1988 }
1989 if (fname == NULL)
1990 fname = (char_u *)"";
1991 fname = vim_strsave(fname); // make a copy, so we can change it
1992 }
1993 else
1994 {
1995 sfname = vim_strsave(fname);
1996 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
1997 // ColorScheme, QuickFixCmd* or DirChanged
1998 if (event == EVENT_FILETYPE
1999 || event == EVENT_SYNTAX
2000 || event == EVENT_CMDLINECHANGED
2001 || event == EVENT_CMDLINEENTER
2002 || event == EVENT_CMDLINELEAVE
2003 || event == EVENT_CMDWINENTER
2004 || event == EVENT_CMDWINLEAVE
2005 || event == EVENT_CMDUNDEFINED
2006 || event == EVENT_FUNCUNDEFINED
2007 || event == EVENT_REMOTEREPLY
2008 || event == EVENT_SPELLFILEMISSING
2009 || event == EVENT_QUICKFIXCMDPRE
2010 || event == EVENT_COLORSCHEME
2011 || event == EVENT_COLORSCHEMEPRE
2012 || event == EVENT_OPTIONSET
2013 || event == EVENT_QUICKFIXCMDPOST
2014 || event == EVENT_DIRCHANGED)
2015 {
2016 fname = vim_strsave(fname);
2017 autocmd_fname_full = TRUE; // don't expand it later
2018 }
2019 else
2020 fname = FullName_save(fname, FALSE);
2021 }
2022 if (fname == NULL) // out of memory
2023 {
2024 vim_free(sfname);
2025 retval = FALSE;
2026 goto BYPASS_AU;
2027 }
2028
2029#ifdef BACKSLASH_IN_FILENAME
2030 /*
2031 * Replace all backslashes with forward slashes. This makes the
2032 * autocommand patterns portable between Unix and MS-DOS.
2033 */
2034 if (sfname != NULL)
2035 forward_slash(sfname);
2036 forward_slash(fname);
2037#endif
2038
2039#ifdef VMS
2040 // remove version for correct match
2041 if (sfname != NULL)
2042 vms_remove_version(sfname);
2043 vms_remove_version(fname);
2044#endif
2045
2046 /*
2047 * Set the name to be used for <amatch>.
2048 */
2049 autocmd_match = fname;
2050
2051
2052 // Don't redraw while doing autocommands.
2053 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002054
2055 // name and lnum are filled in later
2056 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002057 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002058
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002059 save_current_sctx = current_sctx;
2060
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002061#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002062# ifdef FEAT_PROFILE
2063 if (do_profiling == PROF_YES)
2064 prof_child_enter(&wait_time); // doesn't count for the caller itself
2065# endif
2066
2067 // Don't use local function variables, if called from a function.
2068 save_funccal(&funccal_entry);
2069#endif
2070
2071 /*
2072 * When starting to execute autocommands, save the search patterns.
2073 */
2074 if (!autocmd_busy)
2075 {
2076 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002077 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002078 {
2079 saveRedobuff(&save_redo);
2080 did_save_redobuff = TRUE;
2081 }
2082 did_filetype = keep_filetype;
2083 }
2084
2085 /*
2086 * Note that we are applying autocmds. Some commands need to know.
2087 */
2088 autocmd_busy = TRUE;
2089 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2090 ++nesting; // see matching decrement below
2091
2092 // Remember that FileType was triggered. Used for did_filetype().
2093 if (event == EVENT_FILETYPE)
2094 did_filetype = TRUE;
2095
2096 tail = gettail(fname);
2097
2098 // Find first autocommand that matches
2099 patcmd.curpat = first_autopat[(int)event];
2100 patcmd.nextcmd = NULL;
2101 patcmd.group = group;
2102 patcmd.fname = fname;
2103 patcmd.sfname = sfname;
2104 patcmd.tail = tail;
2105 patcmd.event = event;
2106 patcmd.arg_bufnr = autocmd_bufnr;
2107 patcmd.next = NULL;
2108 auto_next_pat(&patcmd, FALSE);
2109
2110 // found one, start executing the autocommands
2111 if (patcmd.curpat != NULL)
2112 {
2113 // add to active_apc_list
2114 patcmd.next = active_apc_list;
2115 active_apc_list = &patcmd;
2116
2117#ifdef FEAT_EVAL
2118 // set v:cmdarg (only when there is a matching pattern)
2119 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2120 if (eap != NULL)
2121 {
2122 save_cmdarg = set_cmdarg(eap, NULL);
2123 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2124 }
2125 else
2126 save_cmdarg = NULL; // avoid gcc warning
2127#endif
2128 retval = TRUE;
2129 // mark the last pattern, to avoid an endless loop when more patterns
2130 // are added when executing autocommands
2131 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2132 ap->last = FALSE;
2133 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002134
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002135 if (nesting == 1)
2136 // make sure cursor and topline are valid
2137 check_lnums(TRUE);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002138
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002139 do_cmdline(NULL, getnextac, (void *)&patcmd,
2140 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002141
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002142 if (nesting == 1)
2143 // restore cursor and topline, unless they were changed
2144 reset_lnums();
Bram Moolenaara68e5952019-04-25 22:22:01 +02002145
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002146#ifdef FEAT_EVAL
2147 if (eap != NULL)
2148 {
2149 (void)set_cmdarg(NULL, save_cmdarg);
2150 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2151 }
2152#endif
2153 // delete from active_apc_list
2154 if (active_apc_list == &patcmd) // just in case
2155 active_apc_list = patcmd.next;
2156 }
2157
2158 --RedrawingDisabled;
2159 autocmd_busy = save_autocmd_busy;
2160 filechangeshell_busy = FALSE;
2161 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002162 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002163 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002164 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002165 vim_free(autocmd_fname);
2166 autocmd_fname = save_autocmd_fname;
2167 autocmd_fname_full = save_autocmd_fname_full;
2168 autocmd_bufnr = save_autocmd_bufnr;
2169 autocmd_match = save_autocmd_match;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002170 current_sctx = save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002171#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002172 restore_funccal();
2173# ifdef FEAT_PROFILE
2174 if (do_profiling == PROF_YES)
2175 prof_child_exit(&wait_time);
2176# endif
2177#endif
2178 KeyTyped = save_KeyTyped;
2179 vim_free(fname);
2180 vim_free(sfname);
2181 --nesting; // see matching increment above
2182
2183 /*
2184 * When stopping to execute autocommands, restore the search patterns and
2185 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2186 * free any windows in the au_pending_free_win list.
2187 */
2188 if (!autocmd_busy)
2189 {
2190 restore_search_patterns();
2191 if (did_save_redobuff)
2192 restoreRedobuff(&save_redo);
2193 did_filetype = FALSE;
2194 while (au_pending_free_buf != NULL)
2195 {
2196 buf_T *b = au_pending_free_buf->b_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002197
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002198 vim_free(au_pending_free_buf);
2199 au_pending_free_buf = b;
2200 }
2201 while (au_pending_free_win != NULL)
2202 {
2203 win_T *w = au_pending_free_win->w_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002204
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002205 vim_free(au_pending_free_win);
2206 au_pending_free_win = w;
2207 }
2208 }
2209
2210 /*
2211 * Some events don't set or reset the Changed flag.
2212 * Check if still in the same buffer!
2213 */
2214 if (curbuf == old_curbuf
2215 && (event == EVENT_BUFREADPOST
2216 || event == EVENT_BUFWRITEPOST
2217 || event == EVENT_FILEAPPENDPOST
2218 || event == EVENT_VIMLEAVE
2219 || event == EVENT_VIMLEAVEPRE))
2220 {
2221#ifdef FEAT_TITLE
2222 if (curbuf->b_changed != save_changed)
2223 need_maketitle = TRUE;
2224#endif
2225 curbuf->b_changed = save_changed;
2226 }
2227
2228 au_cleanup(); // may really delete removed patterns/commands now
2229
2230BYPASS_AU:
2231 // When wiping out a buffer make sure all its buffer-local autocommands
2232 // are deleted.
2233 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2234 aubuflocal_remove(buf);
2235
2236 if (retval == OK && event == EVENT_FILETYPE)
2237 au_did_filetype = TRUE;
2238
2239 return retval;
2240}
2241
2242# ifdef FEAT_EVAL
2243static char_u *old_termresponse = NULL;
2244# endif
2245
2246/*
2247 * Block triggering autocommands until unblock_autocmd() is called.
2248 * Can be used recursively, so long as it's symmetric.
2249 */
2250 void
2251block_autocmds(void)
2252{
2253# ifdef FEAT_EVAL
2254 // Remember the value of v:termresponse.
2255 if (autocmd_blocked == 0)
2256 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2257# endif
2258 ++autocmd_blocked;
2259}
2260
2261 void
2262unblock_autocmds(void)
2263{
2264 --autocmd_blocked;
2265
2266# ifdef FEAT_EVAL
2267 // When v:termresponse was set while autocommands were blocked, trigger
2268 // the autocommands now. Esp. useful when executing a shell command
2269 // during startup (vimdiff).
2270 if (autocmd_blocked == 0
2271 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2272 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2273# endif
2274}
2275
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002276 int
2277is_autocmd_blocked(void)
2278{
2279 return autocmd_blocked != 0;
2280}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002281
2282/*
2283 * Find next autocommand pattern that matches.
2284 */
2285 static void
2286auto_next_pat(
2287 AutoPatCmd *apc,
2288 int stop_at_last) // stop when 'last' flag is set
2289{
2290 AutoPat *ap;
2291 AutoCmd *cp;
2292 char_u *name;
2293 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002294 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002295
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002296 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002297
2298 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2299 {
2300 apc->curpat = NULL;
2301
2302 // Only use a pattern when it has not been removed, has commands and
2303 // the group matches. For buffer-local autocommands only check the
2304 // buffer number.
2305 if (ap->pat != NULL && ap->cmds != NULL
2306 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2307 {
2308 // execution-condition
2309 if (ap->buflocal_nr == 0
2310 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2311 apc->sfname, apc->tail, ap->allow_dirs))
2312 : ap->buflocal_nr == apc->arg_bufnr)
2313 {
2314 name = event_nr2name(apc->event);
2315 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002316 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002317 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002318 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002319 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002320 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002321 (char *)name, (char *)ap->pat);
2322 if (p_verbose >= 8)
2323 {
2324 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002325 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002326 verbose_leave();
2327 }
2328 }
2329
2330 apc->curpat = ap;
2331 apc->nextcmd = ap->cmds;
2332 // mark last command
2333 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2334 cp->last = FALSE;
2335 cp->last = TRUE;
2336 }
2337 line_breakcheck();
2338 if (apc->curpat != NULL) // found a match
2339 break;
2340 }
2341 if (stop_at_last && ap->last)
2342 break;
2343 }
2344}
2345
2346/*
2347 * Get next autocommand command.
2348 * Called by do_cmdline() to get the next line for ":if".
2349 * Returns allocated string, or NULL for end of autocommands.
2350 */
2351 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002352getnextac(
2353 int c UNUSED,
2354 void *cookie,
2355 int indent UNUSED,
2356 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002357{
2358 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2359 char_u *retval;
2360 AutoCmd *ac;
2361
2362 // Can be called again after returning the last line.
2363 if (acp->curpat == NULL)
2364 return NULL;
2365
2366 // repeat until we find an autocommand to execute
2367 for (;;)
2368 {
2369 // skip removed commands
2370 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2371 if (acp->nextcmd->last)
2372 acp->nextcmd = NULL;
2373 else
2374 acp->nextcmd = acp->nextcmd->next;
2375
2376 if (acp->nextcmd != NULL)
2377 break;
2378
2379 // at end of commands, find next pattern that matches
2380 if (acp->curpat->last)
2381 acp->curpat = NULL;
2382 else
2383 acp->curpat = acp->curpat->next;
2384 if (acp->curpat != NULL)
2385 auto_next_pat(acp, TRUE);
2386 if (acp->curpat == NULL)
2387 return NULL;
2388 }
2389
2390 ac = acp->nextcmd;
2391
2392 if (p_verbose >= 9)
2393 {
2394 verbose_enter_scroll();
2395 smsg(_("autocommand %s"), ac->cmd);
2396 msg_puts("\n"); // don't overwrite this either
2397 verbose_leave_scroll();
2398 }
2399 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002400 // Remove one-shot ("once") autocmd in anticipation of its execution.
2401 if (ac->once)
2402 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002403 autocmd_nested = ac->nested;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002404 current_sctx = ac->script_ctx;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002405 if (ac->last)
2406 acp->nextcmd = NULL;
2407 else
2408 acp->nextcmd = ac->next;
2409 return retval;
2410}
2411
2412/*
2413 * Return TRUE if there is a matching autocommand for "fname".
2414 * To account for buffer-local autocommands, function needs to know
2415 * in which buffer the file will be opened.
2416 */
2417 int
2418has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2419{
2420 AutoPat *ap;
2421 char_u *fname;
2422 char_u *tail = gettail(sfname);
2423 int retval = FALSE;
2424
2425 fname = FullName_save(sfname, FALSE);
2426 if (fname == NULL)
2427 return FALSE;
2428
2429#ifdef BACKSLASH_IN_FILENAME
2430 /*
2431 * Replace all backslashes with forward slashes. This makes the
2432 * autocommand patterns portable between Unix and MS-DOS.
2433 */
2434 sfname = vim_strsave(sfname);
2435 if (sfname != NULL)
2436 forward_slash(sfname);
2437 forward_slash(fname);
2438#endif
2439
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002440 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002441 if (ap->pat != NULL && ap->cmds != NULL
2442 && (ap->buflocal_nr == 0
2443 ? match_file_pat(NULL, &ap->reg_prog,
2444 fname, sfname, tail, ap->allow_dirs)
2445 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2446 ))
2447 {
2448 retval = TRUE;
2449 break;
2450 }
2451
2452 vim_free(fname);
2453#ifdef BACKSLASH_IN_FILENAME
2454 vim_free(sfname);
2455#endif
2456
2457 return retval;
2458}
2459
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002460/*
2461 * Function given to ExpandGeneric() to obtain the list of autocommand group
2462 * names.
2463 */
2464 char_u *
2465get_augroup_name(expand_T *xp UNUSED, int idx)
2466{
2467 if (idx == augroups.ga_len) // add "END" add the end
2468 return (char_u *)"END";
2469 if (idx >= augroups.ga_len) // end of list
2470 return NULL;
2471 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2472 // skip deleted entries
2473 return (char_u *)"";
2474 return AUGROUP_NAME(idx); // return a name
2475}
2476
2477static int include_groups = FALSE;
2478
2479 char_u *
2480set_context_in_autocmd(
2481 expand_T *xp,
2482 char_u *arg,
2483 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2484{
2485 char_u *p;
2486 int group;
2487
2488 // check for a group name, skip it if present
2489 include_groups = FALSE;
2490 p = arg;
2491 group = au_get_grouparg(&arg);
2492 if (group == AUGROUP_ERROR)
2493 return NULL;
2494 // If there only is a group name that's what we expand.
2495 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2496 {
2497 arg = p;
2498 group = AUGROUP_ALL;
2499 }
2500
2501 // skip over event name
2502 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2503 if (*p == ',')
2504 arg = p + 1;
2505 if (*p == NUL)
2506 {
2507 if (group == AUGROUP_ALL)
2508 include_groups = TRUE;
2509 xp->xp_context = EXPAND_EVENTS; // expand event name
2510 xp->xp_pattern = arg;
2511 return NULL;
2512 }
2513
2514 // skip over pattern
2515 arg = skipwhite(p);
2516 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2517 arg++;
2518 if (*arg)
2519 return arg; // expand (next) command
2520
2521 if (doautocmd)
2522 xp->xp_context = EXPAND_FILES; // expand file names
2523 else
2524 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2525 return NULL;
2526}
2527
2528/*
2529 * Function given to ExpandGeneric() to obtain the list of event names.
2530 */
2531 char_u *
2532get_event_name(expand_T *xp UNUSED, int idx)
2533{
2534 if (idx < augroups.ga_len) // First list group names, if wanted
2535 {
2536 if (!include_groups || AUGROUP_NAME(idx) == NULL
2537 || AUGROUP_NAME(idx) == get_deleted_augroup())
2538 return (char_u *)""; // skip deleted entries
2539 return AUGROUP_NAME(idx); // return a name
2540 }
2541 return (char_u *)event_names[idx - augroups.ga_len].name;
2542}
2543
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002544
2545#if defined(FEAT_EVAL) || defined(PROTO)
2546/*
2547 * Return TRUE if autocmd is supported.
2548 */
2549 int
2550autocmd_supported(char_u *name)
2551{
2552 char_u *p;
2553
2554 return (event_name2nr(name, &p) != NUM_EVENTS);
2555}
2556
2557/*
2558 * Return TRUE if an autocommand is defined for a group, event and
2559 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2560 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2561 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2562 * Used for:
2563 * exists("#Group") or
2564 * exists("#Group#Event") or
2565 * exists("#Group#Event#pat") or
2566 * exists("#Event") or
2567 * exists("#Event#pat")
2568 */
2569 int
2570au_exists(char_u *arg)
2571{
2572 char_u *arg_save;
2573 char_u *pattern = NULL;
2574 char_u *event_name;
2575 char_u *p;
2576 event_T event;
2577 AutoPat *ap;
2578 buf_T *buflocal_buf = NULL;
2579 int group;
2580 int retval = FALSE;
2581
2582 // Make a copy so that we can change the '#' chars to a NUL.
2583 arg_save = vim_strsave(arg);
2584 if (arg_save == NULL)
2585 return FALSE;
2586 p = vim_strchr(arg_save, '#');
2587 if (p != NULL)
2588 *p++ = NUL;
2589
2590 // First, look for an autocmd group name
2591 group = au_find_group(arg_save);
2592 if (group == AUGROUP_ERROR)
2593 {
2594 // Didn't match a group name, assume the first argument is an event.
2595 group = AUGROUP_ALL;
2596 event_name = arg_save;
2597 }
2598 else
2599 {
2600 if (p == NULL)
2601 {
2602 // "Group": group name is present and it's recognized
2603 retval = TRUE;
2604 goto theend;
2605 }
2606
2607 // Must be "Group#Event" or "Group#Event#pat".
2608 event_name = p;
2609 p = vim_strchr(event_name, '#');
2610 if (p != NULL)
2611 *p++ = NUL; // "Group#Event#pat"
2612 }
2613
2614 pattern = p; // "pattern" is NULL when there is no pattern
2615
2616 // find the index (enum) for the event name
2617 event = event_name2nr(event_name, &p);
2618
2619 // return FALSE if the event name is not recognized
2620 if (event == NUM_EVENTS)
2621 goto theend;
2622
2623 // Find the first autocommand for this event.
2624 // If there isn't any, return FALSE;
2625 // If there is one and no pattern given, return TRUE;
2626 ap = first_autopat[(int)event];
2627 if (ap == NULL)
2628 goto theend;
2629
2630 // if pattern is "<buffer>", special handling is needed which uses curbuf
2631 // for pattern "<buffer=N>, fnamecmp() will work fine
2632 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2633 buflocal_buf = curbuf;
2634
2635 // Check if there is an autocommand with the given pattern.
2636 for ( ; ap != NULL; ap = ap->next)
2637 // only use a pattern when it has not been removed and has commands.
2638 // For buffer-local autocommands, fnamecmp() works fine.
2639 if (ap->pat != NULL && ap->cmds != NULL
2640 && (group == AUGROUP_ALL || ap->group == group)
2641 && (pattern == NULL
2642 || (buflocal_buf == NULL
2643 ? fnamecmp(ap->pat, pattern) == 0
2644 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2645 {
2646 retval = TRUE;
2647 break;
2648 }
2649
2650theend:
2651 vim_free(arg_save);
2652 return retval;
2653}
2654#endif