Files
neovim/test/old/testdir/test_scroll_opt.vim
zeertzjq 57bd41da4d vim-patch:9.2.0429: tests: flaky screendump Test_smoothscroll_incsearch()
Problem:  tests: flaky screendump Test_smoothscroll_incsearch()
Solution: Replace screendump test by WaitForAssert()
          (Yasuhiro Matsumoto)

VerifyScreenDump fails consistently on the macos-15-intel CI runner.
Replace the dump comparisons with assertions that verify the actual
invariant under test: that the visible buffer view stays unchanged
across the four incremental-search keystrokes (i.e. skipcol is not
reset). Drop the now-unused dump files.

closes: vim/vim#20118

e25933014c

Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
2026-05-03 07:21:59 +08:00

2146 lines
62 KiB
VimL
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

" Test for 'scroll', 'scrolloff', 'smoothscroll', etc.
source check.vim
source screendump.vim
source mouse.vim
func Test_reset_scroll()
let scr = &l:scroll
setlocal scroll=1
setlocal scroll&
call assert_equal(scr, &l:scroll)
setlocal scroll=1
setlocal scroll=0
call assert_equal(scr, &l:scroll)
try
execute 'setlocal scroll=' . (winheight(0) + 1)
" not reached
call assert_false(1)
catch
call assert_exception('E49:')
endtry
split
let scr = &l:scroll
setlocal scroll=1
setlocal scroll&
call assert_equal(scr, &l:scroll)
setlocal scroll=1
setlocal scroll=0
call assert_equal(scr, &l:scroll)
quit!
endfunc
func Test_scolloff_even_line_count()
new
resize 6
setlocal scrolloff=3
call setline(1, range(20))
normal 2j
call assert_equal(1, getwininfo(win_getid())[0].topline)
normal j
call assert_equal(1, getwininfo(win_getid())[0].topline)
normal j
call assert_equal(2, getwininfo(win_getid())[0].topline)
normal j
call assert_equal(3, getwininfo(win_getid())[0].topline)
bwipe!
endfunc
func Test_mouse_scroll_inactive_with_cursorbind()
for scb in [0, 1]
for so in [0, 1, 2]
let msg = $'scb={scb} so={so}'
new | only
let w1 = win_getid()
setlocal cursorbind
let &l:scb = scb
let &l:so = so
call setline(1, range(101, 109))
rightbelow vnew
let w2 = win_getid()
setlocal cursorbind
let &l:scb = scb
let &l:so = so
call setline(1, range(101, 109))
normal! $
call assert_equal(3, col('.', w1), msg)
call assert_equal(3, col('.', w2), msg)
call Ntest_setmouse(1, 1)
call feedkeys("\<ScrollWheelDown>", 'xt')
call assert_equal(4, line('w0', w1), msg)
call assert_equal(4 + so, line('.', w1), msg)
call assert_equal(1, line('w0', w2), msg)
call assert_equal(1, line('.', w2), msg)
call feedkeys("\<ScrollWheelDown>", 'xt')
call assert_equal(7, line('w0', w1), msg)
call assert_equal(7 + so, line('.', w1), msg)
call assert_equal(1, line('w0', w2), msg)
call assert_equal(1, line('.', w2), msg)
call feedkeys("\<ScrollWheelUp>", 'xt')
call assert_equal(4, line('w0', w1), msg)
call assert_equal(7 + so, line('.', w1), msg)
call assert_equal(1, line('w0', w2), msg)
call assert_equal(1, line('.', w2), msg)
call feedkeys("\<ScrollWheelUp>", 'xt')
call assert_equal(1, line('w0', w1), msg)
call assert_equal(7 + so, line('.', w1), msg)
call assert_equal(1, line('w0', w2), msg)
call assert_equal(1, line('.', w2), msg)
normal! 0
call assert_equal(1, line('.', w1), msg)
call assert_equal(1, col('.', w1), msg)
call assert_equal(1, line('.', w2), msg)
call assert_equal(1, col('.', w2), msg)
bwipe!
bwipe!
endfor
endfor
endfunc
func Test_CtrlE_CtrlY_stop_at_end()
enew
call setline(1, ['one', 'two'])
set number
exe "normal \<C-Y>"
call assert_equal([" 1 one "], ScreenLines(1, 10))
exe "normal \<C-E>\<C-E>\<C-E>"
call assert_equal([" 2 two "], ScreenLines(1, 10))
bwipe!
set nonumber
endfunc
func Test_smoothscroll_CtrlE_CtrlY()
CheckScreendump
let lines =<< trim END
vim9script
setline(1, [
'line one',
'word '->repeat(20),
'line three',
'long word '->repeat(7),
'line',
'line',
'line',
])
set smoothscroll
:5
END
call writefile(lines, 'XSmoothScroll', 'D')
let buf = RunVimInTerminal('-S XSmoothScroll', #{rows: 12, cols: 40})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smoothscroll_1', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smoothscroll_2', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smoothscroll_3', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smoothscroll_4', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smoothscroll_5', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smoothscroll_6', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smoothscroll_7', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smoothscroll_8', {})
if has('folding')
call term_sendkeys(buf, ":set foldmethod=indent\<CR>")
" move the cursor so we can reuse the same dumps
call term_sendkeys(buf, "5G")
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smoothscroll_1', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smoothscroll_2', {})
call term_sendkeys(buf, "7G")
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smoothscroll_7', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smoothscroll_8', {})
endif
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_multibyte()
CheckScreendump
let lines =<< trim END
set scrolloff=0 smoothscroll
call setline(1, [repeat('ϛ', 45), repeat('2', 36)])
exe "normal G35l\<C-E>k"
END
call writefile(lines, 'XSmoothMultibyte', 'D')
let buf = RunVimInTerminal('-S XSmoothMultibyte', #{rows: 6, cols: 40})
call VerifyScreenDump(buf, 'Test_smoothscroll_multi_1', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_number()
CheckScreendump
let lines =<< trim END
vim9script
setline(1, [
'one ' .. 'word '->repeat(20),
'two ' .. 'long word '->repeat(7),
'line',
'line',
'line',
])
set smoothscroll
set splitkeep=topline
set number cpo+=n
:3
def g:DoRel()
set number relativenumber scrolloff=0
:%del
setline(1, [
'one',
'very long text '->repeat(12),
'three',
])
exe "normal 2Gzt\<C-E>"
enddef
END
call writefile(lines, 'XSmoothNumber', 'D')
let buf = RunVimInTerminal('-S XSmoothNumber', #{rows: 12, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_number_1', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_number_2', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_number_3', {})
call term_sendkeys(buf, ":set cpo-=n\<CR>")
call VerifyScreenDump(buf, 'Test_smooth_number_4', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smooth_number_5', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smooth_number_6', {})
call term_sendkeys(buf, ":botright split\<CR>\<C-L>gg")
call VerifyScreenDump(buf, 'Test_smooth_number_7', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_number_8', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_number_9', {})
call term_sendkeys(buf, ":close\<CR>")
call term_sendkeys(buf, ":call DoRel()\<CR>")
call VerifyScreenDump(buf, 'Test_smooth_number_10', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_list()
CheckScreendump
let lines =<< trim END
vim9script
set smoothscroll scrolloff=0
set list
setline(1, [
'one',
'very long text '->repeat(12),
'three',
])
exe "normal 2Gzt\<C-E>"
END
call writefile(lines, 'XSmoothList', 'D')
let buf = RunVimInTerminal('-S XSmoothList', #{rows: 8, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_list_1', {})
call term_sendkeys(buf, ":set listchars+=precedes:#\<CR>")
call VerifyScreenDump(buf, 'Test_smooth_list_2', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_diff_mode()
CheckScreendump
CheckFeature diff
let lines =<< trim END
vim9script
var text = 'just some text here'
setline(1, text)
set smoothscroll
diffthis
new
setline(1, text)
set smoothscroll
diffthis
END
call writefile(lines, 'XSmoothDiff', 'D')
let buf = RunVimInTerminal('-S XSmoothDiff', #{rows: 8})
call VerifyScreenDump(buf, 'Test_smooth_diff_1', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smooth_diff_1', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_diff_1', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_diff_change_line_default()
CheckScreendump
CheckFeature diff
" Uses the new diffopt default with indent-heuristic and inline:char
let lines =<< trim END
set diffopt=internal,filler,closeoff,indent-heuristic,inline:char,followwrap smoothscroll
call setline(1, repeat(' abc', &columns))
call setline(2, 'bar')
call setline(3, repeat(' abc', &columns))
vnew
call setline(1, repeat(' abc', &columns))
call setline(2, 'foo')
call setline(3, 'bar')
call setline(4, repeat(' abc', &columns))
windo exe "normal! 2gg5\<C-E>"
windo diffthis
END
call writefile(lines, 'XSmoothDiffChangeLine', 'D')
let buf = RunVimInTerminal('-S XSmoothDiffChangeLine', #{rows: 20, columns: 55})
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_1', {})
call term_sendkeys(buf, "Abar")
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_2', {})
call term_sendkeys(buf, "\<Esc>")
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_3a', {})
call term_sendkeys(buf, "yyp")
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_4', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_diff_change_line()
CheckScreendump
CheckFeature diff
" Uses the old diffopt default
let lines =<< trim END
set diffopt=internal,filler,closeoff,followwrap,inline:simple smoothscroll
call setline(1, repeat(' abc', &columns))
call setline(2, 'bar')
call setline(3, repeat(' abc', &columns))
vnew
call setline(1, repeat(' abc', &columns))
call setline(2, 'foo')
call setline(3, 'bar')
call setline(4, repeat(' abc', &columns))
windo exe "normal! 2gg5\<C-E>"
windo diffthis
END
call writefile(lines, 'XSmoothDiffChangeLine', 'D')
let buf = RunVimInTerminal('-S XSmoothDiffChangeLine', #{rows: 20, columns: 55})
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_1', {})
call term_sendkeys(buf, "Abar")
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_2', {})
call term_sendkeys(buf, "\<Esc>")
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_3', {})
call term_sendkeys(buf, "yyp")
call VerifyScreenDump(buf, 'Test_smooth_diff_change_line_4', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_wrap_scrolloff_zero()
CheckScreendump
let lines =<< trim END
vim9script
setline(1, ['Line' .. (' with some text'->repeat(7))]->repeat(7))
set smoothscroll scrolloff=0
:3
END
call writefile(lines, 'XSmoothWrap', 'D')
let buf = RunVimInTerminal('-S XSmoothWrap', #{rows: 8, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_wrap_1', {})
" moving cursor down - whole bottom line shows
call term_sendkeys(buf, "j")
call VerifyScreenDump(buf, 'Test_smooth_wrap_2', {})
call term_sendkeys(buf, "\<C-E>j")
call VerifyScreenDump(buf, 'Test_smooth_wrap_3', {})
call term_sendkeys(buf, "G")
call VerifyScreenDump(buf, 'Test_smooth_wrap_4', {})
call term_sendkeys(buf, "4\<C-Y>G")
call VerifyScreenDump(buf, 'Test_smooth_wrap_4', {})
" moving cursor up right after the <<< marker - no need to show whole line
call term_sendkeys(buf, "2gj3l2k")
call VerifyScreenDump(buf, 'Test_smooth_wrap_5', {})
" moving cursor up where the <<< marker is - whole top line shows
call term_sendkeys(buf, "2j02k")
call VerifyScreenDump(buf, 'Test_smooth_wrap_6', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_wrap_long_line()
CheckScreendump
let lines =<< trim END
vim9script
setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30)) .. ' end', 'four'])
set smoothscroll scrolloff=0
normal 3G10|zt
END
call writefile(lines, 'XSmoothWrap', 'D')
let buf = RunVimInTerminal('-S XSmoothWrap', #{rows: 6, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_long_1', {})
" scrolling up, cursor moves screen line down
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_long_2', {})
call term_sendkeys(buf, "5\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_long_3', {})
" scrolling down, cursor moves screen line up
call term_sendkeys(buf, "5\<C-Y>")
call VerifyScreenDump(buf, 'Test_smooth_long_4', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smooth_long_5', {})
" 'scrolloff' set to 1, scrolling up, cursor moves screen line down
call term_sendkeys(buf, ":set scrolloff=1\<CR>")
call term_sendkeys(buf, "10|\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_long_6', {})
" 'scrolloff' set to 1, scrolling down, cursor moves screen line up
call term_sendkeys(buf, "\<C-E>")
call term_sendkeys(buf, "gjgj")
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smooth_long_7', {})
" 'scrolloff' set to 2, scrolling up, cursor moves screen line down
call term_sendkeys(buf, ":set scrolloff=2\<CR>")
call term_sendkeys(buf, "10|\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_long_8', {})
" 'scrolloff' set to 2, scrolling down, cursor moves screen line up
call term_sendkeys(buf, "\<C-E>")
call term_sendkeys(buf, "gj")
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_smooth_long_9', {})
" 'scrolloff' set to 0, move cursor down one line.
" Cursor should move properly, and since this is a really long line, it will
" be put on top of the screen.
call term_sendkeys(buf, ":set scrolloff=0\<CR>")
call term_sendkeys(buf, "0j")
call VerifyScreenDump(buf, 'Test_smooth_long_10', {})
" Test zt/zz/zb that they work properly when a long line is above it
call term_sendkeys(buf, "zt")
call VerifyScreenDump(buf, 'Test_smooth_long_11', {})
call term_sendkeys(buf, "zz")
call VerifyScreenDump(buf, 'Test_smooth_long_12', {})
call term_sendkeys(buf, "zb")
call VerifyScreenDump(buf, 'Test_smooth_long_13', {})
" Repeat the step and move the cursor down again.
" This time, use a shorter long line that is barely long enough to span more
" than one window. Note that the cursor is at the bottom this time because
" Vim prefers to do so if we are scrolling a few lines only.
call term_sendkeys(buf, ":call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(10)) .. ' end', 'four'])\<CR>")
" Currently visible lines were replaced, test that the lines and cursor
" are correctly displayed.
call VerifyScreenDump(buf, 'Test_smooth_long_14', {})
call term_sendkeys(buf, "3Gzt")
call term_sendkeys(buf, "j")
call VerifyScreenDump(buf, 'Test_smooth_long_15', {})
" Repeat the step but this time start it when the line is smooth-scrolled by
" one line. This tests that the offset calculation is still correct and
" still end up scrolling down to the next line with cursor at bottom of
" screen.
call term_sendkeys(buf, "3Gzt")
call term_sendkeys(buf, "\<C-E>j")
call VerifyScreenDump(buf, 'Test_smooth_long_16', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_one_long_line()
CheckScreendump
let lines =<< trim END
vim9script
setline(1, 'with lots of text '->repeat(7))
set smoothscroll scrolloff=0
END
call writefile(lines, 'XSmoothOneLong', 'D')
let buf = RunVimInTerminal('-S XSmoothOneLong', #{rows: 6, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_one_long_1', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_one_long_2', {})
call term_sendkeys(buf, "0")
call VerifyScreenDump(buf, 'Test_smooth_one_long_1', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_long_line_showbreak()
CheckScreendump
let lines =<< trim END
vim9script
# a line that spans four screen lines
setline(1, 'with lots of text in one line '->repeat(6))
set smoothscroll scrolloff=0
&showbreak = '+++ '
END
call writefile(lines, 'XSmoothLongShowbreak', 'D')
let buf = RunVimInTerminal('-S XSmoothLongShowbreak', #{rows: 6, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_long_showbreak_1', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_long_showbreak_2', {})
call term_sendkeys(buf, "0")
call VerifyScreenDump(buf, 'Test_smooth_long_showbreak_1', {})
call StopVimInTerminal(buf)
endfunc
" Check that 'smoothscroll' marker is drawn over double-width char correctly.
" Run with multiple encodings.
func Test_smoothscroll_marker_over_double_width()
" Run this in a separate Vim instance to avoid messing up.
let after =<< trim [CODE]
scriptencoding utf-8
call setline(1, 'a'->repeat(&columns) .. '口'->repeat(10))
setlocal smoothscroll
redraw
exe "norm \<C-E>"
redraw
" Check the chars one by one. Don't check the whole line concatenated.
call assert_equal('<', screenstring(1, 1))
call assert_equal('<', screenstring(1, 2))
call assert_equal('<', screenstring(1, 3))
call assert_equal(' ', screenstring(1, 4))
call assert_equal('口', screenstring(1, 5))
call assert_equal('口', screenstring(1, 7))
call assert_equal('口', screenstring(1, 9))
call assert_equal('口', screenstring(1, 11))
call assert_equal('口', screenstring(1, 13))
call assert_equal('口', screenstring(1, 15))
call writefile(v:errors, 'Xresult')
qall!
[CODE]
let encodings = ['utf-8', 'cp932', 'cp936', 'cp949', 'cp950']
if !has('win32')
let encodings += ['euc-jp']
endif
if has('nvim')
let encodings = ['utf-8']
endif
for enc in encodings
let msg = 'enc=' .. enc
if RunVim([], after, $'--clean --cmd "set encoding={enc}"')
call assert_equal([], readfile('Xresult'), msg)
endif
call delete('Xresult')
endfor
endfunc
" Same as the test above, but check the text actually shown on screen.
" Only run with UTF-8 encoding.
func Test_smoothscroll_marker_over_double_width_dump()
CheckScreendump
let lines =<< trim END
call setline(1, 'a'->repeat(&columns) .. '口'->repeat(10))
setlocal smoothscroll
END
call writefile(lines, 'XSmoothMarkerOverDoubleWidth', 'D')
let buf = RunVimInTerminal('-S XSmoothMarkerOverDoubleWidth', #{rows: 6, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_marker_over_double_width_1', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_marker_over_double_width_2', {})
call StopVimInTerminal(buf)
endfunc
func s:check_col_calc(win_col, win_line, buf_col)
call assert_equal(a:win_col, wincol())
call assert_equal(a:win_line, winline())
call assert_equal(a:buf_col, col('.'))
endfunc
" Test that if the current cursor is on a smooth scrolled line, we correctly
" reposition it. Also check that we don't miscalculate the values by checking
" the consistency between wincol() and col('.') as they are calculated
" separately in code.
func Test_smoothscroll_cursor_position()
call NewWindow(10, 20)
setl smoothscroll wrap
call setline(1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
call s:check_col_calc(1, 1, 1)
exe "normal \<C-E>"
" Move down another line to avoid blocking the <<< display
call s:check_col_calc(1, 2, 41)
exe "normal \<C-Y>"
call s:check_col_calc(1, 3, 41)
" Test "g0/g<Home>"
exe "normal gg\<C-E>"
norm $gkg0
call s:check_col_calc(4, 1, 24)
" Test moving the cursor behind the <<< display with 'virtualedit'
set virtualedit=all
exe "normal \<C-E>gkh"
call s:check_col_calc(3, 2, 23)
set virtualedit&
normal gg3l
exe "normal \<C-E>"
" Move down only 1 line when we are out of the range of the <<< display
call s:check_col_calc(4, 1, 24)
exe "normal \<C-Y>"
call s:check_col_calc(4, 2, 24)
normal ggg$
exe "normal \<C-E>"
call s:check_col_calc(20, 1, 40)
exe "normal \<C-Y>"
call s:check_col_calc(20, 2, 40)
normal gg
" Test number, where we have indented lines
setl number
call s:check_col_calc(5, 1, 1)
exe "normal \<C-E>"
" Move down only 1 line when the <<< display is on the number column
call s:check_col_calc(5, 1, 17)
exe "normal \<C-Y>"
call s:check_col_calc(5, 2, 17)
normal ggg$
exe "normal \<C-E>"
call s:check_col_calc(20, 1, 32)
exe "normal \<C-Y>"
call s:check_col_calc(20, 2, 32)
normal gg
setl numberwidth=1
" Move down another line when numberwidth is too short to cover the whole
" <<< display
call s:check_col_calc(3, 1, 1)
exe "normal \<C-E>"
call s:check_col_calc(3, 2, 37)
exe "normal \<C-Y>"
call s:check_col_calc(3, 3, 37)
normal ggl
" Only move 1 line down when we are just past the <<< display
call s:check_col_calc(4, 1, 2)
exe "normal \<C-E>"
call s:check_col_calc(4, 1, 20)
exe "normal \<C-Y>"
call s:check_col_calc(4, 2, 20)
normal gg
setl numberwidth&
" Test number + showbreak, so test that the additional indentation works
setl number showbreak=+++
call s:check_col_calc(5, 1, 1)
exe "normal \<C-E>"
call s:check_col_calc(8, 1, 17)
exe "normal \<C-Y>"
call s:check_col_calc(8, 2, 17)
normal gg
" Test number + cpo+=n mode, where wrapped lines aren't indented
setl number cpo+=n showbreak=
call s:check_col_calc(5, 1, 1)
exe "normal \<C-E>"
call s:check_col_calc(1, 2, 37)
exe "normal \<C-Y>"
call s:check_col_calc(1, 3, 37)
normal gg
" Test list + listchars "precedes", where there is always 1 overlap
" regardless of number and cpo-=n.
setl number list listchars=precedes:< cpo-=n
call s:check_col_calc(5, 1, 1)
exe "normal 3|\<C-E>h"
call s:check_col_calc(6, 1, 18)
norm h
call s:check_col_calc(5, 2, 17)
normal gg
bwipe!
endfunc
func Test_smoothscroll_cursor_scrolloff()
call NewWindow(10, 20)
setl smoothscroll wrap
setl scrolloff=3
" 120 chars are 6 screen lines
call setline(1, "abcdefghijklmnopqrstABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrstABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrstABCDEFGHIJKLMNOPQRST")
call setline(2, "below")
call s:check_col_calc(1, 1, 1)
" CTRL-E shows "<<<DEFG...", cursor move four lines down
exe "normal \<C-E>"
call s:check_col_calc(1, 4, 81)
" cursor on start of second line, "gk" moves into first line, skipcol doesn't
" change
exe "normal G0gk"
call s:check_col_calc(1, 5, 101)
" move cursor left one window width worth, scrolls one screen line
exe "normal 20h"
call s:check_col_calc(1, 5, 81)
" move cursor left one window width worth, scrolls one screen line
exe "normal 20h"
call s:check_col_calc(1, 4, 61)
" cursor on last line, "gk" should not cause a scroll
set scrolloff=0
normal G0
call s:check_col_calc(1, 7, 1)
normal gk
call s:check_col_calc(1, 6, 101)
bwipe!
endfunc
" Test that mouse picking is still accurate when we have smooth scrolled lines
func Test_smoothscroll_mouse_pos()
CheckNotGui
CheckUnix
let save_mouse = &mouse
"let save_term = &term
"let save_ttymouse = &ttymouse
set mouse=a "term=xterm ttymouse=xterm2
call NewWindow(10, 20)
setl smoothscroll wrap
" First line will wrap to 3 physical lines. 2nd/3rd lines are short lines.
call setline(1, ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "line 2", "line 3"])
func s:check_mouse_click(row, col, buf_row, buf_col)
call MouseLeftClick(a:row, a:col)
call assert_equal(a:col, wincol())
call assert_equal(a:row, winline())
call assert_equal(a:buf_row, line('.'))
call assert_equal(a:buf_col, col('.'))
endfunc
" Check that clicking without scroll works first.
call s:check_mouse_click(3, 5, 1, 45)
call s:check_mouse_click(4, 1, 2, 1)
call s:check_mouse_click(4, 6, 2, 6)
call s:check_mouse_click(5, 1, 3, 1)
call s:check_mouse_click(5, 6, 3, 6)
" Smooth scroll, and checks that this didn't mess up mouse clicking
exe "normal \<C-E>"
call s:check_mouse_click(2, 5, 1, 45)
call s:check_mouse_click(3, 1, 2, 1)
call s:check_mouse_click(3, 6, 2, 6)
call s:check_mouse_click(4, 1, 3, 1)
call s:check_mouse_click(4, 6, 3, 6)
exe "normal \<C-E>"
call s:check_mouse_click(1, 5, 1, 45)
call s:check_mouse_click(2, 1, 2, 1)
call s:check_mouse_click(2, 6, 2, 6)
call s:check_mouse_click(3, 1, 3, 1)
call s:check_mouse_click(3, 6, 3, 6)
" Make a new first line 11 physical lines tall so it's taller than window
" height, to test overflow calculations with really long lines wrapping.
normal gg
call setline(1, "12345678901234567890"->repeat(11))
exe "normal 6\<C-E>"
call s:check_mouse_click(5, 1, 1, 201)
call s:check_mouse_click(6, 1, 2, 1)
call s:check_mouse_click(7, 1, 3, 1)
let &mouse = save_mouse
"let &term = save_term
"let &ttymouse = save_ttymouse
bwipe!
endfunc
" this was dividing by zero
func Test_smoothscroll_zero_width()
CheckScreendump
let lines =<< trim END
winsize 0 0
vsplit
vsplit
vsplit
vsplit
vsplit
sil norm H
set wrap
set smoothscroll
set number
END
call writefile(lines, 'XSmoothScrollZero', 'D')
let buf = RunVimInTerminal('-u NONE -i NONE -n -m -X -Z -e -s -S XSmoothScrollZero', #{rows: 6, cols: 60, wait_for_ruler: 0})
call VerifyScreenDump(buf, 'Test_smoothscroll_zero_1', {})
call term_sendkeys(buf, ":sil norm \<C-V>\<C-W>\<C-V>\<C-N>\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_zero_2', {})
call StopVimInTerminal(buf)
endfunc
" this was unnecessarily inserting lines
func Test_smoothscroll_ins_lines()
CheckScreendump
let lines =<< trim END
set wrap
set smoothscroll
set scrolloff=0
set conceallevel=2
call setline(1, [
\'line one' .. 'with lots of text in one line '->repeat(2),
\'line two',
\'line three',
\'line four',
\'line five'
\])
END
call writefile(lines, 'XSmoothScrollInsLines', 'D')
let buf = RunVimInTerminal('-S XSmoothScrollInsLines', #{rows: 6, cols: 40})
call term_sendkeys(buf, "\<C-E>gjgk")
call VerifyScreenDump(buf, 'Test_smooth_ins_lines', {})
call StopVimInTerminal(buf)
endfunc
" this placed the cursor in the command line
func Test_smoothscroll_cursormoved_line()
CheckScreendump
let lines =<< trim END
set smoothscroll
call setline(1, [
\'',
\'_'->repeat(&lines * &columns),
\(('_')->repeat(&columns - 2) .. 'xxx')->repeat(2)
\])
autocmd CursorMoved * eval [line('w0'), line('w$')]
call search('xxx')
END
call writefile(lines, 'XSmoothCursorMovedLine', 'D')
let buf = RunVimInTerminal('-S XSmoothCursorMovedLine', #{rows: 6})
call VerifyScreenDump(buf, 'Test_smooth_cursormoved_line', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_eob()
CheckScreendump
let lines =<< trim END
set smoothscroll
call setline(1, ['']->repeat(100))
norm G
END
call writefile(lines, 'XSmoothEob', 'D')
let buf = RunVimInTerminal('-S XSmoothEob', #{rows: 10})
" does not scroll halfway when scrolling to end of buffer
call VerifyScreenDump(buf, 'Test_smooth_eob_1', {})
" cursor is not placed below window
call term_sendkeys(buf, ":call setline(92, 'a'->repeat(100))\<CR>\<C-L>\<C-B>G")
call VerifyScreenDump(buf, 'Test_smooth_eob_2', {})
call StopVimInTerminal(buf)
endfunc
" skipcol should not reset when doing incremental search on the same word
func Test_smoothscroll_incsearch()
CheckRunVimInTerminal
let lines =<< trim END
set smoothscroll number scrolloff=0 incsearch
call setline(1, repeat([''], 20))
call setline(11, repeat('a', 100))
call setline(14, 'bbbb')
END
call writefile(lines, 'XSmoothIncsearch', 'D')
let buf = RunVimInTerminal('-S XSmoothIncsearch', #{rows: 8, cols: 40})
let g:test_is_flaky = 1
call term_sendkeys(buf, "/b")
call WaitForAssert({-> assert_match('^/b\s*$', term_getline(buf, 8))}, 1000)
let view1 = map(range(1, 7), {_, i -> term_getline(buf, i)})
call term_sendkeys(buf, "b")
call WaitForAssert({-> assert_match('^/bb\s*$', term_getline(buf, 8))}, 1000)
call assert_equal(view1, map(range(1, 7), {_, i -> term_getline(buf, i)}))
call term_sendkeys(buf, "b")
call WaitForAssert({-> assert_match('^/bbb\s*$', term_getline(buf, 8))}, 1000)
call assert_equal(view1, map(range(1, 7), {_, i -> term_getline(buf, i)}))
call term_sendkeys(buf, "b")
call WaitForAssert({-> assert_match('^/bbbb\s*$', term_getline(buf, 8))}, 1000)
call assert_equal(view1, map(range(1, 7), {_, i -> term_getline(buf, i)}))
call term_sendkeys(buf, "\<CR>")
call StopVimInTerminal(buf)
endfunc
" Test scrolling multiple lines and stopping at non-zero skipcol.
func Test_smoothscroll_multi_skipcol()
CheckScreendump
let lines =<< trim END
setlocal cursorline scrolloff=0 smoothscroll
call setline(1, repeat([''], 8))
call setline(3, repeat('a', 50))
call setline(4, repeat('a', 50))
call setline(7, 'bbb')
call setline(8, 'ccc')
redraw
END
call writefile(lines, 'XSmoothMultiSkipcol', 'D')
let buf = RunVimInTerminal('-S XSmoothMultiSkipcol', #{rows: 10, cols: 40})
call VerifyScreenDump(buf, 'Test_smooth_multi_skipcol_1', {})
call term_sendkeys(buf, "3\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_multi_skipcol_2', {})
call term_sendkeys(buf, "2\<C-E>")
call VerifyScreenDump(buf, 'Test_smooth_multi_skipcol_3', {})
call StopVimInTerminal(buf)
endfunc
" this was dividing by zero bug in scroll_cursor_bot
func Test_smoothscroll_zero_width_scroll_cursor_bot_noruler()
CheckScreendump
let lines =<< trim END
set noruler
silent normal yy
silent normal 19p
set cpoptions+=n
vsplit
vertical resize 0
set foldcolumn=1
set number
set smoothscroll
silent normal 20G
END
call writefile(lines, 'XSmoothScrollZeroBot', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollZeroBot', #{rows: 19})
call VerifyScreenDump(buf, 'Test_smoothscroll_zero_bot', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_zero_width_scroll_cursor_bot_ruler()
CheckScreendump
let lines =<< trim END
set ruler
silent normal yy
silent normal 19p
set cpoptions+=n
vsplit
vertical resize 0
set foldcolumn=1
set number
set smoothscroll
silent normal 20G
END
call writefile(lines, 'XSmoothScrollZeroBot', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollZeroBot', #{rows: 19})
call VerifyScreenDump(buf, 'Test_smoothscroll_zero_bot_ruler', {})
call StopVimInTerminal(buf)
endfunc
" scroll_cursor_top() should reset skipcol when it changes topline
func Test_smoothscroll_cursor_top_noruler()
CheckScreendump
let lines =<< trim END
set smoothscroll scrolloff=2 noruler
new | 11resize | wincmd j
call setline(1, ['line1', 'line2', 'line3'->repeat(20), 'line4'])
exe "norm G3\<C-E>k"
END
call writefile(lines, 'XSmoothScrollCursorTop', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollCursorTop', #{rows: 12, cols: 40})
call VerifyScreenDump(buf, 'Test_smoothscroll_cursor_top', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_cursor_top_ruler()
CheckScreendump
let lines =<< trim END
set smoothscroll scrolloff=2 ruler
new | 11resize | wincmd j
call setline(1, ['line1', 'line2', 'line3'->repeat(20), 'line4'])
exe "norm G3\<C-E>k"
END
call writefile(lines, 'XSmoothScrollCursorTop', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollCursorTop', #{rows: 12, cols: 40})
call VerifyScreenDump(buf, 'Test_smoothscroll_cursor_ru_top', {})
call StopVimInTerminal(buf)
endfunc
" Division by zero, shouldn't crash
func Test_smoothscroll_crash()
CheckScreendump
let lines =<< trim END
20 new
vsp
put =repeat('aaaa', 20)
set nu fdc=1 smoothscroll cpo+=n
vert resize 0
exe "norm! 0\<c-e>"
END
call writefile(lines, 'XSmoothScrollCrash', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollCrash', #{rows: 12, cols: 40})
call term_sendkeys(buf, "2\<C-E>\<C-L>")
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_insert_bottom_noruler()
CheckScreendump
let lines =<< trim END
call setline(1, repeat([repeat('A very long line ...', 10)], 5))
set wrap smoothscroll scrolloff=0 noruler
END
call writefile(lines, 'XSmoothScrollInsertBottom', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollInsertBottom', #{rows: 9, cols: 40})
call term_sendkeys(buf, "Go123456789\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_insert_bottom', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_insert_bottom_ruler()
CheckScreendump
let lines =<< trim END
call setline(1, repeat([repeat('A very long line ...', 10)], 5))
set wrap smoothscroll scrolloff=0 ruler
END
call writefile(lines, 'XSmoothScrollInsertBottom', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollInsertBottom', #{rows: 9, cols: 40})
call term_sendkeys(buf, "Go123456789\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_insert_bottom_ruler', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_in_qf_window_noruler()
CheckFeature quickfix
CheckScreendump
let lines =<< trim END
set nocompatible display=lastline noruler
copen 5
setlocal number smoothscroll
let g:l = [{'text': 'foo'}] + repeat([{'text': join(range(30))}], 10)
call setqflist(g:l, 'r')
normal! G
wincmd t
let g:l1 = [{'text': join(range(1000))}]
END
call writefile(lines, 'XSmoothScrollInQfWindow', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollInQfWindow', #{rows: 20, cols: 60})
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_1', {})
call term_sendkeys(buf, ":call setqflist([], 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_2', {})
call term_sendkeys(buf, ":call setqflist(g:l, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_3', {})
call term_sendkeys(buf, ":call setqflist(g:l1, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_4', {})
call term_sendkeys(buf, "\<C-W>b$\<C-W>t")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_5', {})
call term_sendkeys(buf, ":call setqflist([], 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_2', {})
call term_sendkeys(buf, ":call setqflist(g:l1, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_4', {})
call term_sendkeys(buf, "\<C-W>b$\<C-W>t")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_5', {})
call term_sendkeys(buf, ":call setqflist(g:l, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_3', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_in_qf_window_ruler()
CheckFeature quickfix
CheckScreendump
let lines =<< trim END
set nocompatible display=lastline ruler
copen 5
setlocal number smoothscroll
let g:l = [{'text': 'foo'}] + repeat([{'text': join(range(30))}], 10)
call setqflist(g:l, 'r')
normal! G
wincmd t
let g:l1 = [{'text': join(range(1000))}]
END
call writefile(lines, 'XSmoothScrollInQfWindow', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothScrollInQfWindow', #{rows: 20, cols: 60})
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_1', {})
call term_sendkeys(buf, ":call setqflist([], 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_2', {})
call term_sendkeys(buf, ":call setqflist(g:l, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_3', {})
call term_sendkeys(buf, ":call setqflist(g:l1, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_4', {})
call term_sendkeys(buf, "\<C-W>b$\<C-W>t")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_5', {})
call term_sendkeys(buf, ":call setqflist([], 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_2', {})
call term_sendkeys(buf, ":call setqflist(g:l1, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_4', {})
call term_sendkeys(buf, "\<C-W>b$\<C-W>t")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_5', {})
call term_sendkeys(buf, ":call setqflist(g:l, 'r')\<CR>")
call VerifyScreenDump(buf, 'Test_smoothscroll_in_qf_window_ru_3', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_in_zero_width_window()
set cpo+=n number smoothscroll
set winwidth=99999 winminwidth=0
vsplit
call assert_equal(0, winwidth(winnr('#')))
call win_execute(win_getid(winnr('#')), "norm! \<C-Y>")
only!
set winwidth& winminwidth&
set cpo-=n nonumber nosmoothscroll
endfunc
func Test_smoothscroll_textoff_small_winwidth()
set smoothscroll number
call setline(1, 'llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch')
vsplit
let textoff = getwininfo(win_getid())[0].textoff
execute 'vertical resize' textoff + 1
redraw
call assert_equal(0, winsaveview().skipcol)
execute "normal! 0\<C-E>"
redraw
call assert_equal(1, winsaveview().skipcol)
execute 'vertical resize' textoff - 1
" This caused a signed integer overflow.
redraw
call assert_equal(1, winsaveview().skipcol)
execute 'vertical resize' textoff
" This caused an infinite loop.
redraw
call assert_equal(1, winsaveview().skipcol)
%bw!
set smoothscroll& number&
endfunc
func Test_smoothscroll_page()
call NewWindow(10, 40)
setlocal smoothscroll
call setline(1, 'abcde '->repeat(150))
exe "norm! \<C-F>"
call assert_equal(400, winsaveview().skipcol)
exe "norm! \<C-F>"
call assert_equal(800, winsaveview().skipcol)
exe "norm! \<C-F>"
call assert_equal(880, winsaveview().skipcol)
exe "norm! \<C-B>"
call assert_equal(480, winsaveview().skipcol)
exe "norm! \<C-B>"
call assert_equal(80, winsaveview().skipcol)
exe "norm! \<C-B>"
call assert_equal(0, winsaveview().skipcol)
" Half-page scrolling does not go beyond end of buffer and moves the cursor.
" Even with 'nostartofline', the correct amount of lines is scrolled.
setl nostartofline
exe "norm! 15|\<C-D>"
call assert_equal(200, winsaveview().skipcol)
call assert_equal(215, col('.'))
exe "norm! \<C-D>"
call assert_equal(400, winsaveview().skipcol)
call assert_equal(415, col('.'))
exe "norm! \<C-D>"
call assert_equal(520, winsaveview().skipcol)
call assert_equal(615, col('.'))
exe "norm! \<C-D>"
call assert_equal(520, winsaveview().skipcol)
call assert_equal(815, col('.'))
exe "norm! \<C-D>"
call assert_equal(520, winsaveview().skipcol)
call assert_equal(895, col('.'))
exe "norm! \<C-U>"
call assert_equal(320, winsaveview().skipcol)
call assert_equal(695, col('.'))
exe "norm! \<C-U>"
call assert_equal(120, winsaveview().skipcol)
call assert_equal(495, col('.'))
exe "norm! \<C-U>"
call assert_equal(0, winsaveview().skipcol)
call assert_equal(295, col('.'))
exe "norm! \<C-U>"
call assert_equal(0, winsaveview().skipcol)
call assert_equal(95, col('.'))
exe "norm! \<C-U>"
call assert_equal(0, winsaveview().skipcol)
call assert_equal(15, col('.'))
bwipe!
endfunc
func Test_smoothscroll_next_topline()
call NewWindow(10, 40)
setlocal smoothscroll
call setline(1, ['abcde '->repeat(150)]->repeat(2))
" Scrolling a screenline that causes the cursor to move to the next buffer
" line should not skip part of that line to bring the cursor into view.
exe "norm! 22\<C-E>"
call assert_equal(880, winsaveview().skipcol)
exe "norm! \<C-E>"
redraw
call assert_equal(0, winsaveview().skipcol)
" Also when scrolling back.
exe "norm! G\<C-Y>"
redraw
call assert_equal(880, winsaveview().skipcol)
" Cursor in correct place when not in the first screenline of a buffer line.
exe "norm! gg4gj20\<C-D>\<C-D>"
redraw
call assert_equal(2, line('w0'))
" Cursor does not end up above topline, adjusting topline later.
setlocal nu cpo+=n
exe "norm! G$g013\<C-Y>"
redraw
call assert_equal(2, line('.'))
call assert_equal(0, winsaveview().skipcol)
set cpo-=n
bwipe!
endfunc
func Test_smoothscroll_long_line_zb()
call NewWindow(10, 40)
call setline(1, 'abcde '->repeat(150))
" Also works without 'smoothscroll' when last line of buffer doesn't fit.
" Used to set topline to buffer line count plus one, causing an empty screen.
norm zb
redraw
call assert_equal(1, winsaveview().topline)
" Moving cursor to bottom works on line that doesn't fit with 'smoothscroll'.
" Skipcol was adjusted later for cursor being on not visible part of line.
setlocal smoothscroll
norm zb
redraw
call assert_equal(520, winsaveview().skipcol)
bwipe!
endfunc
func Test_smooth_long_scrolloff_noruler()
CheckScreendump
let lines =<< trim END
set smoothscroll scrolloff=3
set noruler
call setline(1, ['one', 'two long '->repeat(100), 'three', 'four', 'five', 'six'])
END
call writefile(lines, 'XSmoothLongScrolloff', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothLongScrolloff', #{rows: 8, cols: 40})
call term_sendkeys(buf, ":norm j721|\<CR>")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_1', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_2', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_3', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_4', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_5', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_6', {})
call term_sendkeys(buf, "gk")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_7', {})
call StopVimInTerminal(buf)
endfunc
func Test_smooth_long_scrolloff_ruler()
CheckScreendump
let lines =<< trim END
set smoothscroll scrolloff=3 ruler
call setline(1, ['one', 'two long '->repeat(100), 'three', 'four', 'five', 'six'])
END
call writefile(lines, 'XSmoothLongScrolloff', 'D')
let buf = RunVimInTerminal('-u NONE -S XSmoothLongScrolloff', #{rows: 8, cols: 40})
call term_sendkeys(buf, ":norm j721|\<CR>")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_ru_1', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_ru_2', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_ru_3', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_ru_4', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_ru_5', {})
call term_sendkeys(buf, "gj")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_ru_6', {})
call term_sendkeys(buf, "gk")
call VerifyScreenDump(buf, 'Test_smooth_long_scrolloff_ru_7', {})
call StopVimInTerminal(buf)
endfunc
func Test_smoothscroll_listchars_eol()
call NewWindow(10, 40)
setlocal list listchars=eol:$ scrolloff=0 smoothscroll
call setline(1, repeat('-', 40))
call append(1, repeat(['foobar'], 10))
normal! G
call assert_equal(2, line('w0'))
call assert_equal(0, winsaveview().skipcol)
exe "normal! \<C-Y>"
call assert_equal(1, line('w0'))
call assert_equal(40, winsaveview().skipcol)
exe "normal! \<C-Y>"
call assert_equal(1, line('w0'))
call assert_equal(0, winsaveview().skipcol)
exe "normal! \<C-Y>"
call assert_equal(1, line('w0'))
call assert_equal(0, winsaveview().skipcol)
exe "normal! \<C-E>"
call assert_equal(1, line('w0'))
call assert_equal(40, winsaveview().skipcol)
exe "normal! \<C-E>"
call assert_equal(2, line('w0'))
call assert_equal(0, winsaveview().skipcol)
for ve in ['', 'all', 'onemore']
let &virtualedit = ve
normal! gg
call assert_equal(1, line('w0'))
call assert_equal(0, winsaveview().skipcol)
exe "normal! \<C-E>"
redraw " redrawing should not cause another scroll
call assert_equal(1, line('w0'))
call assert_equal(40, winsaveview().skipcol)
exe "normal! \<C-E>"
redraw
call assert_equal(2, line('w0'))
call assert_equal(0, winsaveview().skipcol)
if ve != 'all'
call assert_equal([0, 2, 1, 0], getpos('.'))
endif
endfor
set virtualedit&
bwipe!
endfunc
" scrolloffpad contract:
" - augment scrolloff only under EOF pressure (insufficient real lines below);
" - do not change explicit "z" viewport placement command semantics;
" - current scope is EOF-only, so BOF behavior remains unchanged.
func Test_scrolloffpad_zb_keeps_bottom_command_semantics()
new
resize 12
setlocal scrolloff=10
call setline(1, map(range(1, 300), 'printf("line %d", v:val)'))
setlocal scrolloffpad=0
normal! gg150Gzb
let baseline = [line('.'), line('w$'), winline()]
setlocal scrolloffpad=1
normal! gg150Gzb
call assert_equal(baseline, [line('.'), line('w$'), winline()])
bwipe!
endfunc
func Test_scrolloffpad_zminus_keeps_bottom_beginline_semantics()
new
resize 12
setlocal scrolloff=10
call setline(1, map(range(1, 300), 'printf(" line %d", v:val)'))
setlocal scrolloffpad=0
normal! gg150Gz-
let baseline = [line('.'), line('w$'), winline(), col('.')]
call assert_equal(match(getline('.'), '\S') + 1, col('.'))
setlocal scrolloffpad=1
normal! gg150Gz-
call assert_equal(baseline, [line('.'), line('w$'), winline(), col('.')])
call assert_equal(match(getline('.'), '\S') + 1, col('.'))
bwipe!
endfunc
func Test_scrolloffpad_zb_is_one_shot_then_scrolloff_reapplies()
new
resize 12
setlocal scrolloff=10
call setline(1, map(range(1, 300), 'printf("line %d", v:val)'))
let after_zb = {}
let after_j = {}
for sop in [0, 1]
let &l:scrolloffpad = sop
normal! gg150Gzb
let after_zb[sop] = [line('.'), line('w$'), winline(), winsaveview().topline]
normal! j
let after_j[sop] = [line('.'), line('w$'), winline(), winsaveview().topline]
call assert_notequal(after_zb[sop][3], after_j[sop][3])
call assert_true(line('.') < line('w$'))
endfor
call assert_equal(after_zb[0], after_zb[1])
call assert_equal(after_j[0], after_j[1])
bwipe!
endfunc
func Test_scrolloffpad_has_no_mid_buffer_effect()
new
resize 12
setlocal scrolloff=10 scrolloffpad=0
call setline(1, map(range(1, 500), 'printf("line %d", v:val)'))
normal! gg150G
let topline_without_pad = winsaveview().topline
setlocal scrolloffpad=1
normal! gg150G
let topline_with_pad = winsaveview().topline
call assert_equal(topline_without_pad, topline_with_pad)
bwipe!
endfunc
func Test_scrolloffpad_changes_eof_pressure_only()
new
resize 12
setlocal scrolloff=10 scrolloffpad=0
call setline(1, map(range(1, 200), 'printf("line %d", v:val)'))
normal! ggG
let view_without_pad = winsaveview()
let cursor_without_pad = line('.')
let row_without_pad = winline()
setlocal scrolloffpad=1
normal! ggG
let view_with_pad = winsaveview()
let row_with_pad = winline()
call assert_equal(line('$'), line('.'))
call assert_equal(cursor_without_pad, line('.'))
call assert_notequal(view_without_pad.topline, view_with_pad.topline)
call assert_true(row_with_pad < row_without_pad)
bwipe!
endfunc
func Test_scrolloffpad_large_scrolloff_no_overflow()
new
resize 12
call setline(1, map(range(1, 200), 'printf("line %d", v:val)'))
setlocal scrolloff=2147483647 scrolloffpad=0
normal! ggG
let view_without_pad = winsaveview()
let row_without_pad = winline()
setlocal scrolloffpad=1
normal! ggG
let view_with_pad = winsaveview()
let row_with_pad = winline()
call assert_equal(line('$'), line('.'))
call assert_notequal(view_without_pad.topline, view_with_pad.topline)
call assert_true(row_with_pad < row_without_pad)
bwipe!
endfunc
func Test_scrolloffpad_boolean_gate_values()
new
resize 12
setlocal scrolloff=10
call setline(1, map(range(1, 200), 'printf("line %d", v:val)'))
let views = {}
let rows = {}
for sop in [0, 1, 2]
let &l:scrolloffpad = sop
normal! ggG
let views[sop] = winsaveview()
let rows[sop] = winline()
call assert_equal(line('$'), line('.'))
endfor
call assert_equal(views[1].topline, views[2].topline)
call assert_equal(rows[1], rows[2])
call assert_notequal(views[0].topline, views[1].topline)
call assert_true(rows[1] < rows[0])
bwipe!
endfunc
func Test_scrolloffpad_requires_scrolloff_nonzero()
new
resize 12
call setline(1, map(range(1, 200), 'printf("line %d", v:val)'))
let states = {}
for so in [0, 10]
let states[so] = {}
for sop in [0, 1]
let &l:scrolloff = so
let &l:scrolloffpad = sop
normal! ggG
let states[so][sop] = [line('.'), line('w0'), line('w$'), winline()]
call assert_equal(line('$'), line('.'))
endfor
endfor
call assert_equal(states[0][0], states[0][1])
call assert_notequal(states[10][0], states[10][1])
call assert_true(states[10][1][3] < states[10][0][3])
bwipe!
endfunc
func Test_scrolloffpad_search_to_eof()
new
resize 12
setlocal scrolloff=10
call setline(1, map(range(1, 200), 'printf("line %d", v:val)'))
call setline(line('$'), 'EOF TARGET')
let states = {}
for sop in [0, 1]
let &l:scrolloffpad = sop
normal! gg
call assert_true(search('EOF TARGET') > 0)
let states[sop] = [line('.'), line('w0'), line('w$'), winline()]
call assert_equal(line('$'), line('.'))
endfor
call assert_notequal(states[0], states[1])
call assert_true(states[1][3] < states[0][3])
bwipe!
endfunc
func Test_scrolloffpad_paging_to_eof()
new
resize 12
setlocal scrolloff=10
call setline(1, map(range(1, 240), 'printf("line %d", v:val)'))
let states = {}
for sop in [0, 1]
let &l:scrolloffpad = sop
normal! gg
let prev = -1
for _ in range(1, 200)
execute "normal! \<C-D>"
if line('.') == prev
break
endif
let prev = line('.')
endfor
let states[sop] = [line('.'), line('w0'), line('w$'), winline()]
call assert_equal(line('$'), line('w$'))
endfor
call assert_notequal(states[0], states[1])
call assert_true(states[1][3] < states[0][3])
bwipe!
endfunc
func Test_scrolloffpad_autocmd_append_at_eof()
let states = {}
for sop in [0, 1]
new
resize 12
setlocal scrolloff=10
let &l:scrolloffpad = sop
call setline(1, map(range(1, 120), 'printf("line %d", v:val)'))
let b:scrolloffpad_appended = 0
augroup ScrolloffpadAppendAtEof
autocmd!
autocmd CursorMoved <buffer> if b:scrolloffpad_appended == 0 && line('.') == line('$') | call append('$', 'appended') | let b:scrolloffpad_appended = 1 | endif
augroup END
normal! ggG
doautocmd <nomodeline> CursorMoved
let states[sop] = [
\ line('.'),
\ line('$'),
\ line('w0'),
\ line('w$'),
\ winline(),
\ b:scrolloffpad_appended,
\ ]
call assert_equal(1, b:scrolloffpad_appended)
call assert_equal(states[sop][1] - 1, states[sop][0])
augroup ScrolloffpadAppendAtEof
autocmd!
augroup END
bwipe!
endfor
call assert_notequal(states[0], states[1])
call assert_true(states[1][4] < states[0][4])
endfunc
func Test_scrolloffpad_eof_no_reverse_scroll_on_j()
new
resize 20
setlocal scrolloff=20 scrolloffpad=1
call setline(1, map(range(1, 80), 'printf("line %d", v:val)'))
normal! gg
let prev_topline = winsaveview().topline
for lnum in range(2, line('$'))
normal! j
let cur_topline = winsaveview().topline
call assert_true(
\ cur_topline >= prev_topline,
\ printf('topline moved backwards at line %d: %d -> %d',
\ lnum, prev_topline, cur_topline))
let prev_topline = cur_topline
endfor
bwipe!
endfunc
func Test_scrolloffpad_bof_unchanged()
new
resize 12
setlocal scrolloff=10 scrolloffpad=0
call setline(1, map(range(1, 200), 'printf("line %d", v:val)'))
normal! Ggg
let view_without_pad = winsaveview()
let w0_without_pad = line('w0')
setlocal scrolloffpad=1
normal! Ggg
let view_with_pad = winsaveview()
let w0_with_pad = line('w0')
call assert_equal(1, w0_without_pad)
call assert_equal(1, w0_with_pad)
call assert_equal(view_without_pad.topline, view_with_pad.topline)
bwipe!
endfunc
func Test_scrolloffpad_mouse_drag_uses_drag_scrolloff()
CheckFeature mouse
let save_mouse = &mouse
set mouse=a
new
resize 20
call setline(1, map(range(1, 240), 'printf("line %d", v:val)'))
setlocal scrolloff=50
let after_drag = {}
for sop in [0, 1]
let &l:scrolloffpad = sop
normal! gg160Gzt
normal! v
call Ntest_setmouse(2, 1)
call feedkeys("\<LeftMouse>", 'xt')
call Ntest_setmouse(3, 1)
call feedkeys("\<LeftDrag>", 'xt')
let after_drag[sop] = [winsaveview().topline, line('.'), winline()]
call feedkeys("\<Esc>", 'xt')
endfor
call assert_equal(after_drag[0], after_drag[1])
bwipe!
let &mouse = save_mouse
endfunc
func Test_scrolloffpad_basic()
CheckScreendump
CheckRunVimInTerminal
let save_termwinsize = &termwinsize
set termwinsize=
let lines =<< trim END
set scrolloff=10
set scrolloffpad=5
enew!
call setline(1, map(range(1, 100), 'printf("line %d", v:val)'))
normal! gg
END
call writefile(lines, 'XScrolloffpadBasic', 'D')
let buf = RunVimInTerminal('-S XScrolloffpadBasic', {'rows': 20, 'cols': 78})
" Enabled: scrolloffpad > 0, expect EOF centering/padding
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! G\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_basic_1', {})
" Beginning-of-file is unchanged (Top)
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! gg\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_basic_2', {})
" Gating: disable scrolloffpad, then go to EOF again
" Expect normal EOF behavior (no extra centering/padding)
call term_sendkeys(buf, "\<Esc>:\<C-U>set scrolloffpad=0\<CR>")
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! G\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_basic_3', {})
call StopVimInTerminal(buf)
let &termwinsize = save_termwinsize
endfunc
func Test_scrolloffpad_smoothscroll()
CheckScreendump
CheckRunVimInTerminal
let save_termwinsize = &termwinsize
set termwinsize=
let lines =<< trim END
set smoothscroll scrolloff=10 scrolloffpad=1
enew!
call setline(1, map(range(1, 100), 'printf("line %d", v:val)'))
normal! gg
END
call writefile(lines, 'XScrolloffpadSmoothscroll', 'D')
let buf = RunVimInTerminal('-S XScrolloffpadSmoothscroll', #{rows: 20, cols: 78})
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! G\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_smoothscroll_1', {})
call term_sendkeys(buf, "\<Esc>:\<C-U>call setline(line('$'), repeat('LONG ', 30))\<CR>")
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! 41|\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_smoothscroll_2', {})
call StopVimInTerminal(buf)
let &termwinsize = save_termwinsize
endfunc
func Test_scrolloffpad_insert_eof()
let save_so = &scrolloff
let save_sop = &scrolloffpad
set scrolloff=10 scrolloffpad=1
enew!
call setline(1, map(range(1, 200), 'printf("line %d", v:val)'))
normal! G
let topline_before = winsaveview().topline
call feedkeys("i\<Esc>", 'xt')
call assert_equal(topline_before, winsaveview().topline)
exe "normal! \<C-E>"
let topline_after = winsaveview().topline
call feedkeys("i\<Esc>", 'xt')
call assert_equal(topline_after, winsaveview().topline)
let &scrolloff = save_so
let &scrolloffpad = save_sop
bwipe!
endfunc
func Test_scrolloffpad_in_diff_mode()
CheckFeature diff
let save_so = &scrolloff
let save_sop = &scrolloffpad
let save_splitright = &splitright
set nosplitright
set scrolloff=10
set scrolloffpad=0
enew
call setline(1, map(range(1, 100), {_, v -> 'line ' .. v}))
diffthis
vnew
call setline(1, map(range(1, 100), {_, v -> 'line ' .. v}))
" Make buffers minimally different to avoid diff folding everything.
call setline(50, 'DIFF LINE 50')
diffthis
windo normal! zR
windo normal! gg
wincmd =
let rows_without = []
let rows_with = []
let near_states = []
let eof_states = []
for sop in [0, 1]
let &scrolloffpad = sop
" Near EOF with real text visible in both windows.
windo normal! 99G
for w in range(1, winnr('$'))
execute w .. 'wincmd w'
let state = [line('.'), line('w0'), line('w$'), winline()]
call assert_equal(99, state[0])
call assert_equal(100, state[2])
if sop == 0
call add(near_states, state)
endif
endfor
call assert_equal(near_states[0], near_states[1])
" EOF in both windows: scrolloffpad should raise the cursor row.
windo normal! G
for w in range(1, winnr('$'))
execute w .. 'wincmd w'
let state = [line('.'), line('w0'), line('w$'), winline()]
call assert_equal(line('$'), state[0])
if sop == 0
call add(eof_states, state)
call add(rows_without, state[3])
else
call add(rows_with, state[3])
endif
endfor
call assert_equal(eof_states[0], eof_states[1])
endfor
call assert_true(rows_with[0] < rows_without[0])
call assert_true(rows_with[1] < rows_without[1])
windo diffoff
%bwipe!
let &scrolloff = save_so
let &scrolloffpad = save_sop
let &splitright = save_splitright
endfunc
func Test_scrolloffpad_diff_eof_filler_behavior()
CheckFeature diff
let save_so = &scrolloff
let save_sop = &scrolloffpad
let save_diffopt = &diffopt
let save_splitright = &splitright
set diffopt+=filler
set scrolloff=10
set scrolloffpad=0
set nosplitright
20new
call setline(1, map(range(1, 100), {_, v -> 'left ' .. v}))
diffthis
let short_wid = win_getid()
vnew
call setline(1, map(range(1, 120), {_, v -> 'right ' .. v}))
diffthis
let long_wid = win_getid()
call assert_true(win_gotoid(short_wid))
let short_height = winheight(0)
call assert_true(win_gotoid(long_wid))
let long_height = winheight(0)
call assert_equal(short_height, long_height)
call assert_equal(20, short_height)
let ordered_diff_wids = [long_wid, short_wid]
let states = {}
for sop in [0, 1]
execute 'set scrolloffpad=' .. sop
for wid in ordered_diff_wids
call assert_true(win_gotoid(wid))
normal! gg
endfor
for wid in ordered_diff_wids
call assert_true(win_gotoid(wid))
normal! G
endfor
call assert_true(win_gotoid(short_wid))
let short_view = winsaveview()
let short_state = [
\ line('.'),
\ line('$'),
\ winline(),
\ short_view.topline,
\ short_view.topfill,
\ diff_filler(line('$') + 1),
\ ]
call assert_equal(short_state[1], short_state[0])
call assert_true(short_state[5] > 0)
call assert_true(win_gotoid(long_wid))
let long_view = winsaveview()
let long_state = [
\ line('.'),
\ line('$'),
\ winline(),
\ long_view.topline,
\ long_view.topfill,
\ ]
call assert_true(long_state[0] > 0 && long_state[0] <= long_state[1])
call assert_equal(short_state[0], long_state[0])
let states[sop] = [short_state, long_state]
endfor
let short_without = states[0][0]
let short_with = states[1][0]
" Environment/layout can shift direction of movement; require only that
" scrolloffpad changes the short-window viewport state under EOF filler.
call assert_true(short_with[2] != short_without[2]
\ || short_with[3] != short_without[3]
\ || short_with[4] != short_without[4])
windo diffoff
call assert_true(win_gotoid(short_wid))
only!
%bwipe!
let &scrolloff = save_so
let &scrolloffpad = save_sop
let &diffopt = save_diffopt
let &splitright = save_splitright
endfunc
func Test_scrolloffpad_with_folds()
CheckScreendump
CheckRunVimInTerminal
CheckFeature folding
let save_termwinsize = &termwinsize
set termwinsize=
let lines =<< trim END
set scrolloff=10
set scrolloffpad=1
enew
call setline(1, map(range(1, 120), {_, v -> 'line ' . v}))
" Create a large fold near the end of the file.
" Fold lines 60-110, leaving 111-120 visible after the fold.
set foldmethod=manual
set foldenable
normal! gg
normal! 60G
normal! zf50j
normal! gg
END
call writefile(lines, 'XScrolloffpadFolds', 'D')
let buf = RunVimInTerminal('-S XScrolloffpadFolds', #{rows: 20, cols: 78})
" Case 1: Jump to end-of-file
" With folds present, scrolloffpad should still
" keep the cursor positioned with padding below EOF
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! G\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_folds_1', {})
" Case 2: Move to the folded line to ensure the fold is actually in view
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! 60G\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_folds_2', {})
" Case 3: Close the fold explicitly and go to EOF again
" Behavior should remain stable with closed folds
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! zc\<CR>")
call term_sendkeys(buf, "\<Esc>:\<C-U>normal! G\<CR>")
call term_sendkeys(buf, "\<C-L>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_scrolloffpad_folds_3', {})
call StopVimInTerminal(buf)
let &termwinsize = save_termwinsize
endfunc
" Resizing to "textoff" after 'smoothscroll' skips part of a wrapped line must
" not crash.
func Test_smoothscroll_textoff_showbreak()
CheckOption smoothscroll
CheckRunVimInTerminal
let donefile = 'XTest_crash_textoff_showbreak_done'
defer delete(donefile)
let lines =<< trim END
set noswapfile
set scrolloff=0
set lines=12 columns=40
call setline(1, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
set number wrap smoothscroll showbreak=>
vsplit
let textoff = getwininfo(win_getid())[0].textoff
execute "normal! 0\<C-E>"
redraw
execute 'vertical resize' textoff
redraw
call writefile(['done'], 'XTest_crash_textoff_showbreak_done')
END
call writefile(lines, 'XTest_crash_textoff_showbreak', 'D')
let buf = 0
let buf = term_start([GetVimProg(), '--clean'], #{term_rows: 24, term_cols: 80})
call TermWait(buf, 200)
call term_sendkeys(buf, ":source XTest_crash_textoff_showbreak\<CR>")
call WaitForAssert({-> assert_true(filereadable(donefile))})
let status = term_getstatus(buf)
call assert_equal('running', status)
call assert_true(filereadable(donefile))
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab