# HG changeset patch # User Christian Brabandt # Date 1520775905 -3600 # Node ID 94e638936d3ee75991f6add5b3a4fb29af8a54b8 # Parent 16773ccde7fe1875e8ec90956dd9a7783a6422a1 patch 8.0.1595: no autocommand triggered before exiting commit https://github.com/vim/vim/commit/12a96de430779b88795fac87a2be666d9f661d1e Author: Bram Moolenaar Date: Sun Mar 11 14:44:18 2018 +0100 patch 8.0.1595: no autocommand triggered before exiting Problem: No autocommand triggered before exiting. Solution: Add the ExitPre autocommand event. diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -285,7 +285,8 @@ Name triggered by ~ |GUIFailed| after starting the GUI failed |TermResponse| after the terminal response to |t_RV| is received -|QuitPre| when using `:quit`, before deciding whether to quit +|QuitPre| when using `:quit`, before deciding whether to exit +|ExitPre| when using a command that may make Vim exit |VimLeavePre| before exiting Vim, before writing the viminfo file |VimLeave| before exiting Vim, after writing the viminfo file @@ -651,6 +652,11 @@ DirChanged The working directory has c "auto" to trigger on 'autochdir'. "drop" to trigger on editing a file is set to the new directory name. + *ExitPre* +ExitPre When using `:quit`, `:wq` in a way it makes + Vim exit, or using `:qall`, just after + |QuitPre|. Can be used to close any + non-essential window. *FileChangedShell* FileChangedShell When Vim notices that the modification time of a file has changed since editing started. @@ -866,6 +872,7 @@ QuitPre When using `:quit`, `:wq` or or quits Vim. Can be used to close any non-essential window if the current window is the last ordinary window. + Also see |ExitPre|. *RemoteReply* RemoteReply When a reply from a Vim that functions as server was received |server2client()|. The diff --git a/src/Makefile b/src/Makefile --- a/src/Makefile +++ b/src/Makefile @@ -2155,6 +2155,7 @@ test_arglist \ test_eval_stuff \ test_ex_undo \ test_ex_z \ + test_exit \ test_exec_while_if \ test_execute_func \ test_exists \ diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7187,8 +7187,35 @@ not_exiting(void) settmode(TMODE_RAW); } + static int +before_quit_autocmds(win_T *wp, int quit_all, int forceit) +{ + apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, wp->w_buffer); + + /* Bail out when autocommands closed the window. + * Refuse to quit when the buffer in the last window is being closed (can + * only happen in autocommands). */ + if (!win_valid(wp) + || curbuf_locked() + || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0)) + return TRUE; + + if (quit_all || (check_more(FALSE, forceit) == OK && only_one_window())) + { + apply_autocmds(EVENT_EXITPRE, NULL, NULL, FALSE, curbuf); + /* Refuse to quit when locked or when the buffer in the last window is + * being closed (can only happen in autocommands). */ + if (curbuf_locked() + || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) + return TRUE; + } + + return FALSE; +} + /* * ":quit": quit current window, quit Vim if the last window is closed. + * ":{nr}quit": quit window {nr} */ static void ex_quit(exarg_T *eap) @@ -7222,12 +7249,9 @@ ex_quit(exarg_T *eap) /* Refuse to quit when locked. */ if (curbuf_locked()) return; - apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, wp->w_buffer); - /* Bail out when autocommands closed the window. - * Refuse to quit when the buffer in the last window is being closed (can - * only happen in autocommands). */ - if (!win_valid(wp) - || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0)) + + /* Trigger QuitPre and maybe ExitPre */ + if (before_quit_autocmds(wp, FALSE, eap->forceit)) return; #ifdef FEAT_NETBEANS_INTG @@ -7301,10 +7325,8 @@ ex_quit_all(exarg_T *eap) text_locked_msg(); return; } - apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); - /* Refuse to quit when locked or when the buffer in the last window is - * being closed (can only happen in autocommands). */ - if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) + + if (before_quit_autocmds(curwin, TRUE, eap->forceit)) return; exiting = TRUE; @@ -7743,7 +7765,7 @@ ex_stop(exarg_T *eap) } /* - * ":exit", ":xit" and ":wq": Write file and exit Vim. + * ":exit", ":xit" and ":wq": Write file and quite the current window. */ static void ex_exit(exarg_T *eap) @@ -7761,10 +7783,8 @@ ex_exit(exarg_T *eap) text_locked_msg(); return; } - apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); - /* Refuse to quit when locked or when the buffer in the last window is - * being closed (can only happen in autocommands). */ - if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) + + if (before_quit_autocmds(curwin, FALSE, eap->forceit)) return; /* diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -7724,6 +7724,7 @@ static struct event_name {"CursorMovedI", EVENT_CURSORMOVEDI}, {"DirChanged", EVENT_DIRCHANGED}, {"EncodingChanged", EVENT_ENCODINGCHANGED}, + {"ExitPre", EVENT_EXITPRE}, {"FileEncoding", EVENT_ENCODINGCHANGED}, {"FileAppendPost", EVENT_FILEAPPENDPOST}, {"FileAppendPre", EVENT_FILEAPPENDPRE}, diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -97,6 +97,7 @@ NEW_TESTS = test_arabic.res \ test_exec_while_if.res \ test_exists.res \ test_exists_autocmd.res \ + test_exit.res \ test_farsi.res \ test_file_size.res \ test_find_complete.res \ diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim new file mode 100644 --- /dev/null +++ b/src/testdir/test_exit.vim @@ -0,0 +1,57 @@ +" Tests for exiting Vim. + +source shared.vim + +func Test_exiting() + let after = [ + \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")', + \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")', + \ 'quit', + \ ] + if RunVim([], after, '') + call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout')) + endif + call delete('Xtestout') + + let after = [ + \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")', + \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")', + \ 'help', + \ 'wincmd w', + \ 'quit', + \ ] + if RunVim([], after, '') + call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout')) + endif + call delete('Xtestout') + + let after = [ + \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")', + \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")', + \ 'split', + \ 'new', + \ 'qall', + \ ] + if RunVim([], after, '') + call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout')) + endif + call delete('Xtestout') + + let after = [ + \ 'au QuitPre * call writefile(["QuitPre"], "Xtestout", "a")', + \ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")', + \ 'augroup nasty', + \ ' au ExitPre * split', + \ 'augroup END', + \ 'quit', + \ 'augroup nasty', + \ ' au! ExitPre', + \ 'augroup END', + \ 'quit', + \ ] + if RunVim([], after, '') + call assert_equal(['QuitPre', 'ExitPre', 'QuitPre', 'ExitPre'], + \ readfile('Xtestout')) + endif + call delete('Xtestout') +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -767,6 +767,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1595, +/**/ 1594, /**/ 1593, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -1277,6 +1277,7 @@ enum auto_event EVENT_COLORSCHEME, /* after loading a colorscheme */ EVENT_COMPLETEDONE, /* after finishing insert complete */ EVENT_DIRCHANGED, /* after changing directory as a result of user cmd */ + EVENT_EXITPRE, /* before exiting */ EVENT_FILEAPPENDPOST, /* after appending to a file */ EVENT_FILEAPPENDPRE, /* before appending to a file */ EVENT_FILEAPPENDCMD, /* append to a file using command */