diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 2 | ||||
-rw-r--r-- | src/nvim/fileio.c | 202 |
2 files changed, 113 insertions, 91 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c23177f23a..5ef2a8772e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -20160,7 +20160,7 @@ void ex_function(exarg_T *eap) skip_until = vim_strsave((char_u *)"."); } - // Check for ":python <<EOF", ":lua <<EOF", etc. + // heredoc: Check for ":python <<EOF", ":lua <<EOF", etc. arg = skipwhite(skiptowhite(p)); if (arg[0] == '<' && arg[1] =='<' && ((p[0] == 'p' && p[1] == 'y' diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index b9de46efc8..f111376d84 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -99,8 +99,9 @@ // defined and will have to be executed. // typedef struct AutoCmd { - char_u *cmd; // The command to be executed (NULL - // when command has been removed) + char_u *cmd; // Command to be executed (NULL when + // command has been removed) + bool once; // "One shot": removed after execution char nested; // If autocommands nest here char last; // last command in list scid_T scriptID; // script ID where defined @@ -121,20 +122,20 @@ typedef struct AutoPat { char last; // last pattern for apply_autocmds() } AutoPat; -/* - * struct used to keep status while executing autocommands for an event. - */ +/// +/// Struct used to keep status while executing autocommands for an event. +/// typedef struct AutoPatCmd { - AutoPat *curpat; /* next AutoPat to examine */ - AutoCmd *nextcmd; /* next AutoCmd to execute */ - int group; /* group being used */ - char_u *fname; /* fname to match with */ - char_u *sfname; /* sfname to match with */ - char_u *tail; /* tail of fname */ - event_T event; /* current event */ - int arg_bufnr; /* initially equal to <abuf>, set to zero when - buf is deleted */ - struct AutoPatCmd *next; /* chain of active apc-s for auto-invalidation*/ + AutoPat *curpat; // next AutoPat to examine + AutoCmd *nextcmd; // next AutoCmd to execute + int group; // group being used + char_u *fname; // fname to match with + char_u *sfname; // sfname to match with + char_u *tail; // tail of fname + event_T event; // current event + int arg_bufnr; // initially equal to <abuf>, set to zero when + // buf is deleted + struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation } AutoPatCmd; #define AUGROUP_DEFAULT -1 /* default autocmd group */ @@ -5563,29 +5564,31 @@ static void show_autocmd(AutoPat *ap, event_T event) } } -/* - * Mark an autocommand pattern for deletion. - */ +// Mark an autocommand handler for deletion. static void au_remove_pat(AutoPat *ap) { xfree(ap->pat); ap->pat = NULL; ap->buflocal_nr = -1; - au_need_clean = TRUE; + au_need_clean = true; } -/* - * Mark all commands for a pattern for deletion. - */ +// Mark all commands for a pattern for deletion. static void au_remove_cmds(AutoPat *ap) { - AutoCmd *ac; - - for (ac = ap->cmds; ac != NULL; ac = ac->next) { + for (AutoCmd *ac = ap->cmds; ac != NULL; ac = ac->next) { xfree(ac->cmd); ac->cmd = NULL; } - au_need_clean = TRUE; + au_need_clean = true; +} + +// Delete one command from an autocmd pattern. +static void au_del_cmd(AutoCmd *ac) +{ + xfree(ac->cmd); + ac->cmd = NULL; + au_need_clean = true; } /* @@ -5674,18 +5677,18 @@ void aubuflocal_remove(buf_T *buf) au_cleanup(); } -/* - * Add an autocmd group name. - * Return it's ID. Returns AUGROUP_ERROR (< 0) for error. - */ +// Add an autocmd group name. +// Return its ID. Returns AUGROUP_ERROR (< 0) for error. static int au_new_group(char_u *name) { int i = au_find_group(name); - if (i == AUGROUP_ERROR) { /* the group doesn't exist yet, add it */ - /* First try using a free entry. */ - for (i = 0; i < augroups.ga_len; ++i) - if (AUGROUP_NAME(i) == NULL) + if (i == AUGROUP_ERROR) { // the group doesn't exist yet, add it. + // First try using a free entry. + for (i = 0; i < augroups.ga_len; i++) { + if (AUGROUP_NAME(i) == NULL) { break; + } + } if (i == augroups.ga_len) { ga_grow(&augroups, 1); } @@ -5701,9 +5704,7 @@ static int au_new_group(char_u *name) static void au_del_group(char_u *name) { - int i; - - i = au_find_group(name); + int i = au_find_group(name); if (i == AUGROUP_ERROR) { // the group doesn't exist EMSG2(_("E367: No such group: \"%s\""), name); } else if (i == current_augroup) { @@ -5760,23 +5761,22 @@ bool au_has_group(const char_u *name) return au_find_group(name) != AUGROUP_ERROR; } -/* - * ":augroup {name}". - */ +/// ":augroup {name}". void do_augroup(char_u *arg, int del_group) { if (del_group) { - if (*arg == NUL) + if (*arg == NUL) { EMSG(_(e_argreq)); - else + } else { au_del_group(arg); - } else if (STRICMP(arg, "end") == 0) /* ":aug end": back to group 0 */ + } + } else if (STRICMP(arg, "end") == 0) { // ":aug end": back to group 0 current_augroup = AUGROUP_DEFAULT; - else if (*arg) { /* ":aug xxx": switch to group xxx */ + } else if (*arg) { // ":aug xxx": switch to group xxx int i = au_new_group(arg); if (i != AUGROUP_ERROR) current_augroup = i; - } else { /* ":aug": list the group names */ + } else { // ":aug": list the group names msg_start(); for (int i = 0; i < augroups.ga_len; ++i) { if (AUGROUP_NAME(i) != NULL) { @@ -5957,38 +5957,38 @@ void au_event_restore(char_u *old_ei) } } -/* - * do_autocmd() -- implements the :autocmd command. Can be used in the - * following ways: - * - * :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that - * will be automatically executed for <event> - * when editing a file matching <pat>, in - * the current group. - * :autocmd <event> <pat> Show the autocommands associated with - * <event> and <pat>. - * :autocmd <event> Show the autocommands associated with - * <event>. - * :autocmd Show all autocommands. - * :autocmd! <event> <pat> <cmd> Remove all autocommands associated with - * <event> and <pat>, and add the command - * <cmd>, for the current group. - * :autocmd! <event> <pat> Remove all autocommands associated with - * <event> and <pat> for the current group. - * :autocmd! <event> Remove all autocommands associated with - * <event> for the current group. - * :autocmd! Remove ALL autocommands for the current - * group. - * - * Multiple events and patterns may be given separated by commas. Here are - * some examples: - * :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic - * :autocmd bufleave * set tw=79 nosmartindent ic infercase - * - * :autocmd * *.c show all autocommands for *.c files. - * - * Mostly a {group} argument can optionally appear before <event>. - */ +// Implements :autocmd. +// Defines an autocmd (does not execute; cf. apply_autocmds_group). +// +// Can be used in the following ways: +// +// :autocmd <event> <pat> <cmd> Add <cmd> to the list of commands that +// will be automatically executed for <event> +// when editing a file matching <pat>, in +// the current group. +// :autocmd <event> <pat> Show the autocommands associated with +// <event> and <pat>. +// :autocmd <event> Show the autocommands associated with +// <event>. +// :autocmd Show all autocommands. +// :autocmd! <event> <pat> <cmd> Remove all autocommands associated with +// <event> and <pat>, and add the command +// <cmd>, for the current group. +// :autocmd! <event> <pat> Remove all autocommands associated with +// <event> and <pat> for the current group. +// :autocmd! <event> Remove all autocommands associated with +// <event> for the current group. +// :autocmd! Remove ALL autocommands for the current +// group. +// +// Multiple events and patterns may be given separated by commas. Here are +// some examples: +// :autocmd bufread,bufenter *.c,*.h set tw=0 smartindent noic +// :autocmd bufleave * set tw=79 nosmartindent ic infercase +// +// :autocmd * *.c show all autocommands for *.c files. +// +// Mostly a {group} argument can optionally appear before <event>. void do_autocmd(char_u *arg_in, int forceit) { char_u *arg = arg_in; @@ -5997,6 +5997,7 @@ void do_autocmd(char_u *arg_in, int forceit) char_u *cmd; int need_free = false; int nested = false; + bool once = false; int group; if (*arg == '|') { @@ -6046,6 +6047,14 @@ void do_autocmd(char_u *arg_in, int forceit) } } + // Check for "once" flag. + cmd = skipwhite(cmd); + if (*cmd != NUL && STRNCMP(cmd, "once", 4) == 0 + && ascii_iswhite(cmd[4])) { + once = true; + cmd = skipwhite(cmd + 4); + } + // Check for "nested" flag. cmd = skipwhite(cmd); if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 @@ -6081,7 +6090,8 @@ void do_autocmd(char_u *arg_in, int forceit) if (*arg == '*' || *arg == NUL || *arg == '|') { for (event_T event = (event_T)0; (int)event < (int)NUM_EVENTS; event = (event_T)((int)event + 1)) { - if (do_autocmd_event(event, pat, nested, cmd, forceit, group) == FAIL) { + if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group) + == FAIL) { break; } } @@ -6089,7 +6099,8 @@ void do_autocmd(char_u *arg_in, int forceit) while (*arg && *arg != '|' && !ascii_iswhite(*arg)) { event_T event = event_name2nr(arg, &arg); assert(event < NUM_EVENTS); - if (do_autocmd_event(event, pat, nested, cmd, forceit, group) == FAIL) { + if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group) + == FAIL) { break; } } @@ -6127,14 +6138,15 @@ static int au_get_grouparg(char_u **argp) return group; } -/* - * do_autocmd() for one event. - * If *pat == NUL do for all patterns. - * If *cmd == NUL show entries. - * If forceit == TRUE delete entries. - * If group is not AUGROUP_ALL, only use this group. - */ -static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd, int forceit, int group) +// do_autocmd() for one event. +// Defines an autocmd (does not execute; cf. apply_autocmds_group). +// +// If *pat == NUL: do for all patterns. +// If *cmd == NUL: show entries. +// If forceit == TRUE: delete entries. +// If group is not AUGROUP_ALL: only use this group. +static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, + char_u *cmd, int forceit, int group) { AutoPat *ap; AutoPat **prev_ap; @@ -6333,6 +6345,7 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd, ac->scriptID = current_SID; ac->next = NULL; *prev_ac = ac; + ac->once = once; ac->nested = nested; } } @@ -6996,7 +7009,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, patcmd.event = event; patcmd.arg_bufnr = autocmd_bufnr; patcmd.next = NULL; - auto_next_pat(&patcmd, FALSE); + auto_next_pat(&patcmd, false); /* found one, start executing the autocommands */ if (patcmd.curpat != NULL) { @@ -7020,8 +7033,11 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, } ap->last = true; check_lnums(true); // make sure cursor and topline are valid + + // Execute the autocmd. The `getnextac` callback handles iteration. do_cmdline(NULL, getnextac, (void *)&patcmd, DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); + if (eap != NULL) { (void)set_cmdarg(NULL, save_cmdarg); set_vim_var_nr(VV_CMDBANG, save_cmdbang); @@ -7233,12 +7249,18 @@ char_u *getnextac(int c, void *cookie, int indent) verbose_leave_scroll(); } retval = vim_strsave(ac->cmd); + // Remove one-shot ("once") autocmd in anticipation of its execution. + if (ac->once) { + au_del_cmd(ac); + } autocmd_nested = ac->nested; current_SID = ac->scriptID; - if (ac->last) + if (ac->last) { acp->nextcmd = NULL; - else + } else { acp->nextcmd = ac->next; + } + return retval; } |