#include "vim.h"
typedef struct AutoCmd
{
char_u *cmd; char once; char nested; char last; #ifdef FEAT_EVAL
sctx_T script_ctx; #endif
struct AutoCmd *next; } AutoCmd;
typedef struct AutoPat
{
struct AutoPat *next; char_u *pat; regprog_T *reg_prog; AutoCmd *cmds; int group; int patlen; int buflocal_nr; char allow_dirs; char last; } AutoPat;
static struct event_name
{
char *name; event_T event; } event_names[] =
{
{"BufAdd", EVENT_BUFADD},
{"BufCreate", EVENT_BUFADD},
{"BufDelete", EVENT_BUFDELETE},
{"BufEnter", EVENT_BUFENTER},
{"BufFilePost", EVENT_BUFFILEPOST},
{"BufFilePre", EVENT_BUFFILEPRE},
{"BufHidden", EVENT_BUFHIDDEN},
{"BufLeave", EVENT_BUFLEAVE},
{"BufNew", EVENT_BUFNEW},
{"BufNewFile", EVENT_BUFNEWFILE},
{"BufRead", EVENT_BUFREADPOST},
{"BufReadCmd", EVENT_BUFREADCMD},
{"BufReadPost", EVENT_BUFREADPOST},
{"BufReadPre", EVENT_BUFREADPRE},
{"BufUnload", EVENT_BUFUNLOAD},
{"BufWinEnter", EVENT_BUFWINENTER},
{"BufWinLeave", EVENT_BUFWINLEAVE},
{"BufWipeout", EVENT_BUFWIPEOUT},
{"BufWrite", EVENT_BUFWRITEPRE},
{"BufWritePost", EVENT_BUFWRITEPOST},
{"BufWritePre", EVENT_BUFWRITEPRE},
{"BufWriteCmd", EVENT_BUFWRITECMD},
{"CmdlineChanged", EVENT_CMDLINECHANGED},
{"CmdlineEnter", EVENT_CMDLINEENTER},
{"CmdlineLeave", EVENT_CMDLINELEAVE},
{"CmdwinEnter", EVENT_CMDWINENTER},
{"CmdwinLeave", EVENT_CMDWINLEAVE},
{"CmdUndefined", EVENT_CMDUNDEFINED},
{"ColorScheme", EVENT_COLORSCHEME},
{"ColorSchemePre", EVENT_COLORSCHEMEPRE},
{"CompleteChanged", EVENT_COMPLETECHANGED},
{"CompleteDone", EVENT_COMPLETEDONE},
{"CompleteDonePre", EVENT_COMPLETEDONEPRE},
{"CursorHold", EVENT_CURSORHOLD},
{"CursorHoldI", EVENT_CURSORHOLDI},
{"CursorMoved", EVENT_CURSORMOVED},
{"CursorMovedI", EVENT_CURSORMOVEDI},
{"DiffUpdated", EVENT_DIFFUPDATED},
{"DirChanged", EVENT_DIRCHANGED},
{"EncodingChanged", EVENT_ENCODINGCHANGED},
{"ExitPre", EVENT_EXITPRE},
{"FileEncoding", EVENT_ENCODINGCHANGED},
{"FileAppendPost", EVENT_FILEAPPENDPOST},
{"FileAppendPre", EVENT_FILEAPPENDPRE},
{"FileAppendCmd", EVENT_FILEAPPENDCMD},
{"FileChangedShell",EVENT_FILECHANGEDSHELL},
{"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
{"FileChangedRO", EVENT_FILECHANGEDRO},
{"FileReadPost", EVENT_FILEREADPOST},
{"FileReadPre", EVENT_FILEREADPRE},
{"FileReadCmd", EVENT_FILEREADCMD},
{"FileType", EVENT_FILETYPE},
{"FileWritePost", EVENT_FILEWRITEPOST},
{"FileWritePre", EVENT_FILEWRITEPRE},
{"FileWriteCmd", EVENT_FILEWRITECMD},
{"FilterReadPost", EVENT_FILTERREADPOST},
{"FilterReadPre", EVENT_FILTERREADPRE},
{"FilterWritePost", EVENT_FILTERWRITEPOST},
{"FilterWritePre", EVENT_FILTERWRITEPRE},
{"FocusGained", EVENT_FOCUSGAINED},
{"FocusLost", EVENT_FOCUSLOST},
{"FuncUndefined", EVENT_FUNCUNDEFINED},
{"GUIEnter", EVENT_GUIENTER},
{"GUIFailed", EVENT_GUIFAILED},
{"InsertChange", EVENT_INSERTCHANGE},
{"InsertEnter", EVENT_INSERTENTER},
{"InsertLeave", EVENT_INSERTLEAVE},
{"InsertCharPre", EVENT_INSERTCHARPRE},
{"MenuPopup", EVENT_MENUPOPUP},
{"OptionSet", EVENT_OPTIONSET},
{"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
{"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
{"QuitPre", EVENT_QUITPRE},
{"RemoteReply", EVENT_REMOTEREPLY},
{"SafeState", EVENT_SAFESTATE},
{"SafeStateAgain", EVENT_SAFESTATEAGAIN},
{"SessionLoadPost", EVENT_SESSIONLOADPOST},
{"ShellCmdPost", EVENT_SHELLCMDPOST},
{"ShellFilterPost", EVENT_SHELLFILTERPOST},
{"SourceCmd", EVENT_SOURCECMD},
{"SourcePre", EVENT_SOURCEPRE},
{"SourcePost", EVENT_SOURCEPOST},
{"SpellFileMissing",EVENT_SPELLFILEMISSING},
{"StdinReadPost", EVENT_STDINREADPOST},
{"StdinReadPre", EVENT_STDINREADPRE},
{"SwapExists", EVENT_SWAPEXISTS},
{"Syntax", EVENT_SYNTAX},
{"TabNew", EVENT_TABNEW},
{"TabClosed", EVENT_TABCLOSED},
{"TabEnter", EVENT_TABENTER},
{"TabLeave", EVENT_TABLEAVE},
{"TermChanged", EVENT_TERMCHANGED},
{"TerminalOpen", EVENT_TERMINALOPEN},
{"TerminalWinOpen", EVENT_TERMINALWINOPEN},
{"TermResponse", EVENT_TERMRESPONSE},
{"TextChanged", EVENT_TEXTCHANGED},
{"TextChangedI", EVENT_TEXTCHANGEDI},
{"TextChangedP", EVENT_TEXTCHANGEDP},
{"User", EVENT_USER},
{"VimEnter", EVENT_VIMENTER},
{"VimLeave", EVENT_VIMLEAVE},
{"VimLeavePre", EVENT_VIMLEAVEPRE},
{"WinNew", EVENT_WINNEW},
{"WinEnter", EVENT_WINENTER},
{"WinLeave", EVENT_WINLEAVE},
{"VimResized", EVENT_VIMRESIZED},
{"TextYankPost", EVENT_TEXTYANKPOST},
{NULL, (event_T)0}
};
static AutoPat *first_autopat[NUM_EVENTS] =
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static AutoPat *last_autopat[NUM_EVENTS] =
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
#define AUGROUP_DEFAULT -1 // default autocmd group
#define AUGROUP_ERROR -2 // erroneous autocmd group
#define AUGROUP_ALL -3 // all autocmd groups
struct AutoPatCmd_S
{
AutoPat *curpat; AutoCmd *nextcmd; int group; char_u *fname; char_u *sfname; char_u *tail; event_T event; int arg_bufnr; AutoPatCmd *next; };
static AutoPatCmd *active_apc_list = NULL;
#define FOR_ALL_AUTOCMD_PATTERNS(event, ap) \
for ((ap) = first_autopat[(int)(event)]; (ap) != NULL; (ap) = (ap)->next)
static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
static char_u *deleted_augroup = NULL;
static int current_augroup = AUGROUP_DEFAULT;
static int au_need_clean = FALSE;
static char_u *event_nr2name(event_T event);
static int au_get_grouparg(char_u **argp);
static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group);
static int apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap);
static void auto_next_pat(AutoPatCmd *apc, int stop_at_last);
static int au_find_group(char_u *name);
static event_T last_event;
static int last_group;
static int autocmd_blocked = 0;
static char_u *
get_deleted_augroup(void)
{
if (deleted_augroup == NULL)
deleted_augroup = (char_u *)_("--Deleted--");
return deleted_augroup;
}
static void
show_autocmd(AutoPat *ap, event_T event)
{
AutoCmd *ac;
if (got_int)
return;
if (ap->pat == NULL) return;
msg_putchar('\n');
if (got_int)
return;
if (event != last_event || ap->group != last_group)
{
if (ap->group != AUGROUP_DEFAULT)
{
if (AUGROUP_NAME(ap->group) == NULL)
msg_puts_attr((char *)get_deleted_augroup(), HL_ATTR(HLF_E));
else
msg_puts_attr((char *)AUGROUP_NAME(ap->group), HL_ATTR(HLF_T));
msg_puts(" ");
}
msg_puts_attr((char *)event_nr2name(event), HL_ATTR(HLF_T));
last_event = event;
last_group = ap->group;
msg_putchar('\n');
if (got_int)
return;
}
msg_col = 4;
msg_outtrans(ap->pat);
for (ac = ap->cmds; ac != NULL; ac = ac->next)
{
if (ac->cmd != NULL) {
if (msg_col >= 14)
msg_putchar('\n');
msg_col = 14;
if (got_int)
return;
msg_outtrans(ac->cmd);
#ifdef FEAT_EVAL
if (p_verbose > 0)
last_set_msg(ac->script_ctx);
#endif
if (got_int)
return;
if (ac->next != NULL)
{
msg_putchar('\n');
if (got_int)
return;
}
}
}
}
static void
au_remove_pat(AutoPat *ap)
{
VIM_CLEAR(ap->pat);
ap->buflocal_nr = -1;
au_need_clean = TRUE;
}
static void
au_remove_cmds(AutoPat *ap)
{
AutoCmd *ac;
for (ac = ap->cmds; ac != NULL; ac = ac->next)
VIM_CLEAR(ac->cmd);
au_need_clean = TRUE;
}
static void au_del_cmd(AutoCmd *ac)
{
VIM_CLEAR(ac->cmd);
au_need_clean = TRUE;
}
static void
au_cleanup(void)
{
AutoPat *ap, **prev_ap;
AutoCmd *ac, **prev_ac;
event_T event;
if (autocmd_busy || !au_need_clean)
return;
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
event = (event_T)((int)event + 1))
{
prev_ap = &(first_autopat[(int)event]);
for (ap = *prev_ap; ap != NULL; ap = *prev_ap)
{
int has_cmd = FALSE;
prev_ac = &(ap->cmds);
for (ac = *prev_ac; ac != NULL; ac = *prev_ac)
{
if (ap->pat == NULL || ac->cmd == NULL)
{
*prev_ac = ac->next;
vim_free(ac->cmd);
vim_free(ac);
}
else
{
has_cmd = TRUE;
prev_ac = &(ac->next);
}
}
if (ap->pat != NULL && !has_cmd)
au_remove_pat(ap);
if (ap->pat == NULL)
{
if (ap->next == NULL)
{
if (prev_ap == &(first_autopat[(int)event]))
last_autopat[(int)event] = NULL;
else
last_autopat[(int)event] = (AutoPat *)prev_ap;
}
*prev_ap = ap->next;
vim_regfree(ap->reg_prog);
vim_free(ap);
}
else
prev_ap = &(ap->next);
}
}
au_need_clean = FALSE;
}
void
aubuflocal_remove(buf_T *buf)
{
AutoPat *ap;
event_T event;
AutoPatCmd *apc;
for (apc = active_apc_list; apc; apc = apc->next)
if (buf->b_fnum == apc->arg_bufnr)
apc->arg_bufnr = 0;
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
event = (event_T)((int)event + 1))
FOR_ALL_AUTOCMD_PATTERNS(event, ap)
if (ap->buflocal_nr == buf->b_fnum)
{
au_remove_pat(ap);
if (p_verbose >= 6)
{
verbose_enter();
smsg(_("auto-removing autocommand: %s <buffer=%d>"),
event_nr2name(event), buf->b_fnum);
verbose_leave();
}
}
au_cleanup();
}
static int
au_new_group(char_u *name)
{
int i;
i = au_find_group(name);
if (i == AUGROUP_ERROR) {
for (i = 0; i < augroups.ga_len; ++i)
if (AUGROUP_NAME(i) == NULL)
break;
if (i == augroups.ga_len && ga_grow(&augroups, 1) == FAIL)
return AUGROUP_ERROR;
AUGROUP_NAME(i) = vim_strsave(name);
if (AUGROUP_NAME(i) == NULL)
return AUGROUP_ERROR;
if (i == augroups.ga_len)
++augroups.ga_len;
}
return i;
}
static void
au_del_group(char_u *name)
{
int i;
i = au_find_group(name);
if (i == AUGROUP_ERROR) semsg(_("E367: No such group: \"%s\""), name);
else if (i == current_augroup)
emsg(_("E936: Cannot delete the current group"));
else
{
event_T event;
AutoPat *ap;
int in_use = FALSE;
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
event = (event_T)((int)event + 1))
{
FOR_ALL_AUTOCMD_PATTERNS(event, ap)
if (ap->group == i && ap->pat != NULL)
{
give_warning((char_u *)_("W19: Deleting augroup that is still in use"), TRUE);
in_use = TRUE;
event = NUM_EVENTS;
break;
}
}
vim_free(AUGROUP_NAME(i));
if (in_use)
AUGROUP_NAME(i) = get_deleted_augroup();
else
AUGROUP_NAME(i) = NULL;
}
}
static int
au_find_group(char_u *name)
{
int i;
for (i = 0; i < augroups.ga_len; ++i)
if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
&& STRCMP(AUGROUP_NAME(i), name) == 0)
return i;
return AUGROUP_ERROR;
}
int
au_has_group(char_u *name)
{
return au_find_group(name) != AUGROUP_ERROR;
}
void
do_augroup(char_u *arg, int del_group)
{
int i;
if (del_group)
{
if (*arg == NUL)
emsg(_(e_argreq));
else
au_del_group(arg);
}
else if (STRICMP(arg, "end") == 0) current_augroup = AUGROUP_DEFAULT;
else if (*arg) {
i = au_new_group(arg);
if (i != AUGROUP_ERROR)
current_augroup = i;
}
else {
msg_start();
for (i = 0; i < augroups.ga_len; ++i)
{
if (AUGROUP_NAME(i) != NULL)
{
msg_puts((char *)AUGROUP_NAME(i));
msg_puts(" ");
}
}
msg_clr_eos();
msg_end();
}
}
#if defined(EXITFREE) || defined(PROTO)
void
free_all_autocmds(void)
{
int i;
char_u *s;
for (current_augroup = -1; current_augroup < augroups.ga_len;
++current_augroup)
do_autocmd((char_u *)"", TRUE);
for (i = 0; i < augroups.ga_len; ++i)
{
s = ((char_u **)(augroups.ga_data))[i];
if (s != get_deleted_augroup())
vim_free(s);
}
ga_clear(&augroups);
}
#endif
static event_T
event_name2nr(char_u *start, char_u **end)
{
char_u *p;
int i;
int len;
for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
;
for (i = 0; event_names[i].name != NULL; ++i)
{
len = (int)STRLEN(event_names[i].name);
if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
break;
}
if (*p == ',')
++p;
*end = p;
if (event_names[i].name == NULL)
return NUM_EVENTS;
return event_names[i].event;
}
static char_u *
event_nr2name(event_T event)
{
int i;
for (i = 0; event_names[i].name != NULL; ++i)
if (event_names[i].event == event)
return (char_u *)event_names[i].name;
return (char_u *)"Unknown";
}
static char_u *
find_end_event(
char_u *arg,
int have_group) {
char_u *pat;
char_u *p;
if (*arg == '*')
{
if (arg[1] && !VIM_ISWHITE(arg[1]))
{
semsg(_("E215: Illegal character after *: %s"), arg);
return NULL;
}
pat = arg + 1;
}
else
{
for (pat = arg; *pat && *pat != '|' && !VIM_ISWHITE(*pat); pat = p)
{
if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS)
{
if (have_group)
semsg(_("E216: No such event: %s"), pat);
else
semsg(_("E216: No such group or event: %s"), pat);
return NULL;
}
}
}
return pat;
}
static int
event_ignored(event_T event)
{
char_u *p = p_ei;
while (*p != NUL)
{
if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
return TRUE;
if (event_name2nr(p, &p) == event)
return TRUE;
}
return FALSE;
}
int
check_ei(void)
{
char_u *p = p_ei;
while (*p)
{
if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
{
p += 3;
if (*p == ',')
++p;
}
else if (event_name2nr(p, &p) == NUM_EVENTS)
return FAIL;
}
return OK;
}
# if defined(FEAT_SYN_HL) || defined(PROTO)
char_u *
au_event_disable(char *what)
{
char_u *new_ei;
char_u *save_ei;
save_ei = vim_strsave(p_ei);
if (save_ei != NULL)
{
new_ei = vim_strnsave(p_ei, (int)(STRLEN(p_ei) + STRLEN(what)));
if (new_ei != NULL)
{
if (*what == ',' && *p_ei == NUL)
STRCPY(new_ei, what + 1);
else
STRCAT(new_ei, what);
set_string_option_direct((char_u *)"ei", -1, new_ei,
OPT_FREE, SID_NONE);
vim_free(new_ei);
}
}
return save_ei;
}
void
au_event_restore(char_u *old_ei)
{
if (old_ei != NULL)
{
set_string_option_direct((char_u *)"ei", -1, old_ei,
OPT_FREE, SID_NONE);
vim_free(old_ei);
}
}
# endif // FEAT_SYN_HL
void
do_autocmd(char_u *arg_in, int forceit)
{
char_u *arg = arg_in;
char_u *pat;
char_u *envpat = NULL;
char_u *cmd;
event_T event;
int need_free = FALSE;
int nested = FALSE;
int once = FALSE;
int group;
int i;
if (*arg == '|')
{
arg = (char_u *)"";
group = AUGROUP_ALL; }
else
{
group = au_get_grouparg(&arg);
if (arg == NULL) return;
}
pat = find_end_event(arg, group != AUGROUP_ALL);
if (pat == NULL)
return;
pat = skipwhite(pat);
if (*pat == '|')
{
pat = (char_u *)"";
cmd = (char_u *)"";
}
else
{
cmd = pat;
while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\'))
cmd++;
if (*cmd)
*cmd++ = NUL;
if (vim_strchr(pat, '$') != NULL || vim_strchr(pat, '~') != NULL)
{
#ifdef BACKSLASH_IN_FILENAME
int p_ssl_save = p_ssl;
p_ssl = TRUE;
#endif
envpat = expand_env_save(pat);
#ifdef BACKSLASH_IN_FILENAME
p_ssl = p_ssl_save;
#endif
if (envpat != NULL)
pat = envpat;
}
cmd = skipwhite(cmd);
for (i = 0; i < 2; i++)
{
if (*cmd != NUL)
{
if (STRNCMP(cmd, "++once", 6) == 0 && VIM_ISWHITE(cmd[6]))
{
if (once)
semsg(_(e_duparg2), "++once");
once = TRUE;
cmd = skipwhite(cmd + 6);
}
if ((STRNCMP(cmd, "++nested", 8) == 0 && VIM_ISWHITE(cmd[8])))
{
if (nested)
semsg(_(e_duparg2), "++nested");
nested = TRUE;
cmd = skipwhite(cmd + 8);
}
if (STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6]))
{
if (nested)
semsg(_(e_duparg2), "nested");
nested = TRUE;
cmd = skipwhite(cmd + 6);
}
}
}
if (*cmd != NUL)
{
cmd = expand_sfile(cmd);
if (cmd == NULL) return;
need_free = TRUE;
}
}
if (!forceit && *cmd == NUL)
msg_puts_title(_("\n--- Autocommands ---"));
last_event = (event_T)-1; last_group = AUGROUP_ERROR; if (*arg == '*' || *arg == NUL || *arg == '|')
{
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
event = (event_T)((int)event + 1))
if (do_autocmd_event(event, pat,
once, nested, cmd, forceit, group) == FAIL)
break;
}
else
{
while (*arg && *arg != '|' && !VIM_ISWHITE(*arg))
if (do_autocmd_event(event_name2nr(arg, &arg), pat,
once, nested, cmd, forceit, group) == FAIL)
break;
}
if (need_free)
vim_free(cmd);
vim_free(envpat);
}
static int
au_get_grouparg(char_u **argp)
{
char_u *group_name;
char_u *p;
char_u *arg = *argp;
int group = AUGROUP_ALL;
for (p = arg; *p && !VIM_ISWHITE(*p) && *p != '|'; ++p)
;
if (p > arg)
{
group_name = vim_strnsave(arg, (int)(p - arg));
if (group_name == NULL) return AUGROUP_ERROR;
group = au_find_group(group_name);
if (group == AUGROUP_ERROR)
group = AUGROUP_ALL; else
*argp = skipwhite(p); vim_free(group_name);
}
return group;
}
static int
do_autocmd_event(
event_T event,
char_u *pat,
int once,
int nested,
char_u *cmd,
int forceit,
int group)
{
AutoPat *ap;
AutoPat **prev_ap;
AutoCmd *ac;
AutoCmd **prev_ac;
int brace_level;
char_u *endpat;
int findgroup;
int allgroups;
int patlen;
int is_buflocal;
int buflocal_nr;
char_u buflocal_pat[25];
if (group == AUGROUP_ALL)
findgroup = current_augroup;
else
findgroup = group;
allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL);
if (*pat == NUL)
{
FOR_ALL_AUTOCMD_PATTERNS(event, ap)
{
if (forceit) {
if (ap->group == findgroup)
au_remove_pat(ap);
}
else if (group == AUGROUP_ALL || ap->group == group)
show_autocmd(ap, event);
}
}
for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat))
{
brace_level = 0;
for (endpat = pat; *endpat && (*endpat != ',' || brace_level
|| (endpat > pat && endpat[-1] == '\\')); ++endpat)
{
if (*endpat == '{')
brace_level++;
else if (*endpat == '}')
brace_level--;
}
if (pat == endpat) continue;
patlen = (int)(endpat - pat);
is_buflocal = FALSE;
buflocal_nr = 0;
if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0
&& pat[patlen - 1] == '>')
{
is_buflocal = TRUE;
if (patlen == 8)
buflocal_nr = curbuf->b_fnum;
else if (patlen > 9 && pat[7] == '=')
{
if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0)
buflocal_nr = autocmd_bufnr;
else if (skipdigits(pat + 8) == pat + patlen - 1)
buflocal_nr = atoi((char *)pat + 8);
}
}
if (is_buflocal)
{
sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr);
pat = buflocal_pat; patlen = (int)STRLEN(buflocal_pat); }
if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL)
prev_ap = &last_autopat[(int)event];
else
prev_ap = &first_autopat[(int)event];
while ((ap = *prev_ap) != NULL)
{
if (ap->pat != NULL)
{
if ((allgroups || ap->group == findgroup)
&& ap->patlen == patlen
&& STRNCMP(pat, ap->pat, patlen) == 0)
{
if (forceit)
{
if (*cmd != NUL && ap->next == NULL)
{
au_remove_cmds(ap);
break;
}
au_remove_pat(ap);
}
else if (*cmd == NUL)
show_autocmd(ap, event);
else if (ap->next == NULL)
break;
}
}
prev_ap = &ap->next;
}
if (*cmd != NUL)
{
if (ap == NULL)
{
if (is_buflocal && (buflocal_nr == 0
|| buflist_findnr(buflocal_nr) == NULL))
{
semsg(_("E680: <buffer=%d>: invalid buffer number "),
buflocal_nr);
return FAIL;
}
ap = ALLOC_ONE(AutoPat);
if (ap == NULL)
return FAIL;
ap->pat = vim_strnsave(pat, patlen);
ap->patlen = patlen;
if (ap->pat == NULL)
{
vim_free(ap);
return FAIL;
}
if (is_buflocal)
{
ap->buflocal_nr = buflocal_nr;
ap->reg_prog = NULL;
}
else
{
char_u *reg_pat;
ap->buflocal_nr = 0;
reg_pat = file_pat_to_reg_pat(pat, endpat,
&ap->allow_dirs, TRUE);
if (reg_pat != NULL)
ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
vim_free(reg_pat);
if (reg_pat == NULL || ap->reg_prog == NULL)
{
vim_free(ap->pat);
vim_free(ap);
return FAIL;
}
}
ap->cmds = NULL;
*prev_ap = ap;
last_autopat[(int)event] = ap;
ap->next = NULL;
if (group == AUGROUP_ALL)
ap->group = current_augroup;
else
ap->group = group;
}
prev_ac = &(ap->cmds);
while ((ac = *prev_ac) != NULL)
prev_ac = &ac->next;
ac = ALLOC_ONE(AutoCmd);
if (ac == NULL)
return FAIL;
ac->cmd = vim_strsave(cmd);
#ifdef FEAT_EVAL
ac->script_ctx = current_sctx;
ac->script_ctx.sc_lnum += SOURCING_LNUM;
#endif
if (ac->cmd == NULL)
{
vim_free(ac);
return FAIL;
}
ac->next = NULL;
*prev_ac = ac;
ac->once = once;
ac->nested = nested;
}
}
au_cleanup(); return OK;
}
int
do_doautocmd(
char_u *arg,
int do_msg, int *did_something)
{
char_u *fname;
int nothing_done = TRUE;
int group;
if (did_something != NULL)
*did_something = FALSE;
group = au_get_grouparg(&arg);
if (arg == NULL) return FAIL;
if (*arg == '*')
{
emsg(_("E217: Can't execute autocommands for ALL events"));
return FAIL;
}
fname = find_end_event(arg, group != AUGROUP_ALL);
if (fname == NULL)
return FAIL;
fname = skipwhite(fname);
while (*arg && !ends_excmd(*arg) && !VIM_ISWHITE(*arg))
if (apply_autocmds_group(event_name2nr(arg, &arg),
fname, NULL, TRUE, group, curbuf, NULL))
nothing_done = FALSE;
if (nothing_done && do_msg)
msg(_("No matching autocommands"));
if (did_something != NULL)
*did_something = !nothing_done;
#ifdef FEAT_EVAL
return aborting() ? FAIL : OK;
#else
return OK;
#endif
}
void
ex_doautoall(exarg_T *eap)
{
int retval;
aco_save_T aco;
buf_T *buf;
bufref_T bufref;
char_u *arg = eap->arg;
int call_do_modelines = check_nomodeline(&arg);
int did_aucmd;
FOR_ALL_BUFFERS(buf)
{
if (buf->b_ml.ml_mfp != NULL)
{
aucmd_prepbuf(&aco, buf);
set_bufref(&bufref, buf);
retval = do_doautocmd(arg, FALSE, &did_aucmd);
if (call_do_modelines && did_aucmd)
{
do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
}
aucmd_restbuf(&aco);
if (retval == FAIL || !bufref_valid(&bufref))
break;
}
}
check_cursor(); }
int
check_nomodeline(char_u **argp)
{
if (STRNCMP(*argp, "<nomodeline>", 12) == 0)
{
*argp = skipwhite(*argp + 12);
return FALSE;
}
return TRUE;
}
void
aucmd_prepbuf(
aco_save_T *aco, buf_T *buf) {
win_T *win;
int save_ea;
#ifdef FEAT_AUTOCHDIR
int save_acd;
#endif
if (buf == curbuf) win = curwin;
else
FOR_ALL_WINDOWS(win)
if (win->w_buffer == buf)
break;
if (win == NULL && aucmd_win == NULL)
{
aucmd_win = win_alloc_popup_win();
if (aucmd_win == NULL)
win = curwin;
}
if (win == NULL && aucmd_win_used)
win = curwin;
aco->save_curwin = curwin;
aco->save_curbuf = curbuf;
aco->save_prevwin = prevwin;
if (win != NULL)
{
aco->use_aucmd_win = FALSE;
curwin = win;
}
else
{
aco->use_aucmd_win = TRUE;
aucmd_win_used = TRUE;
win_init_popup_win(aucmd_win, buf);
aco->globaldir = globaldir;
globaldir = NULL;
block_autocmds();
make_snapshot(SNAP_AUCMD_IDX);
save_ea = p_ea;
p_ea = FALSE;
#ifdef FEAT_AUTOCHDIR
save_acd = p_acd;
p_acd = FALSE;
#endif
(void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
(void)win_comp_pos(); p_ea = save_ea;
#ifdef FEAT_AUTOCHDIR
p_acd = save_acd;
#endif
unblock_autocmds();
curwin = aucmd_win;
}
curbuf = buf;
aco->new_curwin = curwin;
set_bufref(&aco->new_curbuf, curbuf);
}
void
aucmd_restbuf(
aco_save_T *aco) {
int dummy;
if (aco->use_aucmd_win)
{
--curbuf->b_nwindows;
block_autocmds();
if (curwin != aucmd_win)
{
tabpage_T *tp;
win_T *wp;
FOR_ALL_TAB_WINDOWS(tp, wp)
{
if (wp == aucmd_win)
{
if (tp != curtab)
goto_tabpage_tp(tp, TRUE, TRUE);
win_goto(aucmd_win);
goto win_found;
}
}
}
win_found:
(void)winframe_remove(curwin, &dummy, NULL);
win_remove(curwin, NULL);
aucmd_win_used = FALSE;
last_status(FALSE);
if (!valid_tabpage_win(curtab))
close_tabpage(curtab);
restore_snapshot(SNAP_AUCMD_IDX, FALSE);
(void)win_comp_pos(); unblock_autocmds();
if (win_valid(aco->save_curwin))
curwin = aco->save_curwin;
else
curwin = firstwin;
if (win_valid(aco->save_prevwin))
prevwin = aco->save_prevwin;
#ifdef FEAT_EVAL
vars_clear(&aucmd_win->w_vars->dv_hashtab); hash_init(&aucmd_win->w_vars->dv_hashtab); #endif
curbuf = curwin->w_buffer;
vim_free(globaldir);
globaldir = aco->globaldir;
check_cursor();
if (curwin->w_topline > curbuf->b_ml.ml_line_count)
{
curwin->w_topline = curbuf->b_ml.ml_line_count;
#ifdef FEAT_DIFF
curwin->w_topfill = 0;
#endif
}
#if defined(FEAT_GUI)
gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
gui_may_update_scrollbars();
#endif
}
else
{
if (win_valid(aco->save_curwin))
{
if (curwin == aco->new_curwin
&& curbuf != aco->new_curbuf.br_buf
&& bufref_valid(&aco->new_curbuf)
&& aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
{
# if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
if (curwin->w_s == &curbuf->b_s)
curwin->w_s = &aco->new_curbuf.br_buf->b_s;
# endif
--curbuf->b_nwindows;
curbuf = aco->new_curbuf.br_buf;
curwin->w_buffer = curbuf;
++curbuf->b_nwindows;
}
curwin = aco->save_curwin;
curbuf = curwin->w_buffer;
if (win_valid(aco->save_prevwin))
prevwin = aco->save_prevwin;
check_cursor();
}
}
}
static int autocmd_nested = FALSE;
int
apply_autocmds(
event_T event,
char_u *fname, char_u *fname_io, int force, buf_T *buf) {
return apply_autocmds_group(event, fname, fname_io, force,
AUGROUP_ALL, buf, NULL);
}
int
apply_autocmds_exarg(
event_T event,
char_u *fname,
char_u *fname_io,
int force,
buf_T *buf,
exarg_T *eap)
{
return apply_autocmds_group(event, fname, fname_io, force,
AUGROUP_ALL, buf, eap);
}
int
apply_autocmds_retval(
event_T event,
char_u *fname, char_u *fname_io, int force, buf_T *buf, int *retval) {
int did_cmd;
#ifdef FEAT_EVAL
if (should_abort(*retval))
return FALSE;
#endif
did_cmd = apply_autocmds_group(event, fname, fname_io, force,
AUGROUP_ALL, buf, NULL);
if (did_cmd
#ifdef FEAT_EVAL
&& aborting()
#endif
)
*retval = FAIL;
return did_cmd;
}
static int
has_cursorhold(void)
{
return (first_autopat[(int)(get_real_state() == NORMAL_BUSY
? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL);
}
int
trigger_cursorhold(void)
{
int state;
if (!did_cursorhold
&& has_cursorhold()
&& reg_recording == 0
&& typebuf.tb_len == 0
&& !ins_compl_active())
{
state = get_real_state();
if (state == NORMAL_BUSY || (state & INSERT) != 0)
return TRUE;
}
return FALSE;
}
int
has_cursormoved(void)
{
return (first_autopat[(int)EVENT_CURSORMOVED] != NULL);
}
int
has_cursormovedI(void)
{
return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL);
}
int
has_textchanged(void)
{
return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL);
}
int
has_textchangedI(void)
{
return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
}
int
has_textchangedP(void)
{
return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
}
int
has_insertcharpre(void)
{
return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL);
}
int
has_cmdundefined(void)
{
return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL);
}
int
has_funcundefined(void)
{
return (first_autopat[(int)EVENT_FUNCUNDEFINED] != NULL);
}
#if defined(FEAT_EVAL) || defined(PROTO)
int
has_textyankpost(void)
{
return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL);
}
#endif
#if defined(FEAT_EVAL) || defined(PROTO)
int
has_completechanged(void)
{
return (first_autopat[(int)EVENT_COMPLETECHANGED] != NULL);
}
#endif
static int
apply_autocmds_group(
event_T event,
char_u *fname, char_u *fname_io, int force, int group, buf_T *buf, exarg_T *eap UNUSED) {
char_u *sfname = NULL; char_u *tail;
int save_changed;
buf_T *old_curbuf;
int retval = FALSE;
char_u *save_autocmd_fname;
int save_autocmd_fname_full;
int save_autocmd_bufnr;
char_u *save_autocmd_match;
int save_autocmd_busy;
int save_autocmd_nested;
static int nesting = 0;
AutoPatCmd patcmd;
AutoPat *ap;
#ifdef FEAT_EVAL
sctx_T save_current_sctx;
funccal_entry_T funccal_entry;
char_u *save_cmdarg;
long save_cmdbang;
#endif
static int filechangeshell_busy = FALSE;
#ifdef FEAT_PROFILE
proftime_T wait_time;
#endif
int did_save_redobuff = FALSE;
save_redo_T save_redo;
int save_KeyTyped = KeyTyped;
ESTACK_CHECK_DECLARATION
if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
|| autocmd_blocked > 0)
goto BYPASS_AU;
if (autocmd_busy && !(force || autocmd_nested))
goto BYPASS_AU;
#ifdef FEAT_EVAL
if (aborting())
goto BYPASS_AU;
#endif
if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL
|| event == EVENT_FILECHANGEDSHELLPOST))
goto BYPASS_AU;
if (event_ignored(event))
goto BYPASS_AU;
if (nesting == 10)
{
emsg(_("E218: autocommand nesting too deep"));
goto BYPASS_AU;
}
if ( (autocmd_no_enter
&& (event == EVENT_WINENTER || event == EVENT_BUFENTER))
|| (autocmd_no_leave
&& (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE)))
goto BYPASS_AU;
save_autocmd_fname = autocmd_fname;
save_autocmd_fname_full = autocmd_fname_full;
save_autocmd_bufnr = autocmd_bufnr;
save_autocmd_match = autocmd_match;
save_autocmd_busy = autocmd_busy;
save_autocmd_nested = autocmd_nested;
save_changed = curbuf->b_changed;
old_curbuf = curbuf;
if (fname_io == NULL)
{
if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
|| event == EVENT_OPTIONSET)
autocmd_fname = NULL;
else if (fname != NULL && !ends_excmd(*fname))
autocmd_fname = fname;
else if (buf != NULL)
autocmd_fname = buf->b_ffname;
else
autocmd_fname = NULL;
}
else
autocmd_fname = fname_io;
if (autocmd_fname != NULL)
autocmd_fname = vim_strsave(autocmd_fname);
autocmd_fname_full = FALSE;
if (buf == NULL)
autocmd_bufnr = 0;
else
autocmd_bufnr = buf->b_fnum;
if (fname == NULL || *fname == NUL)
{
if (buf == NULL)
fname = NULL;
else
{
#ifdef FEAT_SYN_HL
if (event == EVENT_SYNTAX)
fname = buf->b_p_syn;
else
#endif
if (event == EVENT_FILETYPE)
fname = buf->b_p_ft;
else
{
if (buf->b_sfname != NULL)
sfname = vim_strsave(buf->b_sfname);
fname = buf->b_ffname;
}
}
if (fname == NULL)
fname = (char_u *)"";
fname = vim_strsave(fname); }
else
{
sfname = vim_strsave(fname);
if (event == EVENT_FILETYPE
|| event == EVENT_SYNTAX
|| event == EVENT_CMDLINECHANGED
|| event == EVENT_CMDLINEENTER
|| event == EVENT_CMDLINELEAVE
|| event == EVENT_CMDWINENTER
|| event == EVENT_CMDWINLEAVE
|| event == EVENT_CMDUNDEFINED
|| event == EVENT_FUNCUNDEFINED
|| event == EVENT_REMOTEREPLY
|| event == EVENT_SPELLFILEMISSING
|| event == EVENT_QUICKFIXCMDPRE
|| event == EVENT_COLORSCHEME
|| event == EVENT_COLORSCHEMEPRE
|| event == EVENT_OPTIONSET
|| event == EVENT_QUICKFIXCMDPOST
|| event == EVENT_DIRCHANGED)
{
fname = vim_strsave(fname);
autocmd_fname_full = TRUE; }
else
fname = FullName_save(fname, FALSE);
}
if (fname == NULL) {
vim_free(sfname);
retval = FALSE;
goto BYPASS_AU;
}
#ifdef BACKSLASH_IN_FILENAME
if (sfname != NULL)
forward_slash(sfname);
forward_slash(fname);
#endif
#ifdef VMS
if (sfname != NULL)
vms_remove_version(sfname);
vms_remove_version(fname);
#endif
autocmd_match = fname;
++RedrawingDisabled;
estack_push(ETYPE_AUCMD, NULL, 0);
ESTACK_CHECK_SETUP
#ifdef FEAT_EVAL
save_current_sctx = current_sctx;
# ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
prof_child_enter(&wait_time); # endif
save_funccal(&funccal_entry);
#endif
if (!autocmd_busy)
{
save_search_patterns();
if (!ins_compl_active())
{
saveRedobuff(&save_redo);
did_save_redobuff = TRUE;
}
did_filetype = keep_filetype;
}
autocmd_busy = TRUE;
filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL);
++nesting;
if (event == EVENT_FILETYPE)
did_filetype = TRUE;
tail = gettail(fname);
patcmd.curpat = first_autopat[(int)event];
patcmd.nextcmd = NULL;
patcmd.group = group;
patcmd.fname = fname;
patcmd.sfname = sfname;
patcmd.tail = tail;
patcmd.event = event;
patcmd.arg_bufnr = autocmd_bufnr;
patcmd.next = NULL;
auto_next_pat(&patcmd, FALSE);
if (patcmd.curpat != NULL)
{
patcmd.next = active_apc_list;
active_apc_list = &patcmd;
#ifdef FEAT_EVAL
save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
if (eap != NULL)
{
save_cmdarg = set_cmdarg(eap, NULL);
set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
}
else
save_cmdarg = NULL; #endif
retval = TRUE;
for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
ap->last = FALSE;
ap->last = TRUE;
check_lnums(TRUE);
do_cmdline(NULL, getnextac, (void *)&patcmd,
DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
reset_lnums();
#ifdef FEAT_EVAL
if (eap != NULL)
{
(void)set_cmdarg(NULL, save_cmdarg);
set_vim_var_nr(VV_CMDBANG, save_cmdbang);
}
#endif
if (active_apc_list == &patcmd) active_apc_list = patcmd.next;
}
--RedrawingDisabled;
autocmd_busy = save_autocmd_busy;
filechangeshell_busy = FALSE;
autocmd_nested = save_autocmd_nested;
vim_free(SOURCING_NAME);
ESTACK_CHECK_NOW
estack_pop();
vim_free(autocmd_fname);
autocmd_fname = save_autocmd_fname;
autocmd_fname_full = save_autocmd_fname_full;
autocmd_bufnr = save_autocmd_bufnr;
autocmd_match = save_autocmd_match;
#ifdef FEAT_EVAL
current_sctx = save_current_sctx;
restore_funccal();
# ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
prof_child_exit(&wait_time);
# endif
#endif
KeyTyped = save_KeyTyped;
vim_free(fname);
vim_free(sfname);
--nesting;
if (!autocmd_busy)
{
restore_search_patterns();
if (did_save_redobuff)
restoreRedobuff(&save_redo);
did_filetype = FALSE;
while (au_pending_free_buf != NULL)
{
buf_T *b = au_pending_free_buf->b_next;
vim_free(au_pending_free_buf);
au_pending_free_buf = b;
}
while (au_pending_free_win != NULL)
{
win_T *w = au_pending_free_win->w_next;
vim_free(au_pending_free_win);
au_pending_free_win = w;
}
}
if (curbuf == old_curbuf
&& (event == EVENT_BUFREADPOST
|| event == EVENT_BUFWRITEPOST
|| event == EVENT_FILEAPPENDPOST
|| event == EVENT_VIMLEAVE
|| event == EVENT_VIMLEAVEPRE))
{
#ifdef FEAT_TITLE
if (curbuf->b_changed != save_changed)
need_maketitle = TRUE;
#endif
curbuf->b_changed = save_changed;
}
au_cleanup();
BYPASS_AU:
if (event == EVENT_BUFWIPEOUT && buf != NULL)
aubuflocal_remove(buf);
if (retval == OK && event == EVENT_FILETYPE)
au_did_filetype = TRUE;
return retval;
}
# ifdef FEAT_EVAL
static char_u *old_termresponse = NULL;
# endif
void
block_autocmds(void)
{
# ifdef FEAT_EVAL
if (autocmd_blocked == 0)
old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
# endif
++autocmd_blocked;
}
void
unblock_autocmds(void)
{
--autocmd_blocked;
# ifdef FEAT_EVAL
if (autocmd_blocked == 0
&& get_vim_var_str(VV_TERMRESPONSE) != old_termresponse)
apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
# endif
}
int
is_autocmd_blocked(void)
{
return autocmd_blocked != 0;
}
static void
auto_next_pat(
AutoPatCmd *apc,
int stop_at_last) {
AutoPat *ap;
AutoCmd *cp;
char_u *name;
char *s;
char_u **sourcing_namep = &SOURCING_NAME;
VIM_CLEAR(*sourcing_namep);
for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
{
apc->curpat = NULL;
if (ap->pat != NULL && ap->cmds != NULL
&& (apc->group == AUGROUP_ALL || apc->group == ap->group))
{
if (ap->buflocal_nr == 0
? (match_file_pat(NULL, &ap->reg_prog, apc->fname,
apc->sfname, apc->tail, ap->allow_dirs))
: ap->buflocal_nr == apc->arg_bufnr)
{
name = event_nr2name(apc->event);
s = _("%s Autocommands for \"%s\"");
*sourcing_namep = alloc(STRLEN(s)
+ STRLEN(name) + ap->patlen + 1);
if (*sourcing_namep != NULL)
{
sprintf((char *)*sourcing_namep, s,
(char *)name, (char *)ap->pat);
if (p_verbose >= 8)
{
verbose_enter();
smsg(_("Executing %s"), *sourcing_namep);
verbose_leave();
}
}
apc->curpat = ap;
apc->nextcmd = ap->cmds;
for (cp = ap->cmds; cp->next != NULL; cp = cp->next)
cp->last = FALSE;
cp->last = TRUE;
}
line_breakcheck();
if (apc->curpat != NULL) break;
}
if (stop_at_last && ap->last)
break;
}
}
char_u *
getnextac(int c UNUSED, void *cookie, int indent UNUSED, int do_concat UNUSED)
{
AutoPatCmd *acp = (AutoPatCmd *)cookie;
char_u *retval;
AutoCmd *ac;
if (acp->curpat == NULL)
return NULL;
for (;;)
{
while (acp->nextcmd != NULL && acp->nextcmd->cmd == NULL)
if (acp->nextcmd->last)
acp->nextcmd = NULL;
else
acp->nextcmd = acp->nextcmd->next;
if (acp->nextcmd != NULL)
break;
if (acp->curpat->last)
acp->curpat = NULL;
else
acp->curpat = acp->curpat->next;
if (acp->curpat != NULL)
auto_next_pat(acp, TRUE);
if (acp->curpat == NULL)
return NULL;
}
ac = acp->nextcmd;
if (p_verbose >= 9)
{
verbose_enter_scroll();
smsg(_("autocommand %s"), ac->cmd);
msg_puts("\n"); verbose_leave_scroll();
}
retval = vim_strsave(ac->cmd);
if (ac->once)
au_del_cmd(ac);
autocmd_nested = ac->nested;
#ifdef FEAT_EVAL
current_sctx = ac->script_ctx;
#endif
if (ac->last)
acp->nextcmd = NULL;
else
acp->nextcmd = ac->next;
return retval;
}
int
has_autocmd(event_T event, char_u *sfname, buf_T *buf)
{
AutoPat *ap;
char_u *fname;
char_u *tail = gettail(sfname);
int retval = FALSE;
fname = FullName_save(sfname, FALSE);
if (fname == NULL)
return FALSE;
#ifdef BACKSLASH_IN_FILENAME
sfname = vim_strsave(sfname);
if (sfname != NULL)
forward_slash(sfname);
forward_slash(fname);
#endif
FOR_ALL_AUTOCMD_PATTERNS(event, ap)
if (ap->pat != NULL && ap->cmds != NULL
&& (ap->buflocal_nr == 0
? match_file_pat(NULL, &ap->reg_prog,
fname, sfname, tail, ap->allow_dirs)
: buf != NULL && ap->buflocal_nr == buf->b_fnum
))
{
retval = TRUE;
break;
}
vim_free(fname);
#ifdef BACKSLASH_IN_FILENAME
vim_free(sfname);
#endif
return retval;
}
char_u *
get_augroup_name(expand_T *xp UNUSED, int idx)
{
if (idx == augroups.ga_len) return (char_u *)"END";
if (idx >= augroups.ga_len) return NULL;
if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup())
return (char_u *)"";
return AUGROUP_NAME(idx); }
static int include_groups = FALSE;
char_u *
set_context_in_autocmd(
expand_T *xp,
char_u *arg,
int doautocmd) {
char_u *p;
int group;
include_groups = FALSE;
p = arg;
group = au_get_grouparg(&arg);
if (group == AUGROUP_ERROR)
return NULL;
if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1]))
{
arg = p;
group = AUGROUP_ALL;
}
for (p = arg; *p != NUL && !VIM_ISWHITE(*p); ++p)
if (*p == ',')
arg = p + 1;
if (*p == NUL)
{
if (group == AUGROUP_ALL)
include_groups = TRUE;
xp->xp_context = EXPAND_EVENTS; xp->xp_pattern = arg;
return NULL;
}
arg = skipwhite(p);
while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\'))
arg++;
if (*arg)
return arg;
if (doautocmd)
xp->xp_context = EXPAND_FILES; else
xp->xp_context = EXPAND_NOTHING; return NULL;
}
char_u *
get_event_name(expand_T *xp UNUSED, int idx)
{
if (idx < augroups.ga_len) {
if (!include_groups || AUGROUP_NAME(idx) == NULL
|| AUGROUP_NAME(idx) == get_deleted_augroup())
return (char_u *)""; return AUGROUP_NAME(idx); }
return (char_u *)event_names[idx - augroups.ga_len].name;
}
#if defined(FEAT_EVAL) || defined(PROTO)
int
autocmd_supported(char_u *name)
{
char_u *p;
return (event_name2nr(name, &p) != NUM_EVENTS);
}
int
au_exists(char_u *arg)
{
char_u *arg_save;
char_u *pattern = NULL;
char_u *event_name;
char_u *p;
event_T event;
AutoPat *ap;
buf_T *buflocal_buf = NULL;
int group;
int retval = FALSE;
arg_save = vim_strsave(arg);
if (arg_save == NULL)
return FALSE;
p = vim_strchr(arg_save, '#');
if (p != NULL)
*p++ = NUL;
group = au_find_group(arg_save);
if (group == AUGROUP_ERROR)
{
group = AUGROUP_ALL;
event_name = arg_save;
}
else
{
if (p == NULL)
{
retval = TRUE;
goto theend;
}
event_name = p;
p = vim_strchr(event_name, '#');
if (p != NULL)
*p++ = NUL; }
pattern = p;
event = event_name2nr(event_name, &p);
if (event == NUM_EVENTS)
goto theend;
ap = first_autopat[(int)event];
if (ap == NULL)
goto theend;
if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0)
buflocal_buf = curbuf;
for ( ; ap != NULL; ap = ap->next)
if (ap->pat != NULL && ap->cmds != NULL
&& (group == AUGROUP_ALL || ap->group == group)
&& (pattern == NULL
|| (buflocal_buf == NULL
? fnamecmp(ap->pat, pattern) == 0
: ap->buflocal_nr == buflocal_buf->b_fnum)))
{
retval = TRUE;
break;
}
theend:
vim_free(arg_save);
return retval;
}
#endif