blob: a721e708aac8f7afd05d4b34e0ff83b7dc41bcc9 [file] [log] [blame]
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * autocmd.c: Autocommand related functions
12 */
13
14#include "vim.h"
15
16/*
17 * The autocommands are stored in a list for each event.
18 * Autocommands for the same pattern, that are consecutive, are joined
19 * together, to avoid having to match the pattern too often.
20 * The result is an array of Autopat lists, which point to AutoCmd lists:
21 *
22 * last_autopat[0] -----------------------------+
23 * V
24 * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
25 * Autopat.cmds Autopat.cmds
26 * | |
27 * V V
28 * AutoCmd.next AutoCmd.next
29 * | |
30 * V V
31 * AutoCmd.next NULL
32 * |
33 * V
34 * NULL
35 *
36 * last_autopat[1] --------+
37 * V
38 * first_autopat[1] --> Autopat.next --> NULL
39 * Autopat.cmds
40 * |
41 * V
42 * AutoCmd.next
43 * |
44 * V
45 * NULL
46 * etc.
47 *
48 * The order of AutoCmds is important, this is the order in which they were
49 * defined and will have to be executed.
50 */
51typedef struct AutoCmd
52{
53 char_u *cmd; // The command to be executed (NULL
54 // when command has been removed).
Bram Moolenaareb93f3f2019-04-04 15:04:56 +020055 char once; // "One shot": removed after execution
Bram Moolenaar3e460fd2019-01-26 16:21:07 +010056 char nested; // If autocommands nest here.
57 char last; // last command in list
Bram Moolenaar3e460fd2019-01-26 16:21:07 +010058 sctx_T script_ctx; // script context where defined
Bram Moolenaar3e460fd2019-01-26 16:21:07 +010059 struct AutoCmd *next; // next AutoCmd in list
60} AutoCmd;
61
62typedef struct AutoPat
63{
64 struct AutoPat *next; // Next AutoPat in AutoPat list; MUST
65 // be the first entry.
66 char_u *pat; // pattern as typed (NULL when pattern
67 // has been removed)
68 regprog_T *reg_prog; // compiled regprog for pattern
69 AutoCmd *cmds; // list of commands to do
70 int group; // group ID
71 int patlen; // strlen() of pat
72 int buflocal_nr; // !=0 for buffer-local AutoPat
73 char allow_dirs; // Pattern may match whole path
74 char last; // last pattern for apply_autocmds()
75} AutoPat;
76
77static struct event_name
78{
79 char *name; // event name
80 event_T event; // event number
81} event_names[] =
82{
83 {"BufAdd", EVENT_BUFADD},
84 {"BufCreate", EVENT_BUFADD},
85 {"BufDelete", EVENT_BUFDELETE},
86 {"BufEnter", EVENT_BUFENTER},
87 {"BufFilePost", EVENT_BUFFILEPOST},
88 {"BufFilePre", EVENT_BUFFILEPRE},
89 {"BufHidden", EVENT_BUFHIDDEN},
90 {"BufLeave", EVENT_BUFLEAVE},
91 {"BufNew", EVENT_BUFNEW},
92 {"BufNewFile", EVENT_BUFNEWFILE},
93 {"BufRead", EVENT_BUFREADPOST},
94 {"BufReadCmd", EVENT_BUFREADCMD},
95 {"BufReadPost", EVENT_BUFREADPOST},
96 {"BufReadPre", EVENT_BUFREADPRE},
97 {"BufUnload", EVENT_BUFUNLOAD},
98 {"BufWinEnter", EVENT_BUFWINENTER},
99 {"BufWinLeave", EVENT_BUFWINLEAVE},
100 {"BufWipeout", EVENT_BUFWIPEOUT},
101 {"BufWrite", EVENT_BUFWRITEPRE},
102 {"BufWritePost", EVENT_BUFWRITEPOST},
103 {"BufWritePre", EVENT_BUFWRITEPRE},
104 {"BufWriteCmd", EVENT_BUFWRITECMD},
105 {"CmdlineChanged", EVENT_CMDLINECHANGED},
106 {"CmdlineEnter", EVENT_CMDLINEENTER},
107 {"CmdlineLeave", EVENT_CMDLINELEAVE},
108 {"CmdwinEnter", EVENT_CMDWINENTER},
109 {"CmdwinLeave", EVENT_CMDWINLEAVE},
110 {"CmdUndefined", EVENT_CMDUNDEFINED},
111 {"ColorScheme", EVENT_COLORSCHEME},
112 {"ColorSchemePre", EVENT_COLORSCHEMEPRE},
Bram Moolenaard7f246c2019-04-08 18:15:41 +0200113 {"CompleteChanged", EVENT_COMPLETECHANGED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100114 {"CompleteDone", EVENT_COMPLETEDONE},
Bram Moolenaar3f169ce2020-01-26 22:43:31 +0100115 {"CompleteDonePre", EVENT_COMPLETEDONEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100116 {"CursorHold", EVENT_CURSORHOLD},
117 {"CursorHoldI", EVENT_CURSORHOLDI},
118 {"CursorMoved", EVENT_CURSORMOVED},
119 {"CursorMovedI", EVENT_CURSORMOVEDI},
120 {"DiffUpdated", EVENT_DIFFUPDATED},
121 {"DirChanged", EVENT_DIRCHANGED},
122 {"EncodingChanged", EVENT_ENCODINGCHANGED},
123 {"ExitPre", EVENT_EXITPRE},
124 {"FileEncoding", EVENT_ENCODINGCHANGED},
125 {"FileAppendPost", EVENT_FILEAPPENDPOST},
126 {"FileAppendPre", EVENT_FILEAPPENDPRE},
127 {"FileAppendCmd", EVENT_FILEAPPENDCMD},
128 {"FileChangedShell",EVENT_FILECHANGEDSHELL},
129 {"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
130 {"FileChangedRO", EVENT_FILECHANGEDRO},
131 {"FileReadPost", EVENT_FILEREADPOST},
132 {"FileReadPre", EVENT_FILEREADPRE},
133 {"FileReadCmd", EVENT_FILEREADCMD},
134 {"FileType", EVENT_FILETYPE},
135 {"FileWritePost", EVENT_FILEWRITEPOST},
136 {"FileWritePre", EVENT_FILEWRITEPRE},
137 {"FileWriteCmd", EVENT_FILEWRITECMD},
138 {"FilterReadPost", EVENT_FILTERREADPOST},
139 {"FilterReadPre", EVENT_FILTERREADPRE},
140 {"FilterWritePost", EVENT_FILTERWRITEPOST},
141 {"FilterWritePre", EVENT_FILTERWRITEPRE},
142 {"FocusGained", EVENT_FOCUSGAINED},
143 {"FocusLost", EVENT_FOCUSLOST},
144 {"FuncUndefined", EVENT_FUNCUNDEFINED},
145 {"GUIEnter", EVENT_GUIENTER},
146 {"GUIFailed", EVENT_GUIFAILED},
147 {"InsertChange", EVENT_INSERTCHANGE},
148 {"InsertEnter", EVENT_INSERTENTER},
149 {"InsertLeave", EVENT_INSERTLEAVE},
Bram Moolenaarb53e13a2020-10-21 12:19:53 +0200150 {"InsertLeavePre", EVENT_INSERTLEAVEPRE},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100151 {"InsertCharPre", EVENT_INSERTCHARPRE},
152 {"MenuPopup", EVENT_MENUPOPUP},
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +0200153 {"ModeChanged", EVENT_MODECHANGED},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100154 {"OptionSet", EVENT_OPTIONSET},
155 {"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
156 {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
157 {"QuitPre", EVENT_QUITPRE},
158 {"RemoteReply", EVENT_REMOTEREPLY},
Bram Moolenaar8aeec402019-09-15 23:02:04 +0200159 {"SafeState", EVENT_SAFESTATE},
Bram Moolenaar69198cb2019-09-16 21:58:13 +0200160 {"SafeStateAgain", EVENT_SAFESTATEAGAIN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100161 {"SessionLoadPost", EVENT_SESSIONLOADPOST},
162 {"ShellCmdPost", EVENT_SHELLCMDPOST},
163 {"ShellFilterPost", EVENT_SHELLFILTERPOST},
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200164 {"SigUSR1", EVENT_SIGUSR1},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100165 {"SourceCmd", EVENT_SOURCECMD},
166 {"SourcePre", EVENT_SOURCEPRE},
167 {"SourcePost", EVENT_SOURCEPOST},
168 {"SpellFileMissing",EVENT_SPELLFILEMISSING},
169 {"StdinReadPost", EVENT_STDINREADPOST},
170 {"StdinReadPre", EVENT_STDINREADPRE},
171 {"SwapExists", EVENT_SWAPEXISTS},
172 {"Syntax", EVENT_SYNTAX},
173 {"TabNew", EVENT_TABNEW},
174 {"TabClosed", EVENT_TABCLOSED},
175 {"TabEnter", EVENT_TABENTER},
176 {"TabLeave", EVENT_TABLEAVE},
177 {"TermChanged", EVENT_TERMCHANGED},
178 {"TerminalOpen", EVENT_TERMINALOPEN},
Bram Moolenaar28ed4df2019-10-26 16:21:40 +0200179 {"TerminalWinOpen", EVENT_TERMINALWINOPEN},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100180 {"TermResponse", EVENT_TERMRESPONSE},
181 {"TextChanged", EVENT_TEXTCHANGED},
182 {"TextChangedI", EVENT_TEXTCHANGEDI},
183 {"TextChangedP", EVENT_TEXTCHANGEDP},
184 {"User", EVENT_USER},
185 {"VimEnter", EVENT_VIMENTER},
186 {"VimLeave", EVENT_VIMLEAVE},
187 {"VimLeavePre", EVENT_VIMLEAVEPRE},
188 {"WinNew", EVENT_WINNEW},
189 {"WinEnter", EVENT_WINENTER},
190 {"WinLeave", EVENT_WINLEAVE},
191 {"VimResized", EVENT_VIMRESIZED},
192 {"TextYankPost", EVENT_TEXTYANKPOST},
Bram Moolenaar100118c2020-12-11 19:30:34 +0100193 {"VimSuspend", EVENT_VIMSUSPEND},
194 {"VimResume", EVENT_VIMRESUME},
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100195 {NULL, (event_T)0}
196};
197
198static AutoPat *first_autopat[NUM_EVENTS] =
199{
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 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
206};
207
208static AutoPat *last_autopat[NUM_EVENTS] =
209{
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 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
216};
217
218#define AUGROUP_DEFAULT -1 // default autocmd group
219#define AUGROUP_ERROR -2 // erroneous autocmd group
220#define AUGROUP_ALL -3 // all autocmd groups
221
222/*
223 * struct used to keep status while executing autocommands for an event.
224 */
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100225struct AutoPatCmd_S
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100226{
227 AutoPat *curpat; // next AutoPat to examine
228 AutoCmd *nextcmd; // next AutoCmd to execute
229 int group; // group being used
230 char_u *fname; // fname to match with
231 char_u *sfname; // sfname to match with
232 char_u *tail; // tail of fname
233 event_T event; // current event
234 int arg_bufnr; // Initially equal to <abuf>, set to zero when
235 // buf is deleted.
Bram Moolenaar1a47ae32019-12-29 23:04:25 +0100236 AutoPatCmd *next; // chain of active apc-s for auto-invalidation
237};
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100238
Bram Moolenaarc667da52019-11-30 20:52:27 +0100239static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100240
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200241// Macro to loop over all the patterns for an autocmd event
242#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \
243 for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next)
244
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100245/*
246 * augroups stores a list of autocmd group names.
247 */
248static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
249#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
Bram Moolenaarc667da52019-11-30 20:52:27 +0100250// use get_deleted_augroup() to get this
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100251static char_u *deleted_augroup = NULL;
252
253/*
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100254 * The ID of the current group. Group 0 is the default one.
255 */
256static int current_augroup = AUGROUP_DEFAULT;
257
Bram Moolenaarc667da52019-11-30 20:52:27 +0100258static int au_need_clean = FALSE; // need to delete marked patterns
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100259
260static char_u *event_nr2name(event_T event);
261static int au_get_grouparg(char_u **argp);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200262static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group, int flags);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100263static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
264static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
265static int au_find_group(char_u *name);
266
267static event_T last_event;
268static int last_group;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100269static int autocmd_blocked = 0; // block all autocmds
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100270
271 static char_u *
272get_deleted_augroup(void)
273{
274 if (deleted_augroup == NULL)
275 deleted_augroup = (char_u *)_("--Deleted--");
276 return deleted_augroup;
277}
278
279/*
280 * Show the autocommands for one AutoPat.
281 */
282 static void
283show_autocmd(AutoPat *ap, event_T event)
284{
285 AutoCmd *ac;
286
287 // Check for "got_int" (here and at various places below), which is set
288 // when "q" has been hit for the "--more--" prompt
289 if (got_int)
290 return;
291 if (ap->pat == NULL) // pattern has been removed
292 return;
293
294 msg_putchar('\n');
295 if (got_int)
296 return;
297 if (event != last_event || ap->group != last_group)
298 {
299 if (ap->group != AUGROUP_DEFAULT)
300 {
301 if (AUGROUP_NAME(ap->group) == NULL)
302 msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
303 else
304 msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
305 msg_puts(" ");
306 }
307 msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
308 last_event = event;
309 last_group = ap->group;
310 msg_putchar('\n');
311 if (got_int)
312 return;
313 }
314 msg_col = 4;
315 msg_outtrans(ap->pat);
316
317 for (ac = ap->cmds; ac != NULL; ac = ac->next)
318 {
319 if (ac->cmd != NULL) // skip removed commands
320 {
321 if (msg_col >= 14)
322 msg_putchar('\n');
323 msg_col = 14;
324 if (got_int)
325 return;
326 msg_outtrans(ac->cmd);
327#ifdef FEAT_EVAL
328 if (p_verbose > 0)
329 last_set_msg(ac->script_ctx);
330#endif
331 if (got_int)
332 return;
333 if (ac->next != NULL)
334 {
335 msg_putchar('\n');
336 if (got_int)
337 return;
338 }
339 }
340 }
341}
342
343/*
344 * Mark an autocommand pattern for deletion.
345 */
346 static void
347au_remove_pat(AutoPat *ap)
348{
349 VIM_CLEAR(ap->pat);
350 ap->buflocal_nr = -1;
351 au_need_clean = TRUE;
352}
353
354/*
355 * Mark all commands for a pattern for deletion.
356 */
357 static void
358au_remove_cmds(AutoPat *ap)
359{
360 AutoCmd *ac;
361
362 for (ac = ap->cmds; ac != NULL; ac = ac->next)
363 VIM_CLEAR(ac->cmd);
364 au_need_clean = TRUE;
365}
366
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200367// Delete one command from an autocmd pattern.
368static void au_del_cmd(AutoCmd *ac)
369{
370 VIM_CLEAR(ac->cmd);
371 au_need_clean = TRUE;
372}
373
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100374/*
375 * Cleanup autocommands and patterns that have been deleted.
376 * This is only done when not executing autocommands.
377 */
378 static void
379au_cleanup(void)
380{
381 AutoPat *ap, **prev_ap;
382 AutoCmd *ac, **prev_ac;
383 event_T event;
384
385 if (autocmd_busy || !au_need_clean)
386 return;
387
388 // loop over all events
389 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
390 event = (event_T)((int)event + 1))
391 {
392 // loop over all autocommand patterns
393 prev_ap = &(first_autopat[(int)event]);
394 for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
395 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200396 int has_cmd = FALSE;
397
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200398 // loop over all commands for this pattern
399 prev_ac = &(ap->cmds);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100400 for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
401 {
402 // remove the command if the pattern is to be deleted or when
403 // the command has been marked for deletion
404 if (ap->pat == NULL || ac->cmd == NULL)
405 {
406 *prev_ac = ac->next;
407 vim_free(ac->cmd);
408 vim_free(ac);
409 }
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200410 else
411 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200412 has_cmd = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100413 prev_ac = &(ac->next);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200414 }
415 }
416
Bram Moolenaar8f4aeb52019-04-04 15:40:56 +0200417 if (ap->pat != NULL && !has_cmd)
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200418 // Pattern was not marked for deletion, but all of its
419 // commands were. So mark the pattern for deletion.
420 au_remove_pat(ap);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100421
422 // remove the pattern if it has been marked for deletion
423 if (ap->pat == NULL)
424 {
425 if (ap->next == NULL)
426 {
427 if (prev_ap == &(first_autopat[(int)event]))
428 last_autopat[(int)event] = NULL;
429 else
430 // this depends on the "next" field being the first in
431 // the struct
432 last_autopat[(int)event] = (AutoPat *)prev_ap;
433 }
434 *prev_ap = ap->next;
435 vim_regfree(ap->reg_prog);
436 vim_free(ap);
437 }
438 else
439 prev_ap = &(ap->next);
440 }
441 }
442
443 au_need_clean = FALSE;
444}
445
446/*
447 * Called when buffer is freed, to remove/invalidate related buffer-local
448 * autocmds.
449 */
450 void
451aubuflocal_remove(buf_T *buf)
452{
453 AutoPat *ap;
454 event_T event;
455 AutoPatCmd *apc;
456
457 // invalidate currently executing autocommands
458 for (apc = active_apc_list; apc; apc = apc->next)
459 if (buf->b_fnum == apc->arg_bufnr)
460 apc->arg_bufnr = 0;
461
462 // invalidate buflocals looping through events
463 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
464 event = (event_T)((int)event + 1))
465 // loop over all autocommand patterns
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200466 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100467 if (ap->buflocal_nr == buf->b_fnum)
468 {
469 au_remove_pat(ap);
470 if (p_verbose >= 6)
471 {
472 verbose_enter();
473 smsg(_("auto-removing autocommand: %s <buffer=%d>"),
474 event_nr2name(event), buf->b_fnum);
475 verbose_leave();
476 }
477 }
478 au_cleanup();
479}
480
481/*
482 * Add an autocmd group name.
483 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
484 */
485 static int
486au_new_group(char_u *name)
487{
488 int i;
489
490 i = au_find_group(name);
491 if (i == AUGROUP_ERROR) // the group doesn't exist yet, add it
492 {
493 // First try using a free entry.
494 for (i = 0; i < augroups.ga_len; ++i)
495 if (AUGROUP_NAME(i) == NULL)
496 break;
497 if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
498 return AUGROUP_ERROR;
499
500 AUGROUP_NAME(i) = vim_strsave(name);
501 if (AUGROUP_NAME(i) == NULL)
502 return AUGROUP_ERROR;
503 if (i == augroups.ga_len)
504 ++augroups.ga_len;
505 }
506
507 return i;
508}
509
510 static void
511au_del_group(char_u *name)
512{
513 int i;
514
515 i = au_find_group(name);
516 if (i == AUGROUP_ERROR) // the group doesn't exist
517 semsg(_("E367: No such group: \"%s\""), name);
518 else if (i == current_augroup)
519 emsg(_("E936: Cannot delete the current group"));
520 else
521 {
522 event_T event;
523 AutoPat *ap;
524 int in_use = FALSE;
525
526 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
527 event = (event_T)((int)event + 1))
528 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200529 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100530 if (ap->group == i && ap->pat != NULL)
531 {
532 give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
533 in_use = TRUE;
534 event = NUM_EVENTS;
535 break;
536 }
537 }
538 vim_free(AUGROUP_NAME(i));
539 if (in_use)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100540 AUGROUP_NAME(i) = get_deleted_augroup();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100541 else
542 AUGROUP_NAME(i) = NULL;
543 }
544}
545
546/*
547 * Find the ID of an autocmd group name.
548 * Return its ID. Returns AUGROUP_ERROR (< 0) for error.
549 */
550 static int
551au_find_group(char_u *name)
552{
553 int i;
554
555 for (i = 0; i < augroups.ga_len; ++i)
556 if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
557 && STRCMP(AUGROUP_NAME(i), name) == 0)
558 return i;
559 return AUGROUP_ERROR;
560}
561
562/*
563 * Return TRUE if augroup "name" exists.
564 */
565 int
566au_has_group(char_u *name)
567{
568 return au_find_group(name) != AUGROUP_ERROR;
569}
570
571/*
572 * ":augroup {name}".
573 */
574 void
575do_augroup(char_u *arg, int del_group)
576{
577 int i;
578
579 if (del_group)
580 {
581 if (*arg == NUL)
582 emsg(_(e_argreq));
583 else
584 au_del_group(arg);
585 }
586 else if (STRICMP(arg, "end") == 0) // ":aug end": back to group 0
587 current_augroup = AUGROUP_DEFAULT;
588 else if (*arg) // ":aug xxx": switch to group xxx
589 {
590 i = au_new_group(arg);
591 if (i != AUGROUP_ERROR)
592 current_augroup = i;
593 }
594 else // ":aug": list the group names
595 {
596 msg_start();
597 for (i = 0; i < augroups.ga_len; ++i)
598 {
599 if (AUGROUP_NAME(i) != NULL)
600 {
601 msg_puts((char *)AUGROUP_NAME(i));
602 msg_puts(" ");
603 }
604 }
605 msg_clr_eos();
606 msg_end();
607 }
608}
609
610#if defined(EXITFREE) || defined(PROTO)
611 void
612free_all_autocmds(void)
613{
614 int i;
615 char_u *s;
616
617 for (current_augroup = -1; current_augroup < augroups.ga_len;
618 ++current_augroup)
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200619 do_autocmd(NULL, (char_u *)"", TRUE);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100620
621 for (i = 0; i < augroups.ga_len; ++i)
622 {
623 s = ((char_u **)(augroups.ga_data))[i];
624 if (s != get_deleted_augroup())
625 vim_free(s);
626 }
627 ga_clear(&augroups);
628}
629#endif
630
631/*
632 * Return the event number for event name "start".
633 * Return NUM_EVENTS if the event name was not found.
634 * Return a pointer to the next event name in "end".
635 */
636 static event_T
637event_name2nr(char_u *start, char_u **end)
638{
639 char_u *p;
640 int i;
641 int len;
642
643 // the event name ends with end of line, '|', a blank or a comma
644 for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
645 ;
646 for (i = 0; event_names[i].name != NULL; ++i)
647 {
648 len = (int)STRLEN(event_names[i].name);
649 if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
650 break;
651 }
652 if (*p == ',')
653 ++p;
654 *end = p;
655 if (event_names[i].name == NULL)
656 return NUM_EVENTS;
657 return event_names[i].event;
658}
659
660/*
661 * Return the name for event "event".
662 */
663 static char_u *
664event_nr2name(event_T event)
665{
666 int i;
667
668 for (i = 0; event_names[i].name != NULL; ++i)
669 if (event_names[i].event == event)
670 return (char_u *)event_names[i].name;
671 return (char_u *)"Unknown";
672}
673
674/*
675 * Scan over the events. "*" stands for all events.
676 */
677 static char_u *
678find_end_event(
679 char_u *arg,
680 int have_group) // TRUE when group name was found
681{
682 char_u *pat;
683 char_u *p;
684
685 if (*arg == '*')
686 {
687 if (arg[1] && !VIM_ISWHITE(arg[1]))
688 {
689 semsg(_("E215: Illegal character after *: %s"), arg);
690 return NULL;
691 }
692 pat = arg + 1;
693 }
694 else
695 {
696 for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
697 {
698 if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
699 {
700 if (have_group)
701 semsg(_("E216: No such event: %s"), pat);
702 else
703 semsg(_("E216: No such group or event: %s"), pat);
704 return NULL;
705 }
706 }
707 }
708 return pat;
709}
710
711/*
712 * Return TRUE if "event" is included in 'eventignore'.
713 */
714 static int
715event_ignored(event_T event)
716{
717 char_u *p = p_ei;
718
719 while (*p != NUL)
720 {
721 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
722 return TRUE;
723 if (event_name2nr(p, &p) == event)
724 return TRUE;
725 }
726
727 return FALSE;
728}
729
730/*
731 * Return OK when the contents of p_ei is valid, FAIL otherwise.
732 */
733 int
734check_ei(void)
735{
736 char_u *p = p_ei;
737
738 while (*p)
739 {
740 if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
741 {
742 p += 3;
743 if (*p == ',')
744 ++p;
745 }
746 else if (event_name2nr(p, &p) == NUM_EVENTS)
747 return FAIL;
748 }
749
750 return OK;
751}
752
753# if defined(FEAT_SYN_HL) || defined(PROTO)
754
755/*
756 * Add "what" to 'eventignore' to skip loading syntax highlighting for every
757 * buffer loaded into the window. "what" must start with a comma.
758 * Returns the old value of 'eventignore' in allocated memory.
759 */
760 char_u *
761au_event_disable(char *what)
762{
763 char_u *new_ei;
764 char_u *save_ei;
765
766 save_ei = vim_strsave(p_ei);
767 if (save_ei != NULL)
768 {
Bram Moolenaardf44a272020-06-07 20:49:05 +0200769 new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100770 if (new_ei != NULL)
771 {
772 if (*what == ',' && *p_ei == NUL)
773 STRCPY(new_ei, what + 1);
774 else
775 STRCAT(new_ei, what);
776 set_string_option_direct((char_u *)"ei", -1, new_ei,
777 OPT_FREE, SID_NONE);
778 vim_free(new_ei);
779 }
780 }
781 return save_ei;
782}
783
784 void
785au_event_restore(char_u *old_ei)
786{
787 if (old_ei != NULL)
788 {
789 set_string_option_direct((char_u *)"ei", -1, old_ei,
790 OPT_FREE, SID_NONE);
791 vim_free(old_ei);
792 }
793}
Bram Moolenaarc667da52019-11-30 20:52:27 +0100794# endif // FEAT_SYN_HL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100795
796/*
797 * do_autocmd() -- implements the :autocmd command. Can be used in the
798 * following ways:
799 *
800 * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that
801 * will be automatically executed for <event>
802 * when editing a file matching <pat>, in
803 * the current group.
804 * :autocmd <event> <pat> Show the autocommands associated with
805 * <event> and <pat>.
806 * :autocmd <event> Show the autocommands associated with
807 * <event>.
808 * :autocmd Show all autocommands.
809 * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with
810 * <event> and <pat>, and add the command
811 * <cmd>, for the current group.
812 * :autocmd! <event> <pat> Remove all autocommands associated with
813 * <event> and <pat> for the current group.
814 * :autocmd! <event> Remove all autocommands associated with
815 * <event> for the current group.
816 * :autocmd! Remove ALL autocommands for the current
817 * group.
818 *
819 * Multiple events and patterns may be given separated by commas. Here are
820 * some examples:
821 * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic
822 * :autocmd bufleave * set tw=79 nosmartindent ic infercase
823 *
824 * :autocmd * *.c show all autocommands for *.c files.
825 *
826 * Mostly a {group} argument can optionally appear before <event>.
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200827 * "eap" can be NULL.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100828 */
829 void
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200830do_autocmd(exarg_T *eap, char_u *arg_in, int forceit)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100831{
832 char_u *arg = arg_in;
833 char_u *pat;
834 char_u *envpat = NULL;
835 char_u *cmd;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200836 int cmd_need_free = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100837 event_T event;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200838 char_u *tofree = NULL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100839 int nested = FALSE;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200840 int once = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100841 int group;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200842 int i;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200843 int flags = 0;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100844
845 if (*arg == '|')
846 {
847 arg = (char_u *)"";
848 group = AUGROUP_ALL; // no argument, use all groups
849 }
850 else
851 {
852 /*
853 * Check for a legal group name. If not, use AUGROUP_ALL.
854 */
855 group = au_get_grouparg(&arg);
856 if (arg == NULL) // out of memory
857 return;
858 }
859
860 /*
861 * Scan over the events.
862 * If we find an illegal name, return here, don't do anything.
863 */
864 pat = find_end_event(arg, group != AUGROUP_ALL);
865 if (pat == NULL)
866 return;
867
868 pat = skipwhite(pat);
869 if (*pat == '|')
870 {
871 pat = (char_u *)"";
872 cmd = (char_u *)"";
873 }
874 else
875 {
876 /*
877 * Scan over the pattern. Put a NUL at the end.
878 */
879 cmd = pat;
880 while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
881 cmd++;
882 if (*cmd)
883 *cmd++ = NUL;
884
885 // Expand environment variables in the pattern. Set 'shellslash', we
886 // want forward slashes here.
887 if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
888 {
889#ifdef BACKSLASH_IN_FILENAME
890 int p_ssl_save = p_ssl;
891
892 p_ssl = TRUE;
893#endif
894 envpat = expand_env_save(pat);
895#ifdef BACKSLASH_IN_FILENAME
896 p_ssl = p_ssl_save;
897#endif
898 if (envpat != NULL)
899 pat = envpat;
900 }
901
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100902 cmd = skipwhite(cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200903 for (i = 0; i < 2; i++)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100904 {
Bram Moolenaareb93f3f2019-04-04 15:04:56 +0200905 if (*cmd != NUL)
906 {
907 // Check for "++once" flag.
908 if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
909 {
910 if (once)
911 semsg(_(e_duparg2), "++once");
912 once = TRUE;
913 cmd = skipwhite(cmd + 6);
914 }
915
916 // Check for "++nested" flag.
917 if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
918 {
919 if (nested)
920 semsg(_(e_duparg2), "++nested");
921 nested = TRUE;
922 cmd = skipwhite(cmd + 8);
923 }
924
925 // Check for the old "nested" flag.
926 if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
927 {
928 if (nested)
929 semsg(_(e_duparg2), "nested");
930 nested = TRUE;
931 cmd = skipwhite(cmd + 6);
932 }
933 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100934 }
935
936 /*
937 * Find the start of the commands.
938 * Expand <sfile> in it.
939 */
940 if (*cmd != NUL)
941 {
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200942 if (eap != NULL)
943 // Read a {} block if it follows.
944 cmd = may_get_cmd_block(eap, cmd, &tofree, &flags);
945
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100946 cmd = expand_sfile(cmd);
947 if (cmd == NULL) // some error
948 return;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200949 cmd_need_free = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100950 }
951 }
952
953 /*
954 * Print header when showing autocommands.
955 */
956 if (!forceit && *cmd == NUL)
957 // Highlight title
958 msg_puts_title(_("\n--- Autocommands ---"));
959
960 /*
961 * Loop over the events.
962 */
963 last_event = (event_T)-1; // for listing the event name
964 last_group = AUGROUP_ERROR; // for listing the group name
965 if (*arg == '*' || *arg == NUL || *arg == '|')
966 {
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100967 if (!forceit && *cmd != NUL)
968 emsg(_(e_cannot_define_autocommands_for_all_events));
969 else
970 for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
971 event = (event_T)((int)event + 1))
972 if (do_autocmd_event(event, pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200973 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100974 break;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100975 }
976 else
977 {
978 while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
979 if (do_autocmd_event(event_name2nr(arg, &arg), pat,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200980 once, nested, cmd, forceit, group, flags) == FAIL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100981 break;
982 }
983
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200984 if (cmd_need_free)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100985 vim_free(cmd);
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +0200986 vim_free(tofree);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100987 vim_free(envpat);
988}
989
990/*
991 * Find the group ID in a ":autocmd" or ":doautocmd" argument.
992 * The "argp" argument is advanced to the following argument.
993 *
994 * Returns the group ID, AUGROUP_ERROR for error (out of memory).
995 */
996 static int
997au_get_grouparg(char_u **argp)
998{
999 char_u *group_name;
1000 char_u *p;
1001 char_u *arg = *argp;
1002 int group = AUGROUP_ALL;
1003
1004 for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
1005 ;
1006 if (p > arg)
1007 {
Bram Moolenaardf44a272020-06-07 20:49:05 +02001008 group_name = vim_strnsave(arg, p - arg);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001009 if (group_name == NULL) // out of memory
1010 return AUGROUP_ERROR;
1011 group = au_find_group(group_name);
1012 if (group == AUGROUP_ERROR)
1013 group = AUGROUP_ALL; // no match, use all groups
1014 else
1015 *argp = skipwhite(p); // match, skip over group name
1016 vim_free(group_name);
1017 }
1018 return group;
1019}
1020
1021/*
1022 * do_autocmd() for one event.
1023 * If *pat == NUL do for all patterns.
1024 * If *cmd == NUL show entries.
1025 * If forceit == TRUE delete entries.
1026 * If group is not AUGROUP_ALL, only use this group.
1027 */
1028 static int
1029do_autocmd_event(
1030 event_T event,
1031 char_u *pat,
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001032 int once,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001033 int nested,
1034 char_u *cmd,
1035 int forceit,
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001036 int group,
1037 int flags)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001038{
1039 AutoPat *ap;
1040 AutoPat **prev_ap;
1041 AutoCmd *ac;
1042 AutoCmd **prev_ac;
1043 int brace_level;
1044 char_u *endpat;
1045 int findgroup;
1046 int allgroups;
1047 int patlen;
1048 int is_buflocal;
1049 int buflocal_nr;
Bram Moolenaarc667da52019-11-30 20:52:27 +01001050 char_u buflocal_pat[25]; // for "<buffer=X>"
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001051
1052 if (group == AUGROUP_ALL)
1053 findgroup = current_augroup;
1054 else
1055 findgroup = group;
1056 allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
1057
1058 /*
1059 * Show or delete all patterns for an event.
1060 */
1061 if (*pat == NUL)
1062 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +02001063 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001064 {
1065 if (forceit) // delete the AutoPat, if it's in the current group
1066 {
1067 if (ap->group == findgroup)
1068 au_remove_pat(ap);
1069 }
1070 else if (group == AUGROUP_ALL || ap->group == group)
1071 show_autocmd(ap, event);
1072 }
1073 }
1074
1075 /*
1076 * Loop through all the specified patterns.
1077 */
1078 for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
1079 {
1080 /*
1081 * Find end of the pattern.
1082 * Watch out for a comma in braces, like "*.\{obj,o\}".
1083 */
1084 brace_level = 0;
1085 for (endpat = pat; *endpat && (*endpat != ',' || brace_level
1086 || (endpat > pat && endpat[-1] == '\\')); ++endpat)
1087 {
1088 if (*endpat == '{')
1089 brace_level++;
1090 else if (*endpat == '}')
1091 brace_level--;
1092 }
1093 if (pat == endpat) // ignore single comma
1094 continue;
1095 patlen = (int)(endpat - pat);
1096
1097 /*
1098 * detect special <buflocal[=X]> buffer-local patterns
1099 */
1100 is_buflocal = FALSE;
1101 buflocal_nr = 0;
1102
1103 if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
1104 && pat[patlen - 1] == '>')
1105 {
1106 // "<buffer...>": Error will be printed only for addition.
1107 // printing and removing will proceed silently.
1108 is_buflocal = TRUE;
1109 if (patlen == 8)
1110 // "<buffer>"
1111 buflocal_nr = curbuf->b_fnum;
1112 else if (patlen > 9 && pat[7] == '=')
1113 {
1114 if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
1115 // "<buffer=abuf>"
1116 buflocal_nr = autocmd_bufnr;
1117 else if (skipdigits(pat + 8) == pat + patlen - 1)
1118 // "<buffer=123>"
1119 buflocal_nr = atoi((char *)pat + 8);
1120 }
1121 }
1122
1123 if (is_buflocal)
1124 {
1125 // normalize pat into standard "<buffer>#N" form
1126 sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
1127 pat = buflocal_pat; // can modify pat and patlen
1128 patlen = (int)STRLEN(buflocal_pat); // but not endpat
1129 }
1130
1131 /*
1132 * Find AutoPat entries with this pattern. When adding a command it
1133 * always goes at or after the last one, so start at the end.
1134 */
1135 if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
1136 prev_ap = &last_autopat[(int)event];
1137 else
1138 prev_ap = &first_autopat[(int)event];
1139 while ((ap = *prev_ap) != NULL)
1140 {
1141 if (ap->pat != NULL)
1142 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001143 /*
1144 * Accept a pattern when:
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001145 * - a group was specified and it's that group, or a group was
1146 * not specified and it's the current group, or a group was
1147 * not specified and we are listing
1148 * - the length of the pattern matches
1149 * - the pattern matches.
1150 * For <buffer[=X]>, this condition works because we normalize
1151 * all buffer-local patterns.
1152 */
1153 if ((allgroups || ap->group == findgroup)
1154 && ap->patlen == patlen
1155 && STRNCMP(pat, ap->pat, patlen) == 0)
1156 {
1157 /*
1158 * Remove existing autocommands.
1159 * If adding any new autocmd's for this AutoPat, don't
1160 * delete the pattern from the autopat list, append to
1161 * this list.
1162 */
1163 if (forceit)
1164 {
1165 if (*cmd != NUL && ap->next == NULL)
1166 {
1167 au_remove_cmds(ap);
1168 break;
1169 }
1170 au_remove_pat(ap);
1171 }
1172
1173 /*
1174 * Show autocmd's for this autopat, or buflocals <buffer=X>
1175 */
1176 else if (*cmd == NUL)
1177 show_autocmd(ap, event);
1178
1179 /*
1180 * Add autocmd to this autopat, if it's the last one.
1181 */
1182 else if (ap->next == NULL)
1183 break;
1184 }
1185 }
1186 prev_ap = &ap->next;
1187 }
1188
1189 /*
1190 * Add a new command.
1191 */
1192 if (*cmd != NUL)
1193 {
1194 /*
1195 * If the pattern we want to add a command to does appear at the
1196 * end of the list (or not is not in the list at all), add the
1197 * pattern at the end of the list.
1198 */
1199 if (ap == NULL)
1200 {
Bram Moolenaarc667da52019-11-30 20:52:27 +01001201 // refuse to add buffer-local ap if buffer number is invalid
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001202 if (is_buflocal && (buflocal_nr == 0
1203 || buflist_findnr(buflocal_nr) == NULL))
1204 {
1205 semsg(_("E680: <buffer=%d>: invalid buffer number "),
1206 buflocal_nr);
1207 return FAIL;
1208 }
1209
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001210 ap = ALLOC_ONE(AutoPat);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001211 if (ap == NULL)
1212 return FAIL;
1213 ap->pat = vim_strnsave(pat, patlen);
1214 ap->patlen = patlen;
1215 if (ap->pat == NULL)
1216 {
1217 vim_free(ap);
1218 return FAIL;
1219 }
1220
1221 if (is_buflocal)
1222 {
1223 ap->buflocal_nr = buflocal_nr;
1224 ap->reg_prog = NULL;
1225 }
1226 else
1227 {
1228 char_u *reg_pat;
1229
1230 ap->buflocal_nr = 0;
1231 reg_pat = file_pat_to_reg_pat(pat, endpat,
1232 &ap->allow_dirs, TRUE);
1233 if (reg_pat != NULL)
1234 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1235 vim_free(reg_pat);
1236 if (reg_pat == NULL || ap->reg_prog == NULL)
1237 {
1238 vim_free(ap->pat);
1239 vim_free(ap);
1240 return FAIL;
1241 }
1242 }
1243 ap->cmds = NULL;
1244 *prev_ap = ap;
1245 last_autopat[(int)event] = ap;
1246 ap->next = NULL;
1247 if (group == AUGROUP_ALL)
1248 ap->group = current_augroup;
1249 else
1250 ap->group = group;
1251 }
1252
1253 /*
1254 * Add the autocmd at the end of the AutoCmd list.
1255 */
1256 prev_ac = &(ap->cmds);
1257 while ((ac = *prev_ac) != NULL)
1258 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001259 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001260 if (ac == NULL)
1261 return FAIL;
1262 ac->cmd = vim_strsave(cmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001263 ac->script_ctx = current_sctx;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001264 if (flags & UC_VIM9)
1265 ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001266#ifdef FEAT_EVAL
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001267 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001268#endif
1269 if (ac->cmd == NULL)
1270 {
1271 vim_free(ac);
1272 return FAIL;
1273 }
1274 ac->next = NULL;
1275 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001276 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001277 ac->nested = nested;
1278 }
1279 }
1280
1281 au_cleanup(); // may really delete removed patterns/commands now
1282 return OK;
1283}
1284
1285/*
1286 * Implementation of ":doautocmd [group] event [fname]".
1287 * Return OK for success, FAIL for failure;
1288 */
1289 int
1290do_doautocmd(
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001291 char_u *arg_start,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001292 int do_msg, // give message for no matching autocmds?
1293 int *did_something)
1294{
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001295 char_u *arg = arg_start;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001296 char_u *fname;
1297 int nothing_done = TRUE;
1298 int group;
1299
1300 if (did_something != NULL)
1301 *did_something = FALSE;
1302
1303 /*
1304 * Check for a legal group name. If not, use AUGROUP_ALL.
1305 */
1306 group = au_get_grouparg(&arg);
1307 if (arg == NULL) // out of memory
1308 return FAIL;
1309
1310 if (*arg == '*')
1311 {
1312 emsg(_("E217: Can't execute autocommands for ALL events"));
1313 return FAIL;
1314 }
1315
1316 /*
1317 * Scan over the events.
1318 * If we find an illegal name, return here, don't do anything.
1319 */
1320 fname = find_end_event(arg, group != AUGROUP_ALL);
1321 if (fname == NULL)
1322 return FAIL;
1323
1324 fname = skipwhite(fname);
1325
1326 /*
1327 * Loop over the events.
1328 */
1329 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1330 if (apply_autocmds_group(event_name2nr(arg, &arg),
1331 fname, NULL, TRUE, group, curbuf, NULL))
1332 nothing_done = FALSE;
1333
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001334 if (nothing_done && do_msg
1335#ifdef FEAT_EVAL
1336 && !aborting()
1337#endif
1338 )
1339 smsg(_("No matching autocommands: %s"), arg_start);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001340 if (did_something != NULL)
1341 *did_something = !nothing_done;
1342
1343#ifdef FEAT_EVAL
1344 return aborting() ? FAIL : OK;
1345#else
1346 return OK;
1347#endif
1348}
1349
1350/*
1351 * ":doautoall": execute autocommands for each loaded buffer.
1352 */
1353 void
1354ex_doautoall(exarg_T *eap)
1355{
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001356 int retval = OK;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001357 aco_save_T aco;
1358 buf_T *buf;
1359 bufref_T bufref;
1360 char_u *arg = eap->arg;
1361 int call_do_modelines = check_nomodeline(&arg);
1362 int did_aucmd;
1363
1364 /*
1365 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1366 * equal to curbuf, but for some buffers there may not be a window.
1367 * So we change the buffer for the current window for a moment. This
1368 * gives problems when the autocommands make changes to the list of
1369 * buffers or windows...
1370 */
1371 FOR_ALL_BUFFERS(buf)
1372 {
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001373 // Only do loaded buffers and skip the current buffer, it's done last.
1374 if (buf->b_ml.ml_mfp != NULL && buf != curbuf)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001375 {
1376 // find a window for this buffer and save some values
1377 aucmd_prepbuf(&aco, buf);
1378 set_bufref(&bufref, buf);
1379
1380 // execute the autocommands for this buffer
1381 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1382
1383 if (call_do_modelines && did_aucmd)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001384 // Execute the modeline settings, but don't set window-local
1385 // options if we are using the current window for another
1386 // buffer.
1387 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001388
1389 // restore the current window
1390 aucmd_restbuf(&aco);
1391
1392 // stop if there is some error or buffer was deleted
1393 if (retval == FAIL || !bufref_valid(&bufref))
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001394 {
1395 retval = FAIL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001396 break;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001397 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001398 }
1399 }
1400
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001401 // Execute autocommands for the current buffer last.
1402 if (retval == OK)
1403 {
1404 do_doautocmd(arg, FALSE, &did_aucmd);
1405 if (call_do_modelines && did_aucmd)
1406 do_modelines(0);
1407 }
1408
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001409 check_cursor(); // just in case lines got deleted
1410}
1411
1412/*
1413 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1414 * return TRUE and advance *argp to after it.
1415 * Thus return TRUE when do_modelines() should be called.
1416 */
1417 int
1418check_nomodeline(char_u **argp)
1419{
1420 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1421 {
1422 *argp = skipwhite(*argp + 12);
1423 return FALSE;
1424 }
1425 return TRUE;
1426}
1427
1428/*
1429 * Prepare for executing autocommands for (hidden) buffer "buf".
1430 * Search for a visible window containing the current buffer. If there isn't
1431 * one then use "aucmd_win".
1432 * Set "curbuf" and "curwin" to match "buf".
1433 */
1434 void
1435aucmd_prepbuf(
1436 aco_save_T *aco, // structure to save values in
1437 buf_T *buf) // new curbuf
1438{
1439 win_T *win;
1440 int save_ea;
1441#ifdef FEAT_AUTOCHDIR
1442 int save_acd;
1443#endif
1444
1445 // Find a window that is for the new buffer
1446 if (buf == curbuf) // be quick when buf is curbuf
1447 win = curwin;
1448 else
1449 FOR_ALL_WINDOWS(win)
1450 if (win->w_buffer == buf)
1451 break;
1452
1453 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1454 // back to using the current window.
1455 if (win == NULL && aucmd_win == NULL)
1456 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001457 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001458 if (aucmd_win == NULL)
1459 win = curwin;
1460 }
1461 if (win == NULL && aucmd_win_used)
1462 // Strange recursive autocommand, fall back to using the current
1463 // window. Expect a few side effects...
1464 win = curwin;
1465
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001466 aco->save_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001467 aco->save_curbuf = curbuf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001468 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001469 if (win != NULL)
1470 {
1471 // There is a window for "buf" in the current tab page, make it the
1472 // curwin. This is preferred, it has the least side effects (esp. if
1473 // "buf" is curbuf).
1474 aco->use_aucmd_win = FALSE;
1475 curwin = win;
1476 }
1477 else
1478 {
1479 // There is no window for "buf", use "aucmd_win". To minimize the side
1480 // effects, insert it in the current tab page.
1481 // Anything related to a window (e.g., setting folds) may have
1482 // unexpected results.
1483 aco->use_aucmd_win = TRUE;
1484 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001485
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001486 win_init_popup_win(aucmd_win, buf);
1487
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001488 aco->globaldir = globaldir;
1489 globaldir = NULL;
1490
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001491 // Split the current window, put the aucmd_win in the upper half.
1492 // We don't want the BufEnter or WinEnter autocommands.
1493 block_autocmds();
1494 make_snapshot(SNAP_AUCMD_IDX);
1495 save_ea = p_ea;
1496 p_ea = FALSE;
1497
1498#ifdef FEAT_AUTOCHDIR
1499 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1500 save_acd = p_acd;
1501 p_acd = FALSE;
1502#endif
1503
1504 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
1505 (void)win_comp_pos(); // recompute window positions
1506 p_ea = save_ea;
1507#ifdef FEAT_AUTOCHDIR
1508 p_acd = save_acd;
1509#endif
1510 unblock_autocmds();
1511 curwin = aucmd_win;
1512 }
1513 curbuf = buf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001514 aco->new_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001515 set_bufref(&aco->new_curbuf, curbuf);
1516}
1517
1518/*
1519 * Cleanup after executing autocommands for a (hidden) buffer.
1520 * Restore the window as it was (if possible).
1521 */
1522 void
1523aucmd_restbuf(
1524 aco_save_T *aco) // structure holding saved values
1525{
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001526 int dummy;
1527 win_T *save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001528
1529 if (aco->use_aucmd_win)
1530 {
1531 --curbuf->b_nwindows;
1532 // Find "aucmd_win", it can't be closed, but it may be in another tab
1533 // page. Do not trigger autocommands here.
1534 block_autocmds();
1535 if (curwin != aucmd_win)
1536 {
1537 tabpage_T *tp;
1538 win_T *wp;
1539
1540 FOR_ALL_TAB_WINDOWS(tp, wp)
1541 {
1542 if (wp == aucmd_win)
1543 {
1544 if (tp != curtab)
1545 goto_tabpage_tp(tp, TRUE, TRUE);
1546 win_goto(aucmd_win);
1547 goto win_found;
1548 }
1549 }
1550 }
1551win_found:
1552
1553 // Remove the window and frame from the tree of frames.
1554 (void)winframe_remove(curwin, &dummy, NULL);
1555 win_remove(curwin, NULL);
1556 aucmd_win_used = FALSE;
1557 last_status(FALSE); // may need to remove last status line
1558
1559 if (!valid_tabpage_win(curtab))
1560 // no valid window in current tabpage
1561 close_tabpage(curtab);
1562
1563 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1564 (void)win_comp_pos(); // recompute window positions
1565 unblock_autocmds();
1566
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001567 save_curwin = win_find_by_id(aco->save_curwin_id);
1568 if (save_curwin != NULL)
1569 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001570 else
1571 // Hmm, original window disappeared. Just use the first one.
1572 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001573 curbuf = curwin->w_buffer;
1574#ifdef FEAT_JOB_CHANNEL
1575 // May need to restore insert mode for a prompt buffer.
1576 entering_window(curwin);
1577#endif
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001578 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001579#ifdef FEAT_EVAL
1580 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1581 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1582#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001583 vim_free(globaldir);
1584 globaldir = aco->globaldir;
1585
1586 // the buffer contents may have changed
1587 check_cursor();
1588 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1589 {
1590 curwin->w_topline = curbuf->b_ml.ml_line_count;
1591#ifdef FEAT_DIFF
1592 curwin->w_topfill = 0;
1593#endif
1594 }
1595#if defined(FEAT_GUI)
1596 // Hide the scrollbars from the aucmd_win and update.
1597 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1598 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1599 gui_may_update_scrollbars();
1600#endif
1601 }
1602 else
1603 {
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001604 // Restore curwin. Use the window ID, a window may have been closed
1605 // and the memory re-used for another one.
1606 save_curwin = win_find_by_id(aco->save_curwin_id);
1607 if (save_curwin != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001608 {
1609 // Restore the buffer which was previously edited by curwin, if
1610 // it was changed, we are still the same window and the buffer is
1611 // valid.
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001612 if (curwin->w_id == aco->new_curwin_id
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001613 && curbuf != aco->new_curbuf.br_buf
1614 && bufref_valid(&aco->new_curbuf)
1615 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1616 {
1617# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1618 if (curwin->w_s == &curbuf->b_s)
1619 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1620# endif
1621 --curbuf->b_nwindows;
1622 curbuf = aco->new_curbuf.br_buf;
1623 curwin->w_buffer = curbuf;
1624 ++curbuf->b_nwindows;
1625 }
1626
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001627 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001628 curbuf = curwin->w_buffer;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001629 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001630 // In case the autocommand moves the cursor to a position that
1631 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001632 check_cursor();
1633 }
1634 }
1635}
1636
1637static int autocmd_nested = FALSE;
1638
1639/*
1640 * Execute autocommands for "event" and file name "fname".
1641 * Return TRUE if some commands were executed.
1642 */
1643 int
1644apply_autocmds(
1645 event_T event,
1646 char_u *fname, // NULL or empty means use actual file name
1647 char_u *fname_io, // fname to use for <afile> on cmdline
1648 int force, // when TRUE, ignore autocmd_busy
1649 buf_T *buf) // buffer for <abuf>
1650{
1651 return apply_autocmds_group(event, fname, fname_io, force,
1652 AUGROUP_ALL, buf, NULL);
1653}
1654
1655/*
1656 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1657 * setting v:filearg.
1658 */
1659 int
1660apply_autocmds_exarg(
1661 event_T event,
1662 char_u *fname,
1663 char_u *fname_io,
1664 int force,
1665 buf_T *buf,
1666 exarg_T *eap)
1667{
1668 return apply_autocmds_group(event, fname, fname_io, force,
1669 AUGROUP_ALL, buf, eap);
1670}
1671
1672/*
1673 * Like apply_autocmds(), but handles the caller's retval. If the script
1674 * processing is being aborted or if retval is FAIL when inside a try
1675 * conditional, no autocommands are executed. If otherwise the autocommands
1676 * cause the script to be aborted, retval is set to FAIL.
1677 */
1678 int
1679apply_autocmds_retval(
1680 event_T event,
1681 char_u *fname, // NULL or empty means use actual file name
1682 char_u *fname_io, // fname to use for <afile> on cmdline
1683 int force, // when TRUE, ignore autocmd_busy
1684 buf_T *buf, // buffer for <abuf>
1685 int *retval) // pointer to caller's retval
1686{
1687 int did_cmd;
1688
1689#ifdef FEAT_EVAL
1690 if (should_abort(*retval))
1691 return FALSE;
1692#endif
1693
1694 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1695 AUGROUP_ALL, buf, NULL);
1696 if (did_cmd
1697#ifdef FEAT_EVAL
1698 && aborting()
1699#endif
1700 )
1701 *retval = FAIL;
1702 return did_cmd;
1703}
1704
1705/*
1706 * Return TRUE when there is a CursorHold autocommand defined.
1707 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001708 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001709has_cursorhold(void)
1710{
1711 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1712 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1713}
1714
1715/*
1716 * Return TRUE if the CursorHold event can be triggered.
1717 */
1718 int
1719trigger_cursorhold(void)
1720{
1721 int state;
1722
1723 if (!did_cursorhold
1724 && has_cursorhold()
1725 && reg_recording == 0
1726 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001727 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001728 {
1729 state = get_real_state();
1730 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1731 return TRUE;
1732 }
1733 return FALSE;
1734}
1735
1736/*
1737 * Return TRUE when there is a CursorMoved autocommand defined.
1738 */
1739 int
1740has_cursormoved(void)
1741{
1742 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1743}
1744
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001745/*
1746 * Return TRUE when there is a CursorMovedI autocommand defined.
1747 */
1748 int
1749has_cursormovedI(void)
1750{
1751 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1752}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001753
1754/*
1755 * Return TRUE when there is a TextChanged autocommand defined.
1756 */
1757 int
1758has_textchanged(void)
1759{
1760 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1761}
1762
1763/*
1764 * Return TRUE when there is a TextChangedI autocommand defined.
1765 */
1766 int
1767has_textchangedI(void)
1768{
1769 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1770}
1771
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001772/*
1773 * Return TRUE when there is a TextChangedP autocommand defined.
1774 */
1775 int
1776has_textchangedP(void)
1777{
1778 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1779}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001780
1781/*
1782 * Return TRUE when there is an InsertCharPre autocommand defined.
1783 */
1784 int
1785has_insertcharpre(void)
1786{
1787 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1788}
1789
1790/*
1791 * Return TRUE when there is an CmdUndefined autocommand defined.
1792 */
1793 int
1794has_cmdundefined(void)
1795{
1796 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1797}
1798
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001799#if defined(FEAT_EVAL) || defined(PROTO)
1800/*
1801 * Return TRUE when there is a TextYankPost autocommand defined.
1802 */
1803 int
1804has_textyankpost(void)
1805{
1806 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1807}
1808#endif
1809
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001810#if defined(FEAT_EVAL) || defined(PROTO)
1811/*
1812 * Return TRUE when there is a CompleteChanged autocommand defined.
1813 */
1814 int
1815has_completechanged(void)
1816{
1817 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1818}
1819#endif
1820
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001821#if defined(FEAT_EVAL) || defined(PROTO)
1822/*
1823 * Return TRUE when there is a ModeChanged autocommand defined.
1824 */
1825 int
1826has_modechanged(void)
1827{
1828 return (first_autopat[(int)EVENT_MODECHANGED] != NULL);
1829}
1830#endif
1831
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001832/*
1833 * Execute autocommands for "event" and file name "fname".
1834 * Return TRUE if some commands were executed.
1835 */
1836 static int
1837apply_autocmds_group(
1838 event_T event,
1839 char_u *fname, // NULL or empty means use actual file name
1840 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1841 // use fname
1842 int force, // when TRUE, ignore autocmd_busy
1843 int group, // group ID, or AUGROUP_ALL
1844 buf_T *buf, // buffer for <abuf>
1845 exarg_T *eap UNUSED) // command arguments
1846{
1847 char_u *sfname = NULL; // short file name
1848 char_u *tail;
1849 int save_changed;
1850 buf_T *old_curbuf;
1851 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001852 char_u *save_autocmd_fname;
1853 int save_autocmd_fname_full;
1854 int save_autocmd_bufnr;
1855 char_u *save_autocmd_match;
1856 int save_autocmd_busy;
1857 int save_autocmd_nested;
1858 static int nesting = 0;
1859 AutoPatCmd patcmd;
1860 AutoPat *ap;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001861 sctx_T save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001862#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001863 funccal_entry_T funccal_entry;
1864 char_u *save_cmdarg;
1865 long save_cmdbang;
1866#endif
1867 static int filechangeshell_busy = FALSE;
1868#ifdef FEAT_PROFILE
1869 proftime_T wait_time;
1870#endif
1871 int did_save_redobuff = FALSE;
1872 save_redo_T save_redo;
1873 int save_KeyTyped = KeyTyped;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001874 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001875
1876 /*
1877 * Quickly return if there are no autocommands for this event or
1878 * autocommands are blocked.
1879 */
1880 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1881 || autocmd_blocked > 0)
1882 goto BYPASS_AU;
1883
1884 /*
1885 * When autocommands are busy, new autocommands are only executed when
1886 * explicitly enabled with the "nested" flag.
1887 */
1888 if (autocmd_busy && !(force || autocmd_nested))
1889 goto BYPASS_AU;
1890
1891#ifdef FEAT_EVAL
1892 /*
1893 * Quickly return when immediately aborting on error, or when an interrupt
1894 * occurred or an exception was thrown but not caught.
1895 */
1896 if (aborting())
1897 goto BYPASS_AU;
1898#endif
1899
1900 /*
1901 * FileChangedShell never nests, because it can create an endless loop.
1902 */
1903 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1904 || event == EVENT_FILECHANGEDSHELLPOST))
1905 goto BYPASS_AU;
1906
1907 /*
1908 * Ignore events in 'eventignore'.
1909 */
1910 if (event_ignored(event))
1911 goto BYPASS_AU;
1912
1913 /*
1914 * Allow nesting of autocommands, but restrict the depth, because it's
1915 * possible to create an endless loop.
1916 */
1917 if (nesting == 10)
1918 {
1919 emsg(_("E218: autocommand nesting too deep"));
1920 goto BYPASS_AU;
1921 }
1922
1923 /*
1924 * Check if these autocommands are disabled. Used when doing ":all" or
1925 * ":ball".
1926 */
1927 if ( (autocmd_no_enter
1928 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1929 || (autocmd_no_leave
1930 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1931 goto BYPASS_AU;
1932
1933 /*
1934 * Save the autocmd_* variables and info about the current buffer.
1935 */
1936 save_autocmd_fname = autocmd_fname;
1937 save_autocmd_fname_full = autocmd_fname_full;
1938 save_autocmd_bufnr = autocmd_bufnr;
1939 save_autocmd_match = autocmd_match;
1940 save_autocmd_busy = autocmd_busy;
1941 save_autocmd_nested = autocmd_nested;
1942 save_changed = curbuf->b_changed;
1943 old_curbuf = curbuf;
1944
1945 /*
1946 * Set the file name to be used for <afile>.
1947 * Make a copy to avoid that changing a buffer name or directory makes it
1948 * invalid.
1949 */
1950 if (fname_io == NULL)
1951 {
1952 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001953 || event == EVENT_OPTIONSET
1954 || event == EVENT_MODECHANGED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001955 autocmd_fname = NULL;
1956 else if (fname != NULL && !ends_excmd(*fname))
1957 autocmd_fname = fname;
1958 else if (buf != NULL)
1959 autocmd_fname = buf->b_ffname;
1960 else
1961 autocmd_fname = NULL;
1962 }
1963 else
1964 autocmd_fname = fname_io;
1965 if (autocmd_fname != NULL)
1966 autocmd_fname = vim_strsave(autocmd_fname);
1967 autocmd_fname_full = FALSE; // call FullName_save() later
1968
1969 /*
1970 * Set the buffer number to be used for <abuf>.
1971 */
1972 if (buf == NULL)
1973 autocmd_bufnr = 0;
1974 else
1975 autocmd_bufnr = buf->b_fnum;
1976
1977 /*
1978 * When the file name is NULL or empty, use the file name of buffer "buf".
1979 * Always use the full path of the file name to match with, in case
1980 * "allow_dirs" is set.
1981 */
1982 if (fname == NULL || *fname == NUL)
1983 {
1984 if (buf == NULL)
1985 fname = NULL;
1986 else
1987 {
1988#ifdef FEAT_SYN_HL
1989 if (event == EVENT_SYNTAX)
1990 fname = buf->b_p_syn;
1991 else
1992#endif
1993 if (event == EVENT_FILETYPE)
1994 fname = buf->b_p_ft;
1995 else
1996 {
1997 if (buf->b_sfname != NULL)
1998 sfname = vim_strsave(buf->b_sfname);
1999 fname = buf->b_ffname;
2000 }
2001 }
2002 if (fname == NULL)
2003 fname = (char_u *)"";
2004 fname = vim_strsave(fname); // make a copy, so we can change it
2005 }
2006 else
2007 {
2008 sfname = vim_strsave(fname);
2009 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
2010 // ColorScheme, QuickFixCmd* or DirChanged
2011 if (event == EVENT_FILETYPE
2012 || event == EVENT_SYNTAX
2013 || event == EVENT_CMDLINECHANGED
2014 || event == EVENT_CMDLINEENTER
2015 || event == EVENT_CMDLINELEAVE
2016 || event == EVENT_CMDWINENTER
2017 || event == EVENT_CMDWINLEAVE
2018 || event == EVENT_CMDUNDEFINED
2019 || event == EVENT_FUNCUNDEFINED
2020 || event == EVENT_REMOTEREPLY
2021 || event == EVENT_SPELLFILEMISSING
2022 || event == EVENT_QUICKFIXCMDPRE
2023 || event == EVENT_COLORSCHEME
2024 || event == EVENT_COLORSCHEMEPRE
2025 || event == EVENT_OPTIONSET
2026 || event == EVENT_QUICKFIXCMDPOST
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02002027 || event == EVENT_DIRCHANGED
2028 || event == EVENT_MODECHANGED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002029 {
2030 fname = vim_strsave(fname);
2031 autocmd_fname_full = TRUE; // don't expand it later
2032 }
2033 else
2034 fname = FullName_save(fname, FALSE);
2035 }
2036 if (fname == NULL) // out of memory
2037 {
2038 vim_free(sfname);
2039 retval = FALSE;
2040 goto BYPASS_AU;
2041 }
2042
2043#ifdef BACKSLASH_IN_FILENAME
2044 /*
2045 * Replace all backslashes with forward slashes. This makes the
2046 * autocommand patterns portable between Unix and MS-DOS.
2047 */
2048 if (sfname != NULL)
2049 forward_slash(sfname);
2050 forward_slash(fname);
2051#endif
2052
2053#ifdef VMS
2054 // remove version for correct match
2055 if (sfname != NULL)
2056 vms_remove_version(sfname);
2057 vms_remove_version(fname);
2058#endif
2059
2060 /*
2061 * Set the name to be used for <amatch>.
2062 */
2063 autocmd_match = fname;
2064
2065
2066 // Don't redraw while doing autocommands.
2067 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002068
2069 // name and lnum are filled in later
2070 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002071 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002072
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002073 save_current_sctx = current_sctx;
2074
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002075#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002076# ifdef FEAT_PROFILE
2077 if (do_profiling == PROF_YES)
2078 prof_child_enter(&wait_time); // doesn't count for the caller itself
2079# endif
2080
2081 // Don't use local function variables, if called from a function.
2082 save_funccal(&funccal_entry);
2083#endif
2084
2085 /*
2086 * When starting to execute autocommands, save the search patterns.
2087 */
2088 if (!autocmd_busy)
2089 {
2090 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002091 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002092 {
2093 saveRedobuff(&save_redo);
2094 did_save_redobuff = TRUE;
2095 }
2096 did_filetype = keep_filetype;
2097 }
2098
2099 /*
2100 * Note that we are applying autocmds. Some commands need to know.
2101 */
2102 autocmd_busy = TRUE;
2103 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2104 ++nesting; // see matching decrement below
2105
2106 // Remember that FileType was triggered. Used for did_filetype().
2107 if (event == EVENT_FILETYPE)
2108 did_filetype = TRUE;
2109
2110 tail = gettail(fname);
2111
2112 // Find first autocommand that matches
2113 patcmd.curpat = first_autopat[(int)event];
2114 patcmd.nextcmd = NULL;
2115 patcmd.group = group;
2116 patcmd.fname = fname;
2117 patcmd.sfname = sfname;
2118 patcmd.tail = tail;
2119 patcmd.event = event;
2120 patcmd.arg_bufnr = autocmd_bufnr;
2121 patcmd.next = NULL;
2122 auto_next_pat(&patcmd, FALSE);
2123
2124 // found one, start executing the autocommands
2125 if (patcmd.curpat != NULL)
2126 {
2127 // add to active_apc_list
2128 patcmd.next = active_apc_list;
2129 active_apc_list = &patcmd;
2130
2131#ifdef FEAT_EVAL
2132 // set v:cmdarg (only when there is a matching pattern)
2133 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2134 if (eap != NULL)
2135 {
2136 save_cmdarg = set_cmdarg(eap, NULL);
2137 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2138 }
2139 else
2140 save_cmdarg = NULL; // avoid gcc warning
2141#endif
2142 retval = TRUE;
2143 // mark the last pattern, to avoid an endless loop when more patterns
2144 // are added when executing autocommands
2145 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2146 ap->last = FALSE;
2147 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002148
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002149 if (nesting == 1)
2150 // make sure cursor and topline are valid
2151 check_lnums(TRUE);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002152
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002153 do_cmdline(NULL, getnextac, (void *)&patcmd,
2154 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002155
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002156 if (nesting == 1)
2157 // restore cursor and topline, unless they were changed
2158 reset_lnums();
Bram Moolenaara68e5952019-04-25 22:22:01 +02002159
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002160#ifdef FEAT_EVAL
2161 if (eap != NULL)
2162 {
2163 (void)set_cmdarg(NULL, save_cmdarg);
2164 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2165 }
2166#endif
2167 // delete from active_apc_list
2168 if (active_apc_list == &patcmd) // just in case
2169 active_apc_list = patcmd.next;
2170 }
2171
2172 --RedrawingDisabled;
2173 autocmd_busy = save_autocmd_busy;
2174 filechangeshell_busy = FALSE;
2175 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002176 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002177 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002178 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002179 vim_free(autocmd_fname);
2180 autocmd_fname = save_autocmd_fname;
2181 autocmd_fname_full = save_autocmd_fname_full;
2182 autocmd_bufnr = save_autocmd_bufnr;
2183 autocmd_match = save_autocmd_match;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002184 current_sctx = save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002185#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002186 restore_funccal();
2187# ifdef FEAT_PROFILE
2188 if (do_profiling == PROF_YES)
2189 prof_child_exit(&wait_time);
2190# endif
2191#endif
2192 KeyTyped = save_KeyTyped;
2193 vim_free(fname);
2194 vim_free(sfname);
2195 --nesting; // see matching increment above
2196
2197 /*
2198 * When stopping to execute autocommands, restore the search patterns and
2199 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2200 * free any windows in the au_pending_free_win list.
2201 */
2202 if (!autocmd_busy)
2203 {
2204 restore_search_patterns();
2205 if (did_save_redobuff)
2206 restoreRedobuff(&save_redo);
2207 did_filetype = FALSE;
2208 while (au_pending_free_buf != NULL)
2209 {
2210 buf_T *b = au_pending_free_buf->b_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002211
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002212 vim_free(au_pending_free_buf);
2213 au_pending_free_buf = b;
2214 }
2215 while (au_pending_free_win != NULL)
2216 {
2217 win_T *w = au_pending_free_win->w_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002218
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002219 vim_free(au_pending_free_win);
2220 au_pending_free_win = w;
2221 }
2222 }
2223
2224 /*
2225 * Some events don't set or reset the Changed flag.
2226 * Check if still in the same buffer!
2227 */
2228 if (curbuf == old_curbuf
2229 && (event == EVENT_BUFREADPOST
2230 || event == EVENT_BUFWRITEPOST
2231 || event == EVENT_FILEAPPENDPOST
2232 || event == EVENT_VIMLEAVE
2233 || event == EVENT_VIMLEAVEPRE))
2234 {
2235#ifdef FEAT_TITLE
2236 if (curbuf->b_changed != save_changed)
2237 need_maketitle = TRUE;
2238#endif
2239 curbuf->b_changed = save_changed;
2240 }
2241
2242 au_cleanup(); // may really delete removed patterns/commands now
2243
2244BYPASS_AU:
2245 // When wiping out a buffer make sure all its buffer-local autocommands
2246 // are deleted.
2247 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2248 aubuflocal_remove(buf);
2249
2250 if (retval == OK && event == EVENT_FILETYPE)
2251 au_did_filetype = TRUE;
2252
2253 return retval;
2254}
2255
2256# ifdef FEAT_EVAL
2257static char_u *old_termresponse = NULL;
2258# endif
2259
2260/*
2261 * Block triggering autocommands until unblock_autocmd() is called.
2262 * Can be used recursively, so long as it's symmetric.
2263 */
2264 void
2265block_autocmds(void)
2266{
2267# ifdef FEAT_EVAL
2268 // Remember the value of v:termresponse.
2269 if (autocmd_blocked == 0)
2270 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2271# endif
2272 ++autocmd_blocked;
2273}
2274
2275 void
2276unblock_autocmds(void)
2277{
2278 --autocmd_blocked;
2279
2280# ifdef FEAT_EVAL
2281 // When v:termresponse was set while autocommands were blocked, trigger
2282 // the autocommands now. Esp. useful when executing a shell command
2283 // during startup (vimdiff).
2284 if (autocmd_blocked == 0
2285 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2286 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2287# endif
2288}
2289
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002290 int
2291is_autocmd_blocked(void)
2292{
2293 return autocmd_blocked != 0;
2294}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002295
2296/*
2297 * Find next autocommand pattern that matches.
2298 */
2299 static void
2300auto_next_pat(
2301 AutoPatCmd *apc,
2302 int stop_at_last) // stop when 'last' flag is set
2303{
2304 AutoPat *ap;
2305 AutoCmd *cp;
2306 char_u *name;
2307 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002308 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002309
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002310 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002311
2312 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2313 {
2314 apc->curpat = NULL;
2315
2316 // Only use a pattern when it has not been removed, has commands and
2317 // the group matches. For buffer-local autocommands only check the
2318 // buffer number.
2319 if (ap->pat != NULL && ap->cmds != NULL
2320 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2321 {
2322 // execution-condition
2323 if (ap->buflocal_nr == 0
2324 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2325 apc->sfname, apc->tail, ap->allow_dirs))
2326 : ap->buflocal_nr == apc->arg_bufnr)
2327 {
2328 name = event_nr2name(apc->event);
2329 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002330 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002331 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002332 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002333 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002334 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002335 (char *)name, (char *)ap->pat);
2336 if (p_verbose >= 8)
2337 {
2338 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002339 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002340 verbose_leave();
2341 }
2342 }
2343
2344 apc->curpat = ap;
2345 apc->nextcmd = ap->cmds;
2346 // mark last command
2347 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2348 cp->last = FALSE;
2349 cp->last = TRUE;
2350 }
2351 line_breakcheck();
2352 if (apc->curpat != NULL) // found a match
2353 break;
2354 }
2355 if (stop_at_last && ap->last)
2356 break;
2357 }
2358}
2359
2360/*
2361 * Get next autocommand command.
2362 * Called by do_cmdline() to get the next line for ":if".
2363 * Returns allocated string, or NULL for end of autocommands.
2364 */
2365 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002366getnextac(
2367 int c UNUSED,
2368 void *cookie,
2369 int indent UNUSED,
2370 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002371{
2372 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2373 char_u *retval;
2374 AutoCmd *ac;
2375
2376 // Can be called again after returning the last line.
2377 if (acp->curpat == NULL)
2378 return NULL;
2379
2380 // repeat until we find an autocommand to execute
2381 for (;;)
2382 {
2383 // skip removed commands
2384 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2385 if (acp->nextcmd->last)
2386 acp->nextcmd = NULL;
2387 else
2388 acp->nextcmd = acp->nextcmd->next;
2389
2390 if (acp->nextcmd != NULL)
2391 break;
2392
2393 // at end of commands, find next pattern that matches
2394 if (acp->curpat->last)
2395 acp->curpat = NULL;
2396 else
2397 acp->curpat = acp->curpat->next;
2398 if (acp->curpat != NULL)
2399 auto_next_pat(acp, TRUE);
2400 if (acp->curpat == NULL)
2401 return NULL;
2402 }
2403
2404 ac = acp->nextcmd;
2405
2406 if (p_verbose >= 9)
2407 {
2408 verbose_enter_scroll();
2409 smsg(_("autocommand %s"), ac->cmd);
2410 msg_puts("\n"); // don't overwrite this either
2411 verbose_leave_scroll();
2412 }
2413 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002414 // Remove one-shot ("once") autocmd in anticipation of its execution.
2415 if (ac->once)
2416 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002417 autocmd_nested = ac->nested;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002418 current_sctx = ac->script_ctx;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002419 if (ac->last)
2420 acp->nextcmd = NULL;
2421 else
2422 acp->nextcmd = ac->next;
2423 return retval;
2424}
2425
2426/*
2427 * Return TRUE if there is a matching autocommand for "fname".
2428 * To account for buffer-local autocommands, function needs to know
2429 * in which buffer the file will be opened.
2430 */
2431 int
2432has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2433{
2434 AutoPat *ap;
2435 char_u *fname;
2436 char_u *tail = gettail(sfname);
2437 int retval = FALSE;
2438
2439 fname = FullName_save(sfname, FALSE);
2440 if (fname == NULL)
2441 return FALSE;
2442
2443#ifdef BACKSLASH_IN_FILENAME
2444 /*
2445 * Replace all backslashes with forward slashes. This makes the
2446 * autocommand patterns portable between Unix and MS-DOS.
2447 */
2448 sfname = vim_strsave(sfname);
2449 if (sfname != NULL)
2450 forward_slash(sfname);
2451 forward_slash(fname);
2452#endif
2453
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002454 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002455 if (ap->pat != NULL && ap->cmds != NULL
2456 && (ap->buflocal_nr == 0
2457 ? match_file_pat(NULL, &ap->reg_prog,
2458 fname, sfname, tail, ap->allow_dirs)
2459 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2460 ))
2461 {
2462 retval = TRUE;
2463 break;
2464 }
2465
2466 vim_free(fname);
2467#ifdef BACKSLASH_IN_FILENAME
2468 vim_free(sfname);
2469#endif
2470
2471 return retval;
2472}
2473
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002474/*
2475 * Function given to ExpandGeneric() to obtain the list of autocommand group
2476 * names.
2477 */
2478 char_u *
2479get_augroup_name(expand_T *xp UNUSED, int idx)
2480{
2481 if (idx == augroups.ga_len) // add "END" add the end
2482 return (char_u *)"END";
2483 if (idx >= augroups.ga_len) // end of list
2484 return NULL;
2485 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2486 // skip deleted entries
2487 return (char_u *)"";
2488 return AUGROUP_NAME(idx); // return a name
2489}
2490
2491static int include_groups = FALSE;
2492
2493 char_u *
2494set_context_in_autocmd(
2495 expand_T *xp,
2496 char_u *arg,
2497 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2498{
2499 char_u *p;
2500 int group;
2501
2502 // check for a group name, skip it if present
2503 include_groups = FALSE;
2504 p = arg;
2505 group = au_get_grouparg(&arg);
2506 if (group == AUGROUP_ERROR)
2507 return NULL;
2508 // If there only is a group name that's what we expand.
2509 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2510 {
2511 arg = p;
2512 group = AUGROUP_ALL;
2513 }
2514
2515 // skip over event name
2516 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2517 if (*p == ',')
2518 arg = p + 1;
2519 if (*p == NUL)
2520 {
2521 if (group == AUGROUP_ALL)
2522 include_groups = TRUE;
2523 xp->xp_context = EXPAND_EVENTS; // expand event name
2524 xp->xp_pattern = arg;
2525 return NULL;
2526 }
2527
2528 // skip over pattern
2529 arg = skipwhite(p);
2530 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2531 arg++;
2532 if (*arg)
2533 return arg; // expand (next) command
2534
2535 if (doautocmd)
2536 xp->xp_context = EXPAND_FILES; // expand file names
2537 else
2538 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2539 return NULL;
2540}
2541
2542/*
2543 * Function given to ExpandGeneric() to obtain the list of event names.
2544 */
2545 char_u *
2546get_event_name(expand_T *xp UNUSED, int idx)
2547{
2548 if (idx < augroups.ga_len) // First list group names, if wanted
2549 {
2550 if (!include_groups || AUGROUP_NAME(idx) == NULL
2551 || AUGROUP_NAME(idx) == get_deleted_augroup())
2552 return (char_u *)""; // skip deleted entries
2553 return AUGROUP_NAME(idx); // return a name
2554 }
2555 return (char_u *)event_names[idx - augroups.ga_len].name;
2556}
2557
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002558
2559#if defined(FEAT_EVAL) || defined(PROTO)
2560/*
2561 * Return TRUE if autocmd is supported.
2562 */
2563 int
2564autocmd_supported(char_u *name)
2565{
2566 char_u *p;
2567
2568 return (event_name2nr(name, &p) != NUM_EVENTS);
2569}
2570
2571/*
2572 * Return TRUE if an autocommand is defined for a group, event and
2573 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2574 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2575 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2576 * Used for:
2577 * exists("#Group") or
2578 * exists("#Group#Event") or
2579 * exists("#Group#Event#pat") or
2580 * exists("#Event") or
2581 * exists("#Event#pat")
2582 */
2583 int
2584au_exists(char_u *arg)
2585{
2586 char_u *arg_save;
2587 char_u *pattern = NULL;
2588 char_u *event_name;
2589 char_u *p;
2590 event_T event;
2591 AutoPat *ap;
2592 buf_T *buflocal_buf = NULL;
2593 int group;
2594 int retval = FALSE;
2595
2596 // Make a copy so that we can change the '#' chars to a NUL.
2597 arg_save = vim_strsave(arg);
2598 if (arg_save == NULL)
2599 return FALSE;
2600 p = vim_strchr(arg_save, '#');
2601 if (p != NULL)
2602 *p++ = NUL;
2603
2604 // First, look for an autocmd group name
2605 group = au_find_group(arg_save);
2606 if (group == AUGROUP_ERROR)
2607 {
2608 // Didn't match a group name, assume the first argument is an event.
2609 group = AUGROUP_ALL;
2610 event_name = arg_save;
2611 }
2612 else
2613 {
2614 if (p == NULL)
2615 {
2616 // "Group": group name is present and it's recognized
2617 retval = TRUE;
2618 goto theend;
2619 }
2620
2621 // Must be "Group#Event" or "Group#Event#pat".
2622 event_name = p;
2623 p = vim_strchr(event_name, '#');
2624 if (p != NULL)
2625 *p++ = NUL; // "Group#Event#pat"
2626 }
2627
2628 pattern = p; // "pattern" is NULL when there is no pattern
2629
2630 // find the index (enum) for the event name
2631 event = event_name2nr(event_name, &p);
2632
2633 // return FALSE if the event name is not recognized
2634 if (event == NUM_EVENTS)
2635 goto theend;
2636
2637 // Find the first autocommand for this event.
2638 // If there isn't any, return FALSE;
2639 // If there is one and no pattern given, return TRUE;
2640 ap = first_autopat[(int)event];
2641 if (ap == NULL)
2642 goto theend;
2643
2644 // if pattern is "<buffer>", special handling is needed which uses curbuf
2645 // for pattern "<buffer=N>, fnamecmp() will work fine
2646 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2647 buflocal_buf = curbuf;
2648
2649 // Check if there is an autocommand with the given pattern.
2650 for ( ; ap != NULL; ap = ap->next)
2651 // only use a pattern when it has not been removed and has commands.
2652 // For buffer-local autocommands, fnamecmp() works fine.
2653 if (ap->pat != NULL && ap->cmds != NULL
2654 && (group == AUGROUP_ALL || ap->group == group)
2655 && (pattern == NULL
2656 || (buflocal_buf == NULL
2657 ? fnamecmp(ap->pat, pattern) == 0
2658 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2659 {
2660 retval = TRUE;
2661 break;
2662 }
2663
2664theend:
2665 vim_free(arg_save);
2666 return retval;
2667}
2668#endif