diff options
Diffstat (limited to 'data/vim/patches/8.1.0825')
-rw-r--r-- | data/vim/patches/8.1.0825 | 5747 |
1 files changed, 5747 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.0825 b/data/vim/patches/8.1.0825 new file mode 100644 index 000000000..d3b00eb4e --- /dev/null +++ b/data/vim/patches/8.1.0825 @@ -0,0 +1,5747 @@ +To: vim_dev@googlegroups.com +Subject: Patch 8.1.0825 +Fcc: outbox +From: Bram Moolenaar <Bram@moolenaar.net> +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 8.1.0825 +Problem: Code for autocommands is mixed with file I/O code. +Solution: Move autocommand code to a separate file. (Yegappan Lakshmanan, + closes #3863) +Files: Filelist, src/Make_bc5.mak, src/Make_cyg_ming.mak, + src/Make_dice.mak, src/Make_ivc.mak, src/Make_manx.mak, + src/Make_morph.mak, src/Make_mvc.mak, src/Make_sas.mak, + src/Make_vms.mms, src/Makefile, src/README.txt, src/autocmd.c, + src/fileio.c, src/globals.h, src/proto.h, src/proto/autocmd.pro, + src/proto/fileio.pro + + +*** ../vim-8.1.0824/Filelist 2019-01-17 16:11:02.297811975 +0100 +--- Filelist 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 14,19 **** +--- 14,20 ---- + src/arabic.c \ + src/arabic.h \ + src/ascii.h \ ++ src/autocmd.c \ + src/beval.c \ + src/beval.h \ + src/blob.c \ +*************** +*** 146,151 **** +--- 147,153 ---- + 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 \ +*** ../vim-8.1.0824/src/Make_bc5.mak 2019-01-12 16:10:47.415360504 +0100 +--- src/Make_bc5.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 525,530 **** +--- 525,531 ---- + + vimobj = \ + $(OBJDIR)\arabic.obj \ ++ $(OBJDIR)\autocmd.obj \ + $(OBJDIR)\blowfish.obj \ + $(OBJDIR)\buffer.obj \ + $(OBJDIR)\charset.obj \ +*** ../vim-8.1.0824/src/Make_cyg_ming.mak 2019-01-12 22:47:01.256088105 +0100 +--- src/Make_cyg_ming.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 695,700 **** +--- 695,701 ---- + CUIOBJ = $(OUTDIR)/iscygpty.o + OBJ = \ + $(OUTDIR)/arabic.o \ ++ $(OUTDIR)/autocmd.o \ + $(OUTDIR)/beval.o \ + $(OUTDIR)/blob.o \ + $(OUTDIR)/blowfish.o \ +*** ../vim-8.1.0824/src/Make_dice.mak 2019-01-01 13:20:05.936711257 +0100 +--- src/Make_dice.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 27,32 **** +--- 27,33 ---- + + SRC = \ + arabic.c \ ++ autocmd.c \ + blowfish.c \ + buffer.c \ + charset.c \ +*************** +*** 84,89 **** +--- 85,91 ---- + version.c + + OBJ = o/arabic.o \ ++ o/autocmd.o \ + o/blowfish.o \ + o/buffer.o \ + o/charset.o \ +*************** +*** 161,166 **** +--- 163,170 ---- + + o/arabic.o: arabic.c $(SYMS) + ++ o/autocmd.o: autocmd.c $(SYMS) ++ + o/blowfish.o: blowfish.c $(SYMS) + + o/buffer.o: buffer.c $(SYMS) +*** ../vim-8.1.0824/src/Make_ivc.mak 2019-01-01 13:20:05.936711257 +0100 +--- src/Make_ivc.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 211,216 **** +--- 211,217 ---- + LINK32_OBJS= \ + $(EXTRAS) \ + "$(INTDIR)/arabic.obj" \ ++ "$(INTDIR)/autocmd.obj" \ + "$(INTDIR)/blowfish.obj" \ + "$(INTDIR)/buffer.obj" \ + "$(INTDIR)/charset.obj" \ +*************** +*** 341,346 **** +--- 342,351 ---- + SOURCE=.\arabic.c + # End Source File + # Begin Source File ++ # ++ SOURCE=.\autocmd.c ++ # End Source File ++ # Begin Source File + + SOURCE=.\blowfish.c + # End Source File +*** ../vim-8.1.0824/src/Make_manx.mak 2019-01-01 13:20:05.936711257 +0100 +--- src/Make_manx.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 37,42 **** +--- 37,43 ---- + DEL = $(SHELL) -c rm -f + + SRC = arabic.c \ ++ autocmd.c \ + blowfish.c \ + buffer.c \ + charset.c \ +*************** +*** 96,101 **** +--- 97,103 ---- + 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,158 **** +--- 155,161 ---- + $(TERMLIB) + + PRO = proto/arabic.pro \ ++ proto/autocmd.pro \ + proto/blowfish.pro \ + proto/buffer.pro \ + proto/charset.pro \ +*************** +*** 256,261 **** +--- 259,267 ---- + obj/arabic.o: arabic.c + $(CCSYM) $@ arabic.c + ++ obj/autocmd.o: autocmd.c ++ $(CCSYM) $@ autocmd.c ++ + obj/blowfish.o: blowfish.c + $(CCSYM) $@ blowfish.c + +*** ../vim-8.1.0824/src/Make_morph.mak 2019-01-01 13:20:05.936711257 +0100 +--- src/Make_morph.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 25,30 **** +--- 25,31 ---- + ${CC} ${CFLAGS} $< -o $@ + + SRC = arabic.c \ ++ autocmd.c \ + blowfish.c \ + buffer.c \ + charset.c \ +*** ../vim-8.1.0824/src/Make_mvc.mak 2019-01-12 22:47:01.256088105 +0100 +--- src/Make_mvc.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 700,705 **** +--- 700,706 ---- + + OBJ = \ + $(OUTDIR)\arabic.obj \ ++ $(OUTDIR)\autocmd.obj \ + $(OUTDIR)\beval.obj \ + $(OUTDIR)\blob.obj \ + $(OUTDIR)\blowfish.obj \ +*************** +*** 1345,1350 **** +--- 1346,1353 ---- + + $(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,1624 **** +--- 1622,1628 ---- + # End Custom Build + proto.h: \ + proto/arabic.pro \ ++ proto/autocmd.pro \ + proto/blob.pro \ + proto/blowfish.pro \ + proto/buffer.pro \ +*** ../vim-8.1.0824/src/Make_sas.mak 2019-01-01 13:20:05.936711257 +0100 +--- src/Make_sas.mak 2019-01-26 15:16:55.565118541 +0100 +*************** +*** 90,95 **** +--- 90,96 ---- + + SRC = \ + arabic.c \ ++ autocmd.c \ + blowfish.c \ + buffer.c \ + charset.c \ +*************** +*** 148,153 **** +--- 149,155 ---- + + OBJ = \ + arabic.o \ ++ autocmd.o \ + blowfish.o \ + buffer.o \ + charset.o \ +*************** +*** 206,211 **** +--- 208,214 ---- + + PRO = \ + proto/arabic.pro \ ++ proto/autocmd.pro \ + proto/blowfish.pro \ + proto/buffer.pro \ + proto/charset.pro \ +*************** +*** 319,324 **** +--- 322,329 ---- + # 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 +*** ../vim-8.1.0824/src/Make_vms.mms 2019-01-18 22:58:56.427995669 +0100 +--- src/Make_vms.mms 2019-01-26 15:16:55.569118519 +0100 +*************** +*** 312,318 **** + 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 \ + 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 \ +--- 312,318 ---- + ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \ + $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB) + +! 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,327 **** + $(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 \ + 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 \ +--- 321,327 ---- + $(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) \ + $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC) + +! 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,505 **** +--- 500,506 ---- + .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 \ +*** ../vim-8.1.0824/src/Makefile 2019-01-17 15:43:21.749878443 +0100 +--- src/Makefile 2019-01-26 15:16:55.569118519 +0100 +*************** +*** 1572,1577 **** +--- 1571,1577 ---- + + BASIC_SRC = \ + arabic.c \ ++ autocmd.c \ + beval.c \ + blob.c \ + blowfish.c \ +*************** +*** 1684,1689 **** +--- 1684,1690 ---- + + OBJ_COMMON = \ + objects/arabic.o \ ++ objects/autocmd.o \ + objects/beval.o \ + objects/buffer.o \ + objects/blob.o \ +*************** +*** 1809,1814 **** +--- 1810,1816 ---- + + PRO_AUTO = \ + arabic.pro \ ++ autocmd.pro \ + blowfish.pro \ + buffer.pro \ + charset.pro \ +*************** +*** 2934,2939 **** +--- 2936,2944 ---- + 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,3381 **** +--- 3381,3390 ---- + 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 \ +*** ../vim-8.1.0824/src/README.txt 2019-01-01 13:20:05.936711257 +0100 +--- src/README.txt 2019-01-26 15:16:55.569118519 +0100 +*************** +*** 17,22 **** +--- 17,23 ---- + 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 +*** ../vim-8.1.0824/src/autocmd.c 2019-01-26 16:20:09.764993322 +0100 +--- src/autocmd.c 2019-01-26 16:07:47.061075397 +0100 +*************** +*** 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 ((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; ++ } ++ ++ /* ++ * Return TRUE if "event" is included in 'eventignore'. ++ */ ++ 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; ++ } ++ ++ /* ++ * Return OK when the contents of p_ei is valid, FAIL otherwise. ++ */ ++ 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) ++ ++ /* ++ * Add "what" to 'eventignore' to skip loading syntax highlighting for every ++ * buffer loaded into the window. "what" must start with a comma. ++ * Returns the old value of 'eventignore' in allocated memory. ++ */ ++ 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 */ ++ ++ /* ++ * 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>. ++ */ ++ 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 group; ++ ++ if (*arg == '|') ++ { ++ arg = (char_u *)""; ++ group = AUGROUP_ALL; // no argument, use all groups ++ } ++ else ++ { ++ /* ++ * Check for a legal group name. If not, use AUGROUP_ALL. ++ */ ++ group = au_get_grouparg(&arg); ++ if (arg == NULL) // out of memory ++ return; ++ } ++ ++ /* ++ * Scan over the events. ++ * If we find an illegal name, return here, don't do anything. ++ */ ++ pat = find_end_event(arg, group != AUGROUP_ALL); ++ if (pat == NULL) ++ return; ++ ++ pat = skipwhite(pat); ++ if (*pat == '|') ++ { ++ pat = (char_u *)""; ++ cmd = (char_u *)""; ++ } ++ else ++ { ++ /* ++ * Scan over the pattern. Put a NUL at the end. ++ */ ++ cmd = pat; ++ while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\')) ++ cmd++; ++ if (*cmd) ++ *cmd++ = NUL; ++ ++ // Expand environment variables in the pattern. Set 'shellslash', we ++ // want forward slashes here. ++ 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; ++ } ++ ++ /* ++ * Check for "nested" flag. ++ */ ++ cmd = skipwhite(cmd); ++ if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 ++ && VIM_ISWHITE(cmd[6])) ++ { ++ nested = TRUE; ++ cmd = skipwhite(cmd + 6); ++ } ++ ++ /* ++ * Find the start of the commands. ++ * Expand <sfile> in it. ++ */ ++ if (*cmd != NUL) ++ { ++ cmd = expand_sfile(cmd); ++ if (cmd == NULL) // some error ++ return; ++ need_free = TRUE; ++ } ++ } ++ ++ /* ++ * Print header when showing autocommands. ++ */ ++ if (!forceit && *cmd == NUL) ++ // Highlight title ++ msg_puts_title(_("\n--- Autocommands ---")); ++ ++ /* ++ * Loop over the events. ++ */ ++ last_event = (event_T)-1; // for listing the event name ++ last_group = AUGROUP_ERROR; // for listing the group name ++ 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, ++ nested, cmd, forceit, group) == FAIL) ++ break; ++ } ++ else ++ { ++ while (*arg && *arg != '|' && !VIM_ISWHITE(*arg)) ++ if (do_autocmd_event(event_name2nr(arg, &arg), pat, ++ nested, cmd, forceit, group) == FAIL) ++ break; ++ } ++ ++ if (need_free) ++ vim_free(cmd); ++ vim_free(envpat); ++ } ++ ++ /* ++ * Find the group ID in a ":autocmd" or ":doautocmd" argument. ++ * The "argp" argument is advanced to the following argument. ++ * ++ * Returns the group ID, AUGROUP_ERROR for error (out of memory). ++ */ ++ 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) // out of memory ++ return AUGROUP_ERROR; ++ group = au_find_group(group_name); ++ if (group == AUGROUP_ERROR) ++ group = AUGROUP_ALL; // no match, use all groups ++ else ++ *argp = skipwhite(p); // match, skip over group name ++ vim_free(group_name); ++ } ++ 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) ++ { ++ 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]; /* for "<buffer=X>" */ ++ ++ if (group == AUGROUP_ALL) ++ findgroup = current_augroup; ++ else ++ findgroup = group; ++ allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL); ++ ++ /* ++ * Show or delete all patterns for an event. ++ */ ++ if (*pat == NUL) ++ { ++ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) ++ { ++ if (forceit) // delete the AutoPat, if it's in the current group ++ { ++ if (ap->group == findgroup) ++ au_remove_pat(ap); ++ } ++ else if (group == AUGROUP_ALL || ap->group == group) ++ show_autocmd(ap, event); ++ } ++ } ++ ++ /* ++ * Loop through all the specified patterns. ++ */ ++ for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat)) ++ { ++ /* ++ * Find end of the pattern. ++ * Watch out for a comma in braces, like "*.\{obj,o\}". ++ */ ++ 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) // ignore single comma ++ continue; ++ patlen = (int)(endpat - pat); ++ ++ /* ++ * detect special <buflocal[=X]> buffer-local patterns ++ */ ++ is_buflocal = FALSE; ++ buflocal_nr = 0; ++ ++ if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0 ++ && pat[patlen - 1] == '>') ++ { ++ // "<buffer...>": Error will be printed only for addition. ++ // printing and removing will proceed silently. ++ is_buflocal = TRUE; ++ if (patlen == 8) ++ // "<buffer>" ++ buflocal_nr = curbuf->b_fnum; ++ else if (patlen > 9 && pat[7] == '=') ++ { ++ if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0) ++ // "<buffer=abuf>" ++ buflocal_nr = autocmd_bufnr; ++ else if (skipdigits(pat + 8) == pat + patlen - 1) ++ // "<buffer=123>" ++ buflocal_nr = atoi((char *)pat + 8); ++ } ++ } ++ ++ if (is_buflocal) ++ { ++ // normalize pat into standard "<buffer>#N" form ++ sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr); ++ pat = buflocal_pat; // can modify pat and patlen ++ patlen = (int)STRLEN(buflocal_pat); // but not endpat ++ } ++ ++ /* ++ * Find AutoPat entries with this pattern. When adding a command it ++ * always goes at or after the last one, so start at the end. ++ */ ++ 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) ++ { ++ /* Accept a pattern when: ++ * - a group was specified and it's that group, or a group was ++ * not specified and it's the current group, or a group was ++ * not specified and we are listing ++ * - the length of the pattern matches ++ * - the pattern matches. ++ * For <buffer[=X]>, this condition works because we normalize ++ * all buffer-local patterns. ++ */ ++ if ((allgroups || ap->group == findgroup) ++ && ap->patlen == patlen ++ && STRNCMP(pat, ap->pat, patlen) == 0) ++ { ++ /* ++ * Remove existing autocommands. ++ * If adding any new autocmd's for this AutoPat, don't ++ * delete the pattern from the autopat list, append to ++ * this list. ++ */ ++ if (forceit) ++ { ++ if (*cmd != NUL && ap->next == NULL) ++ { ++ au_remove_cmds(ap); ++ break; ++ } ++ au_remove_pat(ap); ++ } ++ ++ /* ++ * Show autocmd's for this autopat, or buflocals <buffer=X> ++ */ ++ else if (*cmd == NUL) ++ show_autocmd(ap, event); ++ ++ /* ++ * Add autocmd to this autopat, if it's the last one. ++ */ ++ else if (ap->next == NULL) ++ break; ++ } ++ } ++ prev_ap = &ap->next; ++ } ++ ++ /* ++ * Add a new command. ++ */ ++ if (*cmd != NUL) ++ { ++ /* ++ * If the pattern we want to add a command to does appear at the ++ * end of the list (or not is not in the list at all), add the ++ * pattern at the end of the list. ++ */ ++ if (ap == NULL) ++ { ++ /* refuse to add buffer-local ap if buffer number is invalid */ ++ if (is_buflocal && (buflocal_nr == 0 ++ || buflist_findnr(buflocal_nr) == NULL)) ++ { ++ semsg(_("E680: <buffer=%d>: invalid buffer number "), ++ buflocal_nr); ++ return FAIL; ++ } ++ ++ ap = (AutoPat *)alloc((unsigned)sizeof(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; ++ } ++ ++ /* ++ * Add the autocmd at the end of the AutoCmd list. ++ */ ++ prev_ac = &(ap->cmds); ++ while ((ac = *prev_ac) != NULL) ++ prev_ac = &ac->next; ++ ac = (AutoCmd *)alloc((unsigned)sizeof(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->nested = nested; ++ } ++ } ++ ++ au_cleanup(); // may really delete removed patterns/commands now ++ return OK; ++ } ++ ++ /* ++ * Implementation of ":doautocmd [group] event [fname]". ++ * Return OK for success, FAIL for failure; ++ */ ++ int ++ do_doautocmd( ++ char_u *arg, ++ int do_msg, // give message for no matching autocmds? ++ int *did_something) ++ { ++ char_u *fname; ++ int nothing_done = TRUE; ++ int group; ++ ++ if (did_something != NULL) ++ *did_something = FALSE; ++ ++ /* ++ * Check for a legal group name. If not, use AUGROUP_ALL. ++ */ ++ group = au_get_grouparg(&arg); ++ if (arg == NULL) // out of memory ++ return FAIL; ++ ++ if (*arg == '*') ++ { ++ emsg(_("E217: Can't execute autocommands for ALL events")); ++ return FAIL; ++ } ++ ++ /* ++ * Scan over the events. ++ * If we find an illegal name, return here, don't do anything. ++ */ ++ fname = find_end_event(arg, group != AUGROUP_ALL); ++ if (fname == NULL) ++ return FAIL; ++ ++ fname = skipwhite(fname); ++ ++ /* ++ * Loop over the events. ++ */ ++ 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 ++ } ++ ++ /* ++ * ":doautoall": execute autocommands for each loaded buffer. ++ */ ++ 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; ++ ++ /* ++ * This is a bit tricky: For some commands curwin->w_buffer needs to be ++ * equal to curbuf, but for some buffers there may not be a window. ++ * So we change the buffer for the current window for a moment. This ++ * gives problems when the autocommands make changes to the list of ++ * buffers or windows... ++ */ ++ FOR_ALL_BUFFERS(buf) ++ { ++ if (buf->b_ml.ml_mfp != NULL) ++ { ++ // find a window for this buffer and save some values ++ aucmd_prepbuf(&aco, buf); ++ set_bufref(&bufref, buf); ++ ++ // execute the autocommands for this buffer ++ retval = do_doautocmd(arg, FALSE, &did_aucmd); ++ ++ if (call_do_modelines && did_aucmd) ++ { ++ // Execute the modeline settings, but don't set window-local ++ // options if we are using the current window for another ++ // buffer. ++ do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0); ++ } ++ ++ // restore the current window ++ aucmd_restbuf(&aco); ++ ++ // stop if there is some error or buffer was deleted ++ if (retval == FAIL || !bufref_valid(&bufref)) ++ break; ++ } ++ } ++ ++ check_cursor(); // just in case lines got deleted ++ } ++ ++ /* ++ * Check *argp for <nomodeline>. When it is present return FALSE, otherwise ++ * return TRUE and advance *argp to after it. ++ * Thus return TRUE when do_modelines() should be called. ++ */ ++ int ++ check_nomodeline(char_u **argp) ++ { ++ if (STRNCMP(*argp, "<nomodeline>", 12) == 0) ++ { ++ *argp = skipwhite(*argp + 12); ++ return FALSE; ++ } ++ return TRUE; ++ } ++ ++ /* ++ * Prepare for executing autocommands for (hidden) buffer "buf". ++ * Search for a visible window containing the current buffer. If there isn't ++ * one then use "aucmd_win". ++ * Set "curbuf" and "curwin" to match "buf". ++ */ ++ void ++ aucmd_prepbuf( ++ aco_save_T *aco, // structure to save values in ++ buf_T *buf) // new curbuf ++ { ++ win_T *win; ++ int save_ea; ++ #ifdef FEAT_AUTOCHDIR ++ int save_acd; ++ #endif ++ ++ // Find a window that is for the new buffer ++ if (buf == curbuf) // be quick when buf is curbuf ++ win = curwin; ++ else ++ FOR_ALL_WINDOWS(win) ++ if (win->w_buffer == buf) ++ break; ++ ++ // Allocate "aucmd_win" when needed. If this fails (out of memory) fall ++ // back to using the current window. ++ if (win == NULL && aucmd_win == NULL) ++ { ++ win_alloc_aucmd_win(); ++ if (aucmd_win == NULL) ++ win = curwin; ++ } ++ if (win == NULL && aucmd_win_used) ++ // Strange recursive autocommand, fall back to using the current ++ // window. Expect a few side effects... ++ win = curwin; ++ ++ aco->save_curwin = curwin; ++ aco->save_curbuf = curbuf; ++ aco->save_prevwin = prevwin; ++ if (win != NULL) ++ { ++ // There is a window for "buf" in the current tab page, make it the ++ // curwin. This is preferred, it has the least side effects (esp. if ++ // "buf" is curbuf). ++ aco->use_aucmd_win = FALSE; ++ curwin = win; ++ } ++ else ++ { ++ // There is no window for "buf", use "aucmd_win". To minimize the side ++ // effects, insert it in the current tab page. ++ // Anything related to a window (e.g., setting folds) may have ++ // unexpected results. ++ aco->use_aucmd_win = TRUE; ++ aucmd_win_used = TRUE; ++ aucmd_win->w_buffer = buf; ++ #if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) ++ aucmd_win->w_s = &buf->b_s; ++ #endif ++ ++buf->b_nwindows; ++ win_init_empty(aucmd_win); // set cursor and topline to safe values ++ ++ // Make sure w_localdir and globaldir are NULL to avoid a chdir() in ++ // win_enter_ext(). ++ VIM_CLEAR(aucmd_win->w_localdir); ++ aco->globaldir = globaldir; ++ globaldir = NULL; ++ ++ ++ // Split the current window, put the aucmd_win in the upper half. ++ // We don't want the BufEnter or WinEnter autocommands. ++ block_autocmds(); ++ make_snapshot(SNAP_AUCMD_IDX); ++ save_ea = p_ea; ++ p_ea = FALSE; ++ ++ #ifdef FEAT_AUTOCHDIR ++ // Prevent chdir() call in win_enter_ext(), through do_autochdir(). ++ save_acd = p_acd; ++ p_acd = FALSE; ++ #endif ++ ++ (void)win_split_ins(0, WSP_TOP, aucmd_win, 0); ++ (void)win_comp_pos(); // recompute window positions ++ 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); ++ } ++ ++ /* ++ * Cleanup after executing autocommands for a (hidden) buffer. ++ * Restore the window as it was (if possible). ++ */ ++ void ++ aucmd_restbuf( ++ aco_save_T *aco) // structure holding saved values ++ { ++ int dummy; ++ ++ if (aco->use_aucmd_win) ++ { ++ --curbuf->b_nwindows; ++ // Find "aucmd_win", it can't be closed, but it may be in another tab ++ // page. Do not trigger autocommands here. ++ 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: ++ ++ // Remove the window and frame from the tree of frames. ++ (void)winframe_remove(curwin, &dummy, NULL); ++ win_remove(curwin, NULL); ++ aucmd_win_used = FALSE; ++ last_status(FALSE); // may need to remove last status line ++ ++ if (!valid_tabpage_win(curtab)) ++ // no valid window in current tabpage ++ close_tabpage(curtab); ++ ++ restore_snapshot(SNAP_AUCMD_IDX, FALSE); ++ (void)win_comp_pos(); // recompute window positions ++ unblock_autocmds(); ++ ++ if (win_valid(aco->save_curwin)) ++ curwin = aco->save_curwin; ++ else ++ // Hmm, original window disappeared. Just use the first one. ++ curwin = firstwin; ++ if (win_valid(aco->save_prevwin)) ++ prevwin = aco->save_prevwin; ++ #ifdef FEAT_EVAL ++ vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables ++ hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab ++ #endif ++ curbuf = curwin->w_buffer; ++ ++ vim_free(globaldir); ++ globaldir = aco->globaldir; ++ ++ // the buffer contents may have changed ++ 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) ++ // Hide the scrollbars from the aucmd_win and update. ++ 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 ++ { ++ // restore curwin ++ if (win_valid(aco->save_curwin)) ++ { ++ // Restore the buffer which was previously edited by curwin, if ++ // it was changed, we are still the same window and the buffer is ++ // valid. ++ 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; ++ // In case the autocommand move the cursor to a position that that ++ // not exist in curbuf. ++ check_cursor(); ++ } ++ } ++ } ++ ++ static int autocmd_nested = FALSE; ++ ++ /* ++ * Execute autocommands for "event" and file name "fname". ++ * Return TRUE if some commands were executed. ++ */ ++ int ++ apply_autocmds( ++ event_T event, ++ char_u *fname, // NULL or empty means use actual file name ++ char_u *fname_io, // fname to use for <afile> on cmdline ++ int force, // when TRUE, ignore autocmd_busy ++ buf_T *buf) // buffer for <abuf> ++ { ++ return apply_autocmds_group(event, fname, fname_io, force, ++ AUGROUP_ALL, buf, NULL); ++ } ++ ++ /* ++ * Like apply_autocmds(), but with extra "eap" argument. This takes care of ++ * setting v:filearg. ++ */ ++ 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); ++ } ++ ++ /* ++ * Like apply_autocmds(), but handles the caller's retval. If the script ++ * processing is being aborted or if retval is FAIL when inside a try ++ * conditional, no autocommands are executed. If otherwise the autocommands ++ * cause the script to be aborted, retval is set to FAIL. ++ */ ++ int ++ apply_autocmds_retval( ++ event_T event, ++ char_u *fname, // NULL or empty means use actual file name ++ char_u *fname_io, // fname to use for <afile> on cmdline ++ int force, // when TRUE, ignore autocmd_busy ++ buf_T *buf, // buffer for <abuf> ++ int *retval) // pointer to caller's 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; ++ } ++ ++ /* ++ * Return TRUE when there is a CursorHold autocommand defined. ++ */ ++ int ++ has_cursorhold(void) ++ { ++ return (first_autopat[(int)(get_real_state() == NORMAL_BUSY ++ ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL); ++ } ++ ++ /* ++ * Return TRUE if the CursorHold event can be triggered. ++ */ ++ int ++ trigger_cursorhold(void) ++ { ++ int state; ++ ++ if (!did_cursorhold ++ && has_cursorhold() ++ && reg_recording == 0 ++ && typebuf.tb_len == 0 ++ #ifdef FEAT_INS_EXPAND ++ && !ins_compl_active() ++ #endif ++ ) ++ { ++ state = get_real_state(); ++ if (state == NORMAL_BUSY || (state & INSERT) != 0) ++ return TRUE; ++ } ++ return FALSE; ++ } ++ ++ /* ++ * Return TRUE when there is a CursorMoved autocommand defined. ++ */ ++ int ++ has_cursormoved(void) ++ { ++ return (first_autopat[(int)EVENT_CURSORMOVED] != NULL); ++ } ++ ++ #if defined(FEAT_CONCEAL) || defined(PROTO) ++ /* ++ * Return TRUE when there is a CursorMovedI autocommand defined. ++ */ ++ int ++ has_cursormovedI(void) ++ { ++ return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL); ++ } ++ #endif ++ ++ /* ++ * Return TRUE when there is a TextChanged autocommand defined. ++ */ ++ int ++ has_textchanged(void) ++ { ++ return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL); ++ } ++ ++ /* ++ * Return TRUE when there is a TextChangedI autocommand defined. ++ */ ++ int ++ has_textchangedI(void) ++ { ++ return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL); ++ } ++ ++ #if defined(FEAT_INS_EXPAND) || defined(PROTO) ++ /* ++ * Return TRUE when there is a TextChangedP autocommand defined. ++ */ ++ int ++ has_textchangedP(void) ++ { ++ return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL); ++ } ++ #endif ++ ++ /* ++ * Return TRUE when there is an InsertCharPre autocommand defined. ++ */ ++ int ++ has_insertcharpre(void) ++ { ++ return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL); ++ } ++ ++ /* ++ * Return TRUE when there is an CmdUndefined autocommand defined. ++ */ ++ int ++ has_cmdundefined(void) ++ { ++ return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL); ++ } ++ ++ /* ++ * Return TRUE when there is an FuncUndefined autocommand defined. ++ */ ++ int ++ has_funcundefined(void) ++ { ++ return (first_autopat[(int)EVENT_FUNCUNDEFINED] != NULL); ++ } ++ ++ #if defined(FEAT_EVAL) || defined(PROTO) ++ /* ++ * Return TRUE when there is a TextYankPost autocommand defined. ++ */ ++ int ++ has_textyankpost(void) ++ { ++ return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL); ++ } ++ #endif ++ ++ /* ++ * Execute autocommands for "event" and file name "fname". ++ * Return TRUE if some commands were executed. ++ */ ++ static int ++ apply_autocmds_group( ++ event_T event, ++ char_u *fname, // NULL or empty means use actual file name ++ char_u *fname_io, // fname to use for <afile> on cmdline, NULL means ++ // use fname ++ int force, // when TRUE, ignore autocmd_busy ++ int group, // group ID, or AUGROUP_ALL ++ buf_T *buf, // buffer for <abuf> ++ exarg_T *eap UNUSED) // command arguments ++ { ++ char_u *sfname = NULL; // short file name ++ char_u *tail; ++ int save_changed; ++ buf_T *old_curbuf; ++ int retval = FALSE; ++ char_u *save_sourcing_name; ++ linenr_T save_sourcing_lnum; ++ 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; ++ ++ /* ++ * Quickly return if there are no autocommands for this event or ++ * autocommands are blocked. ++ */ ++ if (event == NUM_EVENTS || first_autopat[(int)event] == NULL ++ || autocmd_blocked > 0) ++ goto BYPASS_AU; ++ ++ /* ++ * When autocommands are busy, new autocommands are only executed when ++ * explicitly enabled with the "nested" flag. ++ */ ++ if (autocmd_busy && !(force || autocmd_nested)) ++ goto BYPASS_AU; ++ ++ #ifdef FEAT_EVAL ++ /* ++ * Quickly return when immediately aborting on error, or when an interrupt ++ * occurred or an exception was thrown but not caught. ++ */ ++ if (aborting()) ++ goto BYPASS_AU; ++ #endif ++ ++ /* ++ * FileChangedShell never nests, because it can create an endless loop. ++ */ ++ if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL ++ || event == EVENT_FILECHANGEDSHELLPOST)) ++ goto BYPASS_AU; ++ ++ /* ++ * Ignore events in 'eventignore'. ++ */ ++ if (event_ignored(event)) ++ goto BYPASS_AU; ++ ++ /* ++ * Allow nesting of autocommands, but restrict the depth, because it's ++ * possible to create an endless loop. ++ */ ++ if (nesting == 10) ++ { ++ emsg(_("E218: autocommand nesting too deep")); ++ goto BYPASS_AU; ++ } ++ ++ /* ++ * Check if these autocommands are disabled. Used when doing ":all" or ++ * ":ball". ++ */ ++ if ( (autocmd_no_enter ++ && (event == EVENT_WINENTER || event == EVENT_BUFENTER)) ++ || (autocmd_no_leave ++ && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE))) ++ goto BYPASS_AU; ++ ++ /* ++ * Save the autocmd_* variables and info about the current buffer. ++ */ ++ 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; ++ ++ /* ++ * Set the file name to be used for <afile>. ++ * Make a copy to avoid that changing a buffer name or directory makes it ++ * invalid. ++ */ ++ 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; // call FullName_save() later ++ ++ /* ++ * Set the buffer number to be used for <abuf>. ++ */ ++ if (buf == NULL) ++ autocmd_bufnr = 0; ++ else ++ autocmd_bufnr = buf->b_fnum; ++ ++ /* ++ * When the file name is NULL or empty, use the file name of buffer "buf". ++ * Always use the full path of the file name to match with, in case ++ * "allow_dirs" is set. ++ */ ++ 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); // make a copy, so we can change it ++ } ++ else ++ { ++ sfname = vim_strsave(fname); ++ // Don't try expanding FileType, Syntax, FuncUndefined, WindowID, ++ // ColorScheme, QuickFixCmd* or DirChanged ++ 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; // don't expand it later ++ } ++ else ++ fname = FullName_save(fname, FALSE); ++ } ++ if (fname == NULL) // out of memory ++ { ++ vim_free(sfname); ++ retval = FALSE; ++ goto BYPASS_AU; ++ } ++ ++ #ifdef BACKSLASH_IN_FILENAME ++ /* ++ * Replace all backslashes with forward slashes. This makes the ++ * autocommand patterns portable between Unix and MS-DOS. ++ */ ++ if (sfname != NULL) ++ forward_slash(sfname); ++ forward_slash(fname); ++ #endif ++ ++ #ifdef VMS ++ // remove version for correct match ++ if (sfname != NULL) ++ vms_remove_version(sfname); ++ vms_remove_version(fname); ++ #endif ++ ++ /* ++ * Set the name to be used for <amatch>. ++ */ ++ autocmd_match = fname; ++ ++ ++ // Don't redraw while doing autocommands. ++ ++RedrawingDisabled; ++ save_sourcing_name = sourcing_name; ++ sourcing_name = NULL; // don't free this one ++ save_sourcing_lnum = sourcing_lnum; ++ sourcing_lnum = 0; // no line number here ++ ++ #ifdef FEAT_EVAL ++ save_current_sctx = current_sctx; ++ ++ # ifdef FEAT_PROFILE ++ if (do_profiling == PROF_YES) ++ prof_child_enter(&wait_time); // doesn't count for the caller itself ++ # endif ++ ++ // Don't use local function variables, if called from a function. ++ save_funccal(&funccal_entry); ++ #endif ++ ++ /* ++ * When starting to execute autocommands, save the search patterns. ++ */ ++ if (!autocmd_busy) ++ { ++ save_search_patterns(); ++ #ifdef FEAT_INS_EXPAND ++ if (!ins_compl_active()) ++ #endif ++ { ++ saveRedobuff(&save_redo); ++ did_save_redobuff = TRUE; ++ } ++ did_filetype = keep_filetype; ++ } ++ ++ /* ++ * Note that we are applying autocmds. Some commands need to know. ++ */ ++ autocmd_busy = TRUE; ++ filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL); ++ ++nesting; // see matching decrement below ++ ++ // Remember that FileType was triggered. Used for did_filetype(). ++ if (event == EVENT_FILETYPE) ++ did_filetype = TRUE; ++ ++ tail = gettail(fname); ++ ++ // Find first autocommand that matches ++ 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); ++ ++ // found one, start executing the autocommands ++ if (patcmd.curpat != NULL) ++ { ++ // add to active_apc_list ++ patcmd.next = active_apc_list; ++ active_apc_list = &patcmd; ++ ++ #ifdef FEAT_EVAL ++ // set v:cmdarg (only when there is a matching pattern) ++ 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; // avoid gcc warning ++ #endif ++ retval = TRUE; ++ // mark the last pattern, to avoid an endless loop when more patterns ++ // are added when executing autocommands ++ for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next) ++ ap->last = FALSE; ++ ap->last = TRUE; ++ check_lnums(TRUE); // make sure cursor and topline are valid ++ do_cmdline(NULL, getnextac, (void *)&patcmd, ++ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); ++ #ifdef FEAT_EVAL ++ if (eap != NULL) ++ { ++ (void)set_cmdarg(NULL, save_cmdarg); ++ set_vim_var_nr(VV_CMDBANG, save_cmdbang); ++ } ++ #endif ++ // delete from active_apc_list ++ if (active_apc_list == &patcmd) // just in case ++ active_apc_list = patcmd.next; ++ } ++ ++ --RedrawingDisabled; ++ autocmd_busy = save_autocmd_busy; ++ filechangeshell_busy = FALSE; ++ autocmd_nested = save_autocmd_nested; ++ vim_free(sourcing_name); ++ sourcing_name = save_sourcing_name; ++ sourcing_lnum = save_sourcing_lnum; ++ 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; // see matching increment above ++ ++ /* ++ * When stopping to execute autocommands, restore the search patterns and ++ * the redo buffer. Free any buffers in the au_pending_free_buf list and ++ * free any windows in the au_pending_free_win list. ++ */ ++ 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; ++ } ++ } ++ ++ /* ++ * Some events don't set or reset the Changed flag. ++ * Check if still in the same buffer! ++ */ ++ 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(); // may really delete removed patterns/commands now ++ ++ BYPASS_AU: ++ // When wiping out a buffer make sure all its buffer-local autocommands ++ // are deleted. ++ 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 ++ ++ /* ++ * Block triggering autocommands until unblock_autocmd() is called. ++ * Can be used recursively, so long as it's symmetric. ++ */ ++ void ++ block_autocmds(void) ++ { ++ # ifdef FEAT_EVAL ++ // Remember the value of v:termresponse. ++ if (autocmd_blocked == 0) ++ old_termresponse = get_vim_var_str(VV_TERMRESPONSE); ++ # endif ++ ++autocmd_blocked; ++ } ++ ++ void ++ unblock_autocmds(void) ++ { ++ --autocmd_blocked; ++ ++ # ifdef FEAT_EVAL ++ // When v:termresponse was set while autocommands were blocked, trigger ++ // the autocommands now. Esp. useful when executing a shell command ++ // during startup (vimdiff). ++ if (autocmd_blocked == 0 ++ && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) ++ apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf); ++ # endif ++ } ++ ++ #if defined(FEAT_EVAL) && (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM)) \ ++ || defined(PROTO) ++ int ++ is_autocmd_blocked(void) ++ { ++ return autocmd_blocked != 0; ++ } ++ #endif ++ ++ /* ++ * Find next autocommand pattern that matches. ++ */ ++ static void ++ auto_next_pat( ++ AutoPatCmd *apc, ++ int stop_at_last) // stop when 'last' flag is set ++ { ++ AutoPat *ap; ++ AutoCmd *cp; ++ char_u *name; ++ char *s; ++ ++ VIM_CLEAR(sourcing_name); ++ ++ for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) ++ { ++ apc->curpat = NULL; ++ ++ // Only use a pattern when it has not been removed, has commands and ++ // the group matches. For buffer-local autocommands only check the ++ // buffer number. ++ if (ap->pat != NULL && ap->cmds != NULL ++ && (apc->group == AUGROUP_ALL || apc->group == ap->group)) ++ { ++ // execution-condition ++ 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_name = alloc((unsigned)(STRLEN(s) ++ + STRLEN(name) + ap->patlen + 1)); ++ if (sourcing_name != NULL) ++ { ++ sprintf((char *)sourcing_name, s, ++ (char *)name, (char *)ap->pat); ++ if (p_verbose >= 8) ++ { ++ verbose_enter(); ++ smsg(_("Executing %s"), sourcing_name); ++ verbose_leave(); ++ } ++ } ++ ++ apc->curpat = ap; ++ apc->nextcmd = ap->cmds; ++ // mark last command ++ for (cp = ap->cmds; cp->next != NULL; cp = cp->next) ++ cp->last = FALSE; ++ cp->last = TRUE; ++ } ++ line_breakcheck(); ++ if (apc->curpat != NULL) // found a match ++ break; ++ } ++ if (stop_at_last && ap->last) ++ break; ++ } ++ } ++ ++ /* ++ * Get next autocommand command. ++ * Called by do_cmdline() to get the next line for ":if". ++ * Returns allocated string, or NULL for end of autocommands. ++ */ ++ char_u * ++ getnextac(int c UNUSED, void *cookie, int indent UNUSED) ++ { ++ AutoPatCmd *acp = (AutoPatCmd *)cookie; ++ char_u *retval; ++ AutoCmd *ac; ++ ++ // Can be called again after returning the last line. ++ if (acp->curpat == NULL) ++ return NULL; ++ ++ // repeat until we find an autocommand to execute ++ for (;;) ++ { ++ // skip removed commands ++ 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; ++ ++ // at end of commands, find next pattern that matches ++ 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"); // don't overwrite this either ++ verbose_leave_scroll(); ++ } ++ retval = vim_strsave(ac->cmd); ++ 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; ++ } ++ ++ /* ++ * Return TRUE if there is a matching autocommand for "fname". ++ * To account for buffer-local autocommands, function needs to know ++ * in which buffer the file will be opened. ++ */ ++ 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 ++ /* ++ * Replace all backslashes with forward slashes. This makes the ++ * autocommand patterns portable between Unix and MS-DOS. ++ */ ++ sfname = vim_strsave(sfname); ++ if (sfname != NULL) ++ forward_slash(sfname); ++ forward_slash(fname); ++ #endif ++ ++ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) ++ 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; ++ } ++ ++ #if defined(FEAT_CMDL_COMPL) || defined(PROTO) ++ /* ++ * Function given to ExpandGeneric() to obtain the list of autocommand group ++ * names. ++ */ ++ char_u * ++ get_augroup_name(expand_T *xp UNUSED, int idx) ++ { ++ if (idx == augroups.ga_len) // add "END" add the end ++ return (char_u *)"END"; ++ if (idx >= augroups.ga_len) // end of list ++ return NULL; ++ if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) ++ // skip deleted entries ++ return (char_u *)""; ++ return AUGROUP_NAME(idx); // return a name ++ } ++ ++ static int include_groups = FALSE; ++ ++ char_u * ++ set_context_in_autocmd( ++ expand_T *xp, ++ char_u *arg, ++ int doautocmd) // TRUE for :doauto*, FALSE for :autocmd ++ { ++ char_u *p; ++ int group; ++ ++ // check for a group name, skip it if present ++ include_groups = FALSE; ++ p = arg; ++ group = au_get_grouparg(&arg); ++ if (group == AUGROUP_ERROR) ++ return NULL; ++ // If there only is a group name that's what we expand. ++ if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1])) ++ { ++ arg = p; ++ group = AUGROUP_ALL; ++ } ++ ++ // skip over event name ++ 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; // expand event name ++ xp->xp_pattern = arg; ++ return NULL; ++ } ++ ++ // skip over pattern ++ arg = skipwhite(p); ++ while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\')) ++ arg++; ++ if (*arg) ++ return arg; // expand (next) command ++ ++ if (doautocmd) ++ xp->xp_context = EXPAND_FILES; // expand file names ++ else ++ xp->xp_context = EXPAND_NOTHING; // pattern is not expanded ++ return NULL; ++ } ++ ++ /* ++ * Function given to ExpandGeneric() to obtain the list of event names. ++ */ ++ char_u * ++ get_event_name(expand_T *xp UNUSED, int idx) ++ { ++ if (idx < augroups.ga_len) // First list group names, if wanted ++ { ++ if (!include_groups || AUGROUP_NAME(idx) == NULL ++ || AUGROUP_NAME(idx) == get_deleted_augroup()) ++ return (char_u *)""; // skip deleted entries ++ return AUGROUP_NAME(idx); // return a name ++ } ++ return (char_u *)event_names[idx - augroups.ga_len].name; ++ } ++ ++ #endif // FEAT_CMDL_COMPL ++ ++ #if defined(FEAT_EVAL) || defined(PROTO) ++ /* ++ * Return TRUE if autocmd is supported. ++ */ ++ int ++ autocmd_supported(char_u *name) ++ { ++ char_u *p; ++ ++ return (event_name2nr(name, &p) != NUM_EVENTS); ++ } ++ ++ /* ++ * Return TRUE if an autocommand is defined for a group, event and ++ * pattern: The group can be omitted to accept any group. "event" and "pattern" ++ * can be NULL to accept any event and pattern. "pattern" can be NULL to accept ++ * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted. ++ * Used for: ++ * exists("#Group") or ++ * exists("#Group#Event") or ++ * exists("#Group#Event#pat") or ++ * exists("#Event") or ++ * exists("#Event#pat") ++ */ ++ 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; ++ ++ // Make a copy so that we can change the '#' chars to a NUL. ++ arg_save = vim_strsave(arg); ++ if (arg_save == NULL) ++ return FALSE; ++ p = vim_strchr(arg_save, '#'); ++ if (p != NULL) ++ *p++ = NUL; ++ ++ // First, look for an autocmd group name ++ group = au_find_group(arg_save); ++ if (group == AUGROUP_ERROR) ++ { ++ // Didn't match a group name, assume the first argument is an event. ++ group = AUGROUP_ALL; ++ event_name = arg_save; ++ } ++ else ++ { ++ if (p == NULL) ++ { ++ // "Group": group name is present and it's recognized ++ retval = TRUE; ++ goto theend; ++ } ++ ++ // Must be "Group#Event" or "Group#Event#pat". ++ event_name = p; ++ p = vim_strchr(event_name, '#'); ++ if (p != NULL) ++ *p++ = NUL; // "Group#Event#pat" ++ } ++ ++ pattern = p; // "pattern" is NULL when there is no pattern ++ ++ // find the index (enum) for the event name ++ event = event_name2nr(event_name, &p); ++ ++ // return FALSE if the event name is not recognized ++ if (event == NUM_EVENTS) ++ goto theend; ++ ++ // Find the first autocommand for this event. ++ // If there isn't any, return FALSE; ++ // If there is one and no pattern given, return TRUE; ++ ap = first_autopat[(int)event]; ++ if (ap == NULL) ++ goto theend; ++ ++ // if pattern is "<buffer>", special handling is needed which uses curbuf ++ // for pattern "<buffer=N>, fnamecmp() will work fine ++ if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0) ++ buflocal_buf = curbuf; ++ ++ // Check if there is an autocommand with the given pattern. ++ for ( ; ap != NULL; ap = ap->next) ++ // only use a pattern when it has not been removed and has commands. ++ // For buffer-local autocommands, fnamecmp() works fine. ++ 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 +*** ../vim-8.1.0824/src/fileio.c 2019-01-24 17:59:35.135217476 +0100 +--- src/fileio.c 2019-01-26 15:16:55.569118519 +0100 +*************** +*** 42,53 **** + static void msg_add_eol(void); + static int check_mtime(buf_T *buf, stat_T *s); + static int time_differs(long t1, long t2); +- static int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap); +- static int au_find_group(char_u *name); +- +- #define AUGROUP_DEFAULT -1 /* default autocmd group */ +- #define AUGROUP_ERROR -2 /* erroneous autocmd group */ +- #define AUGROUP_ALL -3 /* all autocmd groups */ + + #define HAS_BW_FLAGS + #define FIO_LATIN1 0x01 /* convert Latin1 */ +--- 42,47 ---- +*************** +*** 120,135 **** + #endif + static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); + +- /* +- * 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. +- */ +- static int au_did_filetype INIT(= FALSE); +- + void + filemess( + buf_T *buf, +--- 114,119 ---- +*************** +*** 6866,6871 **** +--- 6850,6860 ---- + reason = "deleted"; + else if (bufIsChanged(buf)) + reason = "conflict"; ++ /* ++ * Check if the file contents really changed to avoid giving a ++ * warning when only the timestamp was set (e.g., checked out of ++ * CVS). Always warn when the buffer was changed. ++ */ + else if (orig_size != buf->b_orig_size || buf_contents_changed(buf)) + reason = "changed"; + else if (orig_mode != buf->b_orig_mode) +*************** +*** 6912,6923 **** + #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG) + can_reload = TRUE; + #endif +- /* +- * Check if the file contents really changed to avoid +- * giving a warning when only the timestamp was set (e.g., +- * checked out of CVS). Always warn when the buffer was +- * changed. +- */ + if (reason[2] == 'n') + { + mesg = _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well"); +--- 6901,6906 ---- +*************** +*** 7552,10116 **** + } + #endif + +- +- /* +- * Code for automatic commands. +- */ +- +- /* +- * 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 +- }; +- +- /* +- * 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; +- +- /* +- * 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 match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname, char_u *sfname, char_u *tail, int allow_dirs); +- +- +- 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 ((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; +- } +- +- /* +- * Return TRUE if "event" is included in 'eventignore'. +- */ +- 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; +- } +- +- /* +- * Return OK when the contents of p_ei is valid, FAIL otherwise. +- */ +- 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) +- +- /* +- * Add "what" to 'eventignore' to skip loading syntax highlighting for every +- * buffer loaded into the window. "what" must start with a comma. +- * Returns the old value of 'eventignore' in allocated memory. +- */ +- 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 */ +- +- /* +- * 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>. +- */ +- 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 group; +- +- if (*arg == '|') +- { +- arg = (char_u *)""; +- group = AUGROUP_ALL; /* no argument, use all groups */ +- } +- else +- { +- /* +- * Check for a legal group name. If not, use AUGROUP_ALL. +- */ +- group = au_get_grouparg(&arg); +- if (arg == NULL) /* out of memory */ +- return; +- } +- +- /* +- * Scan over the events. +- * If we find an illegal name, return here, don't do anything. +- */ +- pat = find_end_event(arg, group != AUGROUP_ALL); +- if (pat == NULL) +- return; +- +- pat = skipwhite(pat); +- if (*pat == '|') +- { +- pat = (char_u *)""; +- cmd = (char_u *)""; +- } +- else +- { +- /* +- * Scan over the pattern. Put a NUL at the end. +- */ +- cmd = pat; +- while (*cmd && (!VIM_ISWHITE(*cmd) || cmd[-1] == '\\')) +- cmd++; +- if (*cmd) +- *cmd++ = NUL; +- +- /* Expand environment variables in the pattern. Set 'shellslash', we want +- * forward slashes here. */ +- 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; +- } +- +- /* +- * Check for "nested" flag. +- */ +- cmd = skipwhite(cmd); +- if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 && VIM_ISWHITE(cmd[6])) +- { +- nested = TRUE; +- cmd = skipwhite(cmd + 6); +- } +- +- /* +- * Find the start of the commands. +- * Expand <sfile> in it. +- */ +- if (*cmd != NUL) +- { +- cmd = expand_sfile(cmd); +- if (cmd == NULL) /* some error */ +- return; +- need_free = TRUE; +- } +- } +- +- /* +- * Print header when showing autocommands. +- */ +- if (!forceit && *cmd == NUL) +- { +- /* Highlight title */ +- msg_puts_title(_("\n--- Autocommands ---")); +- } +- +- /* +- * Loop over the events. +- */ +- last_event = (event_T)-1; /* for listing the event name */ +- last_group = AUGROUP_ERROR; /* for listing the group name */ +- 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, +- nested, cmd, forceit, group) == FAIL) +- break; +- } +- else +- { +- while (*arg && *arg != '|' && !VIM_ISWHITE(*arg)) +- if (do_autocmd_event(event_name2nr(arg, &arg), pat, +- nested, cmd, forceit, group) == FAIL) +- break; +- } +- +- if (need_free) +- vim_free(cmd); +- vim_free(envpat); +- } +- +- /* +- * Find the group ID in a ":autocmd" or ":doautocmd" argument. +- * The "argp" argument is advanced to the following argument. +- * +- * Returns the group ID, AUGROUP_ERROR for error (out of memory). +- */ +- 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) /* out of memory */ +- return AUGROUP_ERROR; +- group = au_find_group(group_name); +- if (group == AUGROUP_ERROR) +- group = AUGROUP_ALL; /* no match, use all groups */ +- else +- *argp = skipwhite(p); /* match, skip over group name */ +- vim_free(group_name); +- } +- 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) +- { +- 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]; /* for "<buffer=X>" */ +- +- if (group == AUGROUP_ALL) +- findgroup = current_augroup; +- else +- findgroup = group; +- allgroups = (group == AUGROUP_ALL && !forceit && *cmd == NUL); +- +- /* +- * Show or delete all patterns for an event. +- */ +- if (*pat == NUL) +- { +- for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) +- { +- if (forceit) /* delete the AutoPat, if it's in the current group */ +- { +- if (ap->group == findgroup) +- au_remove_pat(ap); +- } +- else if (group == AUGROUP_ALL || ap->group == group) +- show_autocmd(ap, event); +- } +- } +- +- /* +- * Loop through all the specified patterns. +- */ +- for ( ; *pat; pat = (*endpat == ',' ? endpat + 1 : endpat)) +- { +- /* +- * Find end of the pattern. +- * Watch out for a comma in braces, like "*.\{obj,o\}". +- */ +- 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) /* ignore single comma */ +- continue; +- patlen = (int)(endpat - pat); +- +- /* +- * detect special <buflocal[=X]> buffer-local patterns +- */ +- is_buflocal = FALSE; +- buflocal_nr = 0; +- +- if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0 +- && pat[patlen - 1] == '>') +- { +- /* "<buffer...>": Error will be printed only for addition. +- * printing and removing will proceed silently. */ +- is_buflocal = TRUE; +- if (patlen == 8) +- /* "<buffer>" */ +- buflocal_nr = curbuf->b_fnum; +- else if (patlen > 9 && pat[7] == '=') +- { +- if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0) +- /* "<buffer=abuf>" */ +- buflocal_nr = autocmd_bufnr; +- else if (skipdigits(pat + 8) == pat + patlen - 1) +- /* "<buffer=123>" */ +- buflocal_nr = atoi((char *)pat + 8); +- } +- } +- +- if (is_buflocal) +- { +- /* normalize pat into standard "<buffer>#N" form */ +- sprintf((char *)buflocal_pat, "<buffer=%d>", buflocal_nr); +- pat = buflocal_pat; /* can modify pat and patlen */ +- patlen = (int)STRLEN(buflocal_pat); /* but not endpat */ +- } +- +- /* +- * Find AutoPat entries with this pattern. When adding a command it +- * always goes at or after the last one, so start at the end. +- */ +- 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) +- { +- /* Accept a pattern when: +- * - a group was specified and it's that group, or a group was +- * not specified and it's the current group, or a group was +- * not specified and we are listing +- * - the length of the pattern matches +- * - the pattern matches. +- * For <buffer[=X]>, this condition works because we normalize +- * all buffer-local patterns. +- */ +- if ((allgroups || ap->group == findgroup) +- && ap->patlen == patlen +- && STRNCMP(pat, ap->pat, patlen) == 0) +- { +- /* +- * Remove existing autocommands. +- * If adding any new autocmd's for this AutoPat, don't +- * delete the pattern from the autopat list, append to +- * this list. +- */ +- if (forceit) +- { +- if (*cmd != NUL && ap->next == NULL) +- { +- au_remove_cmds(ap); +- break; +- } +- au_remove_pat(ap); +- } +- +- /* +- * Show autocmd's for this autopat, or buflocals <buffer=X> +- */ +- else if (*cmd == NUL) +- show_autocmd(ap, event); +- +- /* +- * Add autocmd to this autopat, if it's the last one. +- */ +- else if (ap->next == NULL) +- break; +- } +- } +- prev_ap = &ap->next; +- } +- +- /* +- * Add a new command. +- */ +- if (*cmd != NUL) +- { +- /* +- * If the pattern we want to add a command to does appear at the +- * end of the list (or not is not in the list at all), add the +- * pattern at the end of the list. +- */ +- if (ap == NULL) +- { +- /* refuse to add buffer-local ap if buffer number is invalid */ +- if (is_buflocal && (buflocal_nr == 0 +- || buflist_findnr(buflocal_nr) == NULL)) +- { +- semsg(_("E680: <buffer=%d>: invalid buffer number "), +- buflocal_nr); +- return FAIL; +- } +- +- ap = (AutoPat *)alloc((unsigned)sizeof(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; +- } +- +- /* +- * Add the autocmd at the end of the AutoCmd list. +- */ +- prev_ac = &(ap->cmds); +- while ((ac = *prev_ac) != NULL) +- prev_ac = &ac->next; +- ac = (AutoCmd *)alloc((unsigned)sizeof(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->nested = nested; +- } +- } +- +- au_cleanup(); /* may really delete removed patterns/commands now */ +- return OK; +- } +- +- /* +- * Implementation of ":doautocmd [group] event [fname]". +- * Return OK for success, FAIL for failure; +- */ +- int +- do_doautocmd( +- char_u *arg, +- int do_msg, /* give message for no matching autocmds? */ +- int *did_something) +- { +- char_u *fname; +- int nothing_done = TRUE; +- int group; +- +- if (did_something != NULL) +- *did_something = FALSE; +- +- /* +- * Check for a legal group name. If not, use AUGROUP_ALL. +- */ +- group = au_get_grouparg(&arg); +- if (arg == NULL) /* out of memory */ +- return FAIL; +- +- if (*arg == '*') +- { +- emsg(_("E217: Can't execute autocommands for ALL events")); +- return FAIL; +- } +- +- /* +- * Scan over the events. +- * If we find an illegal name, return here, don't do anything. +- */ +- fname = find_end_event(arg, group != AUGROUP_ALL); +- if (fname == NULL) +- return FAIL; +- +- fname = skipwhite(fname); +- +- /* +- * Loop over the events. +- */ +- 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 +- } +- +- /* +- * ":doautoall": execute autocommands for each loaded buffer. +- */ +- 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; +- +- /* +- * This is a bit tricky: For some commands curwin->w_buffer needs to be +- * equal to curbuf, but for some buffers there may not be a window. +- * So we change the buffer for the current window for a moment. This +- * gives problems when the autocommands make changes to the list of +- * buffers or windows... +- */ +- FOR_ALL_BUFFERS(buf) +- { +- if (buf->b_ml.ml_mfp != NULL) +- { +- /* find a window for this buffer and save some values */ +- aucmd_prepbuf(&aco, buf); +- set_bufref(&bufref, buf); +- +- /* execute the autocommands for this buffer */ +- retval = do_doautocmd(arg, FALSE, &did_aucmd); +- +- if (call_do_modelines && did_aucmd) +- { +- /* Execute the modeline settings, but don't set window-local +- * options if we are using the current window for another +- * buffer. */ +- do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0); +- } +- +- /* restore the current window */ +- aucmd_restbuf(&aco); +- +- /* stop if there is some error or buffer was deleted */ +- if (retval == FAIL || !bufref_valid(&bufref)) +- break; +- } +- } +- +- check_cursor(); /* just in case lines got deleted */ +- } +- +- /* +- * Check *argp for <nomodeline>. When it is present return FALSE, otherwise +- * return TRUE and advance *argp to after it. +- * Thus return TRUE when do_modelines() should be called. +- */ +- int +- check_nomodeline(char_u **argp) +- { +- if (STRNCMP(*argp, "<nomodeline>", 12) == 0) +- { +- *argp = skipwhite(*argp + 12); +- return FALSE; +- } +- return TRUE; +- } +- +- /* +- * Prepare for executing autocommands for (hidden) buffer "buf". +- * Search for a visible window containing the current buffer. If there isn't +- * one then use "aucmd_win". +- * Set "curbuf" and "curwin" to match "buf". +- */ +- void +- aucmd_prepbuf( +- aco_save_T *aco, /* structure to save values in */ +- buf_T *buf) /* new curbuf */ +- { +- win_T *win; +- int save_ea; +- #ifdef FEAT_AUTOCHDIR +- int save_acd; +- #endif +- +- /* Find a window that is for the new buffer */ +- if (buf == curbuf) /* be quick when buf is curbuf */ +- win = curwin; +- else +- FOR_ALL_WINDOWS(win) +- if (win->w_buffer == buf) +- break; +- +- /* Allocate "aucmd_win" when needed. If this fails (out of memory) fall +- * back to using the current window. */ +- if (win == NULL && aucmd_win == NULL) +- { +- win_alloc_aucmd_win(); +- if (aucmd_win == NULL) +- win = curwin; +- } +- if (win == NULL && aucmd_win_used) +- /* Strange recursive autocommand, fall back to using the current +- * window. Expect a few side effects... */ +- win = curwin; +- +- aco->save_curwin = curwin; +- aco->save_curbuf = curbuf; +- aco->save_prevwin = prevwin; +- if (win != NULL) +- { +- /* There is a window for "buf" in the current tab page, make it the +- * curwin. This is preferred, it has the least side effects (esp. if +- * "buf" is curbuf). */ +- aco->use_aucmd_win = FALSE; +- curwin = win; +- } +- else +- { +- /* There is no window for "buf", use "aucmd_win". To minimize the side +- * effects, insert it in the current tab page. +- * Anything related to a window (e.g., setting folds) may have +- * unexpected results. */ +- aco->use_aucmd_win = TRUE; +- aucmd_win_used = TRUE; +- aucmd_win->w_buffer = buf; +- #if defined(FEAT_SYN_HL) || defined(FEAT_SPELL) +- aucmd_win->w_s = &buf->b_s; +- #endif +- ++buf->b_nwindows; +- win_init_empty(aucmd_win); /* set cursor and topline to safe values */ +- +- /* Make sure w_localdir and globaldir are NULL to avoid a chdir() in +- * win_enter_ext(). */ +- VIM_CLEAR(aucmd_win->w_localdir); +- aco->globaldir = globaldir; +- globaldir = NULL; +- +- +- /* Split the current window, put the aucmd_win in the upper half. +- * We don't want the BufEnter or WinEnter autocommands. */ +- block_autocmds(); +- make_snapshot(SNAP_AUCMD_IDX); +- save_ea = p_ea; +- p_ea = FALSE; +- +- #ifdef FEAT_AUTOCHDIR +- /* Prevent chdir() call in win_enter_ext(), through do_autochdir(). */ +- save_acd = p_acd; +- p_acd = FALSE; +- #endif +- +- (void)win_split_ins(0, WSP_TOP, aucmd_win, 0); +- (void)win_comp_pos(); /* recompute window positions */ +- 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); +- } +- +- /* +- * Cleanup after executing autocommands for a (hidden) buffer. +- * Restore the window as it was (if possible). +- */ +- void +- aucmd_restbuf( +- aco_save_T *aco) /* structure holding saved values */ +- { +- int dummy; +- +- if (aco->use_aucmd_win) +- { +- --curbuf->b_nwindows; +- /* Find "aucmd_win", it can't be closed, but it may be in another tab +- * page. Do not trigger autocommands here. */ +- 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: +- +- /* Remove the window and frame from the tree of frames. */ +- (void)winframe_remove(curwin, &dummy, NULL); +- win_remove(curwin, NULL); +- aucmd_win_used = FALSE; +- last_status(FALSE); /* may need to remove last status line */ +- +- if (!valid_tabpage_win(curtab)) +- /* no valid window in current tabpage */ +- close_tabpage(curtab); +- +- restore_snapshot(SNAP_AUCMD_IDX, FALSE); +- (void)win_comp_pos(); /* recompute window positions */ +- unblock_autocmds(); +- +- if (win_valid(aco->save_curwin)) +- curwin = aco->save_curwin; +- else +- /* Hmm, original window disappeared. Just use the first one. */ +- curwin = firstwin; +- if (win_valid(aco->save_prevwin)) +- prevwin = aco->save_prevwin; +- #ifdef FEAT_EVAL +- vars_clear(&aucmd_win->w_vars->dv_hashtab); /* free all w: variables */ +- hash_init(&aucmd_win->w_vars->dv_hashtab); /* re-use the hashtab */ +- #endif +- curbuf = curwin->w_buffer; +- +- vim_free(globaldir); +- globaldir = aco->globaldir; +- +- /* the buffer contents may have changed */ +- 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) +- /* Hide the scrollbars from the aucmd_win and update. */ +- 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 +- { +- /* restore curwin */ +- if (win_valid(aco->save_curwin)) +- { +- /* Restore the buffer which was previously edited by curwin, if +- * it was changed, we are still the same window and the buffer is +- * valid. */ +- 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; +- /* In case the autocommand move the cursor to a position that that +- * not exist in curbuf. */ +- check_cursor(); +- } +- } +- } +- +- static int autocmd_nested = FALSE; +- +- /* +- * Execute autocommands for "event" and file name "fname". +- * Return TRUE if some commands were executed. +- */ +- int +- apply_autocmds( +- event_T event, +- char_u *fname, /* NULL or empty means use actual file name */ +- char_u *fname_io, /* fname to use for <afile> on cmdline */ +- int force, /* when TRUE, ignore autocmd_busy */ +- buf_T *buf) /* buffer for <abuf> */ +- { +- return apply_autocmds_group(event, fname, fname_io, force, +- AUGROUP_ALL, buf, NULL); +- } +- +- /* +- * Like apply_autocmds(), but with extra "eap" argument. This takes care of +- * setting v:filearg. +- */ +- static 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); +- } +- +- /* +- * Like apply_autocmds(), but handles the caller's retval. If the script +- * processing is being aborted or if retval is FAIL when inside a try +- * conditional, no autocommands are executed. If otherwise the autocommands +- * cause the script to be aborted, retval is set to FAIL. +- */ +- int +- apply_autocmds_retval( +- event_T event, +- char_u *fname, /* NULL or empty means use actual file name */ +- char_u *fname_io, /* fname to use for <afile> on cmdline */ +- int force, /* when TRUE, ignore autocmd_busy */ +- buf_T *buf, /* buffer for <abuf> */ +- int *retval) /* pointer to caller's 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; +- } +- +- /* +- * Return TRUE when there is a CursorHold autocommand defined. +- */ +- int +- has_cursorhold(void) +- { +- return (first_autopat[(int)(get_real_state() == NORMAL_BUSY +- ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL); +- } +- +- /* +- * Return TRUE if the CursorHold event can be triggered. +- */ +- int +- trigger_cursorhold(void) +- { +- int state; +- +- if (!did_cursorhold +- && has_cursorhold() +- && reg_recording == 0 +- && typebuf.tb_len == 0 +- #ifdef FEAT_INS_EXPAND +- && !ins_compl_active() +- #endif +- ) +- { +- state = get_real_state(); +- if (state == NORMAL_BUSY || (state & INSERT) != 0) +- return TRUE; +- } +- return FALSE; +- } +- +- /* +- * Return TRUE when there is a CursorMoved autocommand defined. +- */ +- int +- has_cursormoved(void) +- { +- return (first_autopat[(int)EVENT_CURSORMOVED] != NULL); +- } +- +- #if defined(FEAT_CONCEAL) || defined(PROTO) +- /* +- * Return TRUE when there is a CursorMovedI autocommand defined. +- */ +- int +- has_cursormovedI(void) +- { +- return (first_autopat[(int)EVENT_CURSORMOVEDI] != NULL); +- } +- #endif +- +- /* +- * Return TRUE when there is a TextChanged autocommand defined. +- */ +- int +- has_textchanged(void) +- { +- return (first_autopat[(int)EVENT_TEXTCHANGED] != NULL); +- } +- +- /* +- * Return TRUE when there is a TextChangedI autocommand defined. +- */ +- int +- has_textchangedI(void) +- { +- return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL); +- } +- +- #if defined(FEAT_INS_EXPAND) || defined(PROTO) +- /* +- * Return TRUE when there is a TextChangedP autocommand defined. +- */ +- int +- has_textchangedP(void) +- { +- return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL); +- } +- #endif +- +- /* +- * Return TRUE when there is an InsertCharPre autocommand defined. +- */ +- int +- has_insertcharpre(void) +- { +- return (first_autopat[(int)EVENT_INSERTCHARPRE] != NULL); +- } +- +- /* +- * Return TRUE when there is an CmdUndefined autocommand defined. +- */ +- int +- has_cmdundefined(void) +- { +- return (first_autopat[(int)EVENT_CMDUNDEFINED] != NULL); +- } +- +- /* +- * Return TRUE when there is an FuncUndefined autocommand defined. +- */ +- int +- has_funcundefined(void) +- { +- return (first_autopat[(int)EVENT_FUNCUNDEFINED] != NULL); +- } +- +- #if defined(FEAT_EVAL) || defined(PROTO) +- /* +- * Return TRUE when there is a TextYankPost autocommand defined. +- */ +- int +- has_textyankpost(void) +- { +- return (first_autopat[(int)EVENT_TEXTYANKPOST] != NULL); +- } +- #endif +- +- /* +- * Execute autocommands for "event" and file name "fname". +- * Return TRUE if some commands were executed. +- */ +- static int +- apply_autocmds_group( +- event_T event, +- char_u *fname, /* NULL or empty means use actual file name */ +- char_u *fname_io, /* fname to use for <afile> on cmdline, NULL means +- use fname */ +- int force, /* when TRUE, ignore autocmd_busy */ +- int group, /* group ID, or AUGROUP_ALL */ +- buf_T *buf, /* buffer for <abuf> */ +- exarg_T *eap UNUSED) /* command arguments */ +- { +- char_u *sfname = NULL; /* short file name */ +- char_u *tail; +- int save_changed; +- buf_T *old_curbuf; +- int retval = FALSE; +- char_u *save_sourcing_name; +- linenr_T save_sourcing_lnum; +- 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; +- +- /* +- * Quickly return if there are no autocommands for this event or +- * autocommands are blocked. +- */ +- if (event == NUM_EVENTS || first_autopat[(int)event] == NULL +- || autocmd_blocked > 0) +- goto BYPASS_AU; +- +- /* +- * When autocommands are busy, new autocommands are only executed when +- * explicitly enabled with the "nested" flag. +- */ +- if (autocmd_busy && !(force || autocmd_nested)) +- goto BYPASS_AU; +- +- #ifdef FEAT_EVAL +- /* +- * Quickly return when immediately aborting on error, or when an interrupt +- * occurred or an exception was thrown but not caught. +- */ +- if (aborting()) +- goto BYPASS_AU; +- #endif +- +- /* +- * FileChangedShell never nests, because it can create an endless loop. +- */ +- if (filechangeshell_busy && (event == EVENT_FILECHANGEDSHELL +- || event == EVENT_FILECHANGEDSHELLPOST)) +- goto BYPASS_AU; +- +- /* +- * Ignore events in 'eventignore'. +- */ +- if (event_ignored(event)) +- goto BYPASS_AU; +- +- /* +- * Allow nesting of autocommands, but restrict the depth, because it's +- * possible to create an endless loop. +- */ +- if (nesting == 10) +- { +- emsg(_("E218: autocommand nesting too deep")); +- goto BYPASS_AU; +- } +- +- /* +- * Check if these autocommands are disabled. Used when doing ":all" or +- * ":ball". +- */ +- if ( (autocmd_no_enter +- && (event == EVENT_WINENTER || event == EVENT_BUFENTER)) +- || (autocmd_no_leave +- && (event == EVENT_WINLEAVE || event == EVENT_BUFLEAVE))) +- goto BYPASS_AU; +- +- /* +- * Save the autocmd_* variables and info about the current buffer. +- */ +- 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; +- +- /* +- * Set the file name to be used for <afile>. +- * Make a copy to avoid that changing a buffer name or directory makes it +- * invalid. +- */ +- 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; /* call FullName_save() later */ +- +- /* +- * Set the buffer number to be used for <abuf>. +- */ +- if (buf == NULL) +- autocmd_bufnr = 0; +- else +- autocmd_bufnr = buf->b_fnum; +- +- /* +- * When the file name is NULL or empty, use the file name of buffer "buf". +- * Always use the full path of the file name to match with, in case +- * "allow_dirs" is set. +- */ +- 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); /* make a copy, so we can change it */ +- } +- else +- { +- sfname = vim_strsave(fname); +- /* Don't try expanding FileType, Syntax, FuncUndefined, WindowID, +- * ColorScheme, QuickFixCmd* or DirChanged */ +- 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; /* don't expand it later */ +- } +- else +- fname = FullName_save(fname, FALSE); +- } +- if (fname == NULL) /* out of memory */ +- { +- vim_free(sfname); +- retval = FALSE; +- goto BYPASS_AU; +- } +- +- #ifdef BACKSLASH_IN_FILENAME +- /* +- * Replace all backslashes with forward slashes. This makes the +- * autocommand patterns portable between Unix and MS-DOS. +- */ +- if (sfname != NULL) +- forward_slash(sfname); +- forward_slash(fname); +- #endif +- +- #ifdef VMS +- /* remove version for correct match */ +- if (sfname != NULL) +- vms_remove_version(sfname); +- vms_remove_version(fname); +- #endif +- +- /* +- * Set the name to be used for <amatch>. +- */ +- autocmd_match = fname; +- +- +- /* Don't redraw while doing autocommands. */ +- ++RedrawingDisabled; +- save_sourcing_name = sourcing_name; +- sourcing_name = NULL; /* don't free this one */ +- save_sourcing_lnum = sourcing_lnum; +- sourcing_lnum = 0; /* no line number here */ +- +- #ifdef FEAT_EVAL +- save_current_sctx = current_sctx; +- +- # ifdef FEAT_PROFILE +- if (do_profiling == PROF_YES) +- prof_child_enter(&wait_time); /* doesn't count for the caller itself */ +- # endif +- +- // Don't use local function variables, if called from a function. +- save_funccal(&funccal_entry); +- #endif +- +- /* +- * When starting to execute autocommands, save the search patterns. +- */ +- if (!autocmd_busy) +- { +- save_search_patterns(); +- #ifdef FEAT_INS_EXPAND +- if (!ins_compl_active()) +- #endif +- { +- saveRedobuff(&save_redo); +- did_save_redobuff = TRUE; +- } +- did_filetype = keep_filetype; +- } +- +- /* +- * Note that we are applying autocmds. Some commands need to know. +- */ +- autocmd_busy = TRUE; +- filechangeshell_busy = (event == EVENT_FILECHANGEDSHELL); +- ++nesting; /* see matching decrement below */ +- +- /* Remember that FileType was triggered. Used for did_filetype(). */ +- if (event == EVENT_FILETYPE) +- did_filetype = TRUE; +- +- tail = gettail(fname); +- +- /* Find first autocommand that matches */ +- 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); +- +- /* found one, start executing the autocommands */ +- if (patcmd.curpat != NULL) +- { +- /* add to active_apc_list */ +- patcmd.next = active_apc_list; +- active_apc_list = &patcmd; +- +- #ifdef FEAT_EVAL +- /* set v:cmdarg (only when there is a matching pattern) */ +- 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; /* avoid gcc warning */ +- #endif +- retval = TRUE; +- /* mark the last pattern, to avoid an endless loop when more patterns +- * are added when executing autocommands */ +- for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next) +- ap->last = FALSE; +- ap->last = TRUE; +- check_lnums(TRUE); /* make sure cursor and topline are valid */ +- do_cmdline(NULL, getnextac, (void *)&patcmd, +- DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); +- #ifdef FEAT_EVAL +- if (eap != NULL) +- { +- (void)set_cmdarg(NULL, save_cmdarg); +- set_vim_var_nr(VV_CMDBANG, save_cmdbang); +- } +- #endif +- /* delete from active_apc_list */ +- if (active_apc_list == &patcmd) /* just in case */ +- active_apc_list = patcmd.next; +- } +- +- --RedrawingDisabled; +- autocmd_busy = save_autocmd_busy; +- filechangeshell_busy = FALSE; +- autocmd_nested = save_autocmd_nested; +- vim_free(sourcing_name); +- sourcing_name = save_sourcing_name; +- sourcing_lnum = save_sourcing_lnum; +- 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; /* see matching increment above */ +- +- /* +- * When stopping to execute autocommands, restore the search patterns and +- * the redo buffer. Free any buffers in the au_pending_free_buf list and +- * free any windows in the au_pending_free_win list. +- */ +- 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; +- } +- } +- +- /* +- * Some events don't set or reset the Changed flag. +- * Check if still in the same buffer! +- */ +- 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(); /* may really delete removed patterns/commands now */ +- +- BYPASS_AU: +- /* When wiping out a buffer make sure all its buffer-local autocommands +- * are deleted. */ +- 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 +- +- /* +- * Block triggering autocommands until unblock_autocmd() is called. +- * Can be used recursively, so long as it's symmetric. +- */ +- void +- block_autocmds(void) +- { +- # ifdef FEAT_EVAL +- /* Remember the value of v:termresponse. */ +- if (autocmd_blocked == 0) +- old_termresponse = get_vim_var_str(VV_TERMRESPONSE); +- # endif +- ++autocmd_blocked; +- } +- +- void +- unblock_autocmds(void) +- { +- --autocmd_blocked; +- +- # ifdef FEAT_EVAL +- /* When v:termresponse was set while autocommands were blocked, trigger +- * the autocommands now. Esp. useful when executing a shell command +- * during startup (vimdiff). */ +- if (autocmd_blocked == 0 +- && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) +- apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf); +- # endif +- } +- +- #if defined(FEAT_EVAL) && (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM)) \ +- || defined(PROTO) +- int +- is_autocmd_blocked(void) +- { +- return autocmd_blocked != 0; +- } +- #endif +- +- /* +- * Find next autocommand pattern that matches. +- */ +- static void +- auto_next_pat( +- AutoPatCmd *apc, +- int stop_at_last) /* stop when 'last' flag is set */ +- { +- AutoPat *ap; +- AutoCmd *cp; +- char_u *name; +- char *s; +- +- VIM_CLEAR(sourcing_name); +- +- for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) +- { +- apc->curpat = NULL; +- +- /* Only use a pattern when it has not been removed, has commands and +- * the group matches. For buffer-local autocommands only check the +- * buffer number. */ +- if (ap->pat != NULL && ap->cmds != NULL +- && (apc->group == AUGROUP_ALL || apc->group == ap->group)) +- { +- /* execution-condition */ +- 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_name = alloc((unsigned)(STRLEN(s) +- + STRLEN(name) + ap->patlen + 1)); +- if (sourcing_name != NULL) +- { +- sprintf((char *)sourcing_name, s, +- (char *)name, (char *)ap->pat); +- if (p_verbose >= 8) +- { +- verbose_enter(); +- smsg(_("Executing %s"), sourcing_name); +- verbose_leave(); +- } +- } +- +- apc->curpat = ap; +- apc->nextcmd = ap->cmds; +- /* mark last command */ +- for (cp = ap->cmds; cp->next != NULL; cp = cp->next) +- cp->last = FALSE; +- cp->last = TRUE; +- } +- line_breakcheck(); +- if (apc->curpat != NULL) /* found a match */ +- break; +- } +- if (stop_at_last && ap->last) +- break; +- } +- } +- +- /* +- * Get next autocommand command. +- * Called by do_cmdline() to get the next line for ":if". +- * Returns allocated string, or NULL for end of autocommands. +- */ +- char_u * +- getnextac(int c UNUSED, void *cookie, int indent UNUSED) +- { +- AutoPatCmd *acp = (AutoPatCmd *)cookie; +- char_u *retval; +- AutoCmd *ac; +- +- /* Can be called again after returning the last line. */ +- if (acp->curpat == NULL) +- return NULL; +- +- /* repeat until we find an autocommand to execute */ +- for (;;) +- { +- /* skip removed commands */ +- 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; +- +- /* at end of commands, find next pattern that matches */ +- 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"); /* don't overwrite this either */ +- verbose_leave_scroll(); +- } +- retval = vim_strsave(ac->cmd); +- 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; +- } +- +- /* +- * Return TRUE if there is a matching autocommand for "fname". +- * To account for buffer-local autocommands, function needs to know +- * in which buffer the file will be opened. +- */ +- 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 +- /* +- * Replace all backslashes with forward slashes. This makes the +- * autocommand patterns portable between Unix and MS-DOS. +- */ +- sfname = vim_strsave(sfname); +- if (sfname != NULL) +- forward_slash(sfname); +- forward_slash(fname); +- #endif +- +- for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) +- 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; +- } +- +- #if defined(FEAT_CMDL_COMPL) || defined(PROTO) +- /* +- * Function given to ExpandGeneric() to obtain the list of autocommand group +- * names. +- */ +- char_u * +- get_augroup_name(expand_T *xp UNUSED, int idx) +- { +- if (idx == augroups.ga_len) /* add "END" add the end */ +- return (char_u *)"END"; +- if (idx >= augroups.ga_len) /* end of list */ +- return NULL; +- if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) +- /* skip deleted entries */ +- return (char_u *)""; +- return AUGROUP_NAME(idx); /* return a name */ +- } +- +- static int include_groups = FALSE; +- +- char_u * +- set_context_in_autocmd( +- expand_T *xp, +- char_u *arg, +- int doautocmd) /* TRUE for :doauto*, FALSE for :autocmd */ +- { +- char_u *p; +- int group; +- +- /* check for a group name, skip it if present */ +- include_groups = FALSE; +- p = arg; +- group = au_get_grouparg(&arg); +- if (group == AUGROUP_ERROR) +- return NULL; +- /* If there only is a group name that's what we expand. */ +- if (*arg == NUL && group != AUGROUP_ALL && !VIM_ISWHITE(arg[-1])) +- { +- arg = p; +- group = AUGROUP_ALL; +- } +- +- /* skip over event name */ +- 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; /* expand event name */ +- xp->xp_pattern = arg; +- return NULL; +- } +- +- /* skip over pattern */ +- arg = skipwhite(p); +- while (*arg && (!VIM_ISWHITE(*arg) || arg[-1] == '\\')) +- arg++; +- if (*arg) +- return arg; /* expand (next) command */ +- +- if (doautocmd) +- xp->xp_context = EXPAND_FILES; /* expand file names */ +- else +- xp->xp_context = EXPAND_NOTHING; /* pattern is not expanded */ +- return NULL; +- } +- +- /* +- * Function given to ExpandGeneric() to obtain the list of event names. +- */ +- char_u * +- get_event_name(expand_T *xp UNUSED, int idx) +- { +- if (idx < augroups.ga_len) /* First list group names, if wanted */ +- { +- if (!include_groups || AUGROUP_NAME(idx) == NULL +- || AUGROUP_NAME(idx) == get_deleted_augroup()) +- return (char_u *)""; /* skip deleted entries */ +- return AUGROUP_NAME(idx); /* return a name */ +- } +- return (char_u *)event_names[idx - augroups.ga_len].name; +- } +- +- #endif /* FEAT_CMDL_COMPL */ +- +- #if defined(FEAT_EVAL) || defined(PROTO) +- /* +- * Return TRUE if autocmd is supported. +- */ +- int +- autocmd_supported(char_u *name) +- { +- char_u *p; +- +- return (event_name2nr(name, &p) != NUM_EVENTS); +- } +- +- /* +- * Return TRUE if an autocommand is defined for a group, event and +- * pattern: The group can be omitted to accept any group. "event" and "pattern" +- * can be NULL to accept any event and pattern. "pattern" can be NULL to accept +- * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted. +- * Used for: +- * exists("#Group") or +- * exists("#Group#Event") or +- * exists("#Group#Event#pat") or +- * exists("#Event") or +- * exists("#Event#pat") +- */ +- 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; +- +- /* Make a copy so that we can change the '#' chars to a NUL. */ +- arg_save = vim_strsave(arg); +- if (arg_save == NULL) +- return FALSE; +- p = vim_strchr(arg_save, '#'); +- if (p != NULL) +- *p++ = NUL; +- +- /* First, look for an autocmd group name */ +- group = au_find_group(arg_save); +- if (group == AUGROUP_ERROR) +- { +- /* Didn't match a group name, assume the first argument is an event. */ +- group = AUGROUP_ALL; +- event_name = arg_save; +- } +- else +- { +- if (p == NULL) +- { +- /* "Group": group name is present and it's recognized */ +- retval = TRUE; +- goto theend; +- } +- +- /* Must be "Group#Event" or "Group#Event#pat". */ +- event_name = p; +- p = vim_strchr(event_name, '#'); +- if (p != NULL) +- *p++ = NUL; /* "Group#Event#pat" */ +- } +- +- pattern = p; /* "pattern" is NULL when there is no pattern */ +- +- /* find the index (enum) for the event name */ +- event = event_name2nr(event_name, &p); +- +- /* return FALSE if the event name is not recognized */ +- if (event == NUM_EVENTS) +- goto theend; +- +- /* Find the first autocommand for this event. +- * If there isn't any, return FALSE; +- * If there is one and no pattern given, return TRUE; */ +- ap = first_autopat[(int)event]; +- if (ap == NULL) +- goto theend; +- +- /* if pattern is "<buffer>", special handling is needed which uses curbuf */ +- /* for pattern "<buffer=N>, fnamecmp() will work fine */ +- if (pattern != NULL && STRICMP(pattern, "<buffer>") == 0) +- buflocal_buf = curbuf; +- +- /* Check if there is an autocommand with the given pattern. */ +- for ( ; ap != NULL; ap = ap->next) +- /* only use a pattern when it has not been removed and has commands. */ +- /* For buffer-local autocommands, fnamecmp() works fine. */ +- 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 +- +- + /* + * Try matching a filename with a "pattern" ("prog" is NULL), or use the + * precompiled regprog "prog" ("pattern" is NULL). That avoids calling +--- 7535,7540 ---- +*************** +*** 10118,10124 **** + * Used for autocommands and 'wildignore'. + * Returns TRUE if there is a match, FALSE otherwise. + */ +! static int + match_file_pat( + char_u *pattern, /* pattern to match with */ + regprog_T **prog, /* pre-compiled regprog or NULL */ +--- 7542,7548 ---- + * Used for autocommands and 'wildignore'. + * Returns TRUE if there is a match, FALSE otherwise. + */ +! int + match_file_pat( + char_u *pattern, /* pattern to match with */ + regprog_T **prog, /* pre-compiled regprog or NULL */ +*** ../vim-8.1.0824/src/globals.h 2019-01-24 17:18:37.599462306 +0100 +--- src/globals.h 2019-01-26 15:16:55.569118519 +0100 +*************** +*** 397,402 **** +--- 397,403 ---- + EXTERN int autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */ + EXTERN int modified_was_set; /* did ":set modified" */ + EXTERN int did_filetype INIT(= FALSE); /* FileType event found */ ++ EXTERN int au_did_filetype INIT(= FALSE); + EXTERN int keep_filetype INIT(= FALSE); /* value for did_filetype when + starting to execute + autocommands */ +*** ../vim-8.1.0824/src/proto.h 2019-01-24 17:18:37.599462306 +0100 +--- src/proto.h 2019-01-26 15:16:55.569118519 +0100 +*************** +*** 62,67 **** +--- 62,68 ---- + # include "crypt.pro" + # include "crypt_zip.pro" + # endif ++ # include "autocmd.pro" + # include "buffer.pro" + # include "charset.pro" + # ifdef FEAT_CSCOPE +*** ../vim-8.1.0824/src/proto/autocmd.pro 2019-01-26 16:20:09.788993106 +0100 +--- src/proto/autocmd.pro 2019-01-26 15:18:20.796687736 +0100 +*************** +*** 0 **** +--- 1,39 ---- ++ /* autocmd.c */ ++ void aubuflocal_remove(buf_T *buf); ++ int au_has_group(char_u *name); ++ void do_augroup(char_u *arg, int del_group); ++ void free_all_autocmds(void); ++ int check_ei(void); ++ char_u *au_event_disable(char *what); ++ void au_event_restore(char_u *old_ei); ++ void do_autocmd(char_u *arg_in, int forceit); ++ int do_doautocmd(char_u *arg, int do_msg, int *did_something); ++ void ex_doautoall(exarg_T *eap); ++ int check_nomodeline(char_u **argp); ++ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf); ++ void aucmd_restbuf(aco_save_T *aco); ++ int apply_autocmds(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf); ++ int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap); ++ int apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, int *retval); ++ int has_cursorhold(void); ++ int trigger_cursorhold(void); ++ int has_cursormoved(void); ++ int has_cursormovedI(void); ++ int has_textchanged(void); ++ int has_textchangedI(void); ++ int has_textchangedP(void); ++ int has_insertcharpre(void); ++ int has_cmdundefined(void); ++ int has_funcundefined(void); ++ int has_textyankpost(void); ++ void block_autocmds(void); ++ void unblock_autocmds(void); ++ int is_autocmd_blocked(void); ++ char_u *getnextac(int c, void *cookie, int indent); ++ int has_autocmd(event_T event, char_u *sfname, buf_T *buf); ++ char_u *get_augroup_name(expand_T *xp, int idx); ++ char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd); ++ char_u *get_event_name(expand_T *xp, int idx); ++ int autocmd_supported(char_u *name); ++ int au_exists(char_u *arg); ++ /* vim: set ft=c : */ +*** ../vim-8.1.0824/src/proto/fileio.pro 2018-05-17 13:52:36.000000000 +0200 +--- src/proto/fileio.pro 2019-01-26 15:18:24.756667414 +0100 +*************** +*** 28,69 **** + void vim_deltempdir(void); + char_u *vim_tempname(int extra_char, int keep); + void forward_slash(char_u *fname); +! void aubuflocal_remove(buf_T *buf); +! int au_has_group(char_u *name); +! void do_augroup(char_u *arg, int del_group); +! void free_all_autocmds(void); +! int check_ei(void); +! char_u *au_event_disable(char *what); +! void au_event_restore(char_u *old_ei); +! void do_autocmd(char_u *arg_in, int forceit); +! int do_doautocmd(char_u *arg, int do_msg, int *did_something); +! void ex_doautoall(exarg_T *eap); +! int check_nomodeline(char_u **argp); +! void aucmd_prepbuf(aco_save_T *aco, buf_T *buf); +! void aucmd_restbuf(aco_save_T *aco); +! int apply_autocmds(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf); +! int apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, int *retval); +! int has_cursorhold(void); +! int trigger_cursorhold(void); +! int has_cursormoved(void); +! int has_cursormovedI(void); +! int has_textchanged(void); +! int has_textchangedI(void); +! int has_textchangedP(void); +! int has_insertcharpre(void); +! int has_cmdundefined(void); +! int has_funcundefined(void); +! int has_textyankpost(void); +! void block_autocmds(void); +! void unblock_autocmds(void); +! int is_autocmd_blocked(void); +! char_u *getnextac(int c, void *cookie, int indent); +! int has_autocmd(event_T event, char_u *sfname, buf_T *buf); +! char_u *get_augroup_name(expand_T *xp, int idx); +! char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd); +! char_u *get_event_name(expand_T *xp, int idx); +! int autocmd_supported(char_u *name); +! int au_exists(char_u *arg); + int match_file_list(char_u *list, char_u *sfname, char_u *ffname); + char_u *file_pat_to_reg_pat(char_u *pat, char_u *pat_end, char *allow_dirs, int no_bslash); + long read_eintr(int fd, void *buf, size_t bufsize); +--- 28,34 ---- + void vim_deltempdir(void); + char_u *vim_tempname(int extra_char, int keep); + void forward_slash(char_u *fname); +! int match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname, char_u *sfname, char_u *tail, int allow_dirs); + int match_file_list(char_u *list, char_u *sfname, char_u *ffname); + char_u *file_pat_to_reg_pat(char_u *pat, char_u *pat_end, char *allow_dirs, int no_bslash); + long read_eintr(int fd, void *buf, size_t bufsize); +*** ../vim-8.1.0824/src/version.c 2019-01-26 15:12:52.558260916 +0100 +--- src/version.c 2019-01-26 15:18:32.780626166 +0100 +*************** +*** 789,790 **** +--- 789,792 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 825, + /**/ + +-- +A real patriot is the fellow who gets a parking ticket and rejoices +that the system works. + + + /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ +/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ +\\\ an exciting new programming language -- http://www.Zimbu.org /// + \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |