Merge pull request #37422 from zeertzjq/vim-9.1.0059

vim-patch:9.1.{0059,0117,0671,1043,partial:1110}: WinNewPre
This commit is contained in:
zeertzjq
2026-01-16 16:18:02 +08:00
committed by GitHub
10 changed files with 165 additions and 30 deletions

View File

@@ -1232,6 +1232,20 @@ WinLeave Before leaving a window. If the window to be
WinLeave autocommands (but not for ":new").
Not used for ":qa" or ":q" when exiting Vim.
Before WinClosed.
*WinNewPre*
WinNewPre Before creating a new window. Triggered
before commands that modify window layout by
creating a split.
Not done when creating tab pages and for the
first window, as the window structure is not
initialized yet and so is generally not safe.
It is not allowed to modify window layout
while executing commands for the WinNewPre
event.
Most useful to store current window layout
and compare it with the new layout after the
Window has been created.
*WinNew*
WinNew When a new window was created. Not done for
the first window, when Vim has just started.

View File

@@ -2580,7 +2580,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|VimResized|,
|VimResume|,
|VimSuspend|,
|WinNew|
|WinNew|,
|WinNewPre|
*'expandtab'* *'et'* *'noexpandtab'* *'noet'*
'expandtab' 'et' boolean (default off)

View File

@@ -218,6 +218,7 @@ error('Cannot require a meta file')
--- |'WinEnter'
--- |'WinLeave'
--- |'WinNew'
--- |'WinNewPre'
--- |'WinResized'
--- |'WinScrolled'

View File

@@ -2258,7 +2258,8 @@ vim.go.ei = vim.go.eventignore
--- `VimResized`,
--- `VimResume`,
--- `VimSuspend`,
--- `WinNew`
--- `WinNew`,
--- `WinNewPre`
---
--- @type string
vim.o.eventignorewin = ""

View File

@@ -138,7 +138,8 @@ return {
WinClosed = true, -- after closing a window
WinEnter = true, -- after entering a window
WinLeave = true, -- before leaving a window
WinNew = false, -- when entering a new window
WinNewPre = false, -- before creating a new window
WinNew = false, -- after creating a new window
WinResized = true, -- after a window was resized
WinScrolled = true, -- after a window was scrolled or resized
},

View File

@@ -1127,6 +1127,10 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl
return NULL;
}
if (new_wp == NULL) {
trigger_winnewpre();
}
win_T *oldwin;
if (flags & WSP_TOP) {
oldwin = firstwin;
@@ -3069,6 +3073,13 @@ int win_close(win_T *win, bool free_buf, bool force)
return OK;
}
static void trigger_winnewpre(void)
{
window_layout_lock();
apply_autocmds(EVENT_WINNEWPRE, NULL, NULL, false, NULL);
window_layout_unlock();
}
static void do_autocmd_winclosed(win_T *win)
FUNC_ATTR_NONNULL_ALL
{
@@ -4351,6 +4362,10 @@ void free_tabpage(tabpage_T *tp)
///
/// It will edit the current buffer, like after :split.
///
/// Does not trigger WinNewPre, since the window structures
/// are not completely setup yet and could cause dereferencing
/// NULL pointers
///
/// @param after Put new tabpage after tabpage "after", or after the current
/// tabpage in case of 0.
/// @param filename Will be passed to apply_autocmds().

Binary file not shown.

View File

@@ -276,7 +276,9 @@ endfunc
func Test_win_tab_autocmd()
let g:record = []
defer CleanUpTestAuGroup()
augroup testing
au WinNewPre * call add(g:record, 'WinNewPre')
au WinNew * call add(g:record, 'WinNew')
au WinClosed * call add(g:record, 'WinClosed')
au WinEnter * call add(g:record, 'WinEnter')
@@ -293,7 +295,7 @@ func Test_win_tab_autocmd()
close
call assert_equal([
\ 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter',
\ 'WinLeave', 'WinClosed', 'WinEnter'
@@ -310,10 +312,81 @@ func Test_win_tab_autocmd()
\ 'WinClosed', 'TabClosed'
\ ], g:record)
let g:record = []
copen
help
tabnext
vnew
call assert_equal([
\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter'
\ ], g:record)
unlet g:record
endfunc
func Test_WinNewPre()
" Test that the old window layout can be accessed before a new window is created.
let g:layouts_pre = []
let g:layouts_post = []
augroup testing
au WinNewPre * call add(g:layouts_pre, winlayout())
au WinNew * call add(g:layouts_post, winlayout())
augroup END
defer CleanUpTestAuGroup()
split
call assert_notequal(g:layouts_pre[0], g:layouts_post[0])
split
call assert_equal(g:layouts_pre[1], g:layouts_post[0])
call assert_notequal(g:layouts_pre[1], g:layouts_post[1])
" not triggered for tabnew
tabnew
call assert_equal(2, len(g:layouts_pre))
unlet g:layouts_pre
unlet g:layouts_post
" Test modifying window layout during WinNewPre throws.
let g:caught = 0
augroup testing
au!
au WinNewPre * split
augroup END
unlet g:record
try
vnew
catch
let g:caught += 1
endtry
augroup testing
au!
au WinNewPre * tabnew
augroup END
try
vnew
catch
let g:caught += 1
endtry
augroup testing
au!
au WinNewPre * close
augroup END
try
vnew
catch
let g:caught += 1
endtry
augroup testing
au!
au WinNewPre * tabclose
augroup END
try
vnew
catch
let g:caught += 1
endtry
call assert_equal(4, g:caught)
unlet g:caught
endfunc
func Test_WinResized()
@@ -2820,7 +2893,8 @@ endfunc
func Test_autocmd_nested()
let g:did_nested = 0
augroup Testing
defer CleanUpTestAuGroup()
augroup testing
au WinNew * edit somefile
au BufNew * let g:did_nested = 1
augroup END
@@ -2830,7 +2904,7 @@ func Test_autocmd_nested()
bwipe! somefile
" old nested argument still works
augroup Testing
augroup testing
au!
au WinNew * nested edit somefile
au BufNew * let g:did_nested = 1
@@ -4378,6 +4452,38 @@ func Test_BufEnter_botline()
set hidden&vim
endfunc
" those commands caused null pointer access, see #15464
func Test_WinNewPre_crash()
defer CleanUpTestAuGroup()
let _cmdheight=&cmdheight
augroup testing
au!
autocmd WinNewPre * redraw
augroup END
tabnew
tabclose
augroup testing
au!
autocmd WinNewPre * wincmd t
augroup END
tabnew
tabclose
augroup testing
au!
autocmd WinNewPre * wincmd b
augroup END
tabnew
tabclose
augroup testing
au!
autocmd WinNewPre * set cmdheight+=1
augroup END
tabnew
tabclose
let &cmdheight=_cmdheight
endfunc
" This was using freed memory
func Test_autocmd_BufWinLeave_with_vsp()
new

View File

@@ -191,52 +191,49 @@ func Test_crash1_3()
let buf = RunVimInTerminal('sh', #{cmd: 'sh'})
let file = 'crash/poc_ex_substitute'
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 150)
call s:RunCommandAndWait(buf, args)
let file = 'crash/poc_uaf_exec_instructions'
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 150)
call s:RunCommandAndWait(buf, args)
let file = 'crash/poc_uaf_check_argument_types'
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 150)
call s:RunCommandAndWait(buf, args)
let file = 'crash/double_free'
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 50)
call s:RunCommandAndWait(buf, args)
let file = 'crash/dialog_changed_uaf'
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 150)
call s:RunCommandAndWait(buf, args)
let file = 'crash/nullpointer'
let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call s:RunCommandAndWait(buf, args)
let file = 'crash/heap_overflow3'
let cmn_args = "%s -u NONE -i NONE -n -X -m -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 150)
call s:RunCommandAndWait(buf, args)
let file = 'crash/heap_overflow_glob2regpat'
let cmn_args = "%s -u NONE -i NONE -n -X -m -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 50)
call s:RunCommandAndWait(buf, args)
let file = 'crash/nullptr_regexp_nfa'
let cmn_args = "%s -u NONE -i NONE -n -X -m -n -e -s -S %s -c ':qa!'"
let args = printf(cmn_args, vim, file)
call term_sendkeys(buf, args)
call TermWait(buf, 50)
call s:RunCommandAndWait(buf, args)
" clean up
exe buf .. "bw!"

View File

@@ -1043,8 +1043,7 @@ func Test_win_splitmove()
let s:triggered = []
augroup WinSplitMove
au!
" Nvim: WinNewPre not ported yet. Also needs full port of v9.1.0117 to pass.
" au WinNewPre * let s:triggered += ['WinNewPre']
au WinNewPre * let s:triggered += ['WinNewPre']
au WinNew * let s:triggered += ['WinNew', win_getid()]
au WinClosed * let s:triggered += ['WinClosed', str2nr(expand('<afile>'))]
augroup END