forked from aniani/vim
patch 9.1.0116: win_split_ins may not check available room
Problem: win_split_ins has no check for E36 when moving an existing
window
Solution: check for room and fix the issues in f_win_splitmove()
(Sean Dewar)
win_split_ins has no check for E36 when moving an existing window,
allowing for layouts with many overlapping zero-sized windows to be
created (which may also cause drawing issues with tablines and such).
f_win_splitmove also has some bugs.
So check for room and fix the issues in f_win_splitmove. Handle failure
in the two relevant win_split_ins callers by restoring the original
layout, and factor the common logic into win_splitmove.
Don't check for room when opening an autocommand window, as it's a
temporary window that's rarely interacted with or drawn anyhow, and is
rather important for some autocommands.
Issues fixed in f_win_splitmove:
- Error if splitting is disallowed.
- Fix heap-use-after-frees if autocommands fired from switching to "targetwin"
close "wp" or "oldwin".
- Fix splitting the wrong window if autocommands fired from switching to
"targetwin" switch to a different window.
- Ensure -1 is returned for all errors.
Also handle allocation failure a bit earlier in make_snapshot (callers,
except win_splitmove, don't really care if a snapshot can't be made, so
just ignore the return value).
Note: Test_smoothscroll_in_zero_width_window failed after these changes with
E36, as it was using the previous behaviour to create a zero-width window.
I've fixed the test such that it fails with UBSAN as expected when v9.0.1367 is
reverted (and simplified it too).
related: #14042
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
15935e7f54
commit
0fd44a5ad8
@@ -290,6 +290,16 @@ func Test_window_split_no_room()
|
||||
for s in range(1, hor_split_count) | split | endfor
|
||||
call assert_fails('split', 'E36:')
|
||||
|
||||
botright vsplit
|
||||
wincmd |
|
||||
let layout = winlayout()
|
||||
let restcmd = winrestcmd()
|
||||
call assert_fails('wincmd J', 'E36:')
|
||||
call assert_fails('wincmd K', 'E36:')
|
||||
call assert_equal(layout, winlayout())
|
||||
call assert_equal(restcmd, winrestcmd())
|
||||
only
|
||||
|
||||
" N vertical windows need >= 2*(N - 1) + 1 columns:
|
||||
" - 1 column + 1 separator for each window (except last window)
|
||||
" - 1 column for the last window which does not have separator
|
||||
@@ -302,7 +312,35 @@ func Test_window_split_no_room()
|
||||
for s in range(1, ver_split_count) | vsplit | endfor
|
||||
call assert_fails('vsplit', 'E36:')
|
||||
|
||||
split
|
||||
wincmd |
|
||||
let layout = winlayout()
|
||||
let restcmd = winrestcmd()
|
||||
call assert_fails('wincmd H', 'E36:')
|
||||
call assert_fails('wincmd L', 'E36:')
|
||||
call assert_equal(layout, winlayout())
|
||||
call assert_equal(restcmd, winrestcmd())
|
||||
|
||||
" Check that the last statusline isn't lost.
|
||||
set laststatus=0
|
||||
let restcmd = winrestcmd()
|
||||
wincmd j
|
||||
call setwinvar(winnr('k'), '&statusline', '@#')
|
||||
let last_stl_row = win_screenpos(0)[0] - 1
|
||||
redraw
|
||||
call assert_equal('@#|', GetScreenStr(last_stl_row))
|
||||
call assert_equal('~ |', GetScreenStr(&lines - &cmdheight))
|
||||
call assert_fails('wincmd H', 'E36:')
|
||||
call assert_fails('wincmd L', 'E36:')
|
||||
call assert_equal(layout, winlayout())
|
||||
call assert_equal(restcmd, winrestcmd())
|
||||
call setwinvar(winnr('k'), '&statusline', '=-')
|
||||
redraw
|
||||
call assert_equal('=-|', GetScreenStr(last_stl_row))
|
||||
call assert_equal('~ |', GetScreenStr(&lines - &cmdheight))
|
||||
|
||||
%bw!
|
||||
set laststatus&
|
||||
endfunc
|
||||
|
||||
func Test_window_exchange()
|
||||
@@ -1097,6 +1135,44 @@ func Test_win_splitmove()
|
||||
tabnew
|
||||
call assert_fails('call win_splitmove(1, win_getid(1, 1))', 'E957:')
|
||||
tabclose
|
||||
|
||||
split
|
||||
augroup WinSplitMove
|
||||
au!
|
||||
au WinEnter * ++once call win_gotoid(win_getid(winnr('#')))
|
||||
augroup END
|
||||
call assert_fails('call win_splitmove(winnr(), winnr("#"))', 'E855:')
|
||||
|
||||
augroup WinSplitMove
|
||||
au!
|
||||
au WinLeave * ++once quit
|
||||
augroup END
|
||||
call assert_fails('call win_splitmove(winnr(), winnr("#"))', 'E855:')
|
||||
|
||||
split
|
||||
split
|
||||
augroup WinSplitMove
|
||||
au!
|
||||
au WinEnter * ++once let s:triggered = v:true
|
||||
\| call assert_fails('call win_splitmove(winnr("$"), winnr())', 'E242:')
|
||||
augroup END
|
||||
quit
|
||||
call assert_equal(v:true, s:triggered)
|
||||
unlet! s:triggered
|
||||
|
||||
new
|
||||
augroup WinSplitMove
|
||||
au!
|
||||
au BufHidden * ++once let s:triggered = v:true
|
||||
\| call assert_fails('call win_splitmove(winnr("#"), winnr())', 'E1159:')
|
||||
augroup END
|
||||
hide
|
||||
call assert_equal(v:true, s:triggered)
|
||||
unlet! s:triggered
|
||||
|
||||
au! WinSplitMove
|
||||
augroup! WinSplitMove
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" Test for the :only command
|
||||
@@ -2061,23 +2137,75 @@ func Test_new_help_window_on_error()
|
||||
endfunc
|
||||
|
||||
func Test_smoothscroll_in_zero_width_window()
|
||||
let save_lines = &lines
|
||||
let save_columns = &columns
|
||||
set cpo+=n number smoothscroll
|
||||
set winwidth=99999 winminwidth=0
|
||||
|
||||
winsize 0 24
|
||||
set cpo+=n
|
||||
exe "noremap 0 \<C-W>n\<C-W>L"
|
||||
norm 000000
|
||||
set number smoothscroll
|
||||
exe "norm \<C-Y>"
|
||||
vsplit
|
||||
call assert_equal(0, winwidth(winnr('#')))
|
||||
call win_execute(win_getid(winnr('#')), "norm! \<C-Y>")
|
||||
|
||||
only!
|
||||
let &lines = save_lines
|
||||
let &columns = save_columns
|
||||
set cpo-=n
|
||||
unmap 0
|
||||
set nonumber nosmoothscroll
|
||||
set winwidth& winminwidth&
|
||||
set cpo-=n nonumber nosmoothscroll
|
||||
endfunc
|
||||
|
||||
func Test_splitmove_flatten_frame()
|
||||
split
|
||||
vsplit
|
||||
|
||||
wincmd L
|
||||
let layout = winlayout()
|
||||
wincmd K
|
||||
wincmd L
|
||||
call assert_equal(winlayout(), layout)
|
||||
|
||||
only!
|
||||
endfunc
|
||||
|
||||
func Test_splitmove_autocmd_window_no_room()
|
||||
" Open as many windows as possible
|
||||
while v:true
|
||||
try
|
||||
split
|
||||
catch /E36:/
|
||||
break
|
||||
endtry
|
||||
endwhile
|
||||
while v:true
|
||||
try
|
||||
vsplit
|
||||
catch /E36:/
|
||||
break
|
||||
endtry
|
||||
endwhile
|
||||
|
||||
wincmd j
|
||||
vsplit
|
||||
call assert_fails('wincmd H', 'E36:')
|
||||
call assert_fails('wincmd J', 'E36:')
|
||||
call assert_fails('wincmd K', 'E36:')
|
||||
call assert_fails('wincmd L', 'E36:')
|
||||
|
||||
edit unload me
|
||||
enew
|
||||
bunload! unload\ me
|
||||
augroup SplitMoveAucmdWin
|
||||
au!
|
||||
au BufEnter * ++once let s:triggered = v:true
|
||||
\| call assert_equal('autocmd', win_gettype())
|
||||
augroup END
|
||||
let layout = winlayout()
|
||||
let restcmd = winrestcmd()
|
||||
" bufload opening the autocommand window shouldn't give E36.
|
||||
call bufload('unload me')
|
||||
call assert_equal(v:true, s:triggered)
|
||||
call assert_equal(winlayout(), layout)
|
||||
call assert_equal(winrestcmd(), restcmd)
|
||||
|
||||
unlet! s:triggered
|
||||
au! SplitMoveAucmdWin
|
||||
augroup! SplitMoveAucmdWin
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
Reference in New Issue
Block a user