diff options
-rw-r--r-- | Filelist | 2 | ||||
-rw-r--r-- | src/Make_bc5.mak | 1 | ||||
-rw-r--r-- | src/Make_cyg_ming.mak | 1 | ||||
-rw-r--r-- | src/Make_dice.mak | 4 | ||||
-rw-r--r-- | src/Make_ivc.mak | 5 | ||||
-rw-r--r-- | src/Make_manx.mak | 6 | ||||
-rw-r--r-- | src/Make_morph.mak | 1 | ||||
-rw-r--r-- | src/Make_mvc.mak | 4 | ||||
-rw-r--r-- | src/Make_sas.mak | 5 | ||||
-rw-r--r-- | src/Make_vms.mms | 5 | ||||
-rw-r--r-- | src/Makefile | 10 | ||||
-rw-r--r-- | src/README.txt | 1 | ||||
-rw-r--r-- | src/autocmd.c | 2579 | ||||
-rw-r--r-- | src/fileio.c | 2588 | ||||
-rw-r--r-- | src/globals.h | 1 | ||||
-rw-r--r-- | src/proto.h | 1 | ||||
-rw-r--r-- | src/proto/autocmd.pro | 39 | ||||
-rw-r--r-- | src/proto/fileio.pro | 37 | ||||
-rw-r--r-- | src/version.c | 2 |
19 files changed, 2672 insertions, 2620 deletions
@@ -14,6 +14,7 @@ SRC_ALL = \ src/arabic.c \ src/arabic.h \ src/ascii.h \ + src/autocmd.c \ src/beval.c \ src/beval.h \ src/blob.c \ @@ -146,6 +147,7 @@ SRC_ALL = \ src/proto.h \ src/protodef.h \ src/proto/arabic.pro \ + src/proto/autocmd.pro \ src/proto/beval.pro \ src/proto/blob.pro \ src/proto/blowfish.pro \ diff --git a/src/Make_bc5.mak b/src/Make_bc5.mak index 9760d8f7b2..d0d31d4eb9 100644 --- a/src/Make_bc5.mak +++ b/src/Make_bc5.mak @@ -525,6 +525,7 @@ vimwinmain = \ vimobj = \ $(OBJDIR)\arabic.obj \ + $(OBJDIR)\autocmd.obj \ $(OBJDIR)\blowfish.obj \ $(OBJDIR)\buffer.obj \ $(OBJDIR)\charset.obj \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 7aef61ac33..8d8666ffbe 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -695,6 +695,7 @@ GUIOBJ = $(OUTDIR)/gui.o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_beval.o $(OUTDIR)/os CUIOBJ = $(OUTDIR)/iscygpty.o OBJ = \ $(OUTDIR)/arabic.o \ + $(OUTDIR)/autocmd.o \ $(OUTDIR)/beval.o \ $(OUTDIR)/blob.o \ $(OUTDIR)/blowfish.o \ diff --git a/src/Make_dice.mak b/src/Make_dice.mak index 2daa8d72bf..83614ca911 100644 --- a/src/Make_dice.mak +++ b/src/Make_dice.mak @@ -27,6 +27,7 @@ LD = dcc SRC = \ arabic.c \ + autocmd.c \ blowfish.c \ buffer.c \ charset.c \ @@ -84,6 +85,7 @@ SRC = \ version.c OBJ = o/arabic.o \ + o/autocmd.o \ o/blowfish.o \ o/buffer.o \ o/charset.o \ @@ -161,6 +163,8 @@ $(SYMS) : vim.h globals.h keymap.h macros.h ascii.h term.h os_amiga.h structs.h o/arabic.o: arabic.c $(SYMS) +o/autocmd.o: autocmd.c $(SYMS) + o/blowfish.o: blowfish.c $(SYMS) o/buffer.o: buffer.c $(SYMS) diff --git a/src/Make_ivc.mak b/src/Make_ivc.mak index 784cab9312..0459984dab 100644 --- a/src/Make_ivc.mak +++ b/src/Make_ivc.mak @@ -211,6 +211,7 @@ ALL : .\$(VIM).exe vimrun.exe install.exe uninstal.exe xxd/xxd.exe GvimExt/gvime LINK32_OBJS= \ $(EXTRAS) \ "$(INTDIR)/arabic.obj" \ + "$(INTDIR)/autocmd.obj" \ "$(INTDIR)/blowfish.obj" \ "$(INTDIR)/buffer.obj" \ "$(INTDIR)/charset.obj" \ @@ -341,6 +342,10 @@ GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h SOURCE=.\arabic.c # End Source File # Begin Source File +# +SOURCE=.\autocmd.c +# End Source File +# Begin Source File SOURCE=.\blowfish.c # End Source File diff --git a/src/Make_manx.mak b/src/Make_manx.mak index 04560d4034..b71b923ded 100644 --- a/src/Make_manx.mak +++ b/src/Make_manx.mak @@ -37,6 +37,7 @@ REN = $(SHELL) -c mv -f DEL = $(SHELL) -c rm -f SRC = arabic.c \ + autocmd.c \ blowfish.c \ buffer.c \ charset.c \ @@ -96,6 +97,7 @@ SRC = arabic.c \ INCL = vim.h feature.h keymap.h macros.h ascii.h term.h structs.h os_amiga.h OBJ = obj/arabic.o \ + obj/autocmd.o \ obj/blowfish.o \ obj/buffer.o \ obj/charset.o \ @@ -153,6 +155,7 @@ OBJ = obj/arabic.o \ $(TERMLIB) PRO = proto/arabic.pro \ + proto/autocmd.pro \ proto/blowfish.pro \ proto/buffer.pro \ proto/charset.pro \ @@ -256,6 +259,9 @@ $(OBJ): $(SYMS) obj/arabic.o: arabic.c $(CCSYM) $@ arabic.c +obj/autocmd.o: autocmd.c + $(CCSYM) $@ autocmd.c + obj/blowfish.o: blowfish.c $(CCSYM) $@ blowfish.c diff --git a/src/Make_morph.mak b/src/Make_morph.mak index 70ab5377a3..ae490416f4 100644 --- a/src/Make_morph.mak +++ b/src/Make_morph.mak @@ -25,6 +25,7 @@ RM = rm ${CC} ${CFLAGS} $< -o $@ SRC = arabic.c \ + autocmd.c \ blowfish.c \ buffer.c \ charset.c \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index a3c66819a5..3f8c8a0384 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -700,6 +700,7 @@ INCL = vim.h alloc.h arabic.h ascii.h ex_cmds.h farsi.h feature.h globals.h \ OBJ = \ $(OUTDIR)\arabic.obj \ + $(OUTDIR)\autocmd.obj \ $(OUTDIR)\beval.obj \ $(OUTDIR)\blob.obj \ $(OUTDIR)\blowfish.obj \ @@ -1345,6 +1346,8 @@ $(NEW_TESTS): $(OUTDIR)/arabic.obj: $(OUTDIR) arabic.c $(INCL) +$(OUTDIR)/autocmd.obj: $(OUTDIR) autocmd.c $(INCL) + $(OUTDIR)/beval.obj: $(OUTDIR) beval.c $(INCL) $(OUTDIR)/blob.obj: $(OUTDIR) blob.c $(INCL) @@ -1619,6 +1622,7 @@ auto: # End Custom Build proto.h: \ proto/arabic.pro \ + proto/autocmd.pro \ proto/blob.pro \ proto/blowfish.pro \ proto/buffer.pro \ diff --git a/src/Make_sas.mak b/src/Make_sas.mak index a16908e9c1..c621360eab 100644 --- a/src/Make_sas.mak +++ b/src/Make_sas.mak @@ -90,6 +90,7 @@ PROPT = DEF=PROTO GPROTO GPPARM MAXIMUMERRORS=999 GENPROTOSTATICS GENPROTOPARAME SRC = \ arabic.c \ + autocmd.c \ blowfish.c \ buffer.c \ charset.c \ @@ -148,6 +149,7 @@ SRC = \ OBJ = \ arabic.o \ + autocmd.o \ blowfish.o \ buffer.o \ charset.o \ @@ -206,6 +208,7 @@ OBJ = \ PRO = \ proto/arabic.pro \ + proto/autocmd.pro \ proto/blowfish.pro \ proto/buffer.pro \ proto/charset.pro \ @@ -319,6 +322,8 @@ $(PRO): $(GST) vim.h # dependencies arabic.o: arabic.c proto/arabic.pro: arabic.c +autocmd.o: autocmd.c +proto/autocmd.pro: autocmd.c blowfish.o: blowfish.c proto/blowfish.pro: blowfish.c buffer.o: buffer.c diff --git a/src/Make_vms.mms b/src/Make_vms.mms index 18c68142d8..6a3508980f 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -312,7 +312,7 @@ ALL_CFLAGS_VER = /def=($(MODEL_DEF)$(DEFS)$(DEBUG_DEF)$(PERL_DEF)$(PYTHON_DEF) - ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \ $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB) -SRC = arabic.c beval.obj blob.c blowfish.c buffer.c charset.c crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c \ +SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c charset.c crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c \ evalfunc.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c if_cscope.c if_xcmdsrv.c farsi.c fileio.c fold.c \ getchar.c hardcopy.c hashtab.c json.c list.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \ misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c sign.c \ @@ -321,7 +321,7 @@ SRC = arabic.c beval.obj blob.c blowfish.c buffer.c charset.c crypt.c crypt_zip. $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \ $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC) -OBJ = arabic.obj beval.obj blob.obj blowfish.obj buffer.obj charset.obj crypt.obj crypt_zip.obj dict.obj diff.obj digraph.obj \ +OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj charset.obj crypt.obj crypt_zip.obj dict.obj diff.obj digraph.obj \ edit.obj eval.obj evalfunc.obj ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj \ if_xcmdsrv.obj farsi.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj json.obj list.obj main.obj mark.obj \ menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \ @@ -500,6 +500,7 @@ ruby_env : .ENDIF arabic.obj : arabic.c vim.h +autocmd.obj : autocmd.c vim.h [.auto]config.h feature.h os_unix.h blowfish.obj : blowfish.c vim.h [.auto]config.h feature.h os_unix.h blob.obj : blob.c vim.h [.auto]config.h feature.h os_unix.h buffer.obj : buffer.c vim.h [.auto]config.h feature.h os_unix.h \ diff --git a/src/Makefile b/src/Makefile index 23f01c38bc..2c409f0a62 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1572,6 +1572,7 @@ include testdir/Make_all.mak BASIC_SRC = \ arabic.c \ + autocmd.c \ beval.c \ blob.c \ blowfish.c \ @@ -1684,6 +1685,7 @@ LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) \ OBJ_COMMON = \ objects/arabic.o \ + objects/autocmd.o \ objects/beval.o \ objects/buffer.o \ objects/blob.o \ @@ -1809,6 +1811,7 @@ ALL_OBJ = $(OBJ_COMMON) \ PRO_AUTO = \ arabic.pro \ + autocmd.pro \ blowfish.pro \ buffer.pro \ charset.pro \ @@ -2934,6 +2937,9 @@ $(ALL_OBJ): objects/.dirstamp objects/arabic.o: arabic.c $(CCC) -o $@ arabic.c +objects/autocmd.o: autocmd.c + $(CCC) -o $@ autocmd.c + objects/blob.o: blob.c $(CCC) -o $@ blob.c @@ -3376,6 +3382,10 @@ objects/arabic.o: arabic.c vim.h protodef.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ proto.h globals.h farsi.h arabic.h +objects/autocmd.o: autocmd.c vim.h protodef.h auto/config.h feature.h \ + os_unix.h os_mac.h ascii.h keymap.h term.h macros.h option.h beval.h \ + structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h proto.h globals.h \ + farsi.h arabic.h objects/beval.o: beval.c vim.h protodef.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ diff --git a/src/README.txt b/src/README.txt index 6e7094cec0..e1dc36f69c 100644 --- a/src/README.txt +++ b/src/README.txt @@ -17,6 +17,7 @@ use the CTRL-] command. Use CTRL-T or CTRL-O to jump back. To jump to a file, move the cursor on its name and use the "gf" command. Most code can be found in a file with an obvious name (incomplete list): + autocmd.c autocommands buffer.c manipulating buffers (loaded files) diff.c diff mode (vimdiff) eval.c expression evaluation diff --git a/src/autocmd.c b/src/autocmd.c new file mode 100644 index 0000000000..55650b46f7 --- /dev/null +++ b/src/autocmd.c @@ -0,0 +1,2579 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * autocmd.c: Autocommand related functions + */ + +#include "vim.h" + +/* + * The autocommands are stored in a list for each event. + * Autocommands for the same pattern, that are consecutive, are joined + * together, to avoid having to match the pattern too often. + * The result is an array of Autopat lists, which point to AutoCmd lists: + * + * last_autopat[0] -----------------------------+ + * V + * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL + * Autopat.cmds Autopat.cmds + * | | + * V V + * AutoCmd.next AutoCmd.next + * | | + * V V + * AutoCmd.next NULL + * | + * V + * NULL + * + * last_autopat[1] --------+ + * V + * first_autopat[1] --> Autopat.next --> NULL + * Autopat.cmds + * | + * V + * AutoCmd.next + * | + * V + * NULL + * etc. + * + * The order of AutoCmds is important, this is the order in which they were + * 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 nested; // If autocommands nest here. + char last; // last command in list +#ifdef FEAT_EVAL + sctx_T script_ctx; // script context where defined +#endif + struct AutoCmd *next; // next AutoCmd in list +} AutoCmd; + +typedef struct AutoPat +{ + struct AutoPat *next; // Next AutoPat in AutoPat list; MUST + // be the first entry. + char_u *pat; // pattern as typed (NULL when pattern + // has been removed) + regprog_T *reg_prog; // compiled regprog for pattern + AutoCmd *cmds; // list of commands to do + int group; // group ID + int patlen; // strlen() of pat + int buflocal_nr; // !=0 for buffer-local AutoPat + char allow_dirs; // Pattern may match whole path + char last; // last pattern for apply_autocmds() +} AutoPat; + +static struct event_name +{ + char *name; // event name + event_T event; // event number +} 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}, + {"CompleteDone", EVENT_COMPLETEDONE}, + {"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}, + {"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}, + {"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 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 +} AutoPatCmd; + +static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */ + +/* + * augroups stores a list of autocmd group names. + */ +static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL}; +#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i]) +/* use get_deleted_augroup() to get this */ +static char_u *deleted_augroup = NULL; + +/* + * Set by the apply_autocmds_group function if the given event is equal to + * EVENT_FILETYPE. Used by the readfile function in order to determine if + * EVENT_BUFREADPOST triggered the EVENT_FILETYPE. + * + * Relying on this value requires one to reset it prior calling + * apply_autocmds_group. + */ +int au_did_filetype INIT(= FALSE); + +/* + * The ID of the current group. Group 0 is the default one. + */ +static int current_augroup = AUGROUP_DEFAULT; + +static int au_need_clean = FALSE; /* need to delete marked patterns */ + +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 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; /* block all autocmds */ + + static char_u * +get_deleted_augroup(void) +{ + if (deleted_augroup == NULL) + deleted_augroup = (char_u *)_("--Deleted--"); + return deleted_augroup; +} + +/* + * Show the autocommands for one AutoPat. + */ + static void +show_autocmd(AutoPat *ap, event_T event) +{ + AutoCmd *ac; + + // Check for "got_int" (here and at various places below), which is set + // when "q" has been hit for the "--more--" prompt + if (got_int) + return; + if (ap->pat == NULL) // pattern has been removed + 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) // skip removed commands + { + 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; + } + } + } +} + +/* + * Mark an autocommand pattern for deletion. + */ + static void +au_remove_pat(AutoPat *ap) +{ + VIM_CLEAR(ap->pat); + ap->buflocal_nr = -1; + au_need_clean = TRUE; +} + +/* + * 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) + VIM_CLEAR(ac->cmd); + au_need_clean = TRUE; +} + +/* + * Cleanup autocommands and patterns that have been deleted. + * This is only done when not executing autocommands. + */ + static void +au_cleanup(void) +{ + AutoPat *ap, **prev_ap; + AutoCmd *ac, **prev_ac; + event_T event; + + if (autocmd_busy || !au_need_clean) + return; + + // loop over all events + for (event = (event_T)0; (int)event < (int)NUM_EVENTS; + event = (event_T)((int)event + 1)) + { + // loop over all autocommand patterns + prev_ap = &(first_autopat[(int)event]); + for (ap = *prev_ap; ap != NULL; ap = *prev_ap) + { + // loop over all commands for this pattern + prev_ac = &(ap->cmds); + for (ac = *prev_ac; ac != NULL; ac = *prev_ac) + { + // remove the command if the pattern is to be deleted or when + // the command has been marked for deletion + if (ap->pat == NULL || ac->cmd == NULL) + { + *prev_ac = ac->next; + vim_free(ac->cmd); + vim_free(ac); + } + else + prev_ac = &(ac->next); + } + + // remove the pattern if it has been marked for deletion + if (ap->pat == NULL) + { + if (ap->next == NULL) + { + if (prev_ap == &(first_autopat[(int)event])) + last_autopat[(int)event] = NULL; + else + // this depends on the "next" field being the first in + // the struct + 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; +} + +/* + * Called when buffer is freed, to remove/invalidate related buffer-local + * autocmds. + */ + void +aubuflocal_remove(buf_T *buf) +{ + AutoPat *ap; + event_T event; + AutoPatCmd *apc; + + // invalidate currently executing autocommands + for (apc = active_apc_list; apc; apc = apc->next) + if (buf->b_fnum == apc->arg_bufnr) + apc->arg_bufnr = 0; + + // invalidate buflocals looping through events + for (event = (event_T)0; (int)event < (int)NUM_EVENTS; + event = (event_T)((int)event + 1)) + // loop over all autocommand patterns + for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) + 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(); +} + +/* + * Add an autocmd group name. + * Return its ID. Returns AUGROUP_ERROR (< 0) for error. + */ + static int +au_new_group(char_u *name) +{ + int i; + + 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) + 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) // the group doesn't exist + 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 (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) + 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; + } +} + +/* + * Find the ID of an autocmd group name. + * Return its ID. Returns AUGROUP_ERROR (< 0) for error. + */ + 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; +} + +/* + * Return TRUE if augroup "name" exists. + */ + int +au_has_group(char_u *name) +{ + return au_find_group(name) != AUGROUP_ERROR; +} + +/* + * ":augroup {name}". + */ + 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) // ":aug end": back to group 0 + current_augroup = AUGROUP_DEFAULT; + else if (*arg) // ":aug xxx": switch to group xxx + { + i = au_new_group(arg); + if (i != AUGROUP_ERROR) + current_augroup = i; + } + else // ":aug": list the group names + { + 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 + +/* + * Return the event number for event name "start". + * Return NUM_EVENTS if the event name was not found. + * Return a pointer to the next event name in "end". + */ + static event_T +event_name2nr(char_u *start, char_u **end) +{ + char_u *p; + int i; + int len; + + // the event name ends with end of line, '|', a blank or a comma + 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; +} + +/* + * Return the name for event "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"; +} + +/* + * Scan over the events. "*" stands for all events. + */ + static char_u * +find_end_event( + char_u *arg, + int have_group) // TRUE when group name was found +{ + 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 ((i |