blob: ede8e7dbe0b7d3ceaae9717cf815cd7e689c89fa [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 Moolenaareb93f3f2019-04-04 15:04:56 +0200261static 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 +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)
618 do_autocmd((char_u *)"", TRUE);
619
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>.
826 */
827 void
828do_autocmd(char_u *arg_in, int forceit)
829{
830 char_u *arg = arg_in;
831 char_u *pat;
832 char_u *envpat = NULL;
833 char_u *cmd;
834 event_T event;
835 int need_free = FALSE;
836 int nested = FALSE;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200837 int once = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100838 int group;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200839 int i;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100840
841 if (*arg == '|')
842 {
843 arg = (char_u *)"";
844 group = AUGROUP_ALL; // no argument, use all groups
845 }
846 else
847 {
848 /*
849 * Check for a legal group name. If not, use AUGROUP_ALL.
850 */
851 group = au_get_grouparg(&arg);
852 if (arg == NULL) // out of memory
853 return;
854 }
855
856 /*
857 * Scan over the events.
858 * If we find an illegal name, return here, don't do anything.
859 */
860 pat = find_end_event(arg, group != AUGROUP_ALL);
861 if (pat == NULL)
862 return;
863
864 pat = skipwhite(pat);
865 if (*pat == '|')
866 {
867 pat = (char_u *)"";
868 cmd = (char_u *)"";
869 }
870 else
871 {
872 /*
873 * Scan over the pattern. Put a NUL at the end.
874 */
875 cmd = pat;
876 while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
877 cmd++;
878 if (*cmd)
879 *cmd++ = NUL;
880
881 // Expand environment variables in the pattern. Set 'shellslash', we
882 // want forward slashes here.
883 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
884 {
885#ifdef BACKSLASH_IN_FILENAME
886 int p_ssl_save = p_ssl;
887
888 p_ssl = TRUE;
889#endif
890 envpat = expand_env_save(pat);
891#ifdef BACKSLASH_IN_FILENAME
892 p_ssl = p_ssl_save;
893#endif
894 if (envpat != NULL)
895 pat = envpat;
896 }
897
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100898 cmd = skipwhite(cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200899 for (i = 0; i < 2; i++)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100900 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200901 if (*cmd != NUL)
902 {
903 // Check for "++once" flag.
904 if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
905 {
906 if (once)
907 semsg(_(e_duparg2), "++once");
908 once = TRUE;
909 cmd = skipwhite(cmd + 6);
910 }
911
912 // Check for "++nested" flag.
913 if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
914 {
915 if (nested)
916 semsg(_(e_duparg2), "++nested");
917 nested = TRUE;
918 cmd = skipwhite(cmd + 8);
919 }
920
921 // Check for the old "nested" flag.
922 if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
923 {
924 if (nested)
925 semsg(_(e_duparg2), "nested");
926 nested = TRUE;
927 cmd = skipwhite(cmd + 6);
928 }
929 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100930 }
931
932 /*
933 * Find the start of the commands.
934 * Expand <sfile> in it.
935 */
936 if (*cmd != NUL)
937 {
938 cmd = expand_sfile(cmd);
939 if (cmd == NULL) // some error
940 return;
941 need_free = TRUE;
942 }
943 }
944
945 /*
946 * Print header when showing autocommands.
947 */
948 if (!forceit && *cmd == NUL)
949 // Highlight title
950 msg_puts_title(_("\n--- Autocommands ---"));
951
952 /*
953 * Loop over the events.
954 */
955 last_event = (event_T)-1; // for listing the event name
956 last_group = AUGROUP_ERROR; // for listing the group name
957 if (*arg == '*' || *arg == NUL || *arg == '|')
958 {
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100959 if (!forceit && *cmd != NUL)
960 emsg(_(e_cannot_define_autocommands_for_all_events));
961 else
962 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
963 event = (event_T)((int)event + 1))
964 if (do_autocmd_event(event, pat,
965 once, nested, cmd, forceit, group) == FAIL)
966 break;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100967 }
968 else
969 {
970 while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
971 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200972 once, nested, cmd, forceit, group) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100973 break;
974 }
975
976 if (need_free)
977 vim_free(cmd);
978 vim_free(envpat);
979}
980
981/*
982 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
983 * The "argp" argument is advanced to the following argument.
984 *
985 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
986 */
987 static int
988au_get_grouparg(char_u **argp)
989{
990 char_u *group_name;
991 char_u *p;
992 char_u *arg = *argp;
993 int group = AUGROUP_ALL;
994
995 for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
996 ;
997 if (p > arg)
998 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200999 group_name = vim_strnsave(arg, p - arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001000 if (group_name == NULL) // out of memory
1001 return AUGROUP_ERROR;
1002 group = au_find_group(group_name);
1003 if (group == AUGROUP_ERROR)
1004 group = AUGROUP_ALL; // no match, use all groups
1005 else
1006 *argp = skipwhite(p); // match, skip over group name
1007 vim_free(group_name);
1008 }
1009 return group;
1010}
1011
1012/*
1013 * do_autocmd() for one event.
1014 * If *pat == NUL do for all patterns.
1015 * If *cmd == NUL show entries.
1016 * If forceit == TRUE delete entries.
1017 * If group is not AUGROUP_ALL, only use this group.
1018 */
1019 static int
1020do_autocmd_event(
1021 event_T event,
1022 char_u *pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001023 int once,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001024 int nested,
1025 char_u *cmd,
1026 int forceit,
1027 int group)
1028{
1029 AutoPat *ap;
1030 AutoPat **prev_ap;
1031 AutoCmd *ac;
1032 AutoCmd **prev_ac;
1033 int brace_level;
1034 char_u *endpat;
1035 int findgroup;
1036 int allgroups;
1037 int patlen;
1038 int is_buflocal;
1039 int buflocal_nr;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001040 char_u buflocal_pat[25]; // for "<buffer=X>"
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001041
1042 if (group == AUGROUP_ALL)
1043 findgroup = current_augroup;
1044 else
1045 findgroup = group;
1046 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
1047
1048 /*
1049 * Show or delete all patterns for an event.
1050 */
1051 if (*pat == NUL)
1052 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001053 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001054 {
1055 if (forceit) // delete the AutoPat, if it's in the current group
1056 {
1057 if (ap->group == findgroup)
1058 au_remove_pat(ap);
1059 }
1060 else if (group == AUGROUP_ALL || ap->group == group)
1061 show_autocmd(ap, event);
1062 }
1063 }
1064
1065 /*
1066 * Loop through all the specified patterns.
1067 */
1068 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
1069 {
1070 /*
1071 * Find end of the pattern.
1072 * Watch out for a comma in braces, like "*.\{obj,o\}".
1073 */
1074 brace_level = 0;
1075 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
1076 || (endpat > pat && endpat[-1] == '\\')); ++endpat)
1077 {
1078 if (*endpat == '{')
1079 brace_level++;
1080 else if (*endpat == '}')
1081 brace_level--;
1082 }
1083 if (pat == endpat) // ignore single comma
1084 continue;
1085 patlen = (int)(endpat - pat);
1086
1087 /*
1088 * detect special <buflocal[=X]> buffer-local patterns
1089 */
1090 is_buflocal = FALSE;
1091 buflocal_nr = 0;
1092
1093 if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
1094 && pat[patlen - 1] == '>')
1095 {
1096 // "<buffer...>": Error will be printed only for addition.
1097 // printing and removing will proceed silently.
1098 is_buflocal = TRUE;
1099 if (patlen == 8)
1100 // "<buffer>"
1101 buflocal_nr = curbuf->b_fnum;
1102 else if (patlen > 9 && pat[7] == '=')
1103 {
1104 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
1105 // "<buffer=abuf>"
1106 buflocal_nr = autocmd_bufnr;
1107 else if (skipdigits(pat + 8) == pat + patlen - 1)
1108 // "<buffer=123>"
1109 buflocal_nr = atoi((char *)pat + 8);
1110 }
1111 }
1112
1113 if (is_buflocal)
1114 {
1115 // normalize pat into standard "<buffer>#N" form
1116 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
1117 pat = buflocal_pat; // can modify pat and patlen
1118 patlen = (int)STRLEN(buflocal_pat); // but not endpat
1119 }
1120
1121 /*
1122 * Find AutoPat entries with this pattern. When adding a command it
1123 * always goes at or after the last one, so start at the end.
1124 */
1125 if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
1126 prev_ap = &last_autopat[(int)event];
1127 else
1128 prev_ap = &first_autopat[(int)event];
1129 while ((ap = *prev_ap) != NULL)
1130 {
1131 if (ap->pat != NULL)
1132 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001133 /*
1134 * Accept a pattern when:
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001135 * - a group was specified and it's that group, or a group was
1136 * not specified and it's the current group, or a group was
1137 * not specified and we are listing
1138 * - the length of the pattern matches
1139 * - the pattern matches.
1140 * For <buffer[=X]>, this condition works because we normalize
1141 * all buffer-local patterns.
1142 */
1143 if ((allgroups || ap->group == findgroup)
1144 && ap->patlen == patlen
1145 && STRNCMP(pat, ap->pat, patlen) == 0)
1146 {
1147 /*
1148 * Remove existing autocommands.
1149 * If adding any new autocmd's for this AutoPat, don't
1150 * delete the pattern from the autopat list, append to
1151 * this list.
1152 */
1153 if (forceit)
1154 {
1155 if (*cmd != NUL && ap->next == NULL)
1156 {
1157 au_remove_cmds(ap);
1158 break;
1159 }
1160 au_remove_pat(ap);
1161 }
1162
1163 /*
1164 * Show autocmd's for this autopat, or buflocals <buffer=X>
1165 */
1166 else if (*cmd == NUL)
1167 show_autocmd(ap, event);
1168
1169 /*
1170 * Add autocmd to this autopat, if it's the last one.
1171 */
1172 else if (ap->next == NULL)
1173 break;
1174 }
1175 }
1176 prev_ap = &ap->next;
1177 }
1178
1179 /*
1180 * Add a new command.
1181 */
1182 if (*cmd != NUL)
1183 {
1184 /*
1185 * If the pattern we want to add a command to does appear at the
1186 * end of the list (or not is not in the list at all), add the
1187 * pattern at the end of the list.
1188 */
1189 if (ap == NULL)
1190 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001191 // refuse to add buffer-local ap if buffer number is invalid
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001192 if (is_buflocal && (buflocal_nr == 0
1193 || buflist_findnr(buflocal_nr) == NULL))
1194 {
1195 semsg(_("E680: <buffer=%d>: invalid buffer number "),
1196 buflocal_nr);
1197 return FAIL;
1198 }
1199
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001200 ap = ALLOC_ONE(AutoPat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001201 if (ap == NULL)
1202 return FAIL;
1203 ap->pat = vim_strnsave(pat, patlen);
1204 ap->patlen = patlen;
1205 if (ap->pat == NULL)
1206 {
1207 vim_free(ap);
1208 return FAIL;
1209 }
1210
1211 if (is_buflocal)
1212 {
1213 ap->buflocal_nr = buflocal_nr;
1214 ap->reg_prog = NULL;
1215 }
1216 else
1217 {
1218 char_u *reg_pat;
1219
1220 ap->buflocal_nr = 0;
1221 reg_pat = file_pat_to_reg_pat(pat, endpat,
1222 &ap->allow_dirs, TRUE);
1223 if (reg_pat != NULL)
1224 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1225 vim_free(reg_pat);
1226 if (reg_pat == NULL || ap->reg_prog == NULL)
1227 {
1228 vim_free(ap->pat);
1229 vim_free(ap);
1230 return FAIL;
1231 }
1232 }
1233 ap->cmds = NULL;
1234 *prev_ap = ap;
1235 last_autopat[(int)event] = ap;
1236 ap->next = NULL;
1237 if (group == AUGROUP_ALL)
1238 ap->group = current_augroup;
1239 else
1240 ap->group = group;
1241 }
1242
1243 /*
1244 * Add the autocmd at the end of the AutoCmd list.
1245 */
1246 prev_ac = &(ap->cmds);
1247 while ((ac = *prev_ac) != NULL)
1248 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001249 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001250 if (ac == NULL)
1251 return FAIL;
1252 ac->cmd = vim_strsave(cmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001253 ac->script_ctx = current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001254#ifdef FEAT_EVAL
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001255 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001256#endif
1257 if (ac->cmd == NULL)
1258 {
1259 vim_free(ac);
1260 return FAIL;
1261 }
1262 ac->next = NULL;
1263 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001264 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001265 ac->nested = nested;
1266 }
1267 }
1268
1269 au_cleanup(); // may really delete removed patterns/commands now
1270 return OK;
1271}
1272
1273/*
1274 * Implementation of ":doautocmd [group] event [fname]".
1275 * Return OK for success, FAIL for failure;
1276 */
1277 int
1278do_doautocmd(
1279 char_u *arg,
1280 int do_msg, // give message for no matching autocmds?
1281 int *did_something)
1282{
1283 char_u *fname;
1284 int nothing_done = TRUE;
1285 int group;
1286
1287 if (did_something != NULL)
1288 *did_something = FALSE;
1289
1290 /*
1291 * Check for a legal group name. If not, use AUGROUP_ALL.
1292 */
1293 group = au_get_grouparg(&arg);
1294 if (arg == NULL) // out of memory
1295 return FAIL;
1296
1297 if (*arg == '*')
1298 {
1299 emsg(_("E217: Can't execute autocommands for ALL events"));
1300 return FAIL;
1301 }
1302
1303 /*
1304 * Scan over the events.
1305 * If we find an illegal name, return here, don't do anything.
1306 */
1307 fname = find_end_event(arg, group != AUGROUP_ALL);
1308 if (fname == NULL)
1309 return FAIL;
1310
1311 fname = skipwhite(fname);
1312
1313 /*
1314 * Loop over the events.
1315 */
1316 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1317 if (apply_autocmds_group(event_name2nr(arg, &arg),
1318 fname, NULL, TRUE, group, curbuf, NULL))
1319 nothing_done = FALSE;
1320
1321 if (nothing_done && do_msg)
1322 msg(_("No matching autocommands"));
1323 if (did_something != NULL)
1324 *did_something = !nothing_done;
1325
1326#ifdef FEAT_EVAL
1327 return aborting() ? FAIL : OK;
1328#else
1329 return OK;
1330#endif
1331}
1332
1333/*
1334 * ":doautoall": execute autocommands for each loaded buffer.
1335 */
1336 void
1337ex_doautoall(exarg_T *eap)
1338{
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001339 int retval = OK;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001340 aco_save_T aco;
1341 buf_T *buf;
1342 bufref_T bufref;
1343 char_u *arg = eap->arg;
1344 int call_do_modelines = check_nomodeline(&arg);
1345 int did_aucmd;
1346
1347 /*
1348 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1349 * equal to curbuf, but for some buffers there may not be a window.
1350 * So we change the buffer for the current window for a moment. This
1351 * gives problems when the autocommands make changes to the list of
1352 * buffers or windows...
1353 */
1354 FOR_ALL_BUFFERS(buf)
1355 {
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001356 // Only do loaded buffers and skip the current buffer, it's done last.
1357 if (buf->b_ml.ml_mfp != NULL && buf != curbuf)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001358 {
1359 // find a window for this buffer and save some values
1360 aucmd_prepbuf(&aco, buf);
1361 set_bufref(&bufref, buf);
1362
1363 // execute the autocommands for this buffer
1364 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1365
1366 if (call_do_modelines && did_aucmd)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001367 // Execute the modeline settings, but don't set window-local
1368 // options if we are using the current window for another
1369 // buffer.
1370 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001371
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))
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001377 {
1378 retval = FAIL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001379 break;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001380 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001381 }
1382 }
1383
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001384 // Execute autocommands for the current buffer last.
1385 if (retval == OK)
1386 {
1387 do_doautocmd(arg, FALSE, &did_aucmd);
1388 if (call_do_modelines && did_aucmd)
1389 do_modelines(0);
1390 }
1391
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001392 check_cursor(); // just in case lines got deleted
1393}
1394
1395/*
1396 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1397 * return TRUE and advance *argp to after it.
1398 * Thus return TRUE when do_modelines() should be called.
1399 */
1400 int
1401check_nomodeline(char_u **argp)
1402{
1403 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1404 {
1405 *argp = skipwhite(*argp + 12);
1406 return FALSE;
1407 }
1408 return TRUE;
1409}
1410
1411/*
1412 * Prepare for executing autocommands for (hidden) buffer "buf".
1413 * Search for a visible window containing the current buffer. If there isn't
1414 * one then use "aucmd_win".
1415 * Set "curbuf" and "curwin" to match "buf".
1416 */
1417 void
1418aucmd_prepbuf(
1419 aco_save_T *aco, // structure to save values in
1420 buf_T *buf) // new curbuf
1421{
1422 win_T *win;
1423 int save_ea;
1424#ifdef FEAT_AUTOCHDIR
1425 int save_acd;
1426#endif
1427
1428 // Find a window that is for the new buffer
1429 if (buf == curbuf) // be quick when buf is curbuf
1430 win = curwin;
1431 else
1432 FOR_ALL_WINDOWS(win)
1433 if (win->w_buffer == buf)
1434 break;
1435
1436 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1437 // back to using the current window.
1438 if (win == NULL && aucmd_win == NULL)
1439 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001440 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001441 if (aucmd_win == NULL)
1442 win = curwin;
1443 }
1444 if (win == NULL && aucmd_win_used)
1445 // Strange recursive autocommand, fall back to using the current
1446 // window. Expect a few side effects...
1447 win = curwin;
1448
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001449 aco->save_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001450 aco->save_curbuf = curbuf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001451 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001452 if (win != NULL)
1453 {
1454 // There is a window for "buf" in the current tab page, make it the
1455 // curwin. This is preferred, it has the least side effects (esp. if
1456 // "buf" is curbuf).
1457 aco->use_aucmd_win = FALSE;
1458 curwin = win;
1459 }
1460 else
1461 {
1462 // There is no window for "buf", use "aucmd_win". To minimize the side
1463 // effects, insert it in the current tab page.
1464 // Anything related to a window (e.g., setting folds) may have
1465 // unexpected results.
1466 aco->use_aucmd_win = TRUE;
1467 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001468
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001469 win_init_popup_win(aucmd_win, buf);
1470
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001471 aco->globaldir = globaldir;
1472 globaldir = NULL;
1473
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001474 // Split the current window, put the aucmd_win in the upper half.
1475 // We don't want the BufEnter or WinEnter autocommands.
1476 block_autocmds();
1477 make_snapshot(SNAP_AUCMD_IDX);
1478 save_ea = p_ea;
1479 p_ea = FALSE;
1480
1481#ifdef FEAT_AUTOCHDIR
1482 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1483 save_acd = p_acd;
1484 p_acd = FALSE;
1485#endif
1486
1487 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
1488 (void)win_comp_pos(); // recompute window positions
1489 p_ea = save_ea;
1490#ifdef FEAT_AUTOCHDIR
1491 p_acd = save_acd;
1492#endif
1493 unblock_autocmds();
1494 curwin = aucmd_win;
1495 }
1496 curbuf = buf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001497 aco->new_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001498 set_bufref(&aco->new_curbuf, curbuf);
1499}
1500
1501/*
1502 * Cleanup after executing autocommands for a (hidden) buffer.
1503 * Restore the window as it was (if possible).
1504 */
1505 void
1506aucmd_restbuf(
1507 aco_save_T *aco) // structure holding saved values
1508{
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001509 int dummy;
1510 win_T *save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001511
1512 if (aco->use_aucmd_win)
1513 {
1514 --curbuf->b_nwindows;
1515 // Find "aucmd_win", it can't be closed, but it may be in another tab
1516 // page. Do not trigger autocommands here.
1517 block_autocmds();
1518 if (curwin != aucmd_win)
1519 {
1520 tabpage_T *tp;
1521 win_T *wp;
1522
1523 FOR_ALL_TAB_WINDOWS(tp, wp)
1524 {
1525 if (wp == aucmd_win)
1526 {
1527 if (tp != curtab)
1528 goto_tabpage_tp(tp, TRUE, TRUE);
1529 win_goto(aucmd_win);
1530 goto win_found;
1531 }
1532 }
1533 }
1534win_found:
1535
1536 // Remove the window and frame from the tree of frames.
1537 (void)winframe_remove(curwin, &dummy, NULL);
1538 win_remove(curwin, NULL);
1539 aucmd_win_used = FALSE;
1540 last_status(FALSE); // may need to remove last status line
1541
1542 if (!valid_tabpage_win(curtab))
1543 // no valid window in current tabpage
1544 close_tabpage(curtab);
1545
1546 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1547 (void)win_comp_pos(); // recompute window positions
1548 unblock_autocmds();
1549
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001550 save_curwin = win_find_by_id(aco->save_curwin_id);
1551 if (save_curwin != NULL)
1552 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001553 else
1554 // Hmm, original window disappeared. Just use the first one.
1555 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001556 curbuf = curwin->w_buffer;
1557#ifdef FEAT_JOB_CHANNEL
1558 // May need to restore insert mode for a prompt buffer.
1559 entering_window(curwin);
1560#endif
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001561 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001562#ifdef FEAT_EVAL
1563 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1564 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1565#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001566 vim_free(globaldir);
1567 globaldir = aco->globaldir;
1568
1569 // the buffer contents may have changed
1570 check_cursor();
1571 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1572 {
1573 curwin->w_topline = curbuf->b_ml.ml_line_count;
1574#ifdef FEAT_DIFF
1575 curwin->w_topfill = 0;
1576#endif
1577 }
1578#if defined(FEAT_GUI)
1579 // Hide the scrollbars from the aucmd_win and update.
1580 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1581 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1582 gui_may_update_scrollbars();
1583#endif
1584 }
1585 else
1586 {
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001587 // Restore curwin. Use the window ID, a window may have been closed
1588 // and the memory re-used for another one.
1589 save_curwin = win_find_by_id(aco->save_curwin_id);
1590 if (save_curwin != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001591 {
1592 // Restore the buffer which was previously edited by curwin, if
1593 // it was changed, we are still the same window and the buffer is
1594 // valid.
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001595 if (curwin->w_id == aco->new_curwin_id
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001596 && curbuf != aco->new_curbuf.br_buf
1597 && bufref_valid(&aco->new_curbuf)
1598 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1599 {
1600# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1601 if (curwin->w_s == &curbuf->b_s)
1602 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1603# endif
1604 --curbuf->b_nwindows;
1605 curbuf = aco->new_curbuf.br_buf;
1606 curwin->w_buffer = curbuf;
1607 ++curbuf->b_nwindows;
1608 }
1609
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001610 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001611 curbuf = curwin->w_buffer;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001612 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001613 // In case the autocommand moves the cursor to a position that
1614 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001615 check_cursor();
1616 }
1617 }
1618}
1619
1620static int autocmd_nested = FALSE;
1621
1622/*
1623 * Execute autocommands for "event" and file name "fname".
1624 * Return TRUE if some commands were executed.
1625 */
1626 int
1627apply_autocmds(
1628 event_T event,
1629 char_u *fname, // NULL or empty means use actual file name
1630 char_u *fname_io, // fname to use for <afile> on cmdline
1631 int force, // when TRUE, ignore autocmd_busy
1632 buf_T *buf) // buffer for <abuf>
1633{
1634 return apply_autocmds_group(event, fname, fname_io, force,
1635 AUGROUP_ALL, buf, NULL);
1636}
1637
1638/*
1639 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1640 * setting v:filearg.
1641 */
1642 int
1643apply_autocmds_exarg(
1644 event_T event,
1645 char_u *fname,
1646 char_u *fname_io,
1647 int force,
1648 buf_T *buf,
1649 exarg_T *eap)
1650{
1651 return apply_autocmds_group(event, fname, fname_io, force,
1652 AUGROUP_ALL, buf, eap);
1653}
1654
1655/*
1656 * Like apply_autocmds(), but handles the caller's retval. If the script
1657 * processing is being aborted or if retval is FAIL when inside a try
1658 * conditional, no autocommands are executed. If otherwise the autocommands
1659 * cause the script to be aborted, retval is set to FAIL.
1660 */
1661 int
1662apply_autocmds_retval(
1663 event_T event,
1664 char_u *fname, // NULL or empty means use actual file name
1665 char_u *fname_io, // fname to use for <afile> on cmdline
1666 int force, // when TRUE, ignore autocmd_busy
1667 buf_T *buf, // buffer for <abuf>
1668 int *retval) // pointer to caller's retval
1669{
1670 int did_cmd;
1671
1672#ifdef FEAT_EVAL
1673 if (should_abort(*retval))
1674 return FALSE;
1675#endif
1676
1677 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1678 AUGROUP_ALL, buf, NULL);
1679 if (did_cmd
1680#ifdef FEAT_EVAL
1681 && aborting()
1682#endif
1683 )
1684 *retval = FAIL;
1685 return did_cmd;
1686}
1687
1688/*
1689 * Return TRUE when there is a CursorHold autocommand defined.
1690 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001691 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001692has_cursorhold(void)
1693{
1694 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1695 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1696}
1697
1698/*
1699 * Return TRUE if the CursorHold event can be triggered.
1700 */
1701 int
1702trigger_cursorhold(void)
1703{
1704 int state;
1705
1706 if (!did_cursorhold
1707 && has_cursorhold()
1708 && reg_recording == 0
1709 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001710 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001711 {
1712 state = get_real_state();
1713 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1714 return TRUE;
1715 }
1716 return FALSE;
1717}
1718
1719/*
1720 * Return TRUE when there is a CursorMoved autocommand defined.
1721 */
1722 int
1723has_cursormoved(void)
1724{
1725 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1726}
1727
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001728/*
1729 * Return TRUE when there is a CursorMovedI autocommand defined.
1730 */
1731 int
1732has_cursormovedI(void)
1733{
1734 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1735}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001736
1737/*
1738 * Return TRUE when there is a TextChanged autocommand defined.
1739 */
1740 int
1741has_textchanged(void)
1742{
1743 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1744}
1745
1746/*
1747 * Return TRUE when there is a TextChangedI autocommand defined.
1748 */
1749 int
1750has_textchangedI(void)
1751{
1752 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1753}
1754
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001755/*
1756 * Return TRUE when there is a TextChangedP autocommand defined.
1757 */
1758 int
1759has_textchangedP(void)
1760{
1761 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1762}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001763
1764/*
1765 * Return TRUE when there is an InsertCharPre autocommand defined.
1766 */
1767 int
1768has_insertcharpre(void)
1769{
1770 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1771}
1772
1773/*
1774 * Return TRUE when there is an CmdUndefined autocommand defined.
1775 */
1776 int
1777has_cmdundefined(void)
1778{
1779 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1780}
1781
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001782#if defined(FEAT_EVAL) || defined(PROTO)
1783/*
1784 * Return TRUE when there is a TextYankPost autocommand defined.
1785 */
1786 int
1787has_textyankpost(void)
1788{
1789 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1790}
1791#endif
1792
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001793#if defined(FEAT_EVAL) || defined(PROTO)
1794/*
1795 * Return TRUE when there is a CompleteChanged autocommand defined.
1796 */
1797 int
1798has_completechanged(void)
1799{
1800 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1801}
1802#endif
1803
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001804/*
1805 * Execute autocommands for "event" and file name "fname".
1806 * Return TRUE if some commands were executed.
1807 */
1808 static int
1809apply_autocmds_group(
1810 event_T event,
1811 char_u *fname, // NULL or empty means use actual file name
1812 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1813 // use fname
1814 int force, // when TRUE, ignore autocmd_busy
1815 int group, // group ID, or AUGROUP_ALL
1816 buf_T *buf, // buffer for <abuf>
1817 exarg_T *eap UNUSED) // command arguments
1818{
1819 char_u *sfname = NULL; // short file name
1820 char_u *tail;
1821 int save_changed;
1822 buf_T *old_curbuf;
1823 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001824 char_u *save_autocmd_fname;
1825 int save_autocmd_fname_full;
1826 int save_autocmd_bufnr;
1827 char_u *save_autocmd_match;
1828 int save_autocmd_busy;
1829 int save_autocmd_nested;
1830 static int nesting = 0;
1831 AutoPatCmd patcmd;
1832 AutoPat *ap;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001833 sctx_T save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001834#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001835 funccal_entry_T funccal_entry;
1836 char_u *save_cmdarg;
1837 long save_cmdbang;
1838#endif
1839 static int filechangeshell_busy = FALSE;
1840#ifdef FEAT_PROFILE
1841 proftime_T wait_time;
1842#endif
1843 int did_save_redobuff = FALSE;
1844 save_redo_T save_redo;
1845 int save_KeyTyped = KeyTyped;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001846 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001847
1848 /*
1849 * Quickly return if there are no autocommands for this event or
1850 * autocommands are blocked.
1851 */
1852 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1853 || autocmd_blocked > 0)
1854 goto BYPASS_AU;
1855
1856 /*
1857 * When autocommands are busy, new autocommands are only executed when
1858 * explicitly enabled with the "nested" flag.
1859 */
1860 if (autocmd_busy && !(force || autocmd_nested))
1861 goto BYPASS_AU;
1862
1863#ifdef FEAT_EVAL
1864 /*
1865 * Quickly return when immediately aborting on error, or when an interrupt
1866 * occurred or an exception was thrown but not caught.
1867 */
1868 if (aborting())
1869 goto BYPASS_AU;
1870#endif
1871
1872 /*
1873 * FileChangedShell never nests, because it can create an endless loop.
1874 */
1875 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1876 || event == EVENT_FILECHANGEDSHELLPOST))
1877 goto BYPASS_AU;
1878
1879 /*
1880 * Ignore events in 'eventignore'.
1881 */
1882 if (event_ignored(event))
1883 goto BYPASS_AU;
1884
1885 /*
1886 * Allow nesting of autocommands, but restrict the depth, because it's
1887 * possible to create an endless loop.
1888 */
1889 if (nesting == 10)
1890 {
1891 emsg(_("E218: autocommand nesting too deep"));
1892 goto BYPASS_AU;
1893 }
1894
1895 /*
1896 * Check if these autocommands are disabled. Used when doing ":all" or
1897 * ":ball".
1898 */
1899 if ( (autocmd_no_enter
1900 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1901 || (autocmd_no_leave
1902 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1903 goto BYPASS_AU;
1904
1905 /*
1906 * Save the autocmd_* variables and info about the current buffer.
1907 */
1908 save_autocmd_fname = autocmd_fname;
1909 save_autocmd_fname_full = autocmd_fname_full;
1910 save_autocmd_bufnr = autocmd_bufnr;
1911 save_autocmd_match = autocmd_match;
1912 save_autocmd_busy = autocmd_busy;
1913 save_autocmd_nested = autocmd_nested;
1914 save_changed = curbuf->b_changed;
1915 old_curbuf = curbuf;
1916
1917 /*
1918 * Set the file name to be used for <afile>.
1919 * Make a copy to avoid that changing a buffer name or directory makes it
1920 * invalid.
1921 */
1922 if (fname_io == NULL)
1923 {
1924 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
1925 || event == EVENT_OPTIONSET)
1926 autocmd_fname = NULL;
1927 else if (fname != NULL && !ends_excmd(*fname))
1928 autocmd_fname = fname;
1929 else if (buf != NULL)
1930 autocmd_fname = buf->b_ffname;
1931 else
1932 autocmd_fname = NULL;
1933 }
1934 else
1935 autocmd_fname = fname_io;
1936 if (autocmd_fname != NULL)
1937 autocmd_fname = vim_strsave(autocmd_fname);
1938 autocmd_fname_full = FALSE; // call FullName_save() later
1939
1940 /*
1941 * Set the buffer number to be used for <abuf>.
1942 */
1943 if (buf == NULL)
1944 autocmd_bufnr = 0;
1945 else
1946 autocmd_bufnr = buf->b_fnum;
1947
1948 /*
1949 * When the file name is NULL or empty, use the file name of buffer "buf".
1950 * Always use the full path of the file name to match with, in case
1951 * "allow_dirs" is set.
1952 */
1953 if (fname == NULL || *fname == NUL)
1954 {
1955 if (buf == NULL)
1956 fname = NULL;
1957 else
1958 {
1959#ifdef FEAT_SYN_HL
1960 if (event == EVENT_SYNTAX)
1961 fname = buf->b_p_syn;
1962 else
1963#endif
1964 if (event == EVENT_FILETYPE)
1965 fname = buf->b_p_ft;
1966 else
1967 {
1968 if (buf->b_sfname != NULL)
1969 sfname = vim_strsave(buf->b_sfname);
1970 fname = buf->b_ffname;
1971 }
1972 }
1973 if (fname == NULL)
1974 fname = (char_u *)"";
1975 fname = vim_strsave(fname); // make a copy, so we can change it
1976 }
1977 else
1978 {
1979 sfname = vim_strsave(fname);
1980 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
1981 // ColorScheme, QuickFixCmd* or DirChanged
1982 if (event == EVENT_FILETYPE
1983 || event == EVENT_SYNTAX
1984 || event == EVENT_CMDLINECHANGED
1985 || event == EVENT_CMDLINEENTER
1986 || event == EVENT_CMDLINELEAVE
1987 || event == EVENT_CMDWINENTER
1988 || event == EVENT_CMDWINLEAVE
1989 || event == EVENT_CMDUNDEFINED
1990 || event == EVENT_FUNCUNDEFINED
1991 || event == EVENT_REMOTEREPLY
1992 || event == EVENT_SPELLFILEMISSING
1993 || event == EVENT_QUICKFIXCMDPRE
1994 || event == EVENT_COLORSCHEME
1995 || event == EVENT_COLORSCHEMEPRE
1996 || event == EVENT_OPTIONSET
1997 || event == EVENT_QUICKFIXCMDPOST
1998 || event == EVENT_DIRCHANGED)
1999 {
2000 fname = vim_strsave(fname);
2001 autocmd_fname_full = TRUE; // don't expand it later
2002 }
2003 else
2004 fname = FullName_save(fname, FALSE);
2005 }
2006 if (fname == NULL) // out of memory
2007 {
2008 vim_free(sfname);
2009 retval = FALSE;
2010 goto BYPASS_AU;
2011 }
2012
2013#ifdef BACKSLASH_IN_FILENAME
2014 /*
2015 * Replace all backslashes with forward slashes. This makes the
2016 * autocommand patterns portable between Unix and MS-DOS.
2017 */
2018 if (sfname != NULL)
2019 forward_slash(sfname);
2020 forward_slash(fname);
2021#endif
2022
2023#ifdef VMS
2024 // remove version for correct match
2025 if (sfname != NULL)
2026 vms_remove_version(sfname);
2027 vms_remove_version(fname);
2028#endif
2029
2030 /*
2031 * Set the name to be used for <amatch>.
2032 */
2033 autocmd_match = fname;
2034
2035
2036 // Don't redraw while doing autocommands.
2037 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002038
2039 // name and lnum are filled in later
2040 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002041 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002042
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002043 save_current_sctx = current_sctx;
2044
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002045#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002046# ifdef FEAT_PROFILE
2047 if (do_profiling == PROF_YES)
2048 prof_child_enter(&wait_time); // doesn't count for the caller itself
2049# endif
2050
2051 // Don't use local function variables, if called from a function.
2052 save_funccal(&funccal_entry);
2053#endif
2054
2055 /*
2056 * When starting to execute autocommands, save the search patterns.
2057 */
2058 if (!autocmd_busy)
2059 {
2060 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002061 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002062 {
2063 saveRedobuff(&save_redo);
2064 did_save_redobuff = TRUE;
2065 }
2066 did_filetype = keep_filetype;
2067 }
2068
2069 /*
2070 * Note that we are applying autocmds. Some commands need to know.
2071 */
2072 autocmd_busy = TRUE;
2073 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2074 ++nesting; // see matching decrement below
2075
2076 // Remember that FileType was triggered. Used for did_filetype().
2077 if (event == EVENT_FILETYPE)
2078 did_filetype = TRUE;
2079
2080 tail = gettail(fname);
2081
2082 // Find first autocommand that matches
2083 patcmd.curpat = first_autopat[(int)event];
2084 patcmd.nextcmd = NULL;
2085 patcmd.group = group;
2086 patcmd.fname = fname;
2087 patcmd.sfname = sfname;
2088 patcmd.tail = tail;
2089 patcmd.event = event;
2090 patcmd.arg_bufnr = autocmd_bufnr;
2091 patcmd.next = NULL;
2092 auto_next_pat(&patcmd, FALSE);
2093
2094 // found one, start executing the autocommands
2095 if (patcmd.curpat != NULL)
2096 {
2097 // add to active_apc_list
2098 patcmd.next = active_apc_list;
2099 active_apc_list = &patcmd;
2100
2101#ifdef FEAT_EVAL
2102 // set v:cmdarg (only when there is a matching pattern)
2103 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2104 if (eap != NULL)
2105 {
2106 save_cmdarg = set_cmdarg(eap, NULL);
2107 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2108 }
2109 else
2110 save_cmdarg = NULL; // avoid gcc warning
2111#endif
2112 retval = TRUE;
2113 // mark the last pattern, to avoid an endless loop when more patterns
2114 // are added when executing autocommands
2115 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2116 ap->last = FALSE;
2117 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002118
2119 // make sure cursor and topline are valid
2120 check_lnums(TRUE);
2121
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002122 do_cmdline(NULL, getnextac, (void *)&patcmd,
2123 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002124
2125 // restore cursor and topline, unless they were changed
2126 reset_lnums();
2127
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002128#ifdef FEAT_EVAL
2129 if (eap != NULL)
2130 {
2131 (void)set_cmdarg(NULL, save_cmdarg);
2132 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2133 }
2134#endif
2135 // delete from active_apc_list
2136 if (active_apc_list == &patcmd) // just in case
2137 active_apc_list = patcmd.next;
2138 }
2139
2140 --RedrawingDisabled;
2141 autocmd_busy = save_autocmd_busy;
2142 filechangeshell_busy = FALSE;
2143 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002144 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002145 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002146 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002147 vim_free(autocmd_fname);
2148 autocmd_fname = save_autocmd_fname;
2149 autocmd_fname_full = save_autocmd_fname_full;
2150 autocmd_bufnr = save_autocmd_bufnr;
2151 autocmd_match = save_autocmd_match;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002152 current_sctx = save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002153#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002154 restore_funccal();
2155# ifdef FEAT_PROFILE
2156 if (do_profiling == PROF_YES)
2157 prof_child_exit(&wait_time);
2158# endif
2159#endif
2160 KeyTyped = save_KeyTyped;
2161 vim_free(fname);
2162 vim_free(sfname);
2163 --nesting; // see matching increment above
2164
2165 /*
2166 * When stopping to execute autocommands, restore the search patterns and
2167 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2168 * free any windows in the au_pending_free_win list.
2169 */
2170 if (!autocmd_busy)
2171 {
2172 restore_search_patterns();
2173 if (did_save_redobuff)
2174 restoreRedobuff(&save_redo);
2175 did_filetype = FALSE;
2176 while (au_pending_free_buf != NULL)
2177 {
2178 buf_T *b = au_pending_free_buf->b_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002179
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002180 vim_free(au_pending_free_buf);
2181 au_pending_free_buf = b;
2182 }
2183 while (au_pending_free_win != NULL)
2184 {
2185 win_T *w = au_pending_free_win->w_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002186
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002187 vim_free(au_pending_free_win);
2188 au_pending_free_win = w;
2189 }
2190 }
2191
2192 /*
2193 * Some events don't set or reset the Changed flag.
2194 * Check if still in the same buffer!
2195 */
2196 if (curbuf == old_curbuf
2197 && (event == EVENT_BUFREADPOST
2198 || event == EVENT_BUFWRITEPOST
2199 || event == EVENT_FILEAPPENDPOST
2200 || event == EVENT_VIMLEAVE
2201 || event == EVENT_VIMLEAVEPRE))
2202 {
2203#ifdef FEAT_TITLE
2204 if (curbuf->b_changed != save_changed)
2205 need_maketitle = TRUE;
2206#endif
2207 curbuf->b_changed = save_changed;
2208 }
2209
2210 au_cleanup(); // may really delete removed patterns/commands now
2211
2212BYPASS_AU:
2213 // When wiping out a buffer make sure all its buffer-local autocommands
2214 // are deleted.
2215 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2216 aubuflocal_remove(buf);
2217
2218 if (retval == OK && event == EVENT_FILETYPE)
2219 au_did_filetype = TRUE;
2220
2221 return retval;
2222}
2223
2224# ifdef FEAT_EVAL
2225static char_u *old_termresponse = NULL;
2226# endif
2227
2228/*
2229 * Block triggering autocommands until unblock_autocmd() is called.
2230 * Can be used recursively, so long as it's symmetric.
2231 */
2232 void
2233block_autocmds(void)
2234{
2235# ifdef FEAT_EVAL
2236 // Remember the value of v:termresponse.
2237 if (autocmd_blocked == 0)
2238 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2239# endif
2240 ++autocmd_blocked;
2241}
2242
2243 void
2244unblock_autocmds(void)
2245{
2246 --autocmd_blocked;
2247
2248# ifdef FEAT_EVAL
2249 // When v:termresponse was set while autocommands were blocked, trigger
2250 // the autocommands now. Esp. useful when executing a shell command
2251 // during startup (vimdiff).
2252 if (autocmd_blocked == 0
2253 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2254 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2255# endif
2256}
2257
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002258 int
2259is_autocmd_blocked(void)
2260{
2261 return autocmd_blocked != 0;
2262}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002263
2264/*
2265 * Find next autocommand pattern that matches.
2266 */
2267 static void
2268auto_next_pat(
2269 AutoPatCmd *apc,
2270 int stop_at_last) // stop when 'last' flag is set
2271{
2272 AutoPat *ap;
2273 AutoCmd *cp;
2274 char_u *name;
2275 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002276 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002277
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002278 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002279
2280 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2281 {
2282 apc->curpat = NULL;
2283
2284 // Only use a pattern when it has not been removed, has commands and
2285 // the group matches. For buffer-local autocommands only check the
2286 // buffer number.
2287 if (ap->pat != NULL && ap->cmds != NULL
2288 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2289 {
2290 // execution-condition
2291 if (ap->buflocal_nr == 0
2292 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2293 apc->sfname, apc->tail, ap->allow_dirs))
2294 : ap->buflocal_nr == apc->arg_bufnr)
2295 {
2296 name = event_nr2name(apc->event);
2297 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002298 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002299 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002300 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002301 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002302 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002303 (char *)name, (char *)ap->pat);
2304 if (p_verbose >= 8)
2305 {
2306 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002307 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002308 verbose_leave();
2309 }
2310 }
2311
2312 apc->curpat = ap;
2313 apc->nextcmd = ap->cmds;
2314 // mark last command
2315 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2316 cp->last = FALSE;
2317 cp->last = TRUE;
2318 }
2319 line_breakcheck();
2320 if (apc->curpat != NULL) // found a match
2321 break;
2322 }
2323 if (stop_at_last && ap->last)
2324 break;
2325 }
2326}
2327
2328/*
2329 * Get next autocommand command.
2330 * Called by do_cmdline() to get the next line for ":if".
2331 * Returns allocated string, or NULL for end of autocommands.
2332 */
2333 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002334getnextac(
2335 int c UNUSED,
2336 void *cookie,
2337 int indent UNUSED,
2338 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002339{
2340 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2341 char_u *retval;
2342 AutoCmd *ac;
2343
2344 // Can be called again after returning the last line.
2345 if (acp->curpat == NULL)
2346 return NULL;
2347
2348 // repeat until we find an autocommand to execute
2349 for (;;)
2350 {
2351 // skip removed commands
2352 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2353 if (acp->nextcmd->last)
2354 acp->nextcmd = NULL;
2355 else
2356 acp->nextcmd = acp->nextcmd->next;
2357
2358 if (acp->nextcmd != NULL)
2359 break;
2360
2361 // at end of commands, find next pattern that matches
2362 if (acp->curpat->last)
2363 acp->curpat = NULL;
2364 else
2365 acp->curpat = acp->curpat->next;
2366 if (acp->curpat != NULL)
2367 auto_next_pat(acp, TRUE);
2368 if (acp->curpat == NULL)
2369 return NULL;
2370 }
2371
2372 ac = acp->nextcmd;
2373
2374 if (p_verbose >= 9)
2375 {
2376 verbose_enter_scroll();
2377 smsg(_("autocommand %s"), ac->cmd);
2378 msg_puts("\n"); // don't overwrite this either
2379 verbose_leave_scroll();
2380 }
2381 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002382 // Remove one-shot ("once") autocmd in anticipation of its execution.
2383 if (ac->once)
2384 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002385 autocmd_nested = ac->nested;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002386 current_sctx = ac->script_ctx;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002387 if (ac->last)
2388 acp->nextcmd = NULL;
2389 else
2390 acp->nextcmd = ac->next;
2391 return retval;
2392}
2393
2394/*
2395 * Return TRUE if there is a matching autocommand for "fname".
2396 * To account for buffer-local autocommands, function needs to know
2397 * in which buffer the file will be opened.
2398 */
2399 int
2400has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2401{
2402 AutoPat *ap;
2403 char_u *fname;
2404 char_u *tail = gettail(sfname);
2405 int retval = FALSE;
2406
2407 fname = FullName_save(sfname, FALSE);
2408 if (fname == NULL)
2409 return FALSE;
2410
2411#ifdef BACKSLASH_IN_FILENAME
2412 /*
2413 * Replace all backslashes with forward slashes. This makes the
2414 * autocommand patterns portable between Unix and MS-DOS.
2415 */
2416 sfname = vim_strsave(sfname);
2417 if (sfname != NULL)
2418 forward_slash(sfname);
2419 forward_slash(fname);
2420#endif
2421
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002422 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002423 if (ap->pat != NULL && ap->cmds != NULL
2424 && (ap->buflocal_nr == 0
2425 ? match_file_pat(NULL, &ap->reg_prog,
2426 fname, sfname, tail, ap->allow_dirs)
2427 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2428 ))
2429 {
2430 retval = TRUE;
2431 break;
2432 }
2433
2434 vim_free(fname);
2435#ifdef BACKSLASH_IN_FILENAME
2436 vim_free(sfname);
2437#endif
2438
2439 return retval;
2440}
2441
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002442/*
2443 * Function given to ExpandGeneric() to obtain the list of autocommand group
2444 * names.
2445 */
2446 char_u *
2447get_augroup_name(expand_T *xp UNUSED, int idx)
2448{
2449 if (idx == augroups.ga_len) // add "END" add the end
2450 return (char_u *)"END";
2451 if (idx >= augroups.ga_len) // end of list
2452 return NULL;
2453 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2454 // skip deleted entries
2455 return (char_u *)"";
2456 return AUGROUP_NAME(idx); // return a name
2457}
2458
2459static int include_groups = FALSE;
2460
2461 char_u *
2462set_context_in_autocmd(
2463 expand_T *xp,
2464 char_u *arg,
2465 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2466{
2467 char_u *p;
2468 int group;
2469
2470 // check for a group name, skip it if present
2471 include_groups = FALSE;
2472 p = arg;
2473 group = au_get_grouparg(&arg);
2474 if (group == AUGROUP_ERROR)
2475 return NULL;
2476 // If there only is a group name that's what we expand.
2477 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2478 {
2479 arg = p;
2480 group = AUGROUP_ALL;
2481 }
2482
2483 // skip over event name
2484 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2485 if (*p == ',')
2486 arg = p + 1;
2487 if (*p == NUL)
2488 {
2489 if (group == AUGROUP_ALL)
2490 include_groups = TRUE;
2491 xp->xp_context = EXPAND_EVENTS; // expand event name
2492 xp->xp_pattern = arg;
2493 return NULL;
2494 }
2495
2496 // skip over pattern
2497 arg = skipwhite(p);
2498 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2499 arg++;
2500 if (*arg)
2501 return arg; // expand (next) command
2502
2503 if (doautocmd)
2504 xp->xp_context = EXPAND_FILES; // expand file names
2505 else
2506 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2507 return NULL;
2508}
2509
2510/*
2511 * Function given to ExpandGeneric() to obtain the list of event names.
2512 */
2513 char_u *
2514get_event_name(expand_T *xp UNUSED, int idx)
2515{
2516 if (idx < augroups.ga_len) // First list group names, if wanted
2517 {
2518 if (!include_groups || AUGROUP_NAME(idx) == NULL
2519 || AUGROUP_NAME(idx) == get_deleted_augroup())
2520 return (char_u *)""; // skip deleted entries
2521 return AUGROUP_NAME(idx); // return a name
2522 }
2523 return (char_u *)event_names[idx - augroups.ga_len].name;
2524}
2525
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002526
2527#if defined(FEAT_EVAL) || defined(PROTO)
2528/*
2529 * Return TRUE if autocmd is supported.
2530 */
2531 int
2532autocmd_supported(char_u *name)
2533{
2534 char_u *p;
2535
2536 return (event_name2nr(name, &p) != NUM_EVENTS);
2537}
2538
2539/*
2540 * Return TRUE if an autocommand is defined for a group, event and
2541 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2542 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2543 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2544 * Used for:
2545 * exists("#Group") or
2546 * exists("#Group#Event") or
2547 * exists("#Group#Event#pat") or
2548 * exists("#Event") or
2549 * exists("#Event#pat")
2550 */
2551 int
2552au_exists(char_u *arg)
2553{
2554 char_u *arg_save;
2555 char_u *pattern = NULL;
2556 char_u *event_name;
2557 char_u *p;
2558 event_T event;
2559 AutoPat *ap;
2560 buf_T *buflocal_buf = NULL;
2561 int group;
2562 int retval = FALSE;
2563
2564 // Make a copy so that we can change the '#' chars to a NUL.
2565 arg_save = vim_strsave(arg);
2566 if (arg_save == NULL)
2567 return FALSE;
2568 p = vim_strchr(arg_save, '#');
2569 if (p != NULL)
2570 *p++ = NUL;
2571
2572 // First, look for an autocmd group name
2573 group = au_find_group(arg_save);
2574 if (group == AUGROUP_ERROR)
2575 {
2576 // Didn't match a group name, assume the first argument is an event.
2577 group = AUGROUP_ALL;
2578 event_name = arg_save;
2579 }
2580 else
2581 {
2582 if (p == NULL)
2583 {
2584 // "Group": group name is present and it's recognized
2585 retval = TRUE;
2586 goto theend;
2587 }
2588
2589 // Must be "Group#Event" or "Group#Event#pat".
2590 event_name = p;
2591 p = vim_strchr(event_name, '#');
2592 if (p != NULL)
2593 *p++ = NUL; // "Group#Event#pat"
2594 }
2595
2596 pattern = p; // "pattern" is NULL when there is no pattern
2597
2598 // find the index (enum) for the event name
2599 event = event_name2nr(event_name, &p);
2600
2601 // return FALSE if the event name is not recognized
2602 if (event == NUM_EVENTS)
2603 goto theend;
2604
2605 // Find the first autocommand for this event.
2606 // If there isn't any, return FALSE;
2607 // If there is one and no pattern given, return TRUE;
2608 ap = first_autopat[(int)event];
2609 if (ap == NULL)
2610 goto theend;
2611
2612 // if pattern is "<buffer>", special handling is needed which uses curbuf
2613 // for pattern "<buffer=N>, fnamecmp() will work fine
2614 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2615 buflocal_buf = curbuf;
2616
2617 // Check if there is an autocommand with the given pattern.
2618 for ( ; ap != NULL; ap = ap->next)
2619 // only use a pattern when it has not been removed and has commands.
2620 // For buffer-local autocommands, fnamecmp() works fine.
2621 if (ap->pat != NULL && ap->cmds != NULL
2622 && (group == AUGROUP_ALL || ap->group == group)
2623 && (pattern == NULL
2624 || (buflocal_buf == NULL
2625 ? fnamecmp(ap->pat, pattern) == 0
2626 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2627 {
2628 retval = TRUE;
2629 break;
2630 }
2631
2632theend:
2633 vim_free(arg_save);
2634 return retval;
2635}
2636#endif