blob: c3aa324b34b77d2c57440d98baf870ab059a8b41 [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
58#ifdef FEAT_EVAL
59 sctx_T script_ctx; // script context where defined
60#endif
61 struct AutoCmd *next; // next AutoCmd in list
62} AutoCmd;
63
64typedef struct AutoPat
65{
66 struct AutoPat *next; // Next AutoPat in AutoPat list; MUST
67 // be the first entry.
68 char_u *pat; // pattern as typed (NULL when pattern
69 // has been removed)
70 regprog_T *reg_prog; // compiled regprog for pattern
71 AutoCmd *cmds; // list of commands to do
72 int group; // group ID
73 int patlen; // strlen() of pat
74 int buflocal_nr; // !=0 for buffer-local AutoPat
75 char allow_dirs; // Pattern may match whole path
76 char last; // last pattern for apply_autocmds()
77} AutoPat;
78
79static struct event_name
80{
81 char *name; // event name
82 event_T event; // event number
83} event_names[] =
84{
85 {"BufAdd", EVENT_BUFADD},
86 {"BufCreate", EVENT_BUFADD},
87 {"BufDelete", EVENT_BUFDELETE},
88 {"BufEnter", EVENT_BUFENTER},
89 {"BufFilePost", EVENT_BUFFILEPOST},
90 {"BufFilePre", EVENT_BUFFILEPRE},
91 {"BufHidden", EVENT_BUFHIDDEN},
92 {"BufLeave", EVENT_BUFLEAVE},
93 {"BufNew", EVENT_BUFNEW},
94 {"BufNewFile", EVENT_BUFNEWFILE},
95 {"BufRead", EVENT_BUFREADPOST},
96 {"BufReadCmd", EVENT_BUFREADCMD},
97 {"BufReadPost", EVENT_BUFREADPOST},
98 {"BufReadPre", EVENT_BUFREADPRE},
99 {"BufUnload", EVENT_BUFUNLOAD},
100 {"BufWinEnter", EVENT_BUFWINENTER},
101 {"BufWinLeave", EVENT_BUFWINLEAVE},
102 {"BufWipeout", EVENT_BUFWIPEOUT},
103 {"BufWrite", EVENT_BUFWRITEPRE},
104 {"BufWritePost", EVENT_BUFWRITEPOST},
105 {"BufWritePre", EVENT_BUFWRITEPRE},
106 {"BufWriteCmd", EVENT_BUFWRITECMD},
107 {"CmdlineChanged", EVENT_CMDLINECHANGED},
108 {"CmdlineEnter", EVENT_CMDLINEENTER},
109 {"CmdlineLeave", EVENT_CMDLINELEAVE},
110 {"CmdwinEnter", EVENT_CMDWINENTER},
111 {"CmdwinLeave", EVENT_CMDWINLEAVE},
112 {"CmdUndefined", EVENT_CMDUNDEFINED},
113 {"ColorScheme", EVENT_COLORSCHEME},
114 {"ColorSchemePre", EVENT_COLORSCHEMEPRE},
Bram Moolenaard7f246c2019-04-08 18:15:41 +0200115 {"CompleteChanged", EVENT_COMPLETECHANGED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100116 {"CompleteDone", EVENT_COMPLETEDONE},
Bram Moolenaar3f169ce2020-01-26 22:43:31 +0100117 {"CompleteDonePre", EVENT_COMPLETEDONEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100118 {"CursorHold", EVENT_CURSORHOLD},
119 {"CursorHoldI", EVENT_CURSORHOLDI},
120 {"CursorMoved", EVENT_CURSORMOVED},
121 {"CursorMovedI", EVENT_CURSORMOVEDI},
122 {"DiffUpdated", EVENT_DIFFUPDATED},
123 {"DirChanged", EVENT_DIRCHANGED},
124 {"EncodingChanged", EVENT_ENCODINGCHANGED},
125 {"ExitPre", EVENT_EXITPRE},
126 {"FileEncoding", EVENT_ENCODINGCHANGED},
127 {"FileAppendPost", EVENT_FILEAPPENDPOST},
128 {"FileAppendPre", EVENT_FILEAPPENDPRE},
129 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
130 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
131 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
132 {"FileChangedRO", EVENT_FILECHANGEDRO},
133 {"FileReadPost", EVENT_FILEREADPOST},
134 {"FileReadPre", EVENT_FILEREADPRE},
135 {"FileReadCmd", EVENT_FILEREADCMD},
136 {"FileType", EVENT_FILETYPE},
137 {"FileWritePost", EVENT_FILEWRITEPOST},
138 {"FileWritePre", EVENT_FILEWRITEPRE},
139 {"FileWriteCmd", EVENT_FILEWRITECMD},
140 {"FilterReadPost", EVENT_FILTERREADPOST},
141 {"FilterReadPre", EVENT_FILTERREADPRE},
142 {"FilterWritePost", EVENT_FILTERWRITEPOST},
143 {"FilterWritePre", EVENT_FILTERWRITEPRE},
144 {"FocusGained", EVENT_FOCUSGAINED},
145 {"FocusLost", EVENT_FOCUSLOST},
146 {"FuncUndefined", EVENT_FUNCUNDEFINED},
147 {"GUIEnter", EVENT_GUIENTER},
148 {"GUIFailed", EVENT_GUIFAILED},
149 {"InsertChange", EVENT_INSERTCHANGE},
150 {"InsertEnter", EVENT_INSERTENTER},
151 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaarb53e13a2020-10-21 12:19:53 +0200152 {"InsertLeavePre", EVENT_INSERTLEAVEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100153 {"InsertCharPre", EVENT_INSERTCHARPRE},
154 {"MenuPopup", EVENT_MENUPOPUP},
155 {"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},
190 {"WinEnter", EVENT_WINENTER},
191 {"WinLeave", EVENT_WINLEAVE},
192 {"VimResized", EVENT_VIMRESIZED},
193 {"TextYankPost", EVENT_TEXTYANKPOST},
Bram Moolenaar100118c2020-12-11 19:30:34 +0100194 {"VimSuspend", EVENT_VIMSUSPEND},
195 {"VimResume", EVENT_VIMRESUME},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100196 {NULL, (event_T)0}
197};
198
199static AutoPat *first_autopat[NUM_EVENTS] =
200{
201 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
202 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
204 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
205 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
206 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
207};
208
209static AutoPat *last_autopat[NUM_EVENTS] =
210{
211 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
212 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
213 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
214 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
215 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
216 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
217};
218
219#define AUGROUP_DEFAULT -1 // default autocmd group
220#define AUGROUP_ERROR -2 // erroneous autocmd group
221#define AUGROUP_ALL -3 // all autocmd groups
222
223/*
224 * struct used to keep status while executing autocommands for an event.
225 */
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100226struct AutoPatCmd_S
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100227{
228 AutoPat *curpat; // next AutoPat to examine
229 AutoCmd *nextcmd; // next AutoCmd to execute
230 int group; // group being used
231 char_u *fname; // fname to match with
232 char_u *sfname; // sfname to match with
233 char_u *tail; // tail of fname
234 event_T event; // current event
235 int arg_bufnr; // Initially equal to <abuf>, set to zero when
236 // buf is deleted.
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100237 AutoPatCmd *next; // chain of active apc-s for auto-invalidation
238};
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100239
Bram Moolenaarc667da52019-11-30 20:52:27 +0100240static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100241
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200242// Macro to loop over all the patterns for an autocmd event
243#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \
244 for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next)
245
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100246/*
247 * augroups stores a list of autocmd group names.
248 */
249static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
250#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
Bram Moolenaarc667da52019-11-30 20:52:27 +0100251// use get_deleted_augroup() to get this
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100252static char_u *deleted_augroup = NULL;
253
254/*
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100255 * The ID of the current group. Group 0 is the default one.
256 */
257static int current_augroup = AUGROUP_DEFAULT;
258
Bram Moolenaarc667da52019-11-30 20:52:27 +0100259static int au_need_clean = FALSE; // need to delete marked patterns
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100260
261static char_u *event_nr2name(event_T event);
262static int au_get_grouparg(char_u **argp);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200263static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100264static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
265static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
266static int au_find_group(char_u *name);
267
268static event_T last_event;
269static int last_group;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100270static int autocmd_blocked = 0; // block all autocmds
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100271
272 static char_u *
273get_deleted_augroup(void)
274{
275 if (deleted_augroup == NULL)
276 deleted_augroup = (char_u *)_("--Deleted--");
277 return deleted_augroup;
278}
279
280/*
281 * Show the autocommands for one AutoPat.
282 */
283 static void
284show_autocmd(AutoPat *ap, event_T event)
285{
286 AutoCmd *ac;
287
288 // Check for "got_int" (here and at various places below), which is set
289 // when "q" has been hit for the "--more--" prompt
290 if (got_int)
291 return;
292 if (ap->pat == NULL) // pattern has been removed
293 return;
294
295 msg_putchar('\n');
296 if (got_int)
297 return;
298 if (event != last_event || ap->group != last_group)
299 {
300 if (ap->group != AUGROUP_DEFAULT)
301 {
302 if (AUGROUP_NAME(ap->group) == NULL)
303 msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
304 else
305 msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
306 msg_puts(" ");
307 }
308 msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
309 last_event = event;
310 last_group = ap->group;
311 msg_putchar('\n');
312 if (got_int)
313 return;
314 }
315 msg_col = 4;
316 msg_outtrans(ap->pat);
317
318 for (ac = ap->cmds; ac != NULL; ac = ac->next)
319 {
320 if (ac->cmd != NULL) // skip removed commands
321 {
322 if (msg_col >= 14)
323 msg_putchar('\n');
324 msg_col = 14;
325 if (got_int)
326 return;
327 msg_outtrans(ac->cmd);
328#ifdef FEAT_EVAL
329 if (p_verbose > 0)
330 last_set_msg(ac->script_ctx);
331#endif
332 if (got_int)
333 return;
334 if (ac->next != NULL)
335 {
336 msg_putchar('\n');
337 if (got_int)
338 return;
339 }
340 }
341 }
342}
343
344/*
345 * Mark an autocommand pattern for deletion.
346 */
347 static void
348au_remove_pat(AutoPat *ap)
349{
350 VIM_CLEAR(ap->pat);
351 ap->buflocal_nr = -1;
352 au_need_clean = TRUE;
353}
354
355/*
356 * Mark all commands for a pattern for deletion.
357 */
358 static void
359au_remove_cmds(AutoPat *ap)
360{
361 AutoCmd *ac;
362
363 for (ac = ap->cmds; ac != NULL; ac = ac->next)
364 VIM_CLEAR(ac->cmd);
365 au_need_clean = TRUE;
366}
367
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200368// Delete one command from an autocmd pattern.
369static void au_del_cmd(AutoCmd *ac)
370{
371 VIM_CLEAR(ac->cmd);
372 au_need_clean = TRUE;
373}
374
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100375/*
376 * Cleanup autocommands and patterns that have been deleted.
377 * This is only done when not executing autocommands.
378 */
379 static void
380au_cleanup(void)
381{
382 AutoPat *ap, **prev_ap;
383 AutoCmd *ac, **prev_ac;
384 event_T event;
385
386 if (autocmd_busy || !au_need_clean)
387 return;
388
389 // loop over all events
390 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
391 event = (event_T)((int)event + 1))
392 {
393 // loop over all autocommand patterns
394 prev_ap = &(first_autopat[(int)event]);
395 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
396 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200397 int has_cmd = FALSE;
398
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200399 // loop over all commands for this pattern
400 prev_ac = &(ap->cmds);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100401 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
402 {
403 // remove the command if the pattern is to be deleted or when
404 // the command has been marked for deletion
405 if (ap->pat == NULL || ac->cmd == NULL)
406 {
407 *prev_ac = ac->next;
408 vim_free(ac->cmd);
409 vim_free(ac);
410 }
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200411 else
412 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200413 has_cmd = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100414 prev_ac = &(ac->next);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200415 }
416 }
417
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200418 if (ap->pat != NULL && !has_cmd)
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200419 // Pattern was not marked for deletion, but all of its
420 // commands were. So mark the pattern for deletion.
421 au_remove_pat(ap);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100422
423 // remove the pattern if it has been marked for deletion
424 if (ap->pat == NULL)
425 {
426 if (ap->next == NULL)
427 {
428 if (prev_ap == &(first_autopat[(int)event]))
429 last_autopat[(int)event] = NULL;
430 else
431 // this depends on the "next" field being the first in
432 // the struct
433 last_autopat[(int)event] = (AutoPat *)prev_ap;
434 }
435 *prev_ap = ap->next;
436 vim_regfree(ap->reg_prog);
437 vim_free(ap);
438 }
439 else
440 prev_ap = &(ap->next);
441 }
442 }
443
444 au_need_clean = FALSE;
445}
446
447/*
448 * Called when buffer is freed, to remove/invalidate related buffer-local
449 * autocmds.
450 */
451 void
452aubuflocal_remove(buf_T *buf)
453{
454 AutoPat *ap;
455 event_T event;
456 AutoPatCmd *apc;
457
458 // invalidate currently executing autocommands
459 for (apc = active_apc_list; apc; apc = apc->next)
460 if (buf->b_fnum == apc->arg_bufnr)
461 apc->arg_bufnr = 0;
462
463 // invalidate buflocals looping through events
464 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
465 event = (event_T)((int)event + 1))
466 // loop over all autocommand patterns
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200467 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100468 if (ap->buflocal_nr == buf->b_fnum)
469 {
470 au_remove_pat(ap);
471 if (p_verbose >= 6)
472 {
473 verbose_enter();
474 smsg(_("auto-removing autocommand: %s <buffer=%d>"),
475 event_nr2name(event), buf->b_fnum);
476 verbose_leave();
477 }
478 }
479 au_cleanup();
480}
481
482/*
483 * Add an autocmd group name.
484 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
485 */
486 static int
487au_new_group(char_u *name)
488{
489 int i;
490
491 i = au_find_group(name);
492 if (i == AUGROUP_ERROR) // the group doesn't exist yet, add it
493 {
494 // First try using a free entry.
495 for (i = 0; i < augroups.ga_len; ++i)
496 if (AUGROUP_NAME(i) == NULL)
497 break;
498 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
499 return AUGROUP_ERROR;
500
501 AUGROUP_NAME(i) = vim_strsave(name);
502 if (AUGROUP_NAME(i) == NULL)
503 return AUGROUP_ERROR;
504 if (i == augroups.ga_len)
505 ++augroups.ga_len;
506 }
507
508 return i;
509}
510
511 static void
512au_del_group(char_u *name)
513{
514 int i;
515
516 i = au_find_group(name);
517 if (i == AUGROUP_ERROR) // the group doesn't exist
518 semsg(_("E367: No such group: \"%s\""), name);
519 else if (i == current_augroup)
520 emsg(_("E936: Cannot delete the current group"));
521 else
522 {
523 event_T event;
524 AutoPat *ap;
525 int in_use = FALSE;
526
527 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
528 event = (event_T)((int)event + 1))
529 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200530 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100531 if (ap->group == i && ap->pat != NULL)
532 {
533 give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
534 in_use = TRUE;
535 event = NUM_EVENTS;
536 break;
537 }
538 }
539 vim_free(AUGROUP_NAME(i));
540 if (in_use)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100541 AUGROUP_NAME(i) = get_deleted_augroup();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100542 else
543 AUGROUP_NAME(i) = NULL;
544 }
545}
546
547/*
548 * Find the ID of an autocmd group name.
549 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
550 */
551 static int
552au_find_group(char_u *name)
553{
554 int i;
555
556 for (i = 0; i < augroups.ga_len; ++i)
557 if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
558 && STRCMP(AUGROUP_NAME(i), name) == 0)
559 return i;
560 return AUGROUP_ERROR;
561}
562
563/*
564 * Return TRUE if augroup "name" exists.
565 */
566 int
567au_has_group(char_u *name)
568{
569 return au_find_group(name) != AUGROUP_ERROR;
570}
571
572/*
573 * ":augroup {name}".
574 */
575 void
576do_augroup(char_u *arg, int del_group)
577{
578 int i;
579
580 if (del_group)
581 {
582 if (*arg == NUL)
583 emsg(_(e_argreq));
584 else
585 au_del_group(arg);
586 }
587 else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0
588 current_augroup = AUGROUP_DEFAULT;
589 else if (*arg) // ":aug xxx": switch to group xxx
590 {
591 i = au_new_group(arg);
592 if (i != AUGROUP_ERROR)
593 current_augroup = i;
594 }
595 else // ":aug": list the group names
596 {
597 msg_start();
598 for (i = 0; i < augroups.ga_len; ++i)
599 {
600 if (AUGROUP_NAME(i) != NULL)
601 {
602 msg_puts((char *)AUGROUP_NAME(i));
603 msg_puts(" ");
604 }
605 }
606 msg_clr_eos();
607 msg_end();
608 }
609}
610
611#if defined(EXITFREE) || defined(PROTO)
612 void
613free_all_autocmds(void)
614{
615 int i;
616 char_u *s;
617
618 for (current_augroup = -1; current_augroup < augroups.ga_len;
619 ++current_augroup)
620 do_autocmd((char_u *)"", TRUE);
621
622 for (i = 0; i < augroups.ga_len; ++i)
623 {
624 s = ((char_u **)(augroups.ga_data))[i];
625 if (s != get_deleted_augroup())
626 vim_free(s);
627 }
628 ga_clear(&augroups);
629}
630#endif
631
632/*
633 * Return the event number for event name "start".
634 * Return NUM_EVENTS if the event name was not found.
635 * Return a pointer to the next event name in "end".
636 */
637 static event_T
638event_name2nr(char_u *start, char_u **end)
639{
640 char_u *p;
641 int i;
642 int len;
643
644 // the event name ends with end of line, '|', a blank or a comma
645 for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
646 ;
647 for (i = 0; event_names[i].name != NULL; ++i)
648 {
649 len = (int)STRLEN(event_names[i].name);
650 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
651 break;
652 }
653 if (*p == ',')
654 ++p;
655 *end = p;
656 if (event_names[i].name == NULL)
657 return NUM_EVENTS;
658 return event_names[i].event;
659}
660
661/*
662 * Return the name for event "event".
663 */
664 static char_u *
665event_nr2name(event_T event)
666{
667 int i;
668
669 for (i = 0; event_names[i].name != NULL; ++i)
670 if (event_names[i].event == event)
671 return (char_u *)event_names[i].name;
672 return (char_u *)"Unknown";
673}
674
675/*
676 * Scan over the events. "*" stands for all events.
677 */
678 static char_u *
679find_end_event(
680 char_u *arg,
681 int have_group) // TRUE when group name was found
682{
683 char_u *pat;
684 char_u *p;
685
686 if (*arg == '*')
687 {
688 if (arg[1] && !VIM_ISWHITE(arg[1]))
689 {
690 semsg(_("E215: Illegal character after *: %s"), arg);
691 return NULL;
692 }
693 pat = arg + 1;
694 }
695 else
696 {
697 for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
698 {
699 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
700 {
701 if (have_group)
702 semsg(_("E216: No such event: %s"), pat);
703 else
704 semsg(_("E216: No such group or event: %s"), pat);
705 return NULL;
706 }
707 }
708 }
709 return pat;
710}
711
712/*
713 * Return TRUE if "event" is included in 'eventignore'.
714 */
715 static int
716event_ignored(event_T event)
717{
718 char_u *p = p_ei;
719
720 while (*p != NUL)
721 {
722 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
723 return TRUE;
724 if (event_name2nr(p, &p) == event)
725 return TRUE;
726 }
727
728 return FALSE;
729}
730
731/*
732 * Return OK when the contents of p_ei is valid, FAIL otherwise.
733 */
734 int
735check_ei(void)
736{
737 char_u *p = p_ei;
738
739 while (*p)
740 {
741 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
742 {
743 p += 3;
744 if (*p == ',')
745 ++p;
746 }
747 else if (event_name2nr(p, &p) == NUM_EVENTS)
748 return FAIL;
749 }
750
751 return OK;
752}
753
754# if defined(FEAT_SYN_HL) || defined(PROTO)
755
756/*
757 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
758 * buffer loaded into the window. "what" must start with a comma.
759 * Returns the old value of 'eventignore' in allocated memory.
760 */
761 char_u *
762au_event_disable(char *what)
763{
764 char_u *new_ei;
765 char_u *save_ei;
766
767 save_ei = vim_strsave(p_ei);
768 if (save_ei != NULL)
769 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200770 new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100771 if (new_ei != NULL)
772 {
773 if (*what == ',' && *p_ei == NUL)
774 STRCPY(new_ei, what + 1);
775 else
776 STRCAT(new_ei, what);
777 set_string_option_direct((char_u *)"ei", -1, new_ei,
778 OPT_FREE, SID_NONE);
779 vim_free(new_ei);
780 }
781 }
782 return save_ei;
783}
784
785 void
786au_event_restore(char_u *old_ei)
787{
788 if (old_ei != NULL)
789 {
790 set_string_option_direct((char_u *)"ei", -1, old_ei,
791 OPT_FREE, SID_NONE);
792 vim_free(old_ei);
793 }
794}
Bram Moolenaarc667da52019-11-30 20:52:27 +0100795# endif // FEAT_SYN_HL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100796
797/*
798 * do_autocmd() -- implements the :autocmd command. Can be used in the
799 * following ways:
800 *
801 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
802 * will be automatically executed for <event>
803 * when editing a file matching <pat>, in
804 * the current group.
805 * :autocmd <event> <pat> Show the autocommands associated with
806 * <event> and <pat>.
807 * :autocmd <event> Show the autocommands associated with
808 * <event>.
809 * :autocmd Show all autocommands.
810 * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
811 * <event> and <pat>, and add the command
812 * <cmd>, for the current group.
813 * :autocmd! <event> <pat> Remove all autocommands associated with
814 * <event> and <pat> for the current group.
815 * :autocmd! <event> Remove all autocommands associated with
816 * <event> for the current group.
817 * :autocmd! Remove ALL autocommands for the current
818 * group.
819 *
820 * Multiple events and patterns may be given separated by commas. Here are
821 * some examples:
822 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
823 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
824 *
825 * :autocmd * *.c show all autocommands for *.c files.
826 *
827 * Mostly a {group} argument can optionally appear before <event>.
828 */
829 void
830do_autocmd(char_u *arg_in, int forceit)
831{
832 char_u *arg = arg_in;
833 char_u *pat;
834 char_u *envpat = NULL;
835 char_u *cmd;
836 event_T event;
837 int need_free = FALSE;
838 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 Moolenaar3e460fd2019-01-26 16:21:07 +0100842
843 if (*arg == '|')
844 {
845 arg = (char_u *)"";
846 group = AUGROUP_ALL; // no argument, use all groups
847 }
848 else
849 {
850 /*
851 * Check for a legal group name. If not, use AUGROUP_ALL.
852 */
853 group = au_get_grouparg(&arg);
854 if (arg == NULL) // out of memory
855 return;
856 }
857
858 /*
859 * Scan over the events.
860 * If we find an illegal name, return here, don't do anything.
861 */
862 pat = find_end_event(arg, group != AUGROUP_ALL);
863 if (pat == NULL)
864 return;
865
866 pat = skipwhite(pat);
867 if (*pat == '|')
868 {
869 pat = (char_u *)"";
870 cmd = (char_u *)"";
871 }
872 else
873 {
874 /*
875 * Scan over the pattern. Put a NUL at the end.
876 */
877 cmd = pat;
878 while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
879 cmd++;
880 if (*cmd)
881 *cmd++ = NUL;
882
883 // Expand environment variables in the pattern. Set 'shellslash', we
884 // want forward slashes here.
885 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
886 {
887#ifdef BACKSLASH_IN_FILENAME
888 int p_ssl_save = p_ssl;
889
890 p_ssl = TRUE;
891#endif
892 envpat = expand_env_save(pat);
893#ifdef BACKSLASH_IN_FILENAME
894 p_ssl = p_ssl_save;
895#endif
896 if (envpat != NULL)
897 pat = envpat;
898 }
899
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100900 cmd = skipwhite(cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200901 for (i = 0; i < 2; i++)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100902 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200903 if (*cmd != NUL)
904 {
905 // Check for "++once" flag.
906 if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
907 {
908 if (once)
909 semsg(_(e_duparg2), "++once");
910 once = TRUE;
911 cmd = skipwhite(cmd + 6);
912 }
913
914 // Check for "++nested" flag.
915 if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
916 {
917 if (nested)
918 semsg(_(e_duparg2), "++nested");
919 nested = TRUE;
920 cmd = skipwhite(cmd + 8);
921 }
922
923 // Check for the old "nested" flag.
924 if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
925 {
926 if (nested)
927 semsg(_(e_duparg2), "nested");
928 nested = TRUE;
929 cmd = skipwhite(cmd + 6);
930 }
931 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100932 }
933
934 /*
935 * Find the start of the commands.
936 * Expand <sfile> in it.
937 */
938 if (*cmd != NUL)
939 {
940 cmd = expand_sfile(cmd);
941 if (cmd == NULL) // some error
942 return;
943 need_free = TRUE;
944 }
945 }
946
947 /*
948 * Print header when showing autocommands.
949 */
950 if (!forceit && *cmd == NUL)
951 // Highlight title
952 msg_puts_title(_("\n--- Autocommands ---"));
953
954 /*
955 * Loop over the events.
956 */
957 last_event = (event_T)-1; // for listing the event name
958 last_group = AUGROUP_ERROR; // for listing the group name
959 if (*arg == '*' || *arg == NUL || *arg == '|')
960 {
961 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
962 event = (event_T)((int)event + 1))
963 if (do_autocmd_event(event, pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200964 once, nested, cmd, forceit, group) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100965 break;
966 }
967 else
968 {
969 while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
970 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200971 once, nested, cmd, forceit, group) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100972 break;
973 }
974
975 if (need_free)
976 vim_free(cmd);
977 vim_free(envpat);
978}
979
980/*
981 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
982 * The "argp" argument is advanced to the following argument.
983 *
984 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
985 */
986 static int
987au_get_grouparg(char_u **argp)
988{
989 char_u *group_name;
990 char_u *p;
991 char_u *arg = *argp;
992 int group = AUGROUP_ALL;
993
994 for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
995 ;
996 if (p > arg)
997 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200998 group_name = vim_strnsave(arg, p - arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100999 if (group_name == NULL) // out of memory
1000 return AUGROUP_ERROR;
1001 group = au_find_group(group_name);
1002 if (group == AUGROUP_ERROR)
1003 group = AUGROUP_ALL; // no match, use all groups
1004 else
1005 *argp = skipwhite(p); // match, skip over group name
1006 vim_free(group_name);
1007 }
1008 return group;
1009}
1010
1011/*
1012 * do_autocmd() for one event.
1013 * If *pat == NUL do for all patterns.
1014 * If *cmd == NUL show entries.
1015 * If forceit == TRUE delete entries.
1016 * If group is not AUGROUP_ALL, only use this group.
1017 */
1018 static int
1019do_autocmd_event(
1020 event_T event,
1021 char_u *pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001022 int once,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001023 int nested,
1024 char_u *cmd,
1025 int forceit,
1026 int group)
1027{
1028 AutoPat *ap;
1029 AutoPat **prev_ap;
1030 AutoCmd *ac;
1031 AutoCmd **prev_ac;
1032 int brace_level;
1033 char_u *endpat;
1034 int findgroup;
1035 int allgroups;
1036 int patlen;
1037 int is_buflocal;
1038 int buflocal_nr;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001039 char_u buflocal_pat[25]; // for "<buffer=X>"
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001040
1041 if (group == AUGROUP_ALL)
1042 findgroup = current_augroup;
1043 else
1044 findgroup = group;
1045 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
1046
1047 /*
1048 * Show or delete all patterns for an event.
1049 */
1050 if (*pat == NUL)
1051 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001052 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001053 {
1054 if (forceit) // delete the AutoPat, if it's in the current group
1055 {
1056 if (ap->group == findgroup)
1057 au_remove_pat(ap);
1058 }
1059 else if (group == AUGROUP_ALL || ap->group == group)
1060 show_autocmd(ap, event);
1061 }
1062 }
1063
1064 /*
1065 * Loop through all the specified patterns.
1066 */
1067 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
1068 {
1069 /*
1070 * Find end of the pattern.
1071 * Watch out for a comma in braces, like "*.\{obj,o\}".
1072 */
1073 brace_level = 0;
1074 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
1075 || (endpat > pat && endpat[-1] == '\\')); ++endpat)
1076 {
1077 if (*endpat == '{')
1078 brace_level++;
1079 else if (*endpat == '}')
1080 brace_level--;
1081 }
1082 if (pat == endpat) // ignore single comma
1083 continue;
1084 patlen = (int)(endpat - pat);
1085
1086 /*
1087 * detect special <buflocal[=X]> buffer-local patterns
1088 */
1089 is_buflocal = FALSE;
1090 buflocal_nr = 0;
1091
1092 if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
1093 && pat[patlen - 1] == '>')
1094 {
1095 // "<buffer...>": Error will be printed only for addition.
1096 // printing and removing will proceed silently.
1097 is_buflocal = TRUE;
1098 if (patlen == 8)
1099 // "<buffer>"
1100 buflocal_nr = curbuf->b_fnum;
1101 else if (patlen > 9 && pat[7] == '=')
1102 {
1103 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
1104 // "<buffer=abuf>"
1105 buflocal_nr = autocmd_bufnr;
1106 else if (skipdigits(pat + 8) == pat + patlen - 1)
1107 // "<buffer=123>"
1108 buflocal_nr = atoi((char *)pat + 8);
1109 }
1110 }
1111
1112 if (is_buflocal)
1113 {
1114 // normalize pat into standard "<buffer>#N" form
1115 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
1116 pat = buflocal_pat; // can modify pat and patlen
1117 patlen = (int)STRLEN(buflocal_pat); // but not endpat
1118 }
1119
1120 /*
1121 * Find AutoPat entries with this pattern. When adding a command it
1122 * always goes at or after the last one, so start at the end.
1123 */
1124 if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
1125 prev_ap = &last_autopat[(int)event];
1126 else
1127 prev_ap = &first_autopat[(int)event];
1128 while ((ap = *prev_ap) != NULL)
1129 {
1130 if (ap->pat != NULL)
1131 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001132 /*
1133 * Accept a pattern when:
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001134 * - a group was specified and it's that group, or a group was
1135 * not specified and it's the current group, or a group was
1136 * not specified and we are listing
1137 * - the length of the pattern matches
1138 * - the pattern matches.
1139 * For <buffer[=X]>, this condition works because we normalize
1140 * all buffer-local patterns.
1141 */
1142 if ((allgroups || ap->group == findgroup)
1143 && ap->patlen == patlen
1144 && STRNCMP(pat, ap->pat, patlen) == 0)
1145 {
1146 /*
1147 * Remove existing autocommands.
1148 * If adding any new autocmd's for this AutoPat, don't
1149 * delete the pattern from the autopat list, append to
1150 * this list.
1151 */
1152 if (forceit)
1153 {
1154 if (*cmd != NUL && ap->next == NULL)
1155 {
1156 au_remove_cmds(ap);
1157 break;
1158 }
1159 au_remove_pat(ap);
1160 }
1161
1162 /*
1163 * Show autocmd's for this autopat, or buflocals <buffer=X>
1164 */
1165 else if (*cmd == NUL)
1166 show_autocmd(ap, event);
1167
1168 /*
1169 * Add autocmd to this autopat, if it's the last one.
1170 */
1171 else if (ap->next == NULL)
1172 break;
1173 }
1174 }
1175 prev_ap = &ap->next;
1176 }
1177
1178 /*
1179 * Add a new command.
1180 */
1181 if (*cmd != NUL)
1182 {
1183 /*
1184 * If the pattern we want to add a command to does appear at the
1185 * end of the list (or not is not in the list at all), add the
1186 * pattern at the end of the list.
1187 */
1188 if (ap == NULL)
1189 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001190 // refuse to add buffer-local ap if buffer number is invalid
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001191 if (is_buflocal && (buflocal_nr == 0
1192 || buflist_findnr(buflocal_nr) == NULL))
1193 {
1194 semsg(_("E680: <buffer=%d>: invalid buffer number "),
1195 buflocal_nr);
1196 return FAIL;
1197 }
1198
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001199 ap = ALLOC_ONE(AutoPat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001200 if (ap == NULL)
1201 return FAIL;
1202 ap->pat = vim_strnsave(pat, patlen);
1203 ap->patlen = patlen;
1204 if (ap->pat == NULL)
1205 {
1206 vim_free(ap);
1207 return FAIL;
1208 }
1209
1210 if (is_buflocal)
1211 {
1212 ap->buflocal_nr = buflocal_nr;
1213 ap->reg_prog = NULL;
1214 }
1215 else
1216 {
1217 char_u *reg_pat;
1218
1219 ap->buflocal_nr = 0;
1220 reg_pat = file_pat_to_reg_pat(pat, endpat,
1221 &ap->allow_dirs, TRUE);
1222 if (reg_pat != NULL)
1223 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1224 vim_free(reg_pat);
1225 if (reg_pat == NULL || ap->reg_prog == NULL)
1226 {
1227 vim_free(ap->pat);
1228 vim_free(ap);
1229 return FAIL;
1230 }
1231 }
1232 ap->cmds = NULL;
1233 *prev_ap = ap;
1234 last_autopat[(int)event] = ap;
1235 ap->next = NULL;
1236 if (group == AUGROUP_ALL)
1237 ap->group = current_augroup;
1238 else
1239 ap->group = group;
1240 }
1241
1242 /*
1243 * Add the autocmd at the end of the AutoCmd list.
1244 */
1245 prev_ac = &(ap->cmds);
1246 while ((ac = *prev_ac) != NULL)
1247 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001248 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001249 if (ac == NULL)
1250 return FAIL;
1251 ac->cmd = vim_strsave(cmd);
1252#ifdef FEAT_EVAL
1253 ac->script_ctx = current_sctx;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001254 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001255#endif
1256 if (ac->cmd == NULL)
1257 {
1258 vim_free(ac);
1259 return FAIL;
1260 }
1261 ac->next = NULL;
1262 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001263 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001264 ac->nested = nested;
1265 }
1266 }
1267
1268 au_cleanup(); // may really delete removed patterns/commands now
1269 return OK;
1270}
1271
1272/*
1273 * Implementation of ":doautocmd [group] event [fname]".
1274 * Return OK for success, FAIL for failure;
1275 */
1276 int
1277do_doautocmd(
1278 char_u *arg,
1279 int do_msg, // give message for no matching autocmds?
1280 int *did_something)
1281{
1282 char_u *fname;
1283 int nothing_done = TRUE;
1284 int group;
1285
1286 if (did_something != NULL)
1287 *did_something = FALSE;
1288
1289 /*
1290 * Check for a legal group name. If not, use AUGROUP_ALL.
1291 */
1292 group = au_get_grouparg(&arg);
1293 if (arg == NULL) // out of memory
1294 return FAIL;
1295
1296 if (*arg == '*')
1297 {
1298 emsg(_("E217: Can't execute autocommands for ALL events"));
1299 return FAIL;
1300 }
1301
1302 /*
1303 * Scan over the events.
1304 * If we find an illegal name, return here, don't do anything.
1305 */
1306 fname = find_end_event(arg, group != AUGROUP_ALL);
1307 if (fname == NULL)
1308 return FAIL;
1309
1310 fname = skipwhite(fname);
1311
1312 /*
1313 * Loop over the events.
1314 */
1315 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1316 if (apply_autocmds_group(event_name2nr(arg, &arg),
1317 fname, NULL, TRUE, group, curbuf, NULL))
1318 nothing_done = FALSE;
1319
1320 if (nothing_done && do_msg)
1321 msg(_("No matching autocommands"));
1322 if (did_something != NULL)
1323 *did_something = !nothing_done;
1324
1325#ifdef FEAT_EVAL
1326 return aborting() ? FAIL : OK;
1327#else
1328 return OK;
1329#endif
1330}
1331
1332/*
1333 * ":doautoall": execute autocommands for each loaded buffer.
1334 */
1335 void
1336ex_doautoall(exarg_T *eap)
1337{
1338 int retval;
1339 aco_save_T aco;
1340 buf_T *buf;
1341 bufref_T bufref;
1342 char_u *arg = eap->arg;
1343 int call_do_modelines = check_nomodeline(&arg);
1344 int did_aucmd;
1345
1346 /*
1347 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1348 * equal to curbuf, but for some buffers there may not be a window.
1349 * So we change the buffer for the current window for a moment. This
1350 * gives problems when the autocommands make changes to the list of
1351 * buffers or windows...
1352 */
1353 FOR_ALL_BUFFERS(buf)
1354 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02001355 if (buf->b_ml.ml_mfp != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001356 {
1357 // find a window for this buffer and save some values
1358 aucmd_prepbuf(&aco, buf);
1359 set_bufref(&bufref, buf);
1360
1361 // execute the autocommands for this buffer
1362 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1363
1364 if (call_do_modelines && did_aucmd)
1365 {
1366 // Execute the modeline settings, but don't set window-local
1367 // options if we are using the current window for another
1368 // buffer.
1369 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
1370 }
1371
1372 // restore the current window
1373 aucmd_restbuf(&aco);
1374
1375 // stop if there is some error or buffer was deleted
1376 if (retval == FAIL || !bufref_valid(&bufref))
1377 break;
1378 }
1379 }
1380
1381 check_cursor(); // just in case lines got deleted
1382}
1383
1384/*
1385 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1386 * return TRUE and advance *argp to after it.
1387 * Thus return TRUE when do_modelines() should be called.
1388 */
1389 int
1390check_nomodeline(char_u **argp)
1391{
1392 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1393 {
1394 *argp = skipwhite(*argp + 12);
1395 return FALSE;
1396 }
1397 return TRUE;
1398}
1399
1400/*
1401 * Prepare for executing autocommands for (hidden) buffer "buf".
1402 * Search for a visible window containing the current buffer. If there isn't
1403 * one then use "aucmd_win".
1404 * Set "curbuf" and "curwin" to match "buf".
1405 */
1406 void
1407aucmd_prepbuf(
1408 aco_save_T *aco, // structure to save values in
1409 buf_T *buf) // new curbuf
1410{
1411 win_T *win;
1412 int save_ea;
1413#ifdef FEAT_AUTOCHDIR
1414 int save_acd;
1415#endif
1416
1417 // Find a window that is for the new buffer
1418 if (buf == curbuf) // be quick when buf is curbuf
1419 win = curwin;
1420 else
1421 FOR_ALL_WINDOWS(win)
1422 if (win->w_buffer == buf)
1423 break;
1424
1425 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1426 // back to using the current window.
1427 if (win == NULL && aucmd_win == NULL)
1428 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001429 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001430 if (aucmd_win == NULL)
1431 win = curwin;
1432 }
1433 if (win == NULL && aucmd_win_used)
1434 // Strange recursive autocommand, fall back to using the current
1435 // window. Expect a few side effects...
1436 win = curwin;
1437
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001438 aco->save_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001439 aco->save_curbuf = curbuf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001440 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001441 if (win != NULL)
1442 {
1443 // There is a window for "buf" in the current tab page, make it the
1444 // curwin. This is preferred, it has the least side effects (esp. if
1445 // "buf" is curbuf).
1446 aco->use_aucmd_win = FALSE;
1447 curwin = win;
1448 }
1449 else
1450 {
1451 // There is no window for "buf", use "aucmd_win". To minimize the side
1452 // effects, insert it in the current tab page.
1453 // Anything related to a window (e.g., setting folds) may have
1454 // unexpected results.
1455 aco->use_aucmd_win = TRUE;
1456 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001457
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001458 win_init_popup_win(aucmd_win, buf);
1459
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001460 aco->globaldir = globaldir;
1461 globaldir = NULL;
1462
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001463 // Split the current window, put the aucmd_win in the upper half.
1464 // We don't want the BufEnter or WinEnter autocommands.
1465 block_autocmds();
1466 make_snapshot(SNAP_AUCMD_IDX);
1467 save_ea = p_ea;
1468 p_ea = FALSE;
1469
1470#ifdef FEAT_AUTOCHDIR
1471 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1472 save_acd = p_acd;
1473 p_acd = FALSE;
1474#endif
1475
1476 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
1477 (void)win_comp_pos(); // recompute window positions
1478 p_ea = save_ea;
1479#ifdef FEAT_AUTOCHDIR
1480 p_acd = save_acd;
1481#endif
1482 unblock_autocmds();
1483 curwin = aucmd_win;
1484 }
1485 curbuf = buf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001486 aco->new_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001487 set_bufref(&aco->new_curbuf, curbuf);
1488}
1489
1490/*
1491 * Cleanup after executing autocommands for a (hidden) buffer.
1492 * Restore the window as it was (if possible).
1493 */
1494 void
1495aucmd_restbuf(
1496 aco_save_T *aco) // structure holding saved values
1497{
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001498 int dummy;
1499 win_T *save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001500
1501 if (aco->use_aucmd_win)
1502 {
1503 --curbuf->b_nwindows;
1504 // Find "aucmd_win", it can't be closed, but it may be in another tab
1505 // page. Do not trigger autocommands here.
1506 block_autocmds();
1507 if (curwin != aucmd_win)
1508 {
1509 tabpage_T *tp;
1510 win_T *wp;
1511
1512 FOR_ALL_TAB_WINDOWS(tp, wp)
1513 {
1514 if (wp == aucmd_win)
1515 {
1516 if (tp != curtab)
1517 goto_tabpage_tp(tp, TRUE, TRUE);
1518 win_goto(aucmd_win);
1519 goto win_found;
1520 }
1521 }
1522 }
1523win_found:
1524
1525 // Remove the window and frame from the tree of frames.
1526 (void)winframe_remove(curwin, &dummy, NULL);
1527 win_remove(curwin, NULL);
1528 aucmd_win_used = FALSE;
1529 last_status(FALSE); // may need to remove last status line
1530
1531 if (!valid_tabpage_win(curtab))
1532 // no valid window in current tabpage
1533 close_tabpage(curtab);
1534
1535 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1536 (void)win_comp_pos(); // recompute window positions
1537 unblock_autocmds();
1538
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001539 save_curwin = win_find_by_id(aco->save_curwin_id);
1540 if (save_curwin != NULL)
1541 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001542 else
1543 // Hmm, original window disappeared. Just use the first one.
1544 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001545 curbuf = curwin->w_buffer;
1546#ifdef FEAT_JOB_CHANNEL
1547 // May need to restore insert mode for a prompt buffer.
1548 entering_window(curwin);
1549#endif
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001550 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001551#ifdef FEAT_EVAL
1552 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1553 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1554#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001555 vim_free(globaldir);
1556 globaldir = aco->globaldir;
1557
1558 // the buffer contents may have changed
1559 check_cursor();
1560 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1561 {
1562 curwin->w_topline = curbuf->b_ml.ml_line_count;
1563#ifdef FEAT_DIFF
1564 curwin->w_topfill = 0;
1565#endif
1566 }
1567#if defined(FEAT_GUI)
1568 // Hide the scrollbars from the aucmd_win and update.
1569 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1570 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1571 gui_may_update_scrollbars();
1572#endif
1573 }
1574 else
1575 {
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001576 // Restore curwin. Use the window ID, a window may have been closed
1577 // and the memory re-used for another one.
1578 save_curwin = win_find_by_id(aco->save_curwin_id);
1579 if (save_curwin != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001580 {
1581 // Restore the buffer which was previously edited by curwin, if
1582 // it was changed, we are still the same window and the buffer is
1583 // valid.
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001584 if (curwin->w_id == aco->new_curwin_id
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001585 && curbuf != aco->new_curbuf.br_buf
1586 && bufref_valid(&aco->new_curbuf)
1587 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1588 {
1589# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1590 if (curwin->w_s == &curbuf->b_s)
1591 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1592# endif
1593 --curbuf->b_nwindows;
1594 curbuf = aco->new_curbuf.br_buf;
1595 curwin->w_buffer = curbuf;
1596 ++curbuf->b_nwindows;
1597 }
1598
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001599 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001600 curbuf = curwin->w_buffer;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001601 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001602 // In case the autocommand moves the cursor to a position that
1603 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001604 check_cursor();
1605 }
1606 }
1607}
1608
1609static int autocmd_nested = FALSE;
1610
1611/*
1612 * Execute autocommands for "event" and file name "fname".
1613 * Return TRUE if some commands were executed.
1614 */
1615 int
1616apply_autocmds(
1617 event_T event,
1618 char_u *fname, // NULL or empty means use actual file name
1619 char_u *fname_io, // fname to use for <afile> on cmdline
1620 int force, // when TRUE, ignore autocmd_busy
1621 buf_T *buf) // buffer for <abuf>
1622{
1623 return apply_autocmds_group(event, fname, fname_io, force,
1624 AUGROUP_ALL, buf, NULL);
1625}
1626
1627/*
1628 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1629 * setting v:filearg.
1630 */
1631 int
1632apply_autocmds_exarg(
1633 event_T event,
1634 char_u *fname,
1635 char_u *fname_io,
1636 int force,
1637 buf_T *buf,
1638 exarg_T *eap)
1639{
1640 return apply_autocmds_group(event, fname, fname_io, force,
1641 AUGROUP_ALL, buf, eap);
1642}
1643
1644/*
1645 * Like apply_autocmds(), but handles the caller's retval. If the script
1646 * processing is being aborted or if retval is FAIL when inside a try
1647 * conditional, no autocommands are executed. If otherwise the autocommands
1648 * cause the script to be aborted, retval is set to FAIL.
1649 */
1650 int
1651apply_autocmds_retval(
1652 event_T event,
1653 char_u *fname, // NULL or empty means use actual file name
1654 char_u *fname_io, // fname to use for <afile> on cmdline
1655 int force, // when TRUE, ignore autocmd_busy
1656 buf_T *buf, // buffer for <abuf>
1657 int *retval) // pointer to caller's retval
1658{
1659 int did_cmd;
1660
1661#ifdef FEAT_EVAL
1662 if (should_abort(*retval))
1663 return FALSE;
1664#endif
1665
1666 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1667 AUGROUP_ALL, buf, NULL);
1668 if (did_cmd
1669#ifdef FEAT_EVAL
1670 && aborting()
1671#endif
1672 )
1673 *retval = FAIL;
1674 return did_cmd;
1675}
1676
1677/*
1678 * Return TRUE when there is a CursorHold autocommand defined.
1679 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001680 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001681has_cursorhold(void)
1682{
1683 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1684 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1685}
1686
1687/*
1688 * Return TRUE if the CursorHold event can be triggered.
1689 */
1690 int
1691trigger_cursorhold(void)
1692{
1693 int state;
1694
1695 if (!did_cursorhold
1696 && has_cursorhold()
1697 && reg_recording == 0
1698 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001699 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001700 {
1701 state = get_real_state();
1702 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1703 return TRUE;
1704 }
1705 return FALSE;
1706}
1707
1708/*
1709 * Return TRUE when there is a CursorMoved autocommand defined.
1710 */
1711 int
1712has_cursormoved(void)
1713{
1714 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1715}
1716
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001717/*
1718 * Return TRUE when there is a CursorMovedI autocommand defined.
1719 */
1720 int
1721has_cursormovedI(void)
1722{
1723 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1724}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001725
1726/*
1727 * Return TRUE when there is a TextChanged autocommand defined.
1728 */
1729 int
1730has_textchanged(void)
1731{
1732 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1733}
1734
1735/*
1736 * Return TRUE when there is a TextChangedI autocommand defined.
1737 */
1738 int
1739has_textchangedI(void)
1740{
1741 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1742}
1743
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001744/*
1745 * Return TRUE when there is a TextChangedP autocommand defined.
1746 */
1747 int
1748has_textchangedP(void)
1749{
1750 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1751}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001752
1753/*
1754 * Return TRUE when there is an InsertCharPre autocommand defined.
1755 */
1756 int
1757has_insertcharpre(void)
1758{
1759 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1760}
1761
1762/*
1763 * Return TRUE when there is an CmdUndefined autocommand defined.
1764 */
1765 int
1766has_cmdundefined(void)
1767{
1768 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1769}
1770
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001771#if defined(FEAT_EVAL) || defined(PROTO)
1772/*
1773 * Return TRUE when there is a TextYankPost autocommand defined.
1774 */
1775 int
1776has_textyankpost(void)
1777{
1778 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1779}
1780#endif
1781
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001782#if defined(FEAT_EVAL) || defined(PROTO)
1783/*
1784 * Return TRUE when there is a CompleteChanged autocommand defined.
1785 */
1786 int
1787has_completechanged(void)
1788{
1789 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1790}
1791#endif
1792
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001793/*
1794 * Execute autocommands for "event" and file name "fname".
1795 * Return TRUE if some commands were executed.
1796 */
1797 static int
1798apply_autocmds_group(
1799 event_T event,
1800 char_u *fname, // NULL or empty means use actual file name
1801 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1802 // use fname
1803 int force, // when TRUE, ignore autocmd_busy
1804 int group, // group ID, or AUGROUP_ALL
1805 buf_T *buf, // buffer for <abuf>
1806 exarg_T *eap UNUSED) // command arguments
1807{
1808 char_u *sfname = NULL; // short file name
1809 char_u *tail;
1810 int save_changed;
1811 buf_T *old_curbuf;
1812 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001813 char_u *save_autocmd_fname;
1814 int save_autocmd_fname_full;
1815 int save_autocmd_bufnr;
1816 char_u *save_autocmd_match;
1817 int save_autocmd_busy;
1818 int save_autocmd_nested;
1819 static int nesting = 0;
1820 AutoPatCmd patcmd;
1821 AutoPat *ap;
1822#ifdef FEAT_EVAL
1823 sctx_T save_current_sctx;
1824 funccal_entry_T funccal_entry;
1825 char_u *save_cmdarg;
1826 long save_cmdbang;
1827#endif
1828 static int filechangeshell_busy = FALSE;
1829#ifdef FEAT_PROFILE
1830 proftime_T wait_time;
1831#endif
1832 int did_save_redobuff = FALSE;
1833 save_redo_T save_redo;
1834 int save_KeyTyped = KeyTyped;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001835 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001836
1837 /*
1838 * Quickly return if there are no autocommands for this event or
1839 * autocommands are blocked.
1840 */
1841 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1842 || autocmd_blocked > 0)
1843 goto BYPASS_AU;
1844
1845 /*
1846 * When autocommands are busy, new autocommands are only executed when
1847 * explicitly enabled with the "nested" flag.
1848 */
1849 if (autocmd_busy && !(force || autocmd_nested))
1850 goto BYPASS_AU;
1851
1852#ifdef FEAT_EVAL
1853 /*
1854 * Quickly return when immediately aborting on error, or when an interrupt
1855 * occurred or an exception was thrown but not caught.
1856 */
1857 if (aborting())
1858 goto BYPASS_AU;
1859#endif
1860
1861 /*
1862 * FileChangedShell never nests, because it can create an endless loop.
1863 */
1864 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1865 || event == EVENT_FILECHANGEDSHELLPOST))
1866 goto BYPASS_AU;
1867
1868 /*
1869 * Ignore events in 'eventignore'.
1870 */
1871 if (event_ignored(event))
1872 goto BYPASS_AU;
1873
1874 /*
1875 * Allow nesting of autocommands, but restrict the depth, because it's
1876 * possible to create an endless loop.
1877 */
1878 if (nesting == 10)
1879 {
1880 emsg(_("E218: autocommand nesting too deep"));
1881 goto BYPASS_AU;
1882 }
1883
1884 /*
1885 * Check if these autocommands are disabled. Used when doing ":all" or
1886 * ":ball".
1887 */
1888 if ( (autocmd_no_enter
1889 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1890 || (autocmd_no_leave
1891 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1892 goto BYPASS_AU;
1893
1894 /*
1895 * Save the autocmd_* variables and info about the current buffer.
1896 */
1897 save_autocmd_fname = autocmd_fname;
1898 save_autocmd_fname_full = autocmd_fname_full;
1899 save_autocmd_bufnr = autocmd_bufnr;
1900 save_autocmd_match = autocmd_match;
1901 save_autocmd_busy = autocmd_busy;
1902 save_autocmd_nested = autocmd_nested;
1903 save_changed = curbuf->b_changed;
1904 old_curbuf = curbuf;
1905
1906 /*
1907 * Set the file name to be used for <afile>.
1908 * Make a copy to avoid that changing a buffer name or directory makes it
1909 * invalid.
1910 */
1911 if (fname_io == NULL)
1912 {
1913 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
1914 || event == EVENT_OPTIONSET)
1915 autocmd_fname = NULL;
1916 else if (fname != NULL && !ends_excmd(*fname))
1917 autocmd_fname = fname;
1918 else if (buf != NULL)
1919 autocmd_fname = buf->b_ffname;
1920 else
1921 autocmd_fname = NULL;
1922 }
1923 else
1924 autocmd_fname = fname_io;
1925 if (autocmd_fname != NULL)
1926 autocmd_fname = vim_strsave(autocmd_fname);
1927 autocmd_fname_full = FALSE; // call FullName_save() later
1928
1929 /*
1930 * Set the buffer number to be used for <abuf>.
1931 */
1932 if (buf == NULL)
1933 autocmd_bufnr = 0;
1934 else
1935 autocmd_bufnr = buf->b_fnum;
1936
1937 /*
1938 * When the file name is NULL or empty, use the file name of buffer "buf".
1939 * Always use the full path of the file name to match with, in case
1940 * "allow_dirs" is set.
1941 */
1942 if (fname == NULL || *fname == NUL)
1943 {
1944 if (buf == NULL)
1945 fname = NULL;
1946 else
1947 {
1948#ifdef FEAT_SYN_HL
1949 if (event == EVENT_SYNTAX)
1950 fname = buf->b_p_syn;
1951 else
1952#endif
1953 if (event == EVENT_FILETYPE)
1954 fname = buf->b_p_ft;
1955 else
1956 {
1957 if (buf->b_sfname != NULL)
1958 sfname = vim_strsave(buf->b_sfname);
1959 fname = buf->b_ffname;
1960 }
1961 }
1962 if (fname == NULL)
1963 fname = (char_u *)"";
1964 fname = vim_strsave(fname); // make a copy, so we can change it
1965 }
1966 else
1967 {
1968 sfname = vim_strsave(fname);
1969 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
1970 // ColorScheme, QuickFixCmd* or DirChanged
1971 if (event == EVENT_FILETYPE
1972 || event == EVENT_SYNTAX
1973 || event == EVENT_CMDLINECHANGED
1974 || event == EVENT_CMDLINEENTER
1975 || event == EVENT_CMDLINELEAVE
1976 || event == EVENT_CMDWINENTER
1977 || event == EVENT_CMDWINLEAVE
1978 || event == EVENT_CMDUNDEFINED
1979 || event == EVENT_FUNCUNDEFINED
1980 || event == EVENT_REMOTEREPLY
1981 || event == EVENT_SPELLFILEMISSING
1982 || event == EVENT_QUICKFIXCMDPRE
1983 || event == EVENT_COLORSCHEME
1984 || event == EVENT_COLORSCHEMEPRE
1985 || event == EVENT_OPTIONSET
1986 || event == EVENT_QUICKFIXCMDPOST
1987 || event == EVENT_DIRCHANGED)
1988 {
1989 fname = vim_strsave(fname);
1990 autocmd_fname_full = TRUE; // don't expand it later
1991 }
1992 else
1993 fname = FullName_save(fname, FALSE);
1994 }
1995 if (fname == NULL) // out of memory
1996 {
1997 vim_free(sfname);
1998 retval = FALSE;
1999 goto BYPASS_AU;
2000 }
2001
2002#ifdef BACKSLASH_IN_FILENAME
2003 /*
2004 * Replace all backslashes with forward slashes. This makes the
2005 * autocommand patterns portable between Unix and MS-DOS.
2006 */
2007 if (sfname != NULL)
2008 forward_slash(sfname);
2009 forward_slash(fname);
2010#endif
2011
2012#ifdef VMS
2013 // remove version for correct match
2014 if (sfname != NULL)
2015 vms_remove_version(sfname);
2016 vms_remove_version(fname);
2017#endif
2018
2019 /*
2020 * Set the name to be used for <amatch>.
2021 */
2022 autocmd_match = fname;
2023
2024
2025 // Don't redraw while doing autocommands.
2026 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002027
2028 // name and lnum are filled in later
2029 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002030 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002031
2032#ifdef FEAT_EVAL
2033 save_current_sctx = current_sctx;
2034
2035# ifdef FEAT_PROFILE
2036 if (do_profiling == PROF_YES)
2037 prof_child_enter(&wait_time); // doesn't count for the caller itself
2038# endif
2039
2040 // Don't use local function variables, if called from a function.
2041 save_funccal(&funccal_entry);
2042#endif
2043
2044 /*
2045 * When starting to execute autocommands, save the search patterns.
2046 */
2047 if (!autocmd_busy)
2048 {
2049 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002050 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002051 {
2052 saveRedobuff(&save_redo);
2053 did_save_redobuff = TRUE;
2054 }
2055 did_filetype = keep_filetype;
2056 }
2057
2058 /*
2059 * Note that we are applying autocmds. Some commands need to know.
2060 */
2061 autocmd_busy = TRUE;
2062 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2063 ++nesting; // see matching decrement below
2064
2065 // Remember that FileType was triggered. Used for did_filetype().
2066 if (event == EVENT_FILETYPE)
2067 did_filetype = TRUE;
2068
2069 tail = gettail(fname);
2070
2071 // Find first autocommand that matches
2072 patcmd.curpat = first_autopat[(int)event];
2073 patcmd.nextcmd = NULL;
2074 patcmd.group = group;
2075 patcmd.fname = fname;
2076 patcmd.sfname = sfname;
2077 patcmd.tail = tail;
2078 patcmd.event = event;
2079 patcmd.arg_bufnr = autocmd_bufnr;
2080 patcmd.next = NULL;
2081 auto_next_pat(&patcmd, FALSE);
2082
2083 // found one, start executing the autocommands
2084 if (patcmd.curpat != NULL)
2085 {
2086 // add to active_apc_list
2087 patcmd.next = active_apc_list;
2088 active_apc_list = &patcmd;
2089
2090#ifdef FEAT_EVAL
2091 // set v:cmdarg (only when there is a matching pattern)
2092 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2093 if (eap != NULL)
2094 {
2095 save_cmdarg = set_cmdarg(eap, NULL);
2096 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2097 }
2098 else
2099 save_cmdarg = NULL; // avoid gcc warning
2100#endif
2101 retval = TRUE;
2102 // mark the last pattern, to avoid an endless loop when more patterns
2103 // are added when executing autocommands
2104 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2105 ap->last = FALSE;
2106 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002107
2108 // make sure cursor and topline are valid
2109 check_lnums(TRUE);
2110
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002111 do_cmdline(NULL, getnextac, (void *)&patcmd,
2112 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002113
2114 // restore cursor and topline, unless they were changed
2115 reset_lnums();
2116
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002117#ifdef FEAT_EVAL
2118 if (eap != NULL)
2119 {
2120 (void)set_cmdarg(NULL, save_cmdarg);
2121 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2122 }
2123#endif
2124 // delete from active_apc_list
2125 if (active_apc_list == &patcmd) // just in case
2126 active_apc_list = patcmd.next;
2127 }
2128
2129 --RedrawingDisabled;
2130 autocmd_busy = save_autocmd_busy;
2131 filechangeshell_busy = FALSE;
2132 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002133 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002134 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002135 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002136 vim_free(autocmd_fname);
2137 autocmd_fname = save_autocmd_fname;
2138 autocmd_fname_full = save_autocmd_fname_full;
2139 autocmd_bufnr = save_autocmd_bufnr;
2140 autocmd_match = save_autocmd_match;
2141#ifdef FEAT_EVAL
2142 current_sctx = save_current_sctx;
2143 restore_funccal();
2144# ifdef FEAT_PROFILE
2145 if (do_profiling == PROF_YES)
2146 prof_child_exit(&wait_time);
2147# endif
2148#endif
2149 KeyTyped = save_KeyTyped;
2150 vim_free(fname);
2151 vim_free(sfname);
2152 --nesting; // see matching increment above
2153
2154 /*
2155 * When stopping to execute autocommands, restore the search patterns and
2156 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2157 * free any windows in the au_pending_free_win list.
2158 */
2159 if (!autocmd_busy)
2160 {
2161 restore_search_patterns();
2162 if (did_save_redobuff)
2163 restoreRedobuff(&save_redo);
2164 did_filetype = FALSE;
2165 while (au_pending_free_buf != NULL)
2166 {
2167 buf_T *b = au_pending_free_buf->b_next;
2168 vim_free(au_pending_free_buf);
2169 au_pending_free_buf = b;
2170 }
2171 while (au_pending_free_win != NULL)
2172 {
2173 win_T *w = au_pending_free_win->w_next;
2174 vim_free(au_pending_free_win);
2175 au_pending_free_win = w;
2176 }
2177 }
2178
2179 /*
2180 * Some events don't set or reset the Changed flag.
2181 * Check if still in the same buffer!
2182 */
2183 if (curbuf == old_curbuf
2184 && (event == EVENT_BUFREADPOST
2185 || event == EVENT_BUFWRITEPOST
2186 || event == EVENT_FILEAPPENDPOST
2187 || event == EVENT_VIMLEAVE
2188 || event == EVENT_VIMLEAVEPRE))
2189 {
2190#ifdef FEAT_TITLE
2191 if (curbuf->b_changed != save_changed)
2192 need_maketitle = TRUE;
2193#endif
2194 curbuf->b_changed = save_changed;
2195 }
2196
2197 au_cleanup(); // may really delete removed patterns/commands now
2198
2199BYPASS_AU:
2200 // When wiping out a buffer make sure all its buffer-local autocommands
2201 // are deleted.
2202 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2203 aubuflocal_remove(buf);
2204
2205 if (retval == OK && event == EVENT_FILETYPE)
2206 au_did_filetype = TRUE;
2207
2208 return retval;
2209}
2210
2211# ifdef FEAT_EVAL
2212static char_u *old_termresponse = NULL;
2213# endif
2214
2215/*
2216 * Block triggering autocommands until unblock_autocmd() is called.
2217 * Can be used recursively, so long as it's symmetric.
2218 */
2219 void
2220block_autocmds(void)
2221{
2222# ifdef FEAT_EVAL
2223 // Remember the value of v:termresponse.
2224 if (autocmd_blocked == 0)
2225 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2226# endif
2227 ++autocmd_blocked;
2228}
2229
2230 void
2231unblock_autocmds(void)
2232{
2233 --autocmd_blocked;
2234
2235# ifdef FEAT_EVAL
2236 // When v:termresponse was set while autocommands were blocked, trigger
2237 // the autocommands now. Esp. useful when executing a shell command
2238 // during startup (vimdiff).
2239 if (autocmd_blocked == 0
2240 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2241 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2242# endif
2243}
2244
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002245 int
2246is_autocmd_blocked(void)
2247{
2248 return autocmd_blocked != 0;
2249}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002250
2251/*
2252 * Find next autocommand pattern that matches.
2253 */
2254 static void
2255auto_next_pat(
2256 AutoPatCmd *apc,
2257 int stop_at_last) // stop when 'last' flag is set
2258{
2259 AutoPat *ap;
2260 AutoCmd *cp;
2261 char_u *name;
2262 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002263 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002264
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002265 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002266
2267 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2268 {
2269 apc->curpat = NULL;
2270
2271 // Only use a pattern when it has not been removed, has commands and
2272 // the group matches. For buffer-local autocommands only check the
2273 // buffer number.
2274 if (ap->pat != NULL && ap->cmds != NULL
2275 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2276 {
2277 // execution-condition
2278 if (ap->buflocal_nr == 0
2279 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2280 apc->sfname, apc->tail, ap->allow_dirs))
2281 : ap->buflocal_nr == apc->arg_bufnr)
2282 {
2283 name = event_nr2name(apc->event);
2284 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002285 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002286 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002287 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002288 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002289 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002290 (char *)name, (char *)ap->pat);
2291 if (p_verbose >= 8)
2292 {
2293 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002294 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002295 verbose_leave();
2296 }
2297 }
2298
2299 apc->curpat = ap;
2300 apc->nextcmd = ap->cmds;
2301 // mark last command
2302 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2303 cp->last = FALSE;
2304 cp->last = TRUE;
2305 }
2306 line_breakcheck();
2307 if (apc->curpat != NULL) // found a match
2308 break;
2309 }
2310 if (stop_at_last && ap->last)
2311 break;
2312 }
2313}
2314
2315/*
2316 * Get next autocommand command.
2317 * Called by do_cmdline() to get the next line for ":if".
2318 * Returns allocated string, or NULL for end of autocommands.
2319 */
2320 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002321getnextac(
2322 int c UNUSED,
2323 void *cookie,
2324 int indent UNUSED,
2325 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002326{
2327 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2328 char_u *retval;
2329 AutoCmd *ac;
2330
2331 // Can be called again after returning the last line.
2332 if (acp->curpat == NULL)
2333 return NULL;
2334
2335 // repeat until we find an autocommand to execute
2336 for (;;)
2337 {
2338 // skip removed commands
2339 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2340 if (acp->nextcmd->last)
2341 acp->nextcmd = NULL;
2342 else
2343 acp->nextcmd = acp->nextcmd->next;
2344
2345 if (acp->nextcmd != NULL)
2346 break;
2347
2348 // at end of commands, find next pattern that matches
2349 if (acp->curpat->last)
2350 acp->curpat = NULL;
2351 else
2352 acp->curpat = acp->curpat->next;
2353 if (acp->curpat != NULL)
2354 auto_next_pat(acp, TRUE);
2355 if (acp->curpat == NULL)
2356 return NULL;
2357 }
2358
2359 ac = acp->nextcmd;
2360
2361 if (p_verbose >= 9)
2362 {
2363 verbose_enter_scroll();
2364 smsg(_("autocommand %s"), ac->cmd);
2365 msg_puts("\n"); // don't overwrite this either
2366 verbose_leave_scroll();
2367 }
2368 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002369 // Remove one-shot ("once") autocmd in anticipation of its execution.
2370 if (ac->once)
2371 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002372 autocmd_nested = ac->nested;
2373#ifdef FEAT_EVAL
2374 current_sctx = ac->script_ctx;
2375#endif
2376 if (ac->last)
2377 acp->nextcmd = NULL;
2378 else
2379 acp->nextcmd = ac->next;
2380 return retval;
2381}
2382
2383/*
2384 * Return TRUE if there is a matching autocommand for "fname".
2385 * To account for buffer-local autocommands, function needs to know
2386 * in which buffer the file will be opened.
2387 */
2388 int
2389has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2390{
2391 AutoPat *ap;
2392 char_u *fname;
2393 char_u *tail = gettail(sfname);
2394 int retval = FALSE;
2395
2396 fname = FullName_save(sfname, FALSE);
2397 if (fname == NULL)
2398 return FALSE;
2399
2400#ifdef BACKSLASH_IN_FILENAME
2401 /*
2402 * Replace all backslashes with forward slashes. This makes the
2403 * autocommand patterns portable between Unix and MS-DOS.
2404 */
2405 sfname = vim_strsave(sfname);
2406 if (sfname != NULL)
2407 forward_slash(sfname);
2408 forward_slash(fname);
2409#endif
2410
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002411 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002412 if (ap->pat != NULL && ap->cmds != NULL
2413 && (ap->buflocal_nr == 0
2414 ? match_file_pat(NULL, &ap->reg_prog,
2415 fname, sfname, tail, ap->allow_dirs)
2416 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2417 ))
2418 {
2419 retval = TRUE;
2420 break;
2421 }
2422
2423 vim_free(fname);
2424#ifdef BACKSLASH_IN_FILENAME
2425 vim_free(sfname);
2426#endif
2427
2428 return retval;
2429}
2430
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002431/*
2432 * Function given to ExpandGeneric() to obtain the list of autocommand group
2433 * names.
2434 */
2435 char_u *
2436get_augroup_name(expand_T *xp UNUSED, int idx)
2437{
2438 if (idx == augroups.ga_len) // add "END" add the end
2439 return (char_u *)"END";
2440 if (idx >= augroups.ga_len) // end of list
2441 return NULL;
2442 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2443 // skip deleted entries
2444 return (char_u *)"";
2445 return AUGROUP_NAME(idx); // return a name
2446}
2447
2448static int include_groups = FALSE;
2449
2450 char_u *
2451set_context_in_autocmd(
2452 expand_T *xp,
2453 char_u *arg,
2454 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2455{
2456 char_u *p;
2457 int group;
2458
2459 // check for a group name, skip it if present
2460 include_groups = FALSE;
2461 p = arg;
2462 group = au_get_grouparg(&arg);
2463 if (group == AUGROUP_ERROR)
2464 return NULL;
2465 // If there only is a group name that's what we expand.
2466 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2467 {
2468 arg = p;
2469 group = AUGROUP_ALL;
2470 }
2471
2472 // skip over event name
2473 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2474 if (*p == ',')
2475 arg = p + 1;
2476 if (*p == NUL)
2477 {
2478 if (group == AUGROUP_ALL)
2479 include_groups = TRUE;
2480 xp->xp_context = EXPAND_EVENTS; // expand event name
2481 xp->xp_pattern = arg;
2482 return NULL;
2483 }
2484
2485 // skip over pattern
2486 arg = skipwhite(p);
2487 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2488 arg++;
2489 if (*arg)
2490 return arg; // expand (next) command
2491
2492 if (doautocmd)
2493 xp->xp_context = EXPAND_FILES; // expand file names
2494 else
2495 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2496 return NULL;
2497}
2498
2499/*
2500 * Function given to ExpandGeneric() to obtain the list of event names.
2501 */
2502 char_u *
2503get_event_name(expand_T *xp UNUSED, int idx)
2504{
2505 if (idx < augroups.ga_len) // First list group names, if wanted
2506 {
2507 if (!include_groups || AUGROUP_NAME(idx) == NULL
2508 || AUGROUP_NAME(idx) == get_deleted_augroup())
2509 return (char_u *)""; // skip deleted entries
2510 return AUGROUP_NAME(idx); // return a name
2511 }
2512 return (char_u *)event_names[idx - augroups.ga_len].name;
2513}
2514
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002515
2516#if defined(FEAT_EVAL) || defined(PROTO)
2517/*
2518 * Return TRUE if autocmd is supported.
2519 */
2520 int
2521autocmd_supported(char_u *name)
2522{
2523 char_u *p;
2524
2525 return (event_name2nr(name, &p) != NUM_EVENTS);
2526}
2527
2528/*
2529 * Return TRUE if an autocommand is defined for a group, event and
2530 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2531 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2532 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2533 * Used for:
2534 * exists("#Group") or
2535 * exists("#Group#Event") or
2536 * exists("#Group#Event#pat") or
2537 * exists("#Event") or
2538 * exists("#Event#pat")
2539 */
2540 int
2541au_exists(char_u *arg)
2542{
2543 char_u *arg_save;
2544 char_u *pattern = NULL;
2545 char_u *event_name;
2546 char_u *p;
2547 event_T event;
2548 AutoPat *ap;
2549 buf_T *buflocal_buf = NULL;
2550 int group;
2551 int retval = FALSE;
2552
2553 // Make a copy so that we can change the '#' chars to a NUL.
2554 arg_save = vim_strsave(arg);
2555 if (arg_save == NULL)
2556 return FALSE;
2557 p = vim_strchr(arg_save, '#');
2558 if (p != NULL)
2559 *p++ = NUL;
2560
2561 // First, look for an autocmd group name
2562 group = au_find_group(arg_save);
2563 if (group == AUGROUP_ERROR)
2564 {
2565 // Didn't match a group name, assume the first argument is an event.
2566 group = AUGROUP_ALL;
2567 event_name = arg_save;
2568 }
2569 else
2570 {
2571 if (p == NULL)
2572 {
2573 // "Group": group name is present and it's recognized
2574 retval = TRUE;
2575 goto theend;
2576 }
2577
2578 // Must be "Group#Event" or "Group#Event#pat".
2579 event_name = p;
2580 p = vim_strchr(event_name, '#');
2581 if (p != NULL)
2582 *p++ = NUL; // "Group#Event#pat"
2583 }
2584
2585 pattern = p; // "pattern" is NULL when there is no pattern
2586
2587 // find the index (enum) for the event name
2588 event = event_name2nr(event_name, &p);
2589
2590 // return FALSE if the event name is not recognized
2591 if (event == NUM_EVENTS)
2592 goto theend;
2593
2594 // Find the first autocommand for this event.
2595 // If there isn't any, return FALSE;
2596 // If there is one and no pattern given, return TRUE;
2597 ap = first_autopat[(int)event];
2598 if (ap == NULL)
2599 goto theend;
2600
2601 // if pattern is "<buffer>", special handling is needed which uses curbuf
2602 // for pattern "<buffer=N>, fnamecmp() will work fine
2603 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2604 buflocal_buf = curbuf;
2605
2606 // Check if there is an autocommand with the given pattern.
2607 for ( ; ap != NULL; ap = ap->next)
2608 // only use a pattern when it has not been removed and has commands.
2609 // For buffer-local autocommands, fnamecmp() works fine.
2610 if (ap->pat != NULL && ap->cmds != NULL
2611 && (group == AUGROUP_ALL || ap->group == group)
2612 && (pattern == NULL
2613 || (buflocal_buf == NULL
2614 ? fnamecmp(ap->pat, pattern) == 0
2615 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2616 {
2617 retval = TRUE;
2618 break;
2619 }
2620
2621theend:
2622 vim_free(arg_save);
2623 return retval;
2624}
2625#endif