mirror of
https://github.com/neovim/neovim.git
synced 2025-09-19 17:58:18 +00:00
Merge #8953 from janlazo/vim-8.0.1190
This commit is contained in:
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
|
57
src/nvim/testdir/test_exit.vim
Normal file
57
src/nvim/testdir/test_exit.vim
Normal 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
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user