diff options
Diffstat (limited to 'data/vim/patches/8.1.0825')
-rw-r--r-- | data/vim/patches/8.1.0825 | 5747 |
1 files changed, 0 insertions, 5747 deletions
diff --git a/data/vim/patches/8.1.0825 b/data/vim/patches/8.1.0825 deleted file mode 100644 index d3b00eb4e..000000000 --- a/data/vim/patches/8.1.0825 +++ /dev/null @@ -1,5747 +0,0 @@ -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 /// |