Merge #8953 from janlazo/vim-8.0.1190

This commit is contained in:
Justin M. Keyes
2018-09-05 09:45:14 +02:00
committed by GitHub
6 changed files with 189 additions and 22 deletions

View File

@@ -274,7 +274,8 @@ Name triggered by ~
|GUIEnter| after starting the GUI successfully |GUIEnter| after starting the GUI successfully
|GUIFailed| after starting the GUI failed |GUIFailed| after starting the GUI failed
|TermResponse| after the terminal response to |t_RV| is received |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 Nvim, before writing the shada file |VimLeavePre| before exiting Nvim, before writing the shada file
|VimLeave| before exiting Nvim, after writing the shada file |VimLeave| before exiting Nvim, after writing the shada file
|VimResume| after Nvim is resumed |VimResume| after Nvim is resumed
@@ -646,6 +647,11 @@ FileChangedRO Before making the first change to a read-only
*E881* *E881*
If the number of lines changes saving for undo If the number of lines changes saving for undo
may fail and the change will be aborted. may fail and the change will be aborted.
*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*
FileChangedShell When Vim notices that the modification time of FileChangedShell When Vim notices that the modification time of
a file has changed since editing started. a file has changed since editing started.
@@ -862,6 +868,7 @@ QuitPre When using `:quit`, `:wq` or `:qall`, before
or quits Vim. Can be used to close any or quits Vim. Can be used to close any
non-essential window if the current window is non-essential window if the current window is
the last ordinary window. the last ordinary window.
Also see |ExitPre|.
*RemoteReply* *RemoteReply*
RemoteReply When a reply from a Vim that functions as RemoteReply When a reply from a Vim that functions as
server was received |server2client()|. The server was received |server2client()|. The

View File

@@ -34,6 +34,7 @@ return {
'CursorMovedI', -- cursor was moved in Insert mode 'CursorMovedI', -- cursor was moved in Insert mode
'DirChanged', -- directory changed 'DirChanged', -- directory changed
'EncodingChanged', -- after changing the 'encoding' option 'EncodingChanged', -- after changing the 'encoding' option
'ExitPre', -- before exiting
'FileAppendCmd', -- append to a file using command 'FileAppendCmd', -- append to a file using command
'FileAppendPost', -- after appending to a file 'FileAppendPost', -- after appending to a file
'FileAppendPre', -- before appending to a file 'FileAppendPre', -- before appending to a file

View File

@@ -1209,7 +1209,7 @@ int autowrite(buf_T *buf, int forceit)
return r; return r;
} }
/// flush all buffers, except the ones that are readonly /// Flush all buffers, except the ones that are readonly or are never written.
void autowrite_all(void) void autowrite_all(void)
{ {
if (!(p_aw || p_awa) || !p_write) { if (!(p_aw || p_awa) || !p_write) {
@@ -1217,7 +1217,7 @@ void autowrite_all(void)
} }
FOR_ALL_BUFFERS(buf) { FOR_ALL_BUFFERS(buf) {
if (bufIsChanged(buf) && !buf->b_p_ro) { if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf)) {
bufref_T bufref; bufref_T bufref;
set_bufref(&bufref, buf); set_bufref(&bufref, buf);
(void)buf_write_all(buf, false); (void)buf_write_all(buf, false);

View File

@@ -5964,9 +5964,35 @@ void not_exiting(void)
exiting = FALSE; exiting = FALSE;
} }
/* static bool before_quit_autocmds(win_T *wp, bool quit_all, int forceit)
* ":quit": quit current window, quit Vim if the last window is closed. {
*/ 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) static void ex_quit(exarg_T *eap)
{ {
if (cmdwin_type != 0) { if (cmdwin_type != 0) {
@@ -5996,11 +6022,9 @@ static void ex_quit(exarg_T *eap)
if (curbuf_locked()) { if (curbuf_locked()) {
return; return;
} }
apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, wp->w_buffer);
// Refuse to quit when locked or when the buffer in the last window is // Trigger QuitPre and maybe ExitPre
// being closed (can only happen in autocommands). if (before_quit_autocmds(wp, false, eap->forceit)) {
if (!win_valid(wp)
|| (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0)) {
return; return;
} }
@@ -6025,6 +6049,7 @@ static void ex_quit(exarg_T *eap)
if (only_one_window() && (ONE_WINDOW || eap->addr_count == 0)) { if (only_one_window() && (ONE_WINDOW || eap->addr_count == 0)) {
getout(0); getout(0);
} }
not_exiting();
// close window; may free buffer // close window; may free buffer
win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit); win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit);
} }
@@ -6057,10 +6082,8 @@ static void ex_quit_all(exarg_T *eap)
text_locked_msg(); text_locked_msg();
return; return;
} }
apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, curbuf);
// Refuse to quit when locked or when the buffer in the last window is if (before_quit_autocmds(curwin, true, eap->forceit)) {
// being closed (can only happen in autocommands).
if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) {
return; return;
} }
@@ -6346,9 +6369,7 @@ static void ex_stop(exarg_T *eap)
} }
} }
/* // ":exit", ":xit" and ":wq": Write file and quite the current window.
* ":exit", ":xit" and ":wq": Write file and exit Vim.
*/
static void ex_exit(exarg_T *eap) static void ex_exit(exarg_T *eap)
{ {
if (cmdwin_type != 0) { if (cmdwin_type != 0) {
@@ -6360,10 +6381,8 @@ static void ex_exit(exarg_T *eap)
text_locked_msg(); text_locked_msg();
return; return;
} }
apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, curbuf);
// Refuse to quit when locked or when the buffer in the last window is if (before_quit_autocmds(curwin, false, eap->forceit)) {
// being closed (can only happen in autocommands).
if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) {
return; return;
} }
@@ -6382,6 +6401,7 @@ static void ex_exit(exarg_T *eap)
// quit last window, exit Vim // quit last window, exit Vim
getout(0); getout(0);
} }
not_exiting();
// Quit current window, may free the buffer. // Quit current window, may free the buffer.
win_close(curwin, !buf_hide(curwin->w_buffer)); win_close(curwin, !buf_hide(curwin->w_buffer));
} }

View File

@@ -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

View File

@@ -31,3 +31,85 @@ func Test_writefile_fails_gently()
call assert_fails('call writefile([], [])', 'E730:') call assert_fails('call writefile([], [])', 'E730:')
endfunc endfunc
func SetFlag(timer)
let g:flag = 1
endfunc
func Test_write_quit_split()
" Prevent exiting by splitting window on file write.
augroup testgroup
autocmd BufWritePre * split
augroup END
e! Xfile
call setline(1, 'nothing')
wq
if has('timers')
" timer will not run if "exiting" is still set
let g:flag = 0
call timer_start(1, 'SetFlag')
sleep 50m
call assert_equal(1, g:flag)
unlet g:flag
endif
au! testgroup
bwipe Xfile
call delete('Xfile')
endfunc
func Test_nowrite_quit_split()
" Prevent exiting by opening a help window.
e! Xfile
help
wincmd w
exe winnr() . 'q'
if has('timers')
" timer will not run if "exiting" is still set
let g:flag = 0
call timer_start(1, 'SetFlag')
sleep 50m
call assert_equal(1, g:flag)
unlet g:flag
endif
bwipe Xfile
endfunc
func Test_writefile_autowrite()
set autowrite
new
next Xa Xb Xc
call setline(1, 'aaa')
next
call assert_equal(['aaa'], readfile('Xa'))
call setline(1, 'bbb')
call assert_fails('edit XX')
call assert_false(filereadable('Xb'))
set autowriteall
edit XX
call assert_equal(['bbb'], readfile('Xb'))
bwipe!
call delete('Xa')
call delete('Xb')
set noautowrite
endfunc
func Test_writefile_autowrite_nowrite()
set autowrite
new
next Xa Xb Xc
set buftype=nowrite
call setline(1, 'aaa')
let buf = bufnr('%')
" buffer contents silently lost
edit XX
call assert_false(filereadable('Xa'))
rewind
call assert_equal('', getline(1))
bwipe!
set noautowrite
endfunc