blob: 1704cd4e3a5c98f7f43abe454a61d04b009716ce [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
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100389 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100390 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
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100463 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100464 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
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100526 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100527 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 {
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100698 if ((int)event_name2nr(pat, &p) >= NUM_EVENTS)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +0100699 {
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
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100970 for (event = (event_T)0; (int)event < NUM_EVENTS;
Bram Moolenaar9a046fd2021-01-28 13:47:59 +0100971 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
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01001221#ifdef FEAT_EVAL
1222 // need to initialize last_mode for the first ModeChanged
1223 // autocmd
1224 if (event == EVENT_MODECHANGED && !has_modechanged())
1225 {
1226 typval_T rettv;
1227 typval_T tv[2];
1228
1229 tv[0].v_type = VAR_NUMBER;
1230 tv[0].vval.v_number = 1;
1231 tv[1].v_type = VAR_UNKNOWN;
1232 f_mode(tv, &rettv);
1233 STRCPY(last_mode, rettv.vval.v_string);
1234 vim_free(rettv.vval.v_string);
1235 }
1236#endif
1237
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001238 if (is_buflocal)
1239 {
1240 ap->buflocal_nr = buflocal_nr;
1241 ap->reg_prog = NULL;
1242 }
1243 else
1244 {
1245 char_u *reg_pat;
1246
1247 ap->buflocal_nr = 0;
1248 reg_pat = file_pat_to_reg_pat(pat, endpat,
1249 &ap->allow_dirs, TRUE);
1250 if (reg_pat != NULL)
1251 ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
1252 vim_free(reg_pat);
1253 if (reg_pat == NULL || ap->reg_prog == NULL)
1254 {
1255 vim_free(ap->pat);
1256 vim_free(ap);
1257 return FAIL;
1258 }
1259 }
1260 ap->cmds = NULL;
1261 *prev_ap = ap;
1262 last_autopat[(int)event] = ap;
1263 ap->next = NULL;
1264 if (group == AUGROUP_ALL)
1265 ap->group = current_augroup;
1266 else
1267 ap->group = group;
1268 }
1269
1270 /*
1271 * Add the autocmd at the end of the AutoCmd list.
1272 */
1273 prev_ac = &(ap->cmds);
1274 while ((ac = *prev_ac) != NULL)
1275 prev_ac = &ac->next;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02001276 ac = ALLOC_ONE(AutoCmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001277 if (ac == NULL)
1278 return FAIL;
1279 ac->cmd = vim_strsave(cmd);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001280 ac->script_ctx = current_sctx;
Bram Moolenaar73b8b0a2021-08-01 14:52:32 +02001281 if (flags & UC_VIM9)
1282 ac->script_ctx.sc_version = SCRIPT_VERSION_VIM9;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001283#ifdef FEAT_EVAL
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001284 ac->script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001285#endif
1286 if (ac->cmd == NULL)
1287 {
1288 vim_free(ac);
1289 return FAIL;
1290 }
1291 ac->next = NULL;
1292 *prev_ac = ac;
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02001293 ac->once = once;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001294 ac->nested = nested;
1295 }
1296 }
1297
1298 au_cleanup(); // may really delete removed patterns/commands now
1299 return OK;
1300}
1301
1302/*
1303 * Implementation of ":doautocmd [group] event [fname]".
1304 * Return OK for success, FAIL for failure;
1305 */
1306 int
1307do_doautocmd(
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001308 char_u *arg_start,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001309 int do_msg, // give message for no matching autocmds?
1310 int *did_something)
1311{
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001312 char_u *arg = arg_start;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001313 char_u *fname;
1314 int nothing_done = TRUE;
1315 int group;
1316
1317 if (did_something != NULL)
1318 *did_something = FALSE;
1319
1320 /*
1321 * Check for a legal group name. If not, use AUGROUP_ALL.
1322 */
1323 group = au_get_grouparg(&arg);
1324 if (arg == NULL) // out of memory
1325 return FAIL;
1326
1327 if (*arg == '*')
1328 {
1329 emsg(_("E217: Can't execute autocommands for ALL events"));
1330 return FAIL;
1331 }
1332
1333 /*
1334 * Scan over the events.
1335 * If we find an illegal name, return here, don't do anything.
1336 */
1337 fname = find_end_event(arg, group != AUGROUP_ALL);
1338 if (fname == NULL)
1339 return FAIL;
1340
1341 fname = skipwhite(fname);
1342
1343 /*
1344 * Loop over the events.
1345 */
1346 while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
1347 if (apply_autocmds_group(event_name2nr(arg, &arg),
1348 fname, NULL, TRUE, group, curbuf, NULL))
1349 nothing_done = FALSE;
1350
Bram Moolenaar1b154ea2021-08-07 13:59:43 +02001351 if (nothing_done && do_msg
1352#ifdef FEAT_EVAL
1353 && !aborting()
1354#endif
1355 )
1356 smsg(_("No matching autocommands: %s"), arg_start);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001357 if (did_something != NULL)
1358 *did_something = !nothing_done;
1359
1360#ifdef FEAT_EVAL
1361 return aborting() ? FAIL : OK;
1362#else
1363 return OK;
1364#endif
1365}
1366
1367/*
1368 * ":doautoall": execute autocommands for each loaded buffer.
1369 */
1370 void
1371ex_doautoall(exarg_T *eap)
1372{
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001373 int retval = OK;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001374 aco_save_T aco;
1375 buf_T *buf;
1376 bufref_T bufref;
1377 char_u *arg = eap->arg;
1378 int call_do_modelines = check_nomodeline(&arg);
1379 int did_aucmd;
1380
1381 /*
1382 * This is a bit tricky: For some commands curwin->w_buffer needs to be
1383 * equal to curbuf, but for some buffers there may not be a window.
1384 * So we change the buffer for the current window for a moment. This
1385 * gives problems when the autocommands make changes to the list of
1386 * buffers or windows...
1387 */
1388 FOR_ALL_BUFFERS(buf)
1389 {
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001390 // Only do loaded buffers and skip the current buffer, it's done last.
1391 if (buf->b_ml.ml_mfp != NULL && buf != curbuf)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001392 {
1393 // find a window for this buffer and save some values
1394 aucmd_prepbuf(&aco, buf);
1395 set_bufref(&bufref, buf);
1396
1397 // execute the autocommands for this buffer
1398 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1399
1400 if (call_do_modelines && did_aucmd)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001401 // Execute the modeline settings, but don't set window-local
1402 // options if we are using the current window for another
1403 // buffer.
1404 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001405
1406 // restore the current window
1407 aucmd_restbuf(&aco);
1408
1409 // stop if there is some error or buffer was deleted
1410 if (retval == FAIL || !bufref_valid(&bufref))
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001411 {
1412 retval = FAIL;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001413 break;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001414 }
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001415 }
1416 }
1417
Bram Moolenaar41cd8032021-03-13 15:47:56 +01001418 // Execute autocommands for the current buffer last.
1419 if (retval == OK)
1420 {
1421 do_doautocmd(arg, FALSE, &did_aucmd);
1422 if (call_do_modelines && did_aucmd)
1423 do_modelines(0);
1424 }
1425
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001426 check_cursor(); // just in case lines got deleted
1427}
1428
1429/*
1430 * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
1431 * return TRUE and advance *argp to after it.
1432 * Thus return TRUE when do_modelines() should be called.
1433 */
1434 int
1435check_nomodeline(char_u **argp)
1436{
1437 if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
1438 {
1439 *argp = skipwhite(*argp + 12);
1440 return FALSE;
1441 }
1442 return TRUE;
1443}
1444
1445/*
1446 * Prepare for executing autocommands for (hidden) buffer "buf".
1447 * Search for a visible window containing the current buffer. If there isn't
1448 * one then use "aucmd_win".
1449 * Set "curbuf" and "curwin" to match "buf".
1450 */
1451 void
1452aucmd_prepbuf(
1453 aco_save_T *aco, // structure to save values in
1454 buf_T *buf) // new curbuf
1455{
1456 win_T *win;
1457 int save_ea;
1458#ifdef FEAT_AUTOCHDIR
1459 int save_acd;
1460#endif
1461
1462 // Find a window that is for the new buffer
1463 if (buf == curbuf) // be quick when buf is curbuf
1464 win = curwin;
1465 else
1466 FOR_ALL_WINDOWS(win)
1467 if (win->w_buffer == buf)
1468 break;
1469
1470 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall
1471 // back to using the current window.
1472 if (win == NULL && aucmd_win == NULL)
1473 {
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001474 aucmd_win = win_alloc_popup_win();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001475 if (aucmd_win == NULL)
1476 win = curwin;
1477 }
1478 if (win == NULL && aucmd_win_used)
1479 // Strange recursive autocommand, fall back to using the current
1480 // window. Expect a few side effects...
1481 win = curwin;
1482
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001483 aco->save_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001484 aco->save_curbuf = curbuf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001485 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001486 if (win != NULL)
1487 {
1488 // There is a window for "buf" in the current tab page, make it the
1489 // curwin. This is preferred, it has the least side effects (esp. if
1490 // "buf" is curbuf).
1491 aco->use_aucmd_win = FALSE;
1492 curwin = win;
1493 }
1494 else
1495 {
1496 // There is no window for "buf", use "aucmd_win". To minimize the side
1497 // effects, insert it in the current tab page.
1498 // Anything related to a window (e.g., setting folds) may have
1499 // unexpected results.
1500 aco->use_aucmd_win = TRUE;
1501 aucmd_win_used = TRUE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001502
Bram Moolenaar4d784b22019-05-25 19:51:39 +02001503 win_init_popup_win(aucmd_win, buf);
1504
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001505 aco->globaldir = globaldir;
1506 globaldir = NULL;
1507
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001508 // Split the current window, put the aucmd_win in the upper half.
1509 // We don't want the BufEnter or WinEnter autocommands.
1510 block_autocmds();
1511 make_snapshot(SNAP_AUCMD_IDX);
1512 save_ea = p_ea;
1513 p_ea = FALSE;
1514
1515#ifdef FEAT_AUTOCHDIR
1516 // Prevent chdir() call in win_enter_ext(), through do_autochdir().
1517 save_acd = p_acd;
1518 p_acd = FALSE;
1519#endif
1520
1521 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
1522 (void)win_comp_pos(); // recompute window positions
1523 p_ea = save_ea;
1524#ifdef FEAT_AUTOCHDIR
1525 p_acd = save_acd;
1526#endif
1527 unblock_autocmds();
1528 curwin = aucmd_win;
1529 }
1530 curbuf = buf;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001531 aco->new_curwin_id = curwin->w_id;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001532 set_bufref(&aco->new_curbuf, curbuf);
1533}
1534
1535/*
1536 * Cleanup after executing autocommands for a (hidden) buffer.
1537 * Restore the window as it was (if possible).
1538 */
1539 void
1540aucmd_restbuf(
1541 aco_save_T *aco) // structure holding saved values
1542{
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001543 int dummy;
1544 win_T *save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001545
1546 if (aco->use_aucmd_win)
1547 {
1548 --curbuf->b_nwindows;
1549 // Find "aucmd_win", it can't be closed, but it may be in another tab
1550 // page. Do not trigger autocommands here.
1551 block_autocmds();
1552 if (curwin != aucmd_win)
1553 {
1554 tabpage_T *tp;
1555 win_T *wp;
1556
1557 FOR_ALL_TAB_WINDOWS(tp, wp)
1558 {
1559 if (wp == aucmd_win)
1560 {
1561 if (tp != curtab)
1562 goto_tabpage_tp(tp, TRUE, TRUE);
1563 win_goto(aucmd_win);
1564 goto win_found;
1565 }
1566 }
1567 }
1568win_found:
1569
1570 // Remove the window and frame from the tree of frames.
1571 (void)winframe_remove(curwin, &dummy, NULL);
1572 win_remove(curwin, NULL);
1573 aucmd_win_used = FALSE;
1574 last_status(FALSE); // may need to remove last status line
1575
1576 if (!valid_tabpage_win(curtab))
1577 // no valid window in current tabpage
1578 close_tabpage(curtab);
1579
1580 restore_snapshot(SNAP_AUCMD_IDX, FALSE);
1581 (void)win_comp_pos(); // recompute window positions
1582 unblock_autocmds();
1583
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001584 save_curwin = win_find_by_id(aco->save_curwin_id);
1585 if (save_curwin != NULL)
1586 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001587 else
1588 // Hmm, original window disappeared. Just use the first one.
1589 curwin = firstwin;
Bram Moolenaarbdf931c2020-10-01 22:37:40 +02001590 curbuf = curwin->w_buffer;
1591#ifdef FEAT_JOB_CHANNEL
1592 // May need to restore insert mode for a prompt buffer.
1593 entering_window(curwin);
1594#endif
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001595 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001596#ifdef FEAT_EVAL
1597 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
1598 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
1599#endif
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001600 vim_free(globaldir);
1601 globaldir = aco->globaldir;
1602
1603 // the buffer contents may have changed
1604 check_cursor();
1605 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1606 {
1607 curwin->w_topline = curbuf->b_ml.ml_line_count;
1608#ifdef FEAT_DIFF
1609 curwin->w_topfill = 0;
1610#endif
1611 }
1612#if defined(FEAT_GUI)
1613 // Hide the scrollbars from the aucmd_win and update.
1614 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
1615 gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1616 gui_may_update_scrollbars();
1617#endif
1618 }
1619 else
1620 {
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001621 // Restore curwin. Use the window ID, a window may have been closed
1622 // and the memory re-used for another one.
1623 save_curwin = win_find_by_id(aco->save_curwin_id);
1624 if (save_curwin != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001625 {
1626 // Restore the buffer which was previously edited by curwin, if
1627 // it was changed, we are still the same window and the buffer is
1628 // valid.
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001629 if (curwin->w_id == aco->new_curwin_id
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001630 && curbuf != aco->new_curbuf.br_buf
1631 && bufref_valid(&aco->new_curbuf)
1632 && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
1633 {
1634# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
1635 if (curwin->w_s == &curbuf->b_s)
1636 curwin->w_s = &aco->new_curbuf.br_buf->b_s;
1637# endif
1638 --curbuf->b_nwindows;
1639 curbuf = aco->new_curbuf.br_buf;
1640 curwin->w_buffer = curbuf;
1641 ++curbuf->b_nwindows;
1642 }
1643
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001644 curwin = save_curwin;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001645 curbuf = curwin->w_buffer;
Bram Moolenaarcbcd9cb2020-11-07 16:58:59 +01001646 prevwin = win_find_by_id(aco->save_prevwin_id);
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001647 // In case the autocommand moves the cursor to a position that
1648 // does not exist in curbuf.
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001649 check_cursor();
1650 }
1651 }
1652}
1653
1654static int autocmd_nested = FALSE;
1655
1656/*
1657 * Execute autocommands for "event" and file name "fname".
1658 * Return TRUE if some commands were executed.
1659 */
1660 int
1661apply_autocmds(
1662 event_T event,
1663 char_u *fname, // NULL or empty means use actual file name
1664 char_u *fname_io, // fname to use for <afile> on cmdline
1665 int force, // when TRUE, ignore autocmd_busy
1666 buf_T *buf) // buffer for <abuf>
1667{
1668 return apply_autocmds_group(event, fname, fname_io, force,
1669 AUGROUP_ALL, buf, NULL);
1670}
1671
1672/*
1673 * Like apply_autocmds(), but with extra "eap" argument. This takes care of
1674 * setting v:filearg.
1675 */
1676 int
1677apply_autocmds_exarg(
1678 event_T event,
1679 char_u *fname,
1680 char_u *fname_io,
1681 int force,
1682 buf_T *buf,
1683 exarg_T *eap)
1684{
1685 return apply_autocmds_group(event, fname, fname_io, force,
1686 AUGROUP_ALL, buf, eap);
1687}
1688
1689/*
1690 * Like apply_autocmds(), but handles the caller's retval. If the script
1691 * processing is being aborted or if retval is FAIL when inside a try
1692 * conditional, no autocommands are executed. If otherwise the autocommands
1693 * cause the script to be aborted, retval is set to FAIL.
1694 */
1695 int
1696apply_autocmds_retval(
1697 event_T event,
1698 char_u *fname, // NULL or empty means use actual file name
1699 char_u *fname_io, // fname to use for <afile> on cmdline
1700 int force, // when TRUE, ignore autocmd_busy
1701 buf_T *buf, // buffer for <abuf>
1702 int *retval) // pointer to caller's retval
1703{
1704 int did_cmd;
1705
1706#ifdef FEAT_EVAL
1707 if (should_abort(*retval))
1708 return FALSE;
1709#endif
1710
1711 did_cmd = apply_autocmds_group(event, fname, fname_io, force,
1712 AUGROUP_ALL, buf, NULL);
1713 if (did_cmd
1714#ifdef FEAT_EVAL
1715 && aborting()
1716#endif
1717 )
1718 *retval = FAIL;
1719 return did_cmd;
1720}
1721
1722/*
1723 * Return TRUE when there is a CursorHold autocommand defined.
1724 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02001725 static int
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001726has_cursorhold(void)
1727{
1728 return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
1729 ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
1730}
1731
1732/*
1733 * Return TRUE if the CursorHold event can be triggered.
1734 */
1735 int
1736trigger_cursorhold(void)
1737{
1738 int state;
1739
1740 if (!did_cursorhold
1741 && has_cursorhold()
1742 && reg_recording == 0
1743 && typebuf.tb_len == 0
Bram Moolenaare2c453d2019-08-21 14:37:09 +02001744 && !ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001745 {
1746 state = get_real_state();
1747 if (state == NORMAL_BUSY || (state & INSERT) != 0)
1748 return TRUE;
1749 }
1750 return FALSE;
1751}
1752
1753/*
1754 * Return TRUE when there is a CursorMoved autocommand defined.
1755 */
1756 int
1757has_cursormoved(void)
1758{
1759 return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
1760}
1761
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001762/*
1763 * Return TRUE when there is a CursorMovedI autocommand defined.
1764 */
1765 int
1766has_cursormovedI(void)
1767{
1768 return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
1769}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001770
1771/*
1772 * Return TRUE when there is a TextChanged autocommand defined.
1773 */
1774 int
1775has_textchanged(void)
1776{
1777 return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
1778}
1779
1780/*
1781 * Return TRUE when there is a TextChangedI autocommand defined.
1782 */
1783 int
1784has_textchangedI(void)
1785{
1786 return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
1787}
1788
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001789/*
1790 * Return TRUE when there is a TextChangedP autocommand defined.
1791 */
1792 int
1793has_textchangedP(void)
1794{
1795 return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
1796}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001797
1798/*
1799 * Return TRUE when there is an InsertCharPre autocommand defined.
1800 */
1801 int
1802has_insertcharpre(void)
1803{
1804 return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
1805}
1806
1807/*
1808 * Return TRUE when there is an CmdUndefined autocommand defined.
1809 */
1810 int
1811has_cmdundefined(void)
1812{
1813 return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
1814}
1815
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001816#if defined(FEAT_EVAL) || defined(PROTO)
1817/*
1818 * Return TRUE when there is a TextYankPost autocommand defined.
1819 */
1820 int
1821has_textyankpost(void)
1822{
1823 return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
1824}
1825#endif
1826
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001827#if defined(FEAT_EVAL) || defined(PROTO)
1828/*
1829 * Return TRUE when there is a CompleteChanged autocommand defined.
1830 */
1831 int
1832has_completechanged(void)
1833{
1834 return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
1835}
1836#endif
1837
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001838#if defined(FEAT_EVAL) || defined(PROTO)
1839/*
1840 * Return TRUE when there is a ModeChanged autocommand defined.
1841 */
1842 int
1843has_modechanged(void)
1844{
1845 return (first_autopat[(int)EVENT_MODECHANGED] != NULL);
1846}
1847#endif
1848
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001849/*
1850 * Execute autocommands for "event" and file name "fname".
1851 * Return TRUE if some commands were executed.
1852 */
1853 static int
1854apply_autocmds_group(
1855 event_T event,
1856 char_u *fname, // NULL or empty means use actual file name
1857 char_u *fname_io, // fname to use for <afile> on cmdline, NULL means
1858 // use fname
1859 int force, // when TRUE, ignore autocmd_busy
1860 int group, // group ID, or AUGROUP_ALL
1861 buf_T *buf, // buffer for <abuf>
1862 exarg_T *eap UNUSED) // command arguments
1863{
1864 char_u *sfname = NULL; // short file name
1865 char_u *tail;
1866 int save_changed;
1867 buf_T *old_curbuf;
1868 int retval = FALSE;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001869 char_u *save_autocmd_fname;
1870 int save_autocmd_fname_full;
1871 int save_autocmd_bufnr;
1872 char_u *save_autocmd_match;
1873 int save_autocmd_busy;
1874 int save_autocmd_nested;
1875 static int nesting = 0;
1876 AutoPatCmd patcmd;
1877 AutoPat *ap;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001878 sctx_T save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01001879#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001880 funccal_entry_T funccal_entry;
1881 char_u *save_cmdarg;
1882 long save_cmdbang;
1883#endif
1884 static int filechangeshell_busy = FALSE;
1885#ifdef FEAT_PROFILE
1886 proftime_T wait_time;
1887#endif
1888 int did_save_redobuff = FALSE;
1889 save_redo_T save_redo;
1890 int save_KeyTyped = KeyTyped;
Bram Moolenaare31ee862020-01-07 20:59:34 +01001891 ESTACK_CHECK_DECLARATION
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001892
1893 /*
1894 * Quickly return if there are no autocommands for this event or
1895 * autocommands are blocked.
1896 */
1897 if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
1898 || autocmd_blocked > 0)
1899 goto BYPASS_AU;
1900
1901 /*
1902 * When autocommands are busy, new autocommands are only executed when
1903 * explicitly enabled with the "nested" flag.
1904 */
1905 if (autocmd_busy && !(force || autocmd_nested))
1906 goto BYPASS_AU;
1907
1908#ifdef FEAT_EVAL
1909 /*
1910 * Quickly return when immediately aborting on error, or when an interrupt
1911 * occurred or an exception was thrown but not caught.
1912 */
1913 if (aborting())
1914 goto BYPASS_AU;
1915#endif
1916
1917 /*
1918 * FileChangedShell never nests, because it can create an endless loop.
1919 */
1920 if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
1921 || event == EVENT_FILECHANGEDSHELLPOST))
1922 goto BYPASS_AU;
1923
1924 /*
1925 * Ignore events in 'eventignore'.
1926 */
1927 if (event_ignored(event))
1928 goto BYPASS_AU;
1929
1930 /*
1931 * Allow nesting of autocommands, but restrict the depth, because it's
1932 * possible to create an endless loop.
1933 */
1934 if (nesting == 10)
1935 {
1936 emsg(_("E218: autocommand nesting too deep"));
1937 goto BYPASS_AU;
1938 }
1939
1940 /*
1941 * Check if these autocommands are disabled. Used when doing ":all" or
1942 * ":ball".
1943 */
1944 if ( (autocmd_no_enter
1945 && (event == EVENT_WINENTER || event == EVENT_BUFENTER))
1946 || (autocmd_no_leave
1947 && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
1948 goto BYPASS_AU;
1949
1950 /*
1951 * Save the autocmd_* variables and info about the current buffer.
1952 */
1953 save_autocmd_fname = autocmd_fname;
1954 save_autocmd_fname_full = autocmd_fname_full;
1955 save_autocmd_bufnr = autocmd_bufnr;
1956 save_autocmd_match = autocmd_match;
1957 save_autocmd_busy = autocmd_busy;
1958 save_autocmd_nested = autocmd_nested;
1959 save_changed = curbuf->b_changed;
1960 old_curbuf = curbuf;
1961
1962 /*
1963 * Set the file name to be used for <afile>.
1964 * Make a copy to avoid that changing a buffer name or directory makes it
1965 * invalid.
1966 */
1967 if (fname_io == NULL)
1968 {
1969 if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02001970 || event == EVENT_OPTIONSET
1971 || event == EVENT_MODECHANGED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01001972 autocmd_fname = NULL;
1973 else if (fname != NULL && !ends_excmd(*fname))
1974 autocmd_fname = fname;
1975 else if (buf != NULL)
1976 autocmd_fname = buf->b_ffname;
1977 else
1978 autocmd_fname = NULL;
1979 }
1980 else
1981 autocmd_fname = fname_io;
1982 if (autocmd_fname != NULL)
1983 autocmd_fname = vim_strsave(autocmd_fname);
1984 autocmd_fname_full = FALSE; // call FullName_save() later
1985
1986 /*
1987 * Set the buffer number to be used for <abuf>.
1988 */
1989 if (buf == NULL)
1990 autocmd_bufnr = 0;
1991 else
1992 autocmd_bufnr = buf->b_fnum;
1993
1994 /*
1995 * When the file name is NULL or empty, use the file name of buffer "buf".
1996 * Always use the full path of the file name to match with, in case
1997 * "allow_dirs" is set.
1998 */
1999 if (fname == NULL || *fname == NUL)
2000 {
2001 if (buf == NULL)
2002 fname = NULL;
2003 else
2004 {
2005#ifdef FEAT_SYN_HL
2006 if (event == EVENT_SYNTAX)
2007 fname = buf->b_p_syn;
2008 else
2009#endif
2010 if (event == EVENT_FILETYPE)
2011 fname = buf->b_p_ft;
2012 else
2013 {
2014 if (buf->b_sfname != NULL)
2015 sfname = vim_strsave(buf->b_sfname);
2016 fname = buf->b_ffname;
2017 }
2018 }
2019 if (fname == NULL)
2020 fname = (char_u *)"";
2021 fname = vim_strsave(fname); // make a copy, so we can change it
2022 }
2023 else
2024 {
2025 sfname = vim_strsave(fname);
2026 // Don't try expanding FileType, Syntax, FuncUndefined, WindowID,
2027 // ColorScheme, QuickFixCmd* or DirChanged
2028 if (event == EVENT_FILETYPE
2029 || event == EVENT_SYNTAX
2030 || event == EVENT_CMDLINECHANGED
2031 || event == EVENT_CMDLINEENTER
2032 || event == EVENT_CMDLINELEAVE
2033 || event == EVENT_CMDWINENTER
2034 || event == EVENT_CMDWINLEAVE
2035 || event == EVENT_CMDUNDEFINED
2036 || event == EVENT_FUNCUNDEFINED
2037 || event == EVENT_REMOTEREPLY
2038 || event == EVENT_SPELLFILEMISSING
2039 || event == EVENT_QUICKFIXCMDPRE
2040 || event == EVENT_COLORSCHEME
2041 || event == EVENT_COLORSCHEMEPRE
2042 || event == EVENT_OPTIONSET
2043 || event == EVENT_QUICKFIXCMDPOST
=?UTF-8?q?Magnus=20Gro=C3=9F?=f1e88762021-09-12 13:39:55 +02002044 || event == EVENT_DIRCHANGED
2045 || event == EVENT_MODECHANGED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002046 {
2047 fname = vim_strsave(fname);
2048 autocmd_fname_full = TRUE; // don't expand it later
2049 }
2050 else
2051 fname = FullName_save(fname, FALSE);
2052 }
2053 if (fname == NULL) // out of memory
2054 {
2055 vim_free(sfname);
2056 retval = FALSE;
2057 goto BYPASS_AU;
2058 }
2059
2060#ifdef BACKSLASH_IN_FILENAME
2061 /*
2062 * Replace all backslashes with forward slashes. This makes the
2063 * autocommand patterns portable between Unix and MS-DOS.
2064 */
2065 if (sfname != NULL)
2066 forward_slash(sfname);
2067 forward_slash(fname);
2068#endif
2069
2070#ifdef VMS
2071 // remove version for correct match
2072 if (sfname != NULL)
2073 vms_remove_version(sfname);
2074 vms_remove_version(fname);
2075#endif
2076
2077 /*
2078 * Set the name to be used for <amatch>.
2079 */
2080 autocmd_match = fname;
2081
2082
2083 // Don't redraw while doing autocommands.
2084 ++RedrawingDisabled;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002085
2086 // name and lnum are filled in later
2087 estack_push(ETYPE_AUCMD, NULL, 0);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002088 ESTACK_CHECK_SETUP
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002089
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002090 save_current_sctx = current_sctx;
2091
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002092#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002093# ifdef FEAT_PROFILE
2094 if (do_profiling == PROF_YES)
2095 prof_child_enter(&wait_time); // doesn't count for the caller itself
2096# endif
2097
2098 // Don't use local function variables, if called from a function.
2099 save_funccal(&funccal_entry);
2100#endif
2101
2102 /*
2103 * When starting to execute autocommands, save the search patterns.
2104 */
2105 if (!autocmd_busy)
2106 {
2107 save_search_patterns();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002108 if (!ins_compl_active())
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002109 {
2110 saveRedobuff(&save_redo);
2111 did_save_redobuff = TRUE;
2112 }
2113 did_filetype = keep_filetype;
2114 }
2115
2116 /*
2117 * Note that we are applying autocmds. Some commands need to know.
2118 */
2119 autocmd_busy = TRUE;
2120 filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
2121 ++nesting; // see matching decrement below
2122
2123 // Remember that FileType was triggered. Used for did_filetype().
2124 if (event == EVENT_FILETYPE)
2125 did_filetype = TRUE;
2126
2127 tail = gettail(fname);
2128
2129 // Find first autocommand that matches
2130 patcmd.curpat = first_autopat[(int)event];
2131 patcmd.nextcmd = NULL;
2132 patcmd.group = group;
2133 patcmd.fname = fname;
2134 patcmd.sfname = sfname;
2135 patcmd.tail = tail;
2136 patcmd.event = event;
2137 patcmd.arg_bufnr = autocmd_bufnr;
2138 patcmd.next = NULL;
2139 auto_next_pat(&patcmd, FALSE);
2140
2141 // found one, start executing the autocommands
2142 if (patcmd.curpat != NULL)
2143 {
2144 // add to active_apc_list
2145 patcmd.next = active_apc_list;
2146 active_apc_list = &patcmd;
2147
2148#ifdef FEAT_EVAL
2149 // set v:cmdarg (only when there is a matching pattern)
2150 save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
2151 if (eap != NULL)
2152 {
2153 save_cmdarg = set_cmdarg(eap, NULL);
2154 set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
2155 }
2156 else
2157 save_cmdarg = NULL; // avoid gcc warning
2158#endif
2159 retval = TRUE;
2160 // mark the last pattern, to avoid an endless loop when more patterns
2161 // are added when executing autocommands
2162 for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
2163 ap->last = FALSE;
2164 ap->last = TRUE;
Bram Moolenaara68e5952019-04-25 22:22:01 +02002165
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002166 if (nesting == 1)
2167 // make sure cursor and topline are valid
2168 check_lnums(TRUE);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002169
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002170 do_cmdline(NULL, getnextac, (void *)&patcmd,
2171 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
Bram Moolenaara68e5952019-04-25 22:22:01 +02002172
Bram Moolenaar1e6bbfb2021-04-03 13:19:26 +02002173 if (nesting == 1)
2174 // restore cursor and topline, unless they were changed
2175 reset_lnums();
Bram Moolenaara68e5952019-04-25 22:22:01 +02002176
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002177#ifdef FEAT_EVAL
2178 if (eap != NULL)
2179 {
2180 (void)set_cmdarg(NULL, save_cmdarg);
2181 set_vim_var_nr(VV_CMDBANG, save_cmdbang);
2182 }
2183#endif
2184 // delete from active_apc_list
2185 if (active_apc_list == &patcmd) // just in case
2186 active_apc_list = patcmd.next;
2187 }
2188
2189 --RedrawingDisabled;
2190 autocmd_busy = save_autocmd_busy;
2191 filechangeshell_busy = FALSE;
2192 autocmd_nested = save_autocmd_nested;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002193 vim_free(SOURCING_NAME);
Bram Moolenaare31ee862020-01-07 20:59:34 +01002194 ESTACK_CHECK_NOW
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002195 estack_pop();
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002196 vim_free(autocmd_fname);
2197 autocmd_fname = save_autocmd_fname;
2198 autocmd_fname_full = save_autocmd_fname_full;
2199 autocmd_bufnr = save_autocmd_bufnr;
2200 autocmd_match = save_autocmd_match;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002201 current_sctx = save_current_sctx;
Bram Moolenaar9b8d6222020-12-28 18:26:00 +01002202#ifdef FEAT_EVAL
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002203 restore_funccal();
2204# ifdef FEAT_PROFILE
2205 if (do_profiling == PROF_YES)
2206 prof_child_exit(&wait_time);
2207# endif
2208#endif
2209 KeyTyped = save_KeyTyped;
2210 vim_free(fname);
2211 vim_free(sfname);
2212 --nesting; // see matching increment above
2213
2214 /*
2215 * When stopping to execute autocommands, restore the search patterns and
2216 * the redo buffer. Free any buffers in the au_pending_free_buf list and
2217 * free any windows in the au_pending_free_win list.
2218 */
2219 if (!autocmd_busy)
2220 {
2221 restore_search_patterns();
2222 if (did_save_redobuff)
2223 restoreRedobuff(&save_redo);
2224 did_filetype = FALSE;
2225 while (au_pending_free_buf != NULL)
2226 {
2227 buf_T *b = au_pending_free_buf->b_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002228
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002229 vim_free(au_pending_free_buf);
2230 au_pending_free_buf = b;
2231 }
2232 while (au_pending_free_win != NULL)
2233 {
2234 win_T *w = au_pending_free_win->w_next;
Bram Moolenaar41cd8032021-03-13 15:47:56 +01002235
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002236 vim_free(au_pending_free_win);
2237 au_pending_free_win = w;
2238 }
2239 }
2240
2241 /*
2242 * Some events don't set or reset the Changed flag.
2243 * Check if still in the same buffer!
2244 */
2245 if (curbuf == old_curbuf
2246 && (event == EVENT_BUFREADPOST
2247 || event == EVENT_BUFWRITEPOST
2248 || event == EVENT_FILEAPPENDPOST
2249 || event == EVENT_VIMLEAVE
2250 || event == EVENT_VIMLEAVEPRE))
2251 {
2252#ifdef FEAT_TITLE
2253 if (curbuf->b_changed != save_changed)
2254 need_maketitle = TRUE;
2255#endif
2256 curbuf->b_changed = save_changed;
2257 }
2258
2259 au_cleanup(); // may really delete removed patterns/commands now
2260
2261BYPASS_AU:
2262 // When wiping out a buffer make sure all its buffer-local autocommands
2263 // are deleted.
2264 if (event == EVENT_BUFWIPEOUT && buf != NULL)
2265 aubuflocal_remove(buf);
2266
2267 if (retval == OK && event == EVENT_FILETYPE)
2268 au_did_filetype = TRUE;
2269
2270 return retval;
2271}
2272
2273# ifdef FEAT_EVAL
2274static char_u *old_termresponse = NULL;
2275# endif
2276
2277/*
2278 * Block triggering autocommands until unblock_autocmd() is called.
2279 * Can be used recursively, so long as it's symmetric.
2280 */
2281 void
2282block_autocmds(void)
2283{
2284# ifdef FEAT_EVAL
2285 // Remember the value of v:termresponse.
2286 if (autocmd_blocked == 0)
2287 old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
2288# endif
2289 ++autocmd_blocked;
2290}
2291
2292 void
2293unblock_autocmds(void)
2294{
2295 --autocmd_blocked;
2296
2297# ifdef FEAT_EVAL
2298 // When v:termresponse was set while autocommands were blocked, trigger
2299 // the autocommands now. Esp. useful when executing a shell command
2300 // during startup (vimdiff).
2301 if (autocmd_blocked == 0
2302 && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
2303 apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
2304# endif
2305}
2306
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002307 int
2308is_autocmd_blocked(void)
2309{
2310 return autocmd_blocked != 0;
2311}
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002312
2313/*
2314 * Find next autocommand pattern that matches.
2315 */
2316 static void
2317auto_next_pat(
2318 AutoPatCmd *apc,
2319 int stop_at_last) // stop when 'last' flag is set
2320{
2321 AutoPat *ap;
2322 AutoCmd *cp;
2323 char_u *name;
2324 char *s;
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002325 char_u **sourcing_namep = &SOURCING_NAME;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002326
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002327 VIM_CLEAR(*sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002328
2329 for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
2330 {
2331 apc->curpat = NULL;
2332
2333 // Only use a pattern when it has not been removed, has commands and
2334 // the group matches. For buffer-local autocommands only check the
2335 // buffer number.
2336 if (ap->pat != NULL && ap->cmds != NULL
2337 && (apc->group == AUGROUP_ALL || apc->group == ap->group))
2338 {
2339 // execution-condition
2340 if (ap->buflocal_nr == 0
2341 ? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
2342 apc->sfname, apc->tail, ap->allow_dirs))
2343 : ap->buflocal_nr == apc->arg_bufnr)
2344 {
2345 name = event_nr2name(apc->event);
2346 s = _("%s Autocommands for \"%s\"");
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002347 *sourcing_namep = alloc(STRLEN(s)
Bram Moolenaar964b3742019-05-24 18:54:09 +02002348 + STRLEN(name) + ap->patlen + 1);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002349 if (*sourcing_namep != NULL)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002350 {
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002351 sprintf((char *)*sourcing_namep, s,
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002352 (char *)name, (char *)ap->pat);
2353 if (p_verbose >= 8)
2354 {
2355 verbose_enter();
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01002356 smsg(_("Executing %s"), *sourcing_namep);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002357 verbose_leave();
2358 }
2359 }
2360
2361 apc->curpat = ap;
2362 apc->nextcmd = ap->cmds;
2363 // mark last command
2364 for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
2365 cp->last = FALSE;
2366 cp->last = TRUE;
2367 }
2368 line_breakcheck();
2369 if (apc->curpat != NULL) // found a match
2370 break;
2371 }
2372 if (stop_at_last && ap->last)
2373 break;
2374 }
2375}
2376
2377/*
2378 * Get next autocommand command.
2379 * Called by do_cmdline() to get the next line for ":if".
2380 * Returns allocated string, or NULL for end of autocommands.
2381 */
2382 char_u *
Bram Moolenaar66250c92020-08-20 15:02:42 +02002383getnextac(
2384 int c UNUSED,
2385 void *cookie,
2386 int indent UNUSED,
2387 getline_opt_T options UNUSED)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002388{
2389 AutoPatCmd *acp = (AutoPatCmd *)cookie;
2390 char_u *retval;
2391 AutoCmd *ac;
2392
2393 // Can be called again after returning the last line.
2394 if (acp->curpat == NULL)
2395 return NULL;
2396
2397 // repeat until we find an autocommand to execute
2398 for (;;)
2399 {
2400 // skip removed commands
2401 while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
2402 if (acp->nextcmd->last)
2403 acp->nextcmd = NULL;
2404 else
2405 acp->nextcmd = acp->nextcmd->next;
2406
2407 if (acp->nextcmd != NULL)
2408 break;
2409
2410 // at end of commands, find next pattern that matches
2411 if (acp->curpat->last)
2412 acp->curpat = NULL;
2413 else
2414 acp->curpat = acp->curpat->next;
2415 if (acp->curpat != NULL)
2416 auto_next_pat(acp, TRUE);
2417 if (acp->curpat == NULL)
2418 return NULL;
2419 }
2420
2421 ac = acp->nextcmd;
2422
2423 if (p_verbose >= 9)
2424 {
2425 verbose_enter_scroll();
2426 smsg(_("autocommand %s"), ac->cmd);
2427 msg_puts("\n"); // don't overwrite this either
2428 verbose_leave_scroll();
2429 }
2430 retval = vim_strsave(ac->cmd);
Bram Moolenaareb93f3f2019-04-04 15:04:56 +02002431 // Remove one-shot ("once") autocmd in anticipation of its execution.
2432 if (ac->once)
2433 au_del_cmd(ac);
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002434 autocmd_nested = ac->nested;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002435 current_sctx = ac->script_ctx;
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002436 if (ac->last)
2437 acp->nextcmd = NULL;
2438 else
2439 acp->nextcmd = ac->next;
2440 return retval;
2441}
2442
2443/*
2444 * Return TRUE if there is a matching autocommand for "fname".
2445 * To account for buffer-local autocommands, function needs to know
2446 * in which buffer the file will be opened.
2447 */
2448 int
2449has_autocmd(event_T event, char_u *sfname, buf_T *buf)
2450{
2451 AutoPat *ap;
2452 char_u *fname;
2453 char_u *tail = gettail(sfname);
2454 int retval = FALSE;
2455
2456 fname = FullName_save(sfname, FALSE);
2457 if (fname == NULL)
2458 return FALSE;
2459
2460#ifdef BACKSLASH_IN_FILENAME
2461 /*
2462 * Replace all backslashes with forward slashes. This makes the
2463 * autocommand patterns portable between Unix and MS-DOS.
2464 */
2465 sfname = vim_strsave(sfname);
2466 if (sfname != NULL)
2467 forward_slash(sfname);
2468 forward_slash(fname);
2469#endif
2470
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002471 FOR_ALL_AUTOCMD_PATTERNS(event, ap)
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002472 if (ap->pat != NULL && ap->cmds != NULL
2473 && (ap->buflocal_nr == 0
2474 ? match_file_pat(NULL, &ap->reg_prog,
2475 fname, sfname, tail, ap->allow_dirs)
2476 : buf != NULL && ap->buflocal_nr == buf->b_fnum
2477 ))
2478 {
2479 retval = TRUE;
2480 break;
2481 }
2482
2483 vim_free(fname);
2484#ifdef BACKSLASH_IN_FILENAME
2485 vim_free(sfname);
2486#endif
2487
2488 return retval;
2489}
2490
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002491/*
2492 * Function given to ExpandGeneric() to obtain the list of autocommand group
2493 * names.
2494 */
2495 char_u *
2496get_augroup_name(expand_T *xp UNUSED, int idx)
2497{
2498 if (idx == augroups.ga_len) // add "END" add the end
2499 return (char_u *)"END";
2500 if (idx >= augroups.ga_len) // end of list
2501 return NULL;
2502 if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
2503 // skip deleted entries
2504 return (char_u *)"";
2505 return AUGROUP_NAME(idx); // return a name
2506}
2507
2508static int include_groups = FALSE;
2509
2510 char_u *
2511set_context_in_autocmd(
2512 expand_T *xp,
2513 char_u *arg,
2514 int doautocmd) // TRUE for :doauto*, FALSE for :autocmd
2515{
2516 char_u *p;
2517 int group;
2518
2519 // check for a group name, skip it if present
2520 include_groups = FALSE;
2521 p = arg;
2522 group = au_get_grouparg(&arg);
2523 if (group == AUGROUP_ERROR)
2524 return NULL;
2525 // If there only is a group name that's what we expand.
2526 if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
2527 {
2528 arg = p;
2529 group = AUGROUP_ALL;
2530 }
2531
2532 // skip over event name
2533 for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
2534 if (*p == ',')
2535 arg = p + 1;
2536 if (*p == NUL)
2537 {
2538 if (group == AUGROUP_ALL)
2539 include_groups = TRUE;
2540 xp->xp_context = EXPAND_EVENTS; // expand event name
2541 xp->xp_pattern = arg;
2542 return NULL;
2543 }
2544
2545 // skip over pattern
2546 arg = skipwhite(p);
2547 while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
2548 arg++;
2549 if (*arg)
2550 return arg; // expand (next) command
2551
2552 if (doautocmd)
2553 xp->xp_context = EXPAND_FILES; // expand file names
2554 else
2555 xp->xp_context = EXPAND_NOTHING; // pattern is not expanded
2556 return NULL;
2557}
2558
2559/*
2560 * Function given to ExpandGeneric() to obtain the list of event names.
2561 */
2562 char_u *
2563get_event_name(expand_T *xp UNUSED, int idx)
2564{
2565 if (idx < augroups.ga_len) // First list group names, if wanted
2566 {
2567 if (!include_groups || AUGROUP_NAME(idx) == NULL
2568 || AUGROUP_NAME(idx) == get_deleted_augroup())
2569 return (char_u *)""; // skip deleted entries
2570 return AUGROUP_NAME(idx); // return a name
2571 }
2572 return (char_u *)event_names[idx - augroups.ga_len].name;
2573}
2574
Bram Moolenaar3e460fd2019-01-26 16:21:07 +01002575
2576#if defined(FEAT_EVAL) || defined(PROTO)
2577/*
2578 * Return TRUE if autocmd is supported.
2579 */
2580 int
2581autocmd_supported(char_u *name)
2582{
2583 char_u *p;
2584
2585 return (event_name2nr(name, &p) != NUM_EVENTS);
2586}
2587
2588/*
2589 * Return TRUE if an autocommand is defined for a group, event and
2590 * pattern: The group can be omitted to accept any group. "event" and "pattern"
2591 * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
2592 * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
2593 * Used for:
2594 * exists("#Group") or
2595 * exists("#Group#Event") or
2596 * exists("#Group#Event#pat") or
2597 * exists("#Event") or
2598 * exists("#Event#pat")
2599 */
2600 int
2601au_exists(char_u *arg)
2602{
2603 char_u *arg_save;
2604 char_u *pattern = NULL;
2605 char_u *event_name;
2606 char_u *p;
2607 event_T event;
2608 AutoPat *ap;
2609 buf_T *buflocal_buf = NULL;
2610 int group;
2611 int retval = FALSE;
2612
2613 // Make a copy so that we can change the '#' chars to a NUL.
2614 arg_save = vim_strsave(arg);
2615 if (arg_save == NULL)
2616 return FALSE;
2617 p = vim_strchr(arg_save, '#');
2618 if (p != NULL)
2619 *p++ = NUL;
2620
2621 // First, look for an autocmd group name
2622 group = au_find_group(arg_save);
2623 if (group == AUGROUP_ERROR)
2624 {
2625 // Didn't match a group name, assume the first argument is an event.
2626 group = AUGROUP_ALL;
2627 event_name = arg_save;
2628 }
2629 else
2630 {
2631 if (p == NULL)
2632 {
2633 // "Group": group name is present and it's recognized
2634 retval = TRUE;
2635 goto theend;
2636 }
2637
2638 // Must be "Group#Event" or "Group#Event#pat".
2639 event_name = p;
2640 p = vim_strchr(event_name, '#');
2641 if (p != NULL)
2642 *p++ = NUL; // "Group#Event#pat"
2643 }
2644
2645 pattern = p; // "pattern" is NULL when there is no pattern
2646
2647 // find the index (enum) for the event name
2648 event = event_name2nr(event_name, &p);
2649
2650 // return FALSE if the event name is not recognized
2651 if (event == NUM_EVENTS)
2652 goto theend;
2653
2654 // Find the first autocommand for this event.
2655 // If there isn't any, return FALSE;
2656 // If there is one and no pattern given, return TRUE;
2657 ap = first_autopat[(int)event];
2658 if (ap == NULL)
2659 goto theend;
2660
2661 // if pattern is "<buffer>", special handling is needed which uses curbuf
2662 // for pattern "<buffer=N>, fnamecmp() will work fine
2663 if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
2664 buflocal_buf = curbuf;
2665
2666 // Check if there is an autocommand with the given pattern.
2667 for ( ; ap != NULL; ap = ap->next)
2668 // only use a pattern when it has not been removed and has commands.
2669 // For buffer-local autocommands, fnamecmp() works fine.
2670 if (ap->pat != NULL && ap->cmds != NULL
2671 && (group == AUGROUP_ALL || ap->group == group)
2672 && (pattern == NULL
2673 || (buflocal_buf == NULL
2674 ? fnamecmp(ap->pat, pattern) == 0
2675 : ap->buflocal_nr == buflocal_buf->b_fnum)))
2676 {
2677 retval = TRUE;
2678 break;
2679 }
2680
2681theend:
2682 vim_free(arg_save);
2683 return retval;
2684}
2685#endif