neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

test_window_cmd.vim (62420B)


      1 " Tests for window cmd (:wincmd, :split, :vsplit, :resize and etc...)
      2 
      3 source check.vim
      4 source screendump.vim
      5 
      6 func Test_window_cmd_ls0_with_split()
      7  set ls=0
      8  set splitbelow
      9  split
     10  quit
     11  call assert_equal(0, &lines - &cmdheight - winheight(0))
     12  new | only!
     13  "
     14  set splitbelow&vim
     15  botright split
     16  quit
     17  call assert_equal(0, &lines - &cmdheight - winheight(0))
     18  new | only!
     19  set ls&vim
     20 endfunc
     21 
     22 func Test_window_cmd_ls0_split_scrolling()
     23  CheckRunVimInTerminal
     24 
     25  let lines =<< trim END
     26    set laststatus=0
     27    call setline(1, range(1, 100))
     28    normal! G
     29  END
     30  call writefile(lines, 'XTestLs0SplitScrolling', 'D')
     31  let buf = RunVimInTerminal('-S XTestLs0SplitScrolling', #{rows: 10})
     32 
     33  call term_sendkeys(buf, ":botright split\<CR>")
     34  call WaitForAssert({-> assert_match('Bot$', term_getline(buf, 5))})
     35  call assert_equal('100', term_getline(buf, 4))
     36 
     37  call StopVimInTerminal(buf)
     38 endfunc
     39 
     40 func Test_window_cmd_cmdwin_with_vsp()
     41  let efmt = 'Expected 0 but got %d (in ls=%d, %s window)'
     42  for v in range(0, 2)
     43    exec "set ls=" . v
     44    vsplit
     45    call feedkeys("q:\<CR>")
     46    let ac = &lines - (&cmdheight + winheight(0) + !!v)
     47    let emsg = printf(efmt, ac, v, 'left')
     48    call assert_equal(0, ac, emsg)
     49    wincmd w
     50    let ac = &lines - (&cmdheight + winheight(0) + !!v)
     51    let emsg = printf(efmt, ac, v, 'right')
     52    call assert_equal(0, ac, emsg)
     53    new | only!
     54  endfor
     55  set ls&vim
     56 endfunc
     57 
     58 func Test_cmdheight_not_changed()
     59  set cmdheight=2
     60  set winminheight=0
     61  augroup Maximize
     62    autocmd WinEnter * wincmd _
     63  augroup END
     64  split
     65  tabnew
     66  tabfirst
     67  call assert_equal(2, &cmdheight)
     68 
     69  tabonly!
     70  only
     71  set winminheight& cmdheight&
     72  augroup Maximize
     73    au!
     74  augroup END
     75  augroup! Maximize
     76 endfunc
     77 
     78 " Test for jumping to windows
     79 func Test_window_jump()
     80  new
     81  " jumping to a window with a count greater than the max windows
     82  exe "normal 4\<C-W>w"
     83  call assert_equal(2, winnr())
     84  only
     85 endfunc
     86 
     87 func Test_window_cmd_wincmd_gf()
     88  let fname = 'test_gf.txt'
     89  let swp_fname = '.' . fname . '.swp'
     90  call writefile([], fname, 'D')
     91  call writefile([], swp_fname, 'D')
     92  function s:swap_exists()
     93    let v:swapchoice = s:swap_choice
     94  endfunc
     95  " Remove the catch-all that runtest.vim adds
     96  au! SwapExists
     97  augroup test_window_cmd_wincmd_gf
     98    autocmd!
     99    exec "autocmd SwapExists " . fname . " call s:swap_exists()"
    100  augroup END
    101 
    102  call setline(1, fname)
    103  " (E)dit anyway
    104  let s:swap_choice = 'e'
    105  wincmd gf
    106  call assert_equal(2, tabpagenr())
    107  call assert_equal(fname, bufname("%"))
    108  quit!
    109 
    110  " (Q)uit
    111  let s:swap_choice = 'q'
    112  wincmd gf
    113  call assert_equal(1, tabpagenr())
    114  call assert_notequal(fname, bufname("%"))
    115  new | only!
    116 
    117  augroup! test_window_cmd_wincmd_gf
    118  bw!
    119 endfunc
    120 
    121 func Test_window_quit()
    122  e Xa
    123  split Xb
    124  call assert_equal(2, '$'->winnr())
    125  call assert_equal('Xb', bufname(winbufnr(1)))
    126  call assert_equal('Xa', bufname(winbufnr(2)))
    127 
    128  wincmd q
    129  call assert_equal(1, winnr('$'))
    130  call assert_equal('Xa', bufname(winbufnr(1)))
    131 
    132  bw Xa Xb
    133 endfunc
    134 
    135 func Test_window_horizontal_split()
    136  call assert_equal(1, winnr('$'))
    137  3wincmd s
    138  call assert_equal(2, winnr('$'))
    139  call assert_equal(3, winheight(0))
    140  call assert_equal(winwidth(1), 2->winwidth())
    141 
    142  call assert_fails('botright topleft wincmd s', 'E442:')
    143  bw
    144 endfunc
    145 
    146 func Test_window_vertical_split()
    147  call assert_equal(1, winnr('$'))
    148  3wincmd v
    149  call assert_equal(2, winnr('$'))
    150  call assert_equal(3, winwidth(0))
    151  call assert_equal(winheight(1), winheight(2))
    152 
    153  call assert_fails('botright topleft wincmd v', 'E442:')
    154  bw
    155 endfunc
    156 
    157 " Test the ":wincmd ^" and "<C-W>^" commands.
    158 func Test_window_split_edit_alternate()
    159  " Test for failure when the alternate buffer/file no longer exists.
    160  edit Xfoo | %bw
    161  call assert_fails(':wincmd ^', 'E23:')
    162 
    163  " Test for the expected behavior when we have two named buffers.
    164  edit Xfoo | edit Xbar
    165  wincmd ^
    166  call assert_equal('Xfoo', bufname(winbufnr(1)))
    167  call assert_equal('Xbar', bufname(winbufnr(2)))
    168  only
    169 
    170  " Test for the expected behavior when the alternate buffer is not named.
    171  enew | let l:nr1 = bufnr('%')
    172  edit Xfoo | let l:nr2 = bufnr('%')
    173  wincmd ^
    174  call assert_equal(l:nr1, winbufnr(1))
    175  call assert_equal(l:nr2, winbufnr(2))
    176  only
    177 
    178  " FIXME: this currently fails on AppVeyor, but passes locally
    179  if !has('win32')
    180    " Test the Normal mode command.
    181    call feedkeys("\<C-W>\<C-^>", 'tx')
    182    call assert_equal(l:nr2, winbufnr(1))
    183    call assert_equal(l:nr1, winbufnr(2))
    184  endif
    185 
    186  %bw!
    187 endfunc
    188 
    189 " Test the ":[count]wincmd ^" and "[count]<C-W>^" commands.
    190 func Test_window_split_edit_bufnr()
    191  %bwipeout
    192  let l:nr = bufnr('%') + 1
    193  call assert_fails(':execute "normal! ' . l:nr . '\<C-W>\<C-^>"', 'E92:')
    194  call assert_fails(':' . l:nr . 'wincmd ^', 'E16:')
    195  call assert_fails(':0wincmd ^', 'E16:')
    196 
    197  edit Xfoo | edit Xbar | edit Xbaz
    198  let l:foo_nr = bufnr('Xfoo')
    199  let l:bar_nr = bufnr('Xbar')
    200  let l:baz_nr = bufnr('Xbaz')
    201 
    202  " FIXME: this currently fails on AppVeyor, but passes locally
    203  if !has('win32')
    204    call feedkeys(l:foo_nr . "\<C-W>\<C-^>", 'tx')
    205    call assert_equal('Xfoo', bufname(winbufnr(1)))
    206    call assert_equal('Xbaz', bufname(winbufnr(2)))
    207    only
    208 
    209    call feedkeys(l:bar_nr . "\<C-W>\<C-^>", 'tx')
    210    call assert_equal('Xbar', bufname(winbufnr(1)))
    211    call assert_equal('Xfoo', bufname(winbufnr(2)))
    212    only
    213 
    214    execute l:baz_nr . 'wincmd ^'
    215    call assert_equal('Xbaz', bufname(winbufnr(1)))
    216    call assert_equal('Xbar', bufname(winbufnr(2)))
    217  endif
    218 
    219  %bw!
    220 endfunc
    221 
    222 func s:win_layout_info(tp = tabpagenr()) abort
    223  return #{
    224        \ layout: winlayout(a:tp),
    225        \ pos_sizes: range(1, tabpagewinnr(a:tp, '$'))
    226        \            ->map({_, nr -> win_getid(nr, a:tp)->getwininfo()[0]})
    227        \            ->map({_, wininfo -> #{id: wininfo.winid,
    228        \                                   row: wininfo.winrow,
    229        \                                   col: wininfo.wincol,
    230        \                                   width: wininfo.width,
    231        \                                   height: wininfo.height}})
    232        \            ->sort({a, b -> a.id - b.id})
    233        \ }
    234 endfunc
    235 
    236 func Test_window_split_no_room()
    237  " N horizontal windows need >= 2*N + 1 lines:
    238  " - 1 line + 1 status line in each window
    239  " - 1 Ex command line
    240  "
    241  " 2*N + 1 <= &lines
    242  " N <= (lines - 1)/2
    243  "
    244  " Beyond that number of windows, E36: Not enough room is expected.
    245  let hor_win_count = (&lines - 1)/2
    246  let hor_split_count = hor_win_count - 1
    247  for s in range(1, hor_split_count) | split | endfor
    248  call assert_fails('split', 'E36:')
    249 
    250  botright vsplit
    251  wincmd |
    252  let info = s:win_layout_info()
    253  call assert_fails('wincmd J', 'E36:')
    254  call assert_fails('wincmd K', 'E36:')
    255  call assert_equal(info, s:win_layout_info())
    256  only
    257 
    258  " N vertical windows need >= 2*(N - 1) + 1 columns:
    259  " - 1 column + 1 separator for each window (except last window)
    260  " - 1 column for the last window which does not have separator
    261  "
    262  " 2*(N - 1) + 1 <= &columns
    263  " 2*N - 1 <= &columns
    264  " N <= (&columns + 1)/2
    265  let ver_win_count = (&columns + 1)/2
    266  let ver_split_count = ver_win_count - 1
    267  for s in range(1, ver_split_count) | vsplit | endfor
    268  call assert_fails('vsplit', 'E36:')
    269 
    270  split
    271  wincmd |
    272  let info = s:win_layout_info()
    273  call assert_fails('wincmd H', 'E36:')
    274  call assert_fails('wincmd L', 'E36:')
    275  call assert_equal(info, s:win_layout_info())
    276 
    277  " Check that the last statusline isn't lost.
    278  " Set its window's width to 2 for the test.
    279  wincmd j
    280  set laststatus=0 winminwidth=0
    281  vertical resize 2
    282  " Update expected positions/sizes after the resize.  Layout is unchanged.
    283  let info.pos_sizes = s:win_layout_info().pos_sizes
    284  set winminwidth&
    285  call setwinvar(winnr('k'), '&statusline', '@#')
    286  let last_stl_row = win_screenpos(0)[0] - 1
    287  redraw
    288  call assert_equal('@#|', GetScreenStr(last_stl_row))
    289  call assert_equal('~ |', GetScreenStr(&lines - &cmdheight))
    290 
    291  call assert_fails('wincmd H', 'E36:')
    292  call assert_fails('wincmd L', 'E36:')
    293  call assert_equal(info, s:win_layout_info())
    294  call setwinvar(winnr('k'), '&statusline', '=-')
    295  redraw
    296  call assert_equal('=-|', GetScreenStr(last_stl_row))
    297  call assert_equal('~ |', GetScreenStr(&lines - &cmdheight))
    298 
    299  %bw!
    300  set laststatus&
    301 endfunc
    302 
    303 func Test_window_exchange()
    304  e Xa
    305 
    306  " Nothing happens with window exchange when there is 1 window
    307  wincmd x
    308  call assert_equal(1, winnr('$'))
    309 
    310  split Xb
    311  split Xc
    312 
    313  call assert_equal('Xc', bufname(winbufnr(1)))
    314  call assert_equal('Xb', bufname(winbufnr(2)))
    315  call assert_equal('Xa', bufname(winbufnr(3)))
    316 
    317  " Exchange current window 1 with window 3
    318  3wincmd x
    319  call assert_equal('Xa', bufname(winbufnr(1)))
    320  call assert_equal('Xb', bufname(winbufnr(2)))
    321  call assert_equal('Xc', bufname(winbufnr(3)))
    322 
    323  " Exchange window with next when at the top window
    324  wincmd x
    325  call assert_equal('Xb', bufname(winbufnr(1)))
    326  call assert_equal('Xa', bufname(winbufnr(2)))
    327  call assert_equal('Xc', bufname(winbufnr(3)))
    328 
    329  " Exchange window with next when at the middle window
    330  wincmd j
    331  wincmd x
    332  call assert_equal('Xb', bufname(winbufnr(1)))
    333  call assert_equal('Xc', bufname(winbufnr(2)))
    334  call assert_equal('Xa', bufname(winbufnr(3)))
    335 
    336  " Exchange window with next when at the bottom window.
    337  " When there is no next window, it exchanges with the previous window.
    338  wincmd j
    339  wincmd x
    340  call assert_equal('Xb', bufname(winbufnr(1)))
    341  call assert_equal('Xa', bufname(winbufnr(2)))
    342  call assert_equal('Xc', bufname(winbufnr(3)))
    343 
    344  bw Xa Xb Xc
    345 endfunc
    346 
    347 func Test_window_rotate()
    348  e Xa
    349  split Xb
    350  split Xc
    351  call assert_equal('Xc', bufname(winbufnr(1)))
    352  call assert_equal('Xb', bufname(winbufnr(2)))
    353  call assert_equal('Xa', bufname(winbufnr(3)))
    354 
    355  " Rotate downwards
    356  wincmd r
    357  call assert_equal('Xa', bufname(winbufnr(1)))
    358  call assert_equal('Xc', bufname(winbufnr(2)))
    359  call assert_equal('Xb', bufname(winbufnr(3)))
    360 
    361  2wincmd r
    362  call assert_equal('Xc', bufname(winbufnr(1)))
    363  call assert_equal('Xb', bufname(winbufnr(2)))
    364  call assert_equal('Xa', bufname(winbufnr(3)))
    365 
    366  " Rotate upwards
    367  wincmd R
    368  call assert_equal('Xb', bufname(winbufnr(1)))
    369  call assert_equal('Xa', bufname(winbufnr(2)))
    370  call assert_equal('Xc', bufname(winbufnr(3)))
    371 
    372  2wincmd R
    373  call assert_equal('Xc', bufname(winbufnr(1)))
    374  call assert_equal('Xb', bufname(winbufnr(2)))
    375  call assert_equal('Xa', bufname(winbufnr(3)))
    376 
    377  bot vsplit
    378  call assert_fails('wincmd R', 'E443:')
    379 
    380  bw Xa Xb Xc
    381 endfunc
    382 
    383 func Test_window_height()
    384  e Xa
    385  split Xb
    386 
    387  let [wh1, wh2] = [winheight(1), winheight(2)]
    388  " Active window (1) should have the same height or 1 more
    389  " than the other window.
    390  call assert_inrange(wh2, wh2 + 1, wh1)
    391 
    392  wincmd -
    393  call assert_equal(wh1 - 1, winheight(1))
    394  call assert_equal(wh2 + 1, winheight(2))
    395 
    396  wincmd +
    397  call assert_equal(wh1, winheight(1))
    398  call assert_equal(wh2, 2->winheight())
    399 
    400  2wincmd _
    401  call assert_equal(2, winheight(1))
    402  call assert_equal(wh1 + wh2 - 2, winheight(2))
    403 
    404  wincmd =
    405  call assert_equal(wh1, winheight(1))
    406  call assert_equal(wh2, winheight(2))
    407 
    408  2wincmd _
    409  set winfixheight
    410  split Xc
    411  let [wh1, wh2, wh3] = [winheight(1), winheight(2), winheight(3)]
    412  call assert_equal(2, winheight(2))
    413  call assert_inrange(wh3, wh3 + 1, wh1)
    414  3wincmd +
    415  call assert_equal(2,       winheight(2))
    416  call assert_equal(wh1 + 3, winheight(1))
    417  call assert_equal(wh3 - 3, winheight(3))
    418  wincmd =
    419  call assert_equal(2,   winheight(2))
    420  call assert_equal(wh1, winheight(1))
    421  call assert_equal(wh3, winheight(3))
    422 
    423  wincmd j
    424  set winfixheight&
    425 
    426  wincmd =
    427  let [wh1, wh2, wh3] = [winheight(1), winheight(2), winheight(3)]
    428  " Current window (2) should have the same height or 1 more
    429  " than the other windows.
    430  call assert_inrange(wh1, wh1 + 1, wh2)
    431  call assert_inrange(wh3, wh3 + 1, wh2)
    432 
    433  bw Xa Xb Xc
    434 endfunc
    435 
    436 func Test_wincmd_equal()
    437  edit Xone
    438  below split Xtwo
    439  rightbelow vsplit Xthree
    440  call assert_equal('Xone', bufname(winbufnr(1)))
    441  call assert_equal('Xtwo', bufname(winbufnr(2)))
    442  call assert_equal('Xthree', bufname(winbufnr(3)))
    443 
    444  " Xone and Xtwo should be about the same height
    445  let [wh1, wh2] = [winheight(1), winheight(2)]
    446  call assert_inrange(wh1 - 1, wh1 + 1, wh2)
    447  " Xtwo and Xthree should be about the same width
    448  let [ww2, ww3] = [winwidth(2), winwidth(3)]
    449  call assert_inrange(ww2 - 1, ww2 + 1, ww3)
    450 
    451  1wincmd w
    452  10wincmd _
    453  2wincmd w
    454  20wincmd |
    455  call assert_equal(10, winheight(1))
    456  call assert_equal(20, winwidth(2))
    457 
    458  " equalizing horizontally doesn't change the heights
    459  hor wincmd =
    460  call assert_equal(10, winheight(1))
    461  let [ww2, ww3] = [winwidth(2), winwidth(3)]
    462  call assert_inrange(ww2 - 1, ww2 + 1, ww3)
    463 
    464  2wincmd w
    465  20wincmd |
    466  call assert_equal(20, winwidth(2))
    467  " equalizing vertically doesn't change the widths
    468  vert wincmd =
    469  call assert_equal(20, winwidth(2))
    470  let [wh1, wh2] = [winheight(1), winheight(2)]
    471  call assert_inrange(wh1 - 1, wh1 + 1, wh2)
    472 
    473  bwipe Xone Xtwo Xthree
    474 endfunc
    475 
    476 func Test_window_width()
    477  e Xa
    478  vsplit Xb
    479 
    480  let [ww1, ww2] = [winwidth(1), winwidth(2)]
    481  " Active window (1) should have the same width or 1 more
    482  " than the other window.
    483  call assert_inrange(ww2, ww2 + 1, ww1)
    484 
    485  wincmd <
    486  call assert_equal(ww1 - 1, winwidth(1))
    487  call assert_equal(ww2 + 1, winwidth(2))
    488 
    489  wincmd >
    490  call assert_equal(ww1, winwidth(1))
    491  call assert_equal(ww2, winwidth(2))
    492 
    493  2wincmd |
    494  call assert_equal(2, winwidth(1))
    495  call assert_equal(ww1 + ww2 - 2, winwidth(2))
    496 
    497  wincmd =
    498  call assert_equal(ww1, winwidth(1))
    499  call assert_equal(ww2, winwidth(2))
    500 
    501  2wincmd |
    502  set winfixwidth
    503  vsplit Xc
    504  let [ww1, ww2, ww3] = [winwidth(1), winwidth(2), winwidth(3)]
    505  call assert_equal(2, winwidth(2))
    506  call assert_inrange(ww3, ww3 + 1, ww1)
    507  3wincmd >
    508  call assert_equal(2,       winwidth(2))
    509  call assert_equal(ww1 + 3, winwidth(1))
    510  call assert_equal(ww3 - 3, winwidth(3))
    511  wincmd =
    512  call assert_equal(2,   winwidth(2))
    513  call assert_equal(ww1, winwidth(1))
    514  call assert_equal(ww3, winwidth(3))
    515 
    516  wincmd l
    517  set winfixwidth&
    518 
    519  wincmd =
    520  let [ww1, ww2, ww3] = [winwidth(1), winwidth(2), winwidth(3)]
    521  " Current window (2) should have the same width or 1 more
    522  " than the other windows.
    523  call assert_inrange(ww1, ww1 + 1, ww2)
    524  call assert_inrange(ww3, ww3 + 1, ww2)
    525 
    526  " when the current window width is less than the new 'winwidth', the current
    527  " window width should be increased.
    528  enew | only
    529  split
    530  10vnew
    531  set winwidth=15
    532  call assert_equal(15, winwidth(0))
    533 
    534  %bw!
    535 endfunc
    536 
    537 func Test_equalalways_on_close()
    538  set equalalways
    539  vsplit
    540  windo split
    541  split
    542  wincmd J
    543  " now we have a frame top-left with two windows, a frame top-right with two
    544  " windows and a frame at the bottom, full-width.
    545  let height_1 = winheight(1)
    546  let height_2 = winheight(2)
    547  let height_3 = winheight(3)
    548  let height_4 = winheight(4)
    549  " closing the bottom window causes all windows to be resized.
    550  close
    551  call assert_notequal(height_1, winheight(1))
    552  call assert_notequal(height_2, winheight(2))
    553  call assert_notequal(height_3, winheight(3))
    554  call assert_notequal(height_4, winheight(4))
    555  call assert_equal(winheight(1), winheight(3))
    556  call assert_equal(winheight(2), winheight(4))
    557 
    558  1wincmd w
    559  split
    560  4wincmd w
    561  resize +5
    562  " left column has three windows, equalized heights.
    563  " right column has two windows, top one a bit higher
    564  let height_1 = winheight(1)
    565  let height_2 = winheight(2)
    566  let height_4 = winheight(4)
    567  let height_5 = winheight(5)
    568  3wincmd w
    569  " closing window in left column equalizes heights in left column but not in
    570  " the right column
    571  close
    572  call assert_notequal(height_1, winheight(1))
    573  call assert_notequal(height_2, winheight(2))
    574  call assert_equal(height_4, winheight(3))
    575  call assert_equal(height_5, winheight(4))
    576 
    577  only
    578  set equalalways&
    579 endfunc
    580 
    581 func Test_win_screenpos()
    582  CheckFeature quickfix
    583 
    584  call assert_equal(1, winnr('$'))
    585  split
    586  vsplit
    587  10wincmd _
    588  30wincmd |
    589  call assert_equal([1, 1], win_screenpos(1))
    590  call assert_equal([1, 32], win_screenpos(2))
    591  call assert_equal([12, 1], win_screenpos(3))
    592  call assert_equal([0, 0], win_screenpos(4))
    593  call assert_fails('let l = win_screenpos([])', 'E745:')
    594  only
    595 endfunc
    596 
    597 func Test_window_jump_tag()
    598  CheckFeature quickfix
    599 
    600  help
    601  /Kuwasha
    602  call assert_match('^- |Kuwasha|',  getline('.'))
    603  call assert_equal(2, winnr('$'))
    604  norm! fK
    605  2wincmd }
    606  call assert_equal(3, winnr('$'))
    607  call assert_match('^- |Kuwasha|',  getline('.'))
    608  wincmd k
    609  call assert_match('\*Kuwasha\*',  getline('.'))
    610  call assert_equal(2, winheight(0))
    611 
    612  wincmd z
    613  set previewheight=4
    614  help
    615  /bugs
    616  norm! fb
    617  wincmd }
    618  wincmd k
    619  call assert_match('\*bugs\*',  getline('.'))
    620  call assert_equal(4, winheight(0))
    621  set previewheight&
    622 
    623  %bw!
    624 endfunc
    625 
    626 func Test_window_newtab()
    627  e Xa
    628 
    629  call assert_equal(1, tabpagenr('$'))
    630  call assert_equal("\nAlready only one window", execute('wincmd T'))
    631 
    632  split Xb
    633  split Xc
    634 
    635  wincmd T
    636  call assert_equal(2, tabpagenr('$'))
    637  call assert_equal(['Xb', 'Xa'], map(tabpagebuflist(1), 'bufname(v:val)'))
    638  call assert_equal(['Xc'      ], map(2->tabpagebuflist(), 'bufname(v:val)'))
    639  call assert_equal(['Xc'      ], map(tabpagebuflist(), 'bufname(v:val)'))
    640 
    641  %bw!
    642 endfunc
    643 
    644 func Test_next_split_all()
    645  " This was causing an illegal memory access.
    646  n x
    647  norm axxx
    648  split
    649  split
    650  s/x
    651  s/x
    652  all
    653  bwipe!
    654 endfunc
    655 
    656 " Tests for adjusting window and contents
    657 func GetScreenStr(row)
    658   let str = ""
    659   for c in range(1,3)
    660       let str .= nr2char(screenchar(a:row, c))
    661   endfor
    662   return str
    663 endfunc
    664 
    665 func Test_window_contents()
    666  enew! | only | new
    667  call setline(1, range(1,256))
    668 
    669  exe "norm! \<C-W>t\<C-W>=1Gzt\<C-W>w\<C-W>+"
    670  redraw
    671  let s3 = GetScreenStr(1)
    672  wincmd p
    673  call assert_equal(1, line("w0"))
    674  call assert_equal('1  ', s3)
    675 
    676  exe "norm! \<C-W>t\<C-W>=50Gzt\<C-W>w\<C-W>+"
    677  redraw
    678  let s3 = GetScreenStr(1)
    679  wincmd p
    680  call assert_equal(50, line("w0"))
    681  call assert_equal('50 ', s3)
    682 
    683  exe "norm! \<C-W>t\<C-W>=59Gzt\<C-W>w\<C-W>+"
    684  redraw
    685  let s3 = GetScreenStr(1)
    686  wincmd p
    687  call assert_equal(59, line("w0"))
    688  call assert_equal('59 ', s3)
    689 
    690  %d
    691  call setline(1, ['one', 'two', 'three'])
    692  call assert_equal(1, line('w0'))
    693  call assert_equal(3, line('w$'))
    694 
    695  bwipeout!
    696  call test_garbagecollect_now()
    697 endfunc
    698 
    699 func Test_window_colon_command()
    700  " This was reading invalid memory.
    701  exe "norm! v\<C-W>:\<C-U>echo v:version"
    702 endfunc
    703 
    704 func Test_access_freed_mem()
    705  call assert_equal(&columns, winwidth(0))
    706  " This was accessing freed memory (but with what events?)
    707  au BufEnter,BufLeave,WinEnter,WinLeave 0 vs xxx
    708  arg 0
    709  argadd
    710  call assert_fails("all", "E242:")
    711  au!
    712  bwipe xxx
    713  call assert_equal(&columns, winwidth(0))
    714 endfunc
    715 
    716 func Test_visual_cleared_after_window_split()
    717  new | only!
    718  let smd_save = &showmode
    719  set showmode
    720  let ls_save = &laststatus
    721  set laststatus=1
    722  call setline(1, ['a', 'b', 'c', 'd', ''])
    723  norm! G
    724  exe "norm! kkvk"
    725  redraw
    726  exe "norm! \<C-W>v"
    727  redraw
    728  " check if '-- VISUAL --' disappeared from command line
    729  let columns = range(1, &columns)
    730  let cmdlinechars = map(columns, 'nr2char(screenchar(&lines, v:val))')
    731  let cmdline = join(cmdlinechars, '')
    732  let cmdline_ltrim = substitute(cmdline, '^\s*', "", "")
    733  let mode_shown = substitute(cmdline_ltrim, '\s*$', "", "")
    734  call assert_equal('', mode_shown)
    735  let &showmode = smd_save
    736  let &laststatus = ls_save
    737  bwipe!
    738 endfunc
    739 
    740 func Test_winrestcmd()
    741  2split
    742  3vsplit
    743  let restcmd = winrestcmd()
    744  call assert_equal(2, winheight(0))
    745  call assert_equal(3, winwidth(0))
    746  wincmd =
    747  call assert_notequal(2, winheight(0))
    748  call assert_notequal(3, winwidth(0))
    749  exe restcmd
    750  call assert_equal(2, winheight(0))
    751  call assert_equal(3, winwidth(0))
    752  only
    753 
    754  wincmd v
    755  wincmd s
    756  wincmd v
    757  redraw
    758  let restcmd = winrestcmd()
    759  wincmd _
    760  wincmd |
    761  exe restcmd
    762  redraw
    763  call assert_equal(restcmd, winrestcmd())
    764 
    765  only
    766 endfunc
    767 
    768 func Fun_RenewFile()
    769  " Need to wait a bit for the timestamp to be older.
    770  let old_ftime = getftime("tmp.txt")
    771  while getftime("tmp.txt") == old_ftime
    772    sleep 100m
    773    silent execute '!echo "1" > tmp.txt'
    774  endwhile
    775  sp
    776  wincmd p
    777  edit! tmp.txt
    778 endfunc
    779 
    780 func Test_window_prevwin()
    781  " Can we make this work on MS-Windows?
    782  CheckUnix
    783 
    784  set hidden autoread
    785  call writefile(['2'], 'tmp.txt', 'D')
    786  new tmp.txt
    787  q
    788  call Fun_RenewFile()
    789  call assert_equal(2, winnr())
    790  wincmd p
    791  call assert_equal(1, winnr())
    792  wincmd p
    793  q
    794  call Fun_RenewFile()
    795  call assert_equal(2, winnr())
    796  wincmd p
    797  call assert_equal(1, winnr())
    798  wincmd p
    799  " reset
    800  q
    801  set hidden&vim autoread&vim
    802  delfunc Fun_RenewFile
    803  bw!
    804 endfunc
    805 
    806 func Test_relative_cursor_position_in_one_line_window()
    807  new
    808  only
    809  call setline(1, range(1, 10000))
    810  normal 50%
    811  let lnum = getcurpos()[1]
    812  split
    813  split
    814  " make third window take as many lines as possible, other windows will
    815  " become one line
    816  3wincmd w
    817  for i in range(1, &lines - 6)
    818    wincmd +
    819    redraw!
    820  endfor
    821 
    822  " first and second window should show cursor line
    823  let wininfo = getwininfo()
    824  call assert_equal(lnum, wininfo[0].topline)
    825  call assert_equal(lnum, wininfo[1].topline)
    826 
    827  only!
    828  bwipe!
    829  call assert_fails('call winrestview(v:_null_dict)', 'E1297:')
    830 endfunc
    831 
    832 func Test_relative_cursor_position_after_move_and_resize()
    833  let so_save = &so
    834  set so=0
    835  enew
    836  call setline(1, range(1, 10000))
    837  normal 50%
    838  split
    839  1wincmd w
    840  " Move cursor to first line in window
    841  normal H
    842  redraw!
    843  " Reduce window height to two lines
    844  let height = winheight(0)
    845  while winheight(0) > 2
    846    wincmd -
    847    redraw!
    848  endwhile
    849  " move cursor to second/last line in window
    850  normal j
    851  " restore previous height
    852  while winheight(0) < height
    853    wincmd +
    854    redraw!
    855  endwhile
    856  " make window two lines again
    857  while winheight(0) > 2
    858    wincmd -
    859    redraw!
    860  endwhile
    861 
    862  " cursor should be at bottom line
    863  let info = getwininfo(win_getid())[0]
    864  call assert_equal(info.topline + 1, getcurpos()[1])
    865 
    866  only!
    867  bwipe!
    868  let &so = so_save
    869 endfunc
    870 
    871 func Test_relative_cursor_position_after_resize()
    872  let so_save = &so
    873  set so=0
    874  enew
    875  call setline(1, range(1, 10000))
    876  normal 50%
    877  split
    878  1wincmd w
    879  let winid1 = win_getid()
    880  let info = getwininfo(winid1)[0]
    881  " Move cursor to second line in window
    882  exe "normal " . (info.topline + 1) . "G"
    883  redraw!
    884  let lnum = getcurpos()[1]
    885 
    886  " Make the window only two lines high, cursor should end up in top line
    887  2wincmd w
    888  exe (info.height - 2) . "wincmd +"
    889  redraw!
    890  let info = getwininfo(winid1)[0]
    891  call assert_equal(lnum, info.topline)
    892 
    893  only!
    894  bwipe!
    895  let &so = so_save
    896 endfunc
    897 
    898 func Test_relative_cursor_second_line_after_resize()
    899  let so_save = &so
    900  set so=0
    901  enew
    902  call setline(1, range(1, 10000))
    903  normal 50%
    904  split
    905  1wincmd w
    906  let winid1 = win_getid()
    907  let info = getwininfo(winid1)[0]
    908 
    909  " Make the window only two lines high
    910  2wincmd _
    911 
    912  " Move cursor to second line in window
    913  normal H
    914  normal j
    915 
    916  " Make window size bigger, then back to 2 lines
    917  for i in range(1, 10)
    918    wincmd +
    919    redraw!
    920  endfor
    921  for i in range(1, 10)
    922    wincmd -
    923    redraw!
    924  endfor
    925 
    926  " cursor should end up in bottom line
    927  let info = getwininfo(winid1)[0]
    928  call assert_equal(info.topline + 1, getcurpos()[1])
    929 
    930  only!
    931  bwipe!
    932  let &so = so_save
    933 endfunc
    934 
    935 func Test_split_noscroll()
    936  let so_save = &so
    937  enew
    938  call setline(1, range(1, 8))
    939  normal 100%
    940  split
    941 
    942  1wincmd w
    943  let winid1 = win_getid()
    944  let info1 = getwininfo(winid1)[0]
    945 
    946  2wincmd w
    947  let winid2 = win_getid()
    948  let info2 = getwininfo(winid2)[0]
    949 
    950  call assert_equal(1, info1.topline)
    951  call assert_equal(1, info2.topline)
    952 
    953  " window that fits all lines by itself, but not when split: closing other
    954  " window should restore fraction.
    955  only!
    956  call setline(1, range(1, &lines - 10))
    957  exe &lines / 4
    958  let winid1 = win_getid()
    959  let info1 = getwininfo(winid1)[0]
    960  call assert_equal(1, info1.topline)
    961  new
    962  redraw
    963  close
    964  let info1 = getwininfo(winid1)[0]
    965  call assert_equal(1, info1.topline)
    966 
    967  bwipe!
    968  let &so = so_save
    969 endfunc
    970 
    971 " Tests for the winnr() function
    972 func Test_winnr()
    973  only | tabonly
    974  call assert_equal(1, winnr('j'))
    975  call assert_equal(1, winnr('k'))
    976  call assert_equal(1, winnr('h'))
    977  call assert_equal(1, winnr('l'))
    978 
    979  " create a set of horizontally and vertically split windows
    980  leftabove new | wincmd p
    981  leftabove new | wincmd p
    982  rightbelow new | wincmd p
    983  rightbelow new | wincmd p
    984  leftabove vnew | wincmd p
    985  leftabove vnew | wincmd p
    986  rightbelow vnew | wincmd p
    987  rightbelow vnew | wincmd p
    988 
    989  call assert_equal(8, winnr('j'))
    990  call assert_equal(2, winnr('k'))
    991  call assert_equal(4, winnr('h'))
    992  call assert_equal(6, winnr('l'))
    993  call assert_equal(9, winnr('2j'))
    994  call assert_equal(1, winnr('2k'))
    995  call assert_equal(3, winnr('2h'))
    996  call assert_equal(7, winnr('2l'))
    997 
    998  " Error cases
    999  call assert_fails("echo winnr('0.2k')", 'E15:')
   1000  call assert_equal(2, winnr('-2k'))
   1001  call assert_fails("echo winnr('-2xj')", 'E15:')
   1002  call assert_fails("echo winnr('j2j')", 'E15:')
   1003  call assert_fails("echo winnr('ll')", 'E15:')
   1004  call assert_fails("echo winnr('5')", 'E15:')
   1005  call assert_equal(4, winnr('0h'))
   1006  call assert_fails("let w = winnr([])", 'E730:')
   1007  call assert_equal('unknown', win_gettype(-1))
   1008  call assert_equal(-1, winheight(-1))
   1009  call assert_equal(-1, winwidth(-1))
   1010 
   1011  tabnew
   1012  call assert_equal(8, tabpagewinnr(1, 'j'))
   1013  call assert_equal(2, 1->tabpagewinnr('k'))
   1014  call assert_equal(4, tabpagewinnr(1, 'h'))
   1015  call assert_equal(6, tabpagewinnr(1, 'l'))
   1016 
   1017  only | tabonly
   1018 endfunc
   1019 
   1020 func Test_winrestview()
   1021  split runtest.vim
   1022  normal 50%
   1023  let view = winsaveview()
   1024  close
   1025  split runtest.vim
   1026  eval view->winrestview()
   1027  call assert_equal(view, winsaveview())
   1028 
   1029  bwipe!
   1030  call assert_fails('call winrestview(v:_null_dict)', 'E1297:')
   1031 endfunc
   1032 
   1033 func Test_win_splitmove()
   1034  CheckFeature quickfix
   1035 
   1036  edit a
   1037  leftabove split b
   1038  leftabove vsplit c
   1039  leftabove split d
   1040 
   1041  " win_splitmove doesn't actually create or close any windows, so expect an
   1042  " unchanged winid and no WinNew/WinClosed events, like :wincmd H/J/K/L.
   1043  let s:triggered = []
   1044  augroup WinSplitMove
   1045    au!
   1046    au WinNewPre * let s:triggered += ['WinNewPre']
   1047    au WinNew * let s:triggered += ['WinNew', win_getid()]
   1048    au WinClosed * let s:triggered += ['WinClosed', str2nr(expand('<afile>'))]
   1049  augroup END
   1050  let winid = win_getid()
   1051 
   1052  call assert_equal(0, win_splitmove(winnr(), winnr('l')))
   1053  call assert_equal(bufname(winbufnr(1)), 'c')
   1054  call assert_equal(bufname(winbufnr(2)), 'd')
   1055  call assert_equal(bufname(winbufnr(3)), 'b')
   1056  call assert_equal(bufname(winbufnr(4)), 'a')
   1057  call assert_equal(0, win_splitmove(winnr(), winnr('j'), {'vertical': 1}))
   1058  call assert_equal(0, win_splitmove(winnr(), winnr('j'), {'vertical': 1}))
   1059  call assert_equal(bufname(winbufnr(1)), 'c')
   1060  call assert_equal(bufname(winbufnr(2)), 'b')
   1061  call assert_equal(bufname(winbufnr(3)), 'd')
   1062  call assert_equal(bufname(winbufnr(4)), 'a')
   1063  call assert_equal(0, win_splitmove(winnr(), winnr('k'), {'vertical': 1}))
   1064  call assert_equal(bufname(winbufnr(1)), 'd')
   1065  call assert_equal(bufname(winbufnr(2)), 'c')
   1066  call assert_equal(bufname(winbufnr(3)), 'b')
   1067  call assert_equal(bufname(winbufnr(4)), 'a')
   1068  call assert_equal(0, win_splitmove(winnr(), winnr('j'), {'rightbelow': v:true}))
   1069  call assert_equal(bufname(winbufnr(1)), 'c')
   1070  call assert_equal(bufname(winbufnr(2)), 'b')
   1071  call assert_equal(bufname(winbufnr(3)), 'a')
   1072  call assert_equal(bufname(winbufnr(4)), 'd')
   1073  call assert_fails('call win_splitmove(winnr(), winnr("k"), v:_null_dict)', 'E1297:')
   1074  call assert_equal([], s:triggered)
   1075  call assert_equal(winid, win_getid())
   1076 
   1077  unlet! s:triggered
   1078  au! WinSplitMove
   1079  only | bd
   1080 
   1081  call assert_fails('call win_splitmove(winnr(), 123)', 'E957:')
   1082  call assert_fails('call win_splitmove(123, winnr())', 'E957:')
   1083  call assert_fails('call win_splitmove(winnr(), winnr())', 'E957:')
   1084 
   1085  tabnew
   1086  call assert_fails('call win_splitmove(1, win_getid(1, 1))', 'E957:')
   1087  tabclose
   1088 
   1089  split
   1090  augroup WinSplitMove
   1091    au!
   1092    au WinEnter * ++once call win_gotoid(win_getid(winnr('#')))
   1093  augroup END
   1094  call assert_fails('call win_splitmove(winnr(), winnr("#"))', 'E855:')
   1095 
   1096  augroup WinSplitMove
   1097    au!
   1098    au WinLeave * ++once quit
   1099  augroup END
   1100  call assert_fails('call win_splitmove(winnr(), winnr("#"))', 'E855:')
   1101 
   1102  split
   1103  split
   1104  augroup WinSplitMove
   1105    au!
   1106    au WinEnter * ++once let s:triggered = v:true
   1107          \| call assert_fails('call win_splitmove(winnr(), winnr("$"))', 'E242:')
   1108          \| call assert_fails('call win_splitmove(winnr("$"), winnr())', 'E242:')
   1109  augroup END
   1110  quit
   1111  call assert_equal(v:true, s:triggered)
   1112  unlet! s:triggered
   1113 
   1114  new
   1115  augroup WinSplitMove
   1116    au!
   1117    au BufHidden * ++once let s:triggered = v:true
   1118          \| call assert_fails('call win_splitmove(winnr(), winnr("#"))', 'E1159:')
   1119  augroup END
   1120  hide
   1121  call assert_equal(v:true, s:triggered)
   1122  unlet! s:triggered
   1123 
   1124  split
   1125  let close_win = winnr('#')
   1126  augroup WinSplitMove
   1127    au!
   1128    au WinEnter * ++once quit!
   1129  augroup END
   1130  call win_splitmove(close_win, winnr())
   1131  call assert_equal(0, win_id2win(close_win))
   1132 
   1133  au! WinSplitMove
   1134  augroup! WinSplitMove
   1135  %bw!
   1136 endfunc
   1137 
   1138 " Test for the :only command
   1139 func Test_window_only()
   1140  new
   1141  set modified
   1142  new
   1143  call assert_fails('only', 'E445:')
   1144  only!
   1145  " Test for :only with a count
   1146  let wid = win_getid()
   1147  new
   1148  new
   1149  3only
   1150  call assert_equal(1, winnr('$'))
   1151  call assert_equal(wid, win_getid())
   1152  call assert_fails('close', 'E444:')
   1153  call assert_fails('%close', 'E16:')
   1154 endfunc
   1155 
   1156 " Test for errors with :wincmd
   1157 func Test_wincmd_errors()
   1158  call assert_fails('wincmd g', 'E474:')
   1159  call assert_fails('wincmd ab', 'E474:')
   1160 endfunc
   1161 
   1162 " Test for errors with :winpos
   1163 func Test_winpos_errors()
   1164  throw 'Skipped: Nvim does not have :winpos'
   1165  if !has("gui_running") && !has('win32')
   1166    call assert_fails('winpos', 'E188:')
   1167  endif
   1168  call assert_fails('winpos 10', 'E466:')
   1169 endfunc
   1170 
   1171 " Test for +cmd in a :split command
   1172 func Test_split_cmd()
   1173  split +set\ readonly
   1174  call assert_equal(1, &readonly)
   1175  call assert_equal(2, winnr('$'))
   1176  close
   1177 endfunc
   1178 
   1179 " Create maximum number of horizontally or vertically split windows and then
   1180 " run commands that create a new horizontally/vertically split window
   1181 func Run_noroom_for_newwindow_test(dir_arg)
   1182  let dir = (a:dir_arg == 'v') ? 'vert ' : ''
   1183 
   1184  " Open as many windows as possible
   1185  while v:true
   1186    try
   1187      exe dir . 'new'
   1188    catch /E36:/
   1189      break
   1190    endtry
   1191  endwhile
   1192 
   1193  call writefile(['first', 'second', 'third'], 'Xnorfile1')
   1194  call writefile([], 'Xnorfile2')
   1195  call writefile([], 'Xnorfile3')
   1196 
   1197  " Argument list related commands
   1198  args Xnorfile1 Xnorfile2 Xnorfile3
   1199  next
   1200  for cmd in ['sargument 2', 'snext', 'sprevious', 'sNext', 'srewind',
   1201 		\ 'sfirst', 'slast']
   1202    call assert_fails(dir .. cmd, 'E36:')
   1203  endfor
   1204  %argdelete
   1205 
   1206  " Buffer related commands
   1207  set modified
   1208  hide enew
   1209  for cmd in ['sbuffer Xnorfile1', 'sbnext', 'sbprevious', 'sbNext', 'sbrewind',
   1210 	\ 'sbfirst', 'sblast', 'sball', 'sbmodified', 'sunhide']
   1211    call assert_fails(dir .. cmd, 'E36:')
   1212  endfor
   1213 
   1214  " Window related commands
   1215  for cmd in ['split', 'split Xnorfile2', 'new', 'new Xnorfile3', 'sview Xnorfile1',
   1216 	\ 'sfind runtest.vim']
   1217    call assert_fails(dir .. cmd, 'E36:')
   1218  endfor
   1219 
   1220  " Help
   1221  call assert_fails(dir .. 'help', 'E36:')
   1222  call assert_fails(dir .. 'helpgrep window', 'E36:')
   1223 
   1224  " Command-line window
   1225  if a:dir_arg == 'h'
   1226    " Cmd-line window is always a horizontally split window
   1227    call assert_beeps('call feedkeys("q:\<CR>", "xt")')
   1228  endif
   1229 
   1230  " Quickfix and location list window
   1231  if has('quickfix')
   1232    cexpr ''
   1233    call assert_fails(dir .. 'copen', 'E36:')
   1234    lexpr ''
   1235    call assert_fails(dir .. 'lopen', 'E36:')
   1236 
   1237    " Preview window
   1238    call assert_fails(dir .. 'pedit Xnorfile2', 'E36:')
   1239    call assert_fails(dir .. 'pbuffer', 'E36:')
   1240    call setline(1, 'abc')
   1241    call assert_fails(dir .. 'psearch abc', 'E36:')
   1242  endif
   1243 
   1244  " Window commands (CTRL-W ^ and CTRL-W f)
   1245  if a:dir_arg == 'h'
   1246    call assert_fails('call feedkeys("\<C-W>^", "xt")', 'E36:')
   1247    call setline(1, 'Xnorfile1')
   1248    call assert_fails('call feedkeys("gg\<C-W>f", "xt")', 'E36:')
   1249  endif
   1250  enew!
   1251 
   1252  " Tag commands (:stag, :stselect and :stjump)
   1253  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   1254        \ "second\tXnorfile1\t2",
   1255        \ "third\tXnorfile1\t3",],
   1256        \ 'Xtags')
   1257  set tags=Xtags
   1258  call assert_fails(dir .. 'stag second', 'E36:')
   1259  call assert_fails('call feedkeys(":" .. dir .. "stselect second\n1\n", "xt")', 'E36:')
   1260  call assert_fails(dir .. 'stjump second', 'E36:')
   1261  call assert_fails(dir .. 'ptag second', 'E36:')
   1262  set tags&
   1263  call delete('Xtags')
   1264 
   1265  " :isplit and :dsplit
   1266  call setline(1, ['#define FOO 1', 'FOO'])
   1267  normal 2G
   1268  call assert_fails(dir .. 'isplit FOO', 'E36:')
   1269  call assert_fails(dir .. 'dsplit FOO', 'E36:')
   1270 
   1271  " terminal
   1272  if has('terminal')
   1273    call assert_fails(dir .. 'terminal', 'E36:')
   1274  endif
   1275 
   1276  %bwipe!
   1277  call delete('Xnorfile1')
   1278  call delete('Xnorfile2')
   1279  call delete('Xnorfile3')
   1280  only
   1281 endfunc
   1282 
   1283 func Test_split_cmds_with_no_room()
   1284  call Run_noroom_for_newwindow_test('h')
   1285  call Run_noroom_for_newwindow_test('v')
   1286 endfunc
   1287 
   1288 " Test for various wincmd failures
   1289 func Test_wincmd_fails()
   1290  only!
   1291  call assert_beeps("normal \<C-W>w")
   1292  call assert_beeps("normal \<C-W>p")
   1293  call assert_beeps("normal \<C-W>gk")
   1294  call assert_beeps("normal \<C-W>r")
   1295  call assert_beeps("normal \<C-W>K")
   1296  call assert_beeps("normal \<C-W>H")
   1297  call assert_beeps("normal \<C-W>2gt")
   1298 endfunc
   1299 
   1300 func Test_window_resize()
   1301  " Vertical :resize (absolute, relative, min and max size).
   1302  vsplit
   1303  vert resize 8
   1304  call assert_equal(8, winwidth(0))
   1305  vert resize +2
   1306  call assert_equal(10, winwidth(0))
   1307  vert resize -2
   1308  call assert_equal(8, winwidth(0))
   1309  vert resize
   1310  call assert_equal(&columns - 2, winwidth(0))
   1311  vert resize 0
   1312  call assert_equal(1, winwidth(0))
   1313  vert resize 99999
   1314  call assert_equal(&columns - 2, winwidth(0))
   1315 
   1316  %bwipe!
   1317 
   1318  " Horizontal :resize (with absolute, relative size, min and max size).
   1319  split
   1320  resize 8
   1321  call assert_equal(8, winheight(0))
   1322  resize +2
   1323  call assert_equal(10, winheight(0))
   1324  resize -2
   1325  call assert_equal(8, winheight(0))
   1326  resize
   1327  call assert_equal(&lines - 4, winheight(0))
   1328  resize 0
   1329  call assert_equal(1, winheight(0))
   1330  resize 99999
   1331  call assert_equal(&lines - 4, winheight(0))
   1332 
   1333  " :resize with explicit window number.
   1334  let other_winnr = winnr('j')
   1335  exe other_winnr .. 'resize 10'
   1336  call assert_equal(10, winheight(other_winnr))
   1337  call assert_equal(&lines - 10 - 3, winheight(0))
   1338  exe other_winnr .. 'resize +1'
   1339  exe other_winnr .. 'resize +1'
   1340  call assert_equal(12, winheight(other_winnr))
   1341  call assert_equal(&lines - 10 - 3 -2, winheight(0))
   1342  close
   1343 
   1344  vsplit
   1345  wincmd l
   1346  let other_winnr = winnr('h')
   1347  call assert_notequal(winnr(), other_winnr)
   1348  exe 'vert ' .. other_winnr .. 'resize -' .. &columns
   1349  call assert_equal(0, winwidth(other_winnr))
   1350 
   1351  %bwipe!
   1352 endfunc
   1353 
   1354 " Test for adjusting the window width when a window is closed with some
   1355 " windows using 'winfixwidth'
   1356 func Test_window_width_adjust()
   1357  only
   1358  " Three vertical windows. Windows 1 and 2 have 'winfixwidth' set and close
   1359  " window 2.
   1360  wincmd v
   1361  vert resize 10
   1362  set winfixwidth
   1363  wincmd v
   1364  set winfixwidth
   1365  wincmd c
   1366  call assert_inrange(10, 12, winwidth(1))
   1367  " Three vertical windows. Windows 2 and 3 have 'winfixwidth' set and close
   1368  " window 3.
   1369  only
   1370  set winfixwidth
   1371  wincmd v
   1372  vert resize 10
   1373  set winfixwidth
   1374  wincmd v
   1375  set nowinfixwidth
   1376  wincmd b
   1377  wincmd c
   1378  call assert_inrange(10, 12, winwidth(2))
   1379 
   1380  new | only
   1381 endfunc
   1382 
   1383 " Test for jumping to a vertical/horizontal neighbor window based on the
   1384 " current cursor position
   1385 func Test_window_goto_neighbor()
   1386  %bw!
   1387 
   1388  " Vertical window movement
   1389 
   1390  " create the following window layout:
   1391  "     +--+--+
   1392  "     |w1|w3|
   1393  "     +--+  |
   1394  "     |w2|  |
   1395  "     +--+--+
   1396  "     |w4   |
   1397  "     +-----+
   1398  new
   1399  vsplit
   1400  split
   1401  " vertically jump from w4
   1402  wincmd b
   1403  call setline(1, repeat(' ', &columns))
   1404  call cursor(1, 1)
   1405  wincmd k
   1406  call assert_equal(2, winnr())
   1407  wincmd b
   1408  call cursor(1, &columns)
   1409  redraw!
   1410  wincmd k
   1411  call assert_equal(3, winnr())
   1412  %bw!
   1413 
   1414  " create the following window layout:
   1415  "     +--+--+--+
   1416  "     |w1|w2|w3|
   1417  "     +--+--+--+
   1418  "     |w4      |
   1419  "     +--------+
   1420  new
   1421  vsplit
   1422  vsplit
   1423  wincmd b
   1424  call setline(1, repeat(' ', &columns))
   1425  call cursor(1, 1)
   1426  wincmd k
   1427  call assert_equal(1, winnr())
   1428  wincmd b
   1429  call cursor(1, &columns / 2)
   1430  redraw!
   1431  wincmd k
   1432  call assert_equal(2, winnr())
   1433  wincmd b
   1434  call cursor(1, &columns)
   1435  redraw!
   1436  wincmd k
   1437  call assert_equal(3, winnr())
   1438  %bw!
   1439 
   1440  " Horizontal window movement
   1441 
   1442  " create the following window layout:
   1443  "     +--+--+--+
   1444  "     |w1|w2|w4|
   1445  "     +--+--+  |
   1446  "     |w3   |  |
   1447  "     +-----+--+
   1448  vsplit
   1449  split
   1450  vsplit
   1451  4wincmd l
   1452  call setline(1, repeat([' '], &lines))
   1453  call cursor(1, 1)
   1454  redraw!
   1455  wincmd h
   1456  call assert_equal(2, winnr())
   1457  4wincmd l
   1458  call cursor(&lines, 1)
   1459  redraw!
   1460  wincmd h
   1461  call assert_equal(3, winnr())
   1462  %bw!
   1463 
   1464  " create the following window layout:
   1465  "     +--+--+
   1466  "     |w1|w4|
   1467  "     +--+  +
   1468  "     |w2|  |
   1469  "     +--+  +
   1470  "     |w3|  |
   1471  "     +--+--+
   1472  vsplit
   1473  split
   1474  split
   1475  wincmd l
   1476  call setline(1, repeat([' '], &lines))
   1477  call cursor(1, 1)
   1478  redraw!
   1479  wincmd h
   1480  call assert_equal(1, winnr())
   1481  wincmd l
   1482  call cursor(&lines / 2, 1)
   1483  redraw!
   1484  wincmd h
   1485  call assert_equal(2, winnr())
   1486  wincmd l
   1487  call cursor(&lines, 1)
   1488  redraw!
   1489  wincmd h
   1490  call assert_equal(3, winnr())
   1491  %bw!
   1492 endfunc
   1493 
   1494 " Test for an autocmd closing the destination window when jumping from one
   1495 " window to another.
   1496 func Test_close_dest_window()
   1497  split
   1498  edit Xfile
   1499 
   1500  " Test for BufLeave
   1501  augroup T1
   1502    au!
   1503    au BufLeave Xfile $wincmd c
   1504  augroup END
   1505  wincmd b
   1506  call assert_equal(1, winnr('$'))
   1507  call assert_equal('Xfile', @%)
   1508  augroup T1
   1509    au!
   1510  augroup END
   1511 
   1512  " Test for WinLeave
   1513  new
   1514  wincmd p
   1515  augroup T1
   1516    au!
   1517    au WinLeave * 1wincmd c
   1518  augroup END
   1519  wincmd t
   1520  call assert_equal(1, winnr('$'))
   1521  call assert_equal('Xfile', @%)
   1522  augroup T1
   1523    au!
   1524  augroup END
   1525  augroup! T1
   1526  %bw!
   1527 endfunc
   1528 
   1529 func Test_win_move_separator()
   1530  edit a
   1531  leftabove vsplit b
   1532  let w = winwidth(0)
   1533  " check win_move_separator from left window on left window
   1534  call assert_equal(1, winnr())
   1535  for offset in range(5)
   1536    call assert_true(win_move_separator(0, offset))
   1537    call assert_equal(w + offset, winwidth(0))
   1538    call assert_true(0->win_move_separator(-offset))
   1539    call assert_equal(w, winwidth(0))
   1540  endfor
   1541  " check win_move_separator from right window on left window number
   1542  wincmd l
   1543  call assert_notequal(1, winnr())
   1544  for offset in range(5)
   1545    call assert_true(1->win_move_separator(offset))
   1546    call assert_equal(w + offset, winwidth(1))
   1547    call assert_true(win_move_separator(1, -offset))
   1548    call assert_equal(w, winwidth(1))
   1549  endfor
   1550  " check win_move_separator from right window on left window ID
   1551  let id = win_getid(1)
   1552  for offset in range(5)
   1553    call assert_true(win_move_separator(id, offset))
   1554    call assert_equal(w + offset, winwidth(id))
   1555    call assert_true(id->win_move_separator(-offset))
   1556    call assert_equal(w, winwidth(id))
   1557  endfor
   1558  " check win_move_separator from right window on right window is no-op
   1559  let w0 = winwidth(0)
   1560  call assert_true(win_move_separator(0, 1))
   1561  call assert_equal(w0, winwidth(0))
   1562  call assert_true(win_move_separator(0, -1))
   1563  call assert_equal(w0, winwidth(0))
   1564 
   1565  " check that win_move_separator doesn't error with offsets beyond moving
   1566  " possibility
   1567  call assert_true(win_move_separator(id, 5000))
   1568  call assert_true(winwidth(id) > w)
   1569  call assert_true(win_move_separator(id, -5000))
   1570  call assert_true(winwidth(id) < w)
   1571 
   1572  " check that win_move_separator returns false for an invalid window
   1573  wincmd =
   1574  let w = winwidth(0)
   1575  call assert_false(win_move_separator(-1, 1))
   1576  call assert_equal(w, winwidth(0))
   1577 
   1578  " check that win_move_separator returns false for a floating window
   1579  let id = nvim_open_win(
   1580        \ 0, 0, #{relative: 'editor', row: 2, col: 2, width: 5, height: 3})
   1581  let w = winwidth(id)
   1582  call assert_false(win_move_separator(id, 1))
   1583  call assert_equal(w, winwidth(id))
   1584  call nvim_win_close(id, 1)
   1585 
   1586  " check that using another tabpage fails without crash
   1587  let id = win_getid()
   1588  tabnew
   1589  call assert_fails('call win_move_separator(id, -1)', 'E1308:')
   1590  tabclose
   1591 
   1592  %bwipe!
   1593 endfunc
   1594 
   1595 func Test_win_move_statusline()
   1596  edit a
   1597  leftabove split b
   1598  let h = winheight(0)
   1599  " check win_move_statusline from top window on top window
   1600  call assert_equal(1, winnr())
   1601  for offset in range(5)
   1602    call assert_true(win_move_statusline(0, offset))
   1603    call assert_equal(h + offset, winheight(0))
   1604    call assert_true(0->win_move_statusline(-offset))
   1605    call assert_equal(h, winheight(0))
   1606  endfor
   1607  " check win_move_statusline from bottom window on top window number
   1608  wincmd j
   1609  call assert_notequal(1, winnr())
   1610  for offset in range(5)
   1611    call assert_true(1->win_move_statusline(offset))
   1612    call assert_equal(h + offset, winheight(1))
   1613    call assert_true(win_move_statusline(1, -offset))
   1614    call assert_equal(h, winheight(1))
   1615  endfor
   1616  " check win_move_statusline from bottom window on bottom window
   1617  let h0 = winheight(0)
   1618  for offset in range(5)
   1619    call assert_true(0->win_move_statusline(-offset))
   1620    call assert_equal(h0 - offset, winheight(0))
   1621    call assert_equal(1 + offset, &cmdheight)
   1622    call assert_true(win_move_statusline(0, offset))
   1623    call assert_equal(h0, winheight(0))
   1624    call assert_equal(1, &cmdheight)
   1625  endfor
   1626  " supports cmdheight=0
   1627  set cmdheight=0
   1628  call assert_true(win_move_statusline(0, 1))
   1629  call assert_equal(h0 + 1, winheight(0))
   1630  call assert_equal(0, &cmdheight)
   1631  set cmdheight&
   1632  " check win_move_statusline from bottom window on top window ID
   1633  let id = win_getid(1)
   1634  for offset in range(5)
   1635    call assert_true(win_move_statusline(id, offset))
   1636    call assert_equal(h + offset, winheight(id))
   1637    call assert_true(id->win_move_statusline(-offset))
   1638    call assert_equal(h, winheight(id))
   1639  endfor
   1640 
   1641  " check that win_move_statusline doesn't error with offsets beyond moving
   1642  " possibility
   1643  call assert_true(win_move_statusline(id, 5000))
   1644  call assert_true(winheight(id) > h)
   1645  call assert_true(win_move_statusline(id, -5000))
   1646  call assert_true(winheight(id) < h)
   1647 
   1648  " check that win_move_statusline returns false for an invalid window
   1649  wincmd =
   1650  let h = winheight(0)
   1651  call assert_false(win_move_statusline(-1, 1))
   1652  call assert_equal(h, winheight(0))
   1653 
   1654  " check that win_move_statusline returns false for a floating window
   1655  let id = nvim_open_win(
   1656        \ 0, 0, #{relative: 'editor', row: 2, col: 2, width: 5, height: 3})
   1657  let h = winheight(id)
   1658  call assert_false(win_move_statusline(id, 1))
   1659  call assert_equal(h, winheight(id))
   1660  call nvim_win_close(id, 1)
   1661 
   1662  " check that using another tabpage fails without crash
   1663  let id = win_getid()
   1664  tabnew
   1665  call assert_fails('call win_move_statusline(id, -1)', 'E1308:')
   1666  tabclose
   1667 
   1668  %bwipe!
   1669 endfunc
   1670 
   1671 " Test for window allocation failure
   1672 func Test_window_alloc_failure()
   1673  CheckFunction test_alloc_fail
   1674  %bw!
   1675 
   1676  " test for creating a new window above current window
   1677  call test_alloc_fail(GetAllocId('newwin_wvars'), 0, 0)
   1678  call assert_fails('above new', 'E342:')
   1679  call assert_equal(1, winnr('$'))
   1680 
   1681  " test for creating a new window below current window
   1682  call test_alloc_fail(GetAllocId('newwin_wvars'), 0, 0)
   1683  call assert_fails('below new', 'E342:')
   1684  call assert_equal(1, winnr('$'))
   1685 
   1686  " test for popup window creation failure
   1687  call test_alloc_fail(GetAllocId('newwin_wvars'), 0, 0)
   1688  call assert_fails('call popup_create("Hello", {})', 'E342:')
   1689  call assert_equal([], popup_list())
   1690 
   1691  call test_alloc_fail(GetAllocId('newwin_wvars'), 0, 0)
   1692  call assert_fails('split', 'E342:')
   1693  call assert_equal(1, winnr('$'))
   1694 
   1695  edit Xfile1
   1696  edit Xfile2
   1697  call test_alloc_fail(GetAllocId('newwin_wvars'), 0, 0)
   1698  call assert_fails('sb Xfile1', 'E342:')
   1699  call assert_equal(1, winnr('$'))
   1700  call assert_equal('Xfile2', @%)
   1701  %bw!
   1702 
   1703  " FIXME: The following test crashes Vim
   1704  " test for new tabpage creation failure
   1705  " call test_alloc_fail(GetAllocId('newwin_wvars'), 0, 0)
   1706  " call assert_fails('tabnew', 'E342:')
   1707  " call assert_equal(1, tabpagenr('$'))
   1708  " call assert_equal(1, winnr('$'))
   1709 
   1710  " This test messes up the internal Vim window/frame information. So the
   1711  " Test_window_cmd_cmdwin_with_vsp() test fails after running this test.
   1712  " Open a new tab and close everything else to fix this issue.
   1713  tabnew
   1714  tabonly
   1715 endfunc
   1716 
   1717 func Test_win_equal_last_status()
   1718  let save_lines = &lines
   1719  set lines=20
   1720  set splitbelow
   1721  set laststatus=0
   1722 
   1723  split | split | quit
   1724  call assert_equal(winheight(1), winheight(2))
   1725 
   1726  let &lines = save_lines
   1727  set splitbelow&
   1728  set laststatus&
   1729 endfunc
   1730 
   1731 " Test "screen" and "cursor" values for 'splitkeep' with a sequence of
   1732 " split operations for various options: with and without a winbar,
   1733 " tabline, for each possible value of 'laststatus', 'scrolloff',
   1734 " 'equalalways', and with the cursor at the top, middle and bottom.
   1735 func Test_splitkeep_options()
   1736  " disallow window resizing
   1737  " let save_WS = &t_WS
   1738  " set t_WS=
   1739 
   1740  let gui = has("gui_running")
   1741  inoremap <expr> c "<cmd>copen<bar>wincmd k<CR>"
   1742  for run in range(0, 20)
   1743    let &splitkeep = run > 10 ? 'topline' : 'screen'
   1744    let &scrolloff = (!(run % 4) ? 0 : run)
   1745    let &laststatus = (run % 3)
   1746    let &splitbelow = (run % 3)
   1747    let &equalalways = (run % 2)
   1748    " Nvim: both windows have a winbar after splitting
   1749    " let wsb = (run % 2) && &splitbelow
   1750    let wsb = 0
   1751    let tl = (gui ? 0 : ((run % 5) ? 1 : 0))
   1752    let pos = !(run % 3) ? 'H' : ((run % 2) ? 'M' : 'L')
   1753    tabnew | tabonly! | redraw
   1754    execute (run % 5) ? 'tabnew' : ''
   1755    " execute (run % 2) ? 'nnoremenu 1.10 WinBar.Test :echo' : ''
   1756    let &winbar = (run % 2) ? '%f' : ''
   1757    call setline(1, range(1, 256))
   1758    " No scroll for restore_snapshot
   1759    norm G
   1760    try
   1761      copen | close | colder
   1762    catch /E380/
   1763    endtry
   1764    call assert_equal(257 - winheight(0), line("w0"))
   1765 
   1766    " No scroll for firstwin horizontal split
   1767    execute 'norm gg' . pos
   1768    split | redraw | wincmd k
   1769    call assert_equal(1, line("w0"))
   1770    call assert_equal(&scroll, winheight(0) / 2)
   1771    wincmd j
   1772    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1773 
   1774    " No scroll when resizing windows
   1775    wincmd k | resize +2 | redraw
   1776    call assert_equal(1, line("w0"))
   1777    wincmd j
   1778    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1779 
   1780    " No scroll when dragging statusline
   1781    call win_move_statusline(1, -3)
   1782    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1783    wincmd k
   1784    call assert_equal(1, line("w0"))
   1785 
   1786    " No scroll when changing shellsize
   1787    set lines+=2
   1788    call assert_equal(1, line("w0"))
   1789    wincmd j
   1790    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1791    set lines-=2
   1792    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1793    wincmd k
   1794    call assert_equal(1, line("w0"))
   1795 
   1796    " No scroll when equalizing windows
   1797    wincmd =
   1798    call assert_equal(1, line("w0"))
   1799    wincmd j
   1800    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1801    wincmd k
   1802    call assert_equal(1, line("w0"))
   1803 
   1804    " No scroll in windows split multiple times
   1805    vsplit | split | 4wincmd w
   1806    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1807    1wincmd w | quit | wincmd l | split
   1808    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1809    wincmd j
   1810    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1811 
   1812    " No scroll in small window
   1813    2wincmd w | only | 5split | wincmd k
   1814    call assert_equal(1, line("w0"))
   1815    wincmd j
   1816    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1817 
   1818    " No scroll for vertical split
   1819    quit | vsplit | wincmd l
   1820    call assert_equal(1, line("w0"))
   1821    wincmd h
   1822    call assert_equal(1, line("w0"))
   1823 
   1824    " No scroll in windows split and quit multiple times
   1825    quit | redraw | split | split | quit | redraw
   1826    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
   1827 
   1828    " No scroll for new buffer
   1829    1wincmd w | only | copen | wincmd k
   1830    call assert_equal(1, line("w0"))
   1831    only
   1832    call assert_equal(1, line("w0"))
   1833    above copen | wincmd j
   1834    call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl, line("w0"))
   1835 
   1836    " No scroll when opening cmdwin, and no cursor move when closing cmdwin.
   1837    only | norm ggL
   1838    let curpos = getcurpos()
   1839    norm q:
   1840    call assert_equal(1, line("w0"))
   1841    call assert_equal(curpos, getcurpos())
   1842 
   1843    " Scroll when cursor becomes invalid in insert mode.
   1844    norm Lic
   1845    call assert_equal(curpos, getcurpos(), 'run ' .. run)
   1846 
   1847    " No scroll when topline not equal to 1
   1848    only | execute "norm gg5\<C-e>" | split | wincmd k
   1849    call assert_equal(6, line("w0"))
   1850    wincmd j
   1851    call assert_equal(&spk == 'topline' ? 6 : 5 + win_screenpos(0)[0] - tl - wsb, line("w0"))
   1852  endfor
   1853 
   1854  tabnew | tabonly! | %bwipeout!
   1855  iunmap c
   1856  set scrolloff&
   1857  set splitbelow&
   1858  set laststatus&
   1859  set equalalways&
   1860  set splitkeep&
   1861  " let &t_WS = save_WS
   1862 endfunc
   1863 
   1864 func Test_splitkeep_cmdwin_cursor_position()
   1865  set splitkeep=screen
   1866  call setline(1, range(&lines))
   1867 
   1868  " No scroll when cursor is at near bottom of window and cursor position
   1869  " recompution (done by line('w0') in this test) happens while in cmdwin.
   1870  normal! G
   1871  let firstline = line('w0')
   1872  autocmd CmdwinEnter * ++once autocmd WinEnter * ++once call line('w0')
   1873  execute "normal! q:\<C-w>q"
   1874  redraw!
   1875  call assert_equal(firstline, line('w0'))
   1876 
   1877  " User script can change cursor position successfully while in cmdwin and it
   1878  " shouldn't be changed when closing cmdwin.
   1879  execute "normal! Gq:\<Cmd>call win_execute(winnr('#')->win_getid(), 'call cursor(1, 1)')\<CR>\<C-w>q"
   1880  call assert_equal(1, line('.'))
   1881  call assert_equal(1, col('.'))
   1882 
   1883  execute "normal! Gq:\<Cmd>autocmd WinEnter * ++once call cursor(1, 1)\<CR>\<C-w>q"
   1884  call assert_equal(1, line('.'))
   1885  call assert_equal(1, col('.'))
   1886 
   1887  %bwipeout!
   1888  set splitkeep&
   1889 endfunc
   1890 
   1891 func Test_splitkeep_misc()
   1892  set splitkeep=screen
   1893 
   1894  call setline(1, range(1, &lines))
   1895  " Cursor is adjusted to start and end of buffer
   1896  norm M
   1897  wincmd s
   1898  resize 1
   1899  call assert_equal(1, line('.'))
   1900  wincmd j
   1901  norm GM
   1902  resize 1
   1903  call assert_equal(&lines, line('.'))
   1904  only!
   1905 
   1906  set splitbelow
   1907  norm Gzz
   1908  let top = line('w0')
   1909  " No scroll when aucmd_win is opened
   1910  call setbufvar(bufnr("test", 1) , '&buftype', 'nofile')
   1911  call assert_equal(top, line('w0'))
   1912  " No scroll when tab is changed/closed
   1913  tab help | close
   1914  call assert_equal(top, line('w0'))
   1915  " No scroll when help is closed and buffer line count < window height
   1916  norm ggdG
   1917  call setline(1, range(1, &lines - 10))
   1918  norm G
   1919  let top = line('w0')
   1920  help | quit
   1921  call assert_equal(top, line('w0'))
   1922  " No error when resizing window in autocmd and buffer length changed
   1923  autocmd FileType qf exe "resize" line('$')
   1924  cexpr getline(1, '$')
   1925  copen
   1926  wincmd p
   1927  norm dd
   1928  cexpr getline(1, '$')
   1929 
   1930  %bwipeout!
   1931  set splitbelow&
   1932  set splitkeep&
   1933 endfunc
   1934 
   1935 func Test_splitkeep_screen_cursor_pos()
   1936  new
   1937  set splitkeep=screen
   1938  call setline(1, ["longer than the last", "shorter"])
   1939  norm! $
   1940  wincmd s
   1941  close
   1942  call assert_equal([0, 1, 20, 0], getpos('.'))
   1943  %bwipeout!
   1944  set splitkeep&
   1945 endfunc
   1946 
   1947 func Test_splitkeep_cursor()
   1948  CheckScreendump
   1949  let lines =<< trim END
   1950    set splitkeep=screen
   1951    autocmd CursorMoved * wincmd p | wincmd p
   1952    call setline(1, range(1, 200))
   1953    func CursorEqualize()
   1954      call cursor(100, 1)
   1955      wincmd =
   1956    endfunc
   1957    wincmd s
   1958    call CursorEqualize()
   1959  END
   1960  call writefile(lines, 'XTestSplitkeepCallback', 'D')
   1961  let buf = RunVimInTerminal('-S XTestSplitkeepCallback', #{rows: 8})
   1962 
   1963  call VerifyScreenDump(buf, 'Test_splitkeep_cursor_1', {})
   1964 
   1965  call term_sendkeys(buf, "j")
   1966  call VerifyScreenDump(buf, 'Test_splitkeep_cursor_2', {})
   1967 
   1968  call term_sendkeys(buf, ":set scrolloff=0\<CR>G")
   1969  call VerifyScreenDump(buf, 'Test_splitkeep_cursor_3', {})
   1970 
   1971  call StopVimInTerminal(buf)
   1972 endfunc
   1973 
   1974 func Test_splitkeep_callback()
   1975  CheckScreendump
   1976  let lines =<< trim END
   1977    set splitkeep=screen
   1978    call setline(1, range(&lines))
   1979    function C1(a, b)
   1980      split | wincmd p
   1981    endfunction
   1982    function C2(a, b)
   1983      close | split
   1984    endfunction
   1985    nn j <cmd>call job_start([&sh, &shcf, "true"], { 'exit_cb': 'C1' })<CR>
   1986    nn t <cmd>call popup_create(term_start([&sh, &shcf, "true"],
   1987          \ { 'hidden': 1, 'exit_cb': 'C2' }), {})<CR>
   1988  END
   1989  call writefile(lines, 'XTestSplitkeepCallback', 'D')
   1990  let buf = RunVimInTerminal('-S XTestSplitkeepCallback', #{rows: 8})
   1991 
   1992  call term_sendkeys(buf, "j")
   1993  call VerifyScreenDump(buf, 'Test_splitkeep_callback_1', {})
   1994 
   1995  call term_sendkeys(buf, ":quit\<CR>Ht")
   1996  call VerifyScreenDump(buf, 'Test_splitkeep_callback_2', {})
   1997 
   1998  call term_sendkeys(buf, ":set sb\<CR>:quit\<CR>Gj")
   1999  call VerifyScreenDump(buf, 'Test_splitkeep_callback_3', {})
   2000 
   2001  call term_sendkeys(buf, ":quit\<CR>Gt")
   2002  call VerifyScreenDump(buf, 'Test_splitkeep_callback_4', {})
   2003 
   2004  call StopVimInTerminal(buf)
   2005 endfunc
   2006 
   2007 func Test_splitkeep_fold()
   2008  CheckScreendump
   2009 
   2010  let lines =<< trim END
   2011    set splitkeep=screen
   2012    set foldmethod=marker
   2013    set number
   2014    let line = 1
   2015    for n in range(1, &lines)
   2016      call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
   2017            \ 'after fold'])
   2018      let line += 8
   2019    endfor
   2020  END
   2021  call writefile(lines, 'XTestSplitkeepFold', 'D')
   2022  let buf = RunVimInTerminal('-S XTestSplitkeepFold', #{rows: 10})
   2023 
   2024  call term_sendkeys(buf, "L:wincmd s\<CR>")
   2025  call VerifyScreenDump(buf, 'Test_splitkeep_fold_1', {})
   2026 
   2027  call term_sendkeys(buf, ":quit\<CR>")
   2028  call VerifyScreenDump(buf, 'Test_splitkeep_fold_2', {})
   2029 
   2030  call term_sendkeys(buf, "H:below split\<CR>")
   2031  call VerifyScreenDump(buf, 'Test_splitkeep_fold_3', {})
   2032 
   2033  call term_sendkeys(buf, ":wincmd k\<CR>:quit\<CR>")
   2034  call VerifyScreenDump(buf, 'Test_splitkeep_fold_4', {})
   2035 
   2036  call StopVimInTerminal(buf)
   2037 endfunc
   2038 
   2039 func Test_splitkeep_status()
   2040  CheckScreendump
   2041 
   2042  let lines =<< trim END
   2043    call setline(1, ['a', 'b', 'c'])
   2044    set nomodified
   2045    set splitkeep=screen
   2046    let win = winnr()
   2047    wincmd s
   2048    wincmd j
   2049  END
   2050  call writefile(lines, 'XTestSplitkeepStatus', 'D')
   2051  let buf = RunVimInTerminal('-S XTestSplitkeepStatus', #{rows: 10})
   2052 
   2053  call term_sendkeys(buf, ":call win_move_statusline(win, 1)\<CR>")
   2054  call VerifyScreenDump(buf, 'Test_splitkeep_status_1', {})
   2055 
   2056  call StopVimInTerminal(buf)
   2057 endfunc
   2058 
   2059 " skipcol is not reset unnecessarily and is copied to new window
   2060 func Test_splitkeep_skipcol()
   2061  CheckScreendump
   2062 
   2063  let lines =<< trim END
   2064    set splitkeep=topline smoothscroll splitbelow scrolloff=0
   2065    call setline(1, 'with lots of text in one line '->repeat(6))
   2066    norm 2
   2067    wincmd s
   2068  END
   2069 
   2070  call writefile(lines, 'XTestSplitkeepSkipcol', 'D')
   2071  let buf = RunVimInTerminal('-S XTestSplitkeepSkipcol', #{rows: 12, cols: 40})
   2072 
   2073  call VerifyScreenDump(buf, 'Test_splitkeep_skipcol_1', {})
   2074  call StopVimInTerminal(buf)
   2075 endfunc
   2076 
   2077 func Test_splitkeep_line()
   2078  CheckScreendump
   2079 
   2080  let lines =<< trim END
   2081    set splitkeep=screen nosplitbelow
   2082    autocmd WinResized * call line('w0', 1000)
   2083    call setline(1, range(1000))
   2084  END
   2085 
   2086  call writefile(lines, 'XTestSplitkeepSkipcol', 'D')
   2087  let buf = RunVimInTerminal('-S XTestSplitkeepSkipcol', #{rows: 6, cols: 40})
   2088 
   2089  call VerifyScreenDump(buf, 'Test_splitkeep_line_1', {})
   2090 
   2091  call term_sendkeys(buf, ":wincmd s\<CR>")
   2092  call VerifyScreenDump(buf, 'Test_splitkeep_line_2', {})
   2093  call StopVimInTerminal(buf)
   2094 endfunc
   2095 
   2096 func Test_new_help_window_on_error()
   2097  help change.txt
   2098  execute "normal! /CTRL-@\<CR>"
   2099  silent! execute "normal! \<C-W>]"
   2100 
   2101  let wincount = winnr('$')
   2102  help 'mod'
   2103 
   2104  call assert_equal(wincount, winnr('$'))
   2105  call assert_equal(expand("<cword>"), "'mod'")
   2106 endfunc
   2107 
   2108 func Test_splitmove_flatten_frame()
   2109  split
   2110  vsplit
   2111 
   2112  wincmd L
   2113  let layout = winlayout()
   2114  wincmd K
   2115  wincmd L
   2116  call assert_equal(winlayout(), layout)
   2117 
   2118  only!
   2119 endfunc
   2120 
   2121 func Test_autocmd_window_force_room()
   2122  " Open as many windows as possible
   2123  while v:true
   2124    try
   2125      split
   2126    catch /E36:/
   2127      break
   2128    endtry
   2129  endwhile
   2130  while v:true
   2131    try
   2132      vsplit
   2133    catch /E36:/
   2134      break
   2135    endtry
   2136  endwhile
   2137 
   2138  wincmd j
   2139  vsplit
   2140  call assert_fails('wincmd H', 'E36:')
   2141  call assert_fails('wincmd J', 'E36:')
   2142  call assert_fails('wincmd K', 'E36:')
   2143  call assert_fails('wincmd L', 'E36:')
   2144 
   2145  edit unload me
   2146  enew
   2147  bunload! unload\ me
   2148  augroup AucmdWinForceRoom
   2149    au!
   2150    au BufEnter * ++once let s:triggered = v:true
   2151                      \| call assert_equal('autocmd', win_gettype())
   2152  augroup END
   2153  let info = s:win_layout_info()
   2154  " bufload opening the autocommand window shouldn't give E36.
   2155  call bufload('unload me')
   2156  call assert_equal(v:true, s:triggered)
   2157  call assert_equal(info, s:win_layout_info())
   2158 
   2159  unlet! s:triggered
   2160  au! AucmdWinForceRoom
   2161  augroup! AucmdWinForceRoom
   2162  %bw!
   2163 endfunc
   2164 
   2165 func Test_win_gotoid_splitmove_textlock_cmdwin()
   2166  call setline(1, 'foo')
   2167  new
   2168  let curwin = win_getid()
   2169  call setline(1, 'bar')
   2170 
   2171  set debug+=throw indentexpr=win_gotoid(win_getid(winnr('#')))
   2172  call assert_fails('normal! ==', 'E565:')
   2173  call assert_equal(curwin, win_getid())
   2174  " No error if attempting to switch to curwin; nothing happens.
   2175  set indentexpr=assert_equal(1,win_gotoid(win_getid()))
   2176  normal! ==
   2177  call assert_equal(curwin, win_getid())
   2178 
   2179  set indentexpr=win_splitmove(winnr('#'),winnr())
   2180  call assert_fails('normal! ==', 'E565:')
   2181  call assert_equal(curwin, win_getid())
   2182 
   2183  %bw!
   2184  set debug-=throw indentexpr&
   2185 
   2186  call feedkeys('q:'
   2187           \ .. ":call assert_fails('call win_splitmove(winnr(''#''), winnr())', 'E11:')\<CR>"
   2188           \ .. ":call assert_equal('command', win_gettype())\<CR>"
   2189           \ .. ":call assert_equal('', win_gettype(winnr('#')))\<CR>", 'ntx')
   2190 
   2191  call feedkeys('q:'
   2192           \ .. ":call assert_fails('call win_gotoid(win_getid(winnr(''#'')))', 'E11:')\<CR>"
   2193           "\ No error if attempting to switch to curwin; nothing happens.
   2194           \ .. ":call assert_equal(1, win_gotoid(win_getid()))\<CR>"
   2195           \ .. ":call assert_equal('command', win_gettype())\<CR>"
   2196           \ .. ":call assert_equal('', win_gettype(winnr('#')))\<CR>", 'ntx')
   2197 endfunc
   2198 
   2199 func Test_winfixsize_positions()
   2200  " Check positions are correct when closing a window in a non-current tabpage
   2201  " causes non-adjacent window to fill the space due to 'winfix{width,height}'.
   2202  tabnew
   2203  vsplit
   2204  wincmd |
   2205  split
   2206  set winfixheight
   2207  split foo
   2208  tabfirst
   2209 
   2210  bwipe! foo
   2211  " Save actual values before entering the tabpage.
   2212  let info = s:win_layout_info(2)
   2213  tabnext
   2214  " Compare it with the expected value (after win_comp_pos) from entering.
   2215  call assert_equal(s:win_layout_info(), info)
   2216 
   2217  $tabnew
   2218  split
   2219  split
   2220  wincmd k
   2221  belowright vsplit
   2222  set winfixwidth
   2223  belowright vsplit foo
   2224  tabprevious
   2225 
   2226  bwipe! foo
   2227  " Save actual values before entering the tabpage.
   2228  let info = s:win_layout_info(3)
   2229  tabnext
   2230  " Compare it with the expected value (after win_comp_pos) from entering.
   2231  call assert_equal(s:win_layout_info(), info)
   2232 
   2233  " Check positions unchanged when failing to move a window, if 'winfix{width,
   2234  " height}' would otherwise cause a non-adjacent window to fill the space.
   2235  %bwipe
   2236  call assert_fails('execute "split|"->repeat(&lines)', 'E36:')
   2237  wincmd p
   2238  vsplit
   2239  set winfixwidth
   2240  vsplit
   2241  set winfixwidth
   2242  vsplit
   2243  vsplit
   2244  set winfixwidth
   2245  wincmd p
   2246 
   2247  let info = s:win_layout_info()
   2248  call assert_fails('wincmd J', 'E36:')
   2249  call assert_equal(info, s:win_layout_info())
   2250 
   2251  only
   2252  call assert_fails('execute "vsplit|"->repeat(&columns)', 'E36:')
   2253  belowright split
   2254  set winfixheight
   2255  belowright split
   2256 
   2257  let info = s:win_layout_info()
   2258  call assert_fails('wincmd H', 'E36:')
   2259  call assert_equal(info, s:win_layout_info())
   2260 
   2261  %bwipe
   2262 endfunc
   2263 
   2264 func Test_winfixsize_vsep_statusline()
   2265  CheckScreendump
   2266 
   2267  let lines =<< trim END
   2268    set noequalalways splitbelow splitright
   2269    vsplit
   2270    setlocal winfixwidth
   2271    vsplit
   2272    func SetupWfh()
   2273      set laststatus=0
   2274      only
   2275      split
   2276      set winfixheight
   2277      split
   2278    endfunc
   2279  END
   2280  call writefile(lines, 'XTestWinfixsizeVsepStatusline', 'D')
   2281  let buf = RunVimInTerminal('-S XTestWinfixsizeVsepStatusline', #{rows: 8})
   2282 
   2283  call term_sendkeys(buf, ":echo winwidth(1) winwidth(2) winwidth(3)\n")
   2284  call WaitForAssert({-> assert_match('^16 37 20\>', term_getline(buf, 8))})
   2285 
   2286  call term_sendkeys(buf, ":quit\n")
   2287  call VerifyScreenDump(buf, 'Test_winfixsize_vsep_statusline_1', {})
   2288 
   2289  " Reported widths should be consistent with the screen dump.
   2290  call term_sendkeys(buf, ":echo winwidth(1) winwidth(2)\n")
   2291  " (May be better if 'wfw' window remains at 37 columns, but the resize is
   2292  " consistent with how things currently work for 'winfix*' windows)
   2293  call WaitForAssert({-> assert_match('^36 38\>', term_getline(buf, 8))})
   2294 
   2295  " For good measure, also check bottom-most 'winfixheight' windows don't leave
   2296  " stray statuslines with &laststatus=0.
   2297  call term_sendkeys(buf,
   2298        \ ":call SetupWfh() | echo winheight(1) winheight(2) winheight(3)\n")
   2299  call WaitForAssert({-> assert_match('^1 3 1\>', term_getline(buf, 8))})
   2300 
   2301  call term_sendkeys(buf, ":quit\n")
   2302  call VerifyScreenDump(buf, 'Test_winfixsize_vsep_statusline_2', {})
   2303 
   2304  call term_sendkeys(buf, ":echo winheight(1) winheight(2)\n")
   2305  " (Likewise, may be better if 'wfh' window remains at 3 rows)
   2306  call WaitForAssert({-> assert_match('^2 4\>', term_getline(buf, 8))})
   2307 
   2308  call StopVimInTerminal(buf)
   2309 endfunc
   2310 
   2311 func Test_resize_from_another_tabpage()
   2312  CheckScreendump
   2313 
   2314  let lines =<< trim END
   2315    set laststatus=2
   2316    vnew
   2317    let w = win_getid()
   2318    tabnew
   2319    call win_execute(w, 'vertical resize 20')
   2320    tabprev
   2321  END
   2322  call writefile(lines, 'XTestResizeFromAnotherTabpage', 'D')
   2323  let buf = RunVimInTerminal('-S XTestResizeFromAnotherTabpage', #{rows: 8})
   2324  call VerifyScreenDump(buf, 'Test_resize_from_another_tabpage_1', {})
   2325 
   2326  call StopVimInTerminal(buf)
   2327 endfunc
   2328 
   2329 " vim: shiftwidth=2 sts=2 expandtab