neovim

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

test_winfixbuf.vim (80453B)


      1 " Test 'winfixbuf'
      2 
      3 source check.vim
      4 source shared.vim
      5 
      6 " Find the number of open windows in the current tab
      7 func s:get_windows_count()
      8  return tabpagewinnr(tabpagenr(), '$')
      9 endfunc
     10 
     11 " Create some unnamed buffers.
     12 func s:make_buffers_list()
     13  enew
     14  file first
     15  let l:first = bufnr()
     16 
     17  enew
     18  file middle
     19  let l:middle = bufnr()
     20 
     21  enew
     22  file last
     23  let l:last = bufnr()
     24 
     25  set winfixbuf
     26 
     27  return [l:first, l:last]
     28 endfunc
     29 
     30 " Create some unnamed buffers and add them to an args list
     31 func s:make_args_list()
     32  let [l:first, l:last] = s:make_buffers_list()
     33 
     34  args! first middle last
     35 
     36  return [l:first, l:last]
     37 endfunc
     38 
     39 " Create two buffers and then set the window to 'winfixbuf'
     40 func s:make_buffer_pairs(...)
     41  let l:reversed = get(a:, 1, 0)
     42 
     43  if l:reversed == 1
     44    enew
     45    file original
     46 
     47    set winfixbuf
     48 
     49    enew!
     50    file other
     51    let l:other = bufnr()
     52 
     53    return l:other
     54  endif
     55 
     56  enew
     57  file other
     58  let l:other = bufnr()
     59 
     60  enew
     61  file current
     62 
     63  set winfixbuf
     64 
     65  return l:other
     66 endfunc
     67 
     68 " Create 3 quick buffers and set the window to 'winfixbuf'
     69 func s:make_buffer_trio()
     70  edit first
     71  let l:first = bufnr()
     72  edit second
     73  let l:second = bufnr()
     74 
     75  set winfixbuf
     76 
     77  edit! third
     78  let l:third = bufnr()
     79 
     80  exe $":buffer! {l:second}"
     81 
     82  return [l:first, l:second, l:third]
     83 endfunc
     84 
     85 " Create a location list with at least 2 entries + a 'winfixbuf' window.
     86 func s:make_simple_location_list()
     87  enew
     88  file middle
     89  let l:middle = bufnr()
     90  call append(0, ["winfix search-term", "another line"])
     91 
     92  enew!
     93  file first
     94  let l:first = bufnr()
     95  call append(0, "first search-term")
     96 
     97  enew!
     98  file last
     99  let l:last = bufnr()
    100  call append(0, "last search-term")
    101 
    102  call setloclist(
    103  \  0,
    104  \  [
    105  \    {
    106  \      "filename": "first",
    107  \      "bufnr": l:first,
    108  \      "lnum": 1,
    109  \    },
    110  \    {
    111  \      "filename": "middle",
    112  \      "bufnr": l:middle,
    113  \      "lnum": 1,
    114  \    },
    115  \    {
    116  \      "filename": "middle",
    117  \      "bufnr": l:middle,
    118  \      "lnum": 2,
    119  \    },
    120  \    {
    121  \      "filename": "last",
    122  \      "bufnr": l:last,
    123  \      "lnum": 1,
    124  \    },
    125  \  ]
    126  \)
    127 
    128  set winfixbuf
    129 
    130  return [l:first, l:middle, l:last]
    131 endfunc
    132 
    133 " Create a quickfix with at least 2 entries that are in the current 'winfixbuf' window.
    134 func s:make_simple_quickfix()
    135  enew
    136  file current
    137  let l:current = bufnr()
    138  call append(0, ["winfix search-term", "another line"])
    139 
    140  enew!
    141  file first
    142  let l:first = bufnr()
    143  call append(0, "first search-term")
    144 
    145  enew!
    146  file last
    147  let l:last = bufnr()
    148  call append(0, "last search-term")
    149 
    150  call setqflist(
    151  \  [
    152  \    {
    153  \      "filename": "first",
    154  \      "bufnr": l:first,
    155  \      "lnum": 1,
    156  \    },
    157  \    {
    158  \      "filename": "current",
    159  \      "bufnr": l:current,
    160  \      "lnum": 1,
    161  \    },
    162  \    {
    163  \      "filename": "current",
    164  \      "bufnr": l:current,
    165  \      "lnum": 2,
    166  \    },
    167  \    {
    168  \      "filename": "last",
    169  \      "bufnr": l:last,
    170  \      "lnum": 1,
    171  \    },
    172  \  ]
    173  \)
    174 
    175  set winfixbuf
    176 
    177  return [l:current, l:last]
    178 endfunc
    179 
    180 " Create a quickfix with at least 2 entries that are in the current 'winfixbuf' window.
    181 func s:make_quickfix_windows()
    182  let [l:current, _] = s:make_simple_quickfix()
    183  exe $"buffer! {l:current}"
    184 
    185  split
    186  let l:first_window = win_getid()
    187  exe "normal \<C-w>j"
    188  let l:winfix_window = win_getid()
    189 
    190  " Open the quickfix in a separate split and go to it
    191  copen
    192  let l:quickfix_window = win_getid()
    193 
    194  return [l:first_window, l:winfix_window, l:quickfix_window]
    195 endfunc
    196 
    197 " Revert all changes that occurred in any past test
    198 func s:reset_all_buffers()
    199  %bwipeout!
    200  set nowinfixbuf
    201 
    202  call setqflist([])
    203  call setloclist(0, [], 'f')
    204 
    205  delmarks A-Z0-9
    206 endfunc
    207 
    208 " Find and set the first quickfix entry that points to `buffer`
    209 func s:set_quickfix_by_buffer(buffer)
    210  let l:index = 1  " quickfix indices start at 1
    211  for l:entry in getqflist()
    212    if l:entry["bufnr"] == a:buffer
    213      exe $"{l:index} cc"
    214 
    215      return
    216    endif
    217 
    218    let l:index += 1
    219  endfor
    220 
    221  echoerr $'No quickfix entry matching {a:buffer} could be found.'
    222 endfunc
    223 
    224 " Fail to call :Next on a 'winfixbuf' window unless :Next! is used.
    225 func Test_Next()
    226  call s:reset_all_buffers()
    227 
    228  let [l:first, _] = s:make_args_list()
    229  next!
    230 
    231  call assert_fails("Next", "E1513:")
    232  call assert_notequal(l:first, bufnr())
    233 
    234  Next!
    235  call assert_equal(l:first, bufnr())
    236 endfunc
    237 
    238 " Call :argdo and choose the next available 'nowinfixbuf' window.
    239 func Test_argdo_choose_available_window()
    240  call s:reset_all_buffers()
    241 
    242  let [_, l:last] = s:make_args_list()
    243 
    244  " Make a split window that is 'nowinfixbuf' but make it the second-to-last
    245  " window so that :argdo will first try the 'winfixbuf' window, pass over it,
    246  " and prefer the other 'nowinfixbuf' window, instead.
    247  "
    248  " +-------------------+
    249  " |   'nowinfixbuf'   |
    250  " +-------------------+
    251  " |    'winfixbuf'    |  <-- Cursor is here
    252  " +-------------------+
    253  split
    254  let l:nowinfixbuf_window = win_getid()
    255  " Move to the 'winfixbuf' window now
    256  exe "normal \<C-w>j"
    257  let l:winfixbuf_window = win_getid()
    258  let l:expected_windows = s:get_windows_count()
    259 
    260  argdo echo ''
    261  call assert_equal(l:nowinfixbuf_window, win_getid())
    262  call assert_equal(l:last, bufnr())
    263  call assert_equal(l:expected_windows, s:get_windows_count())
    264 endfunc
    265 
    266 " Call :argdo and create a new split window if all available windows are 'winfixbuf'.
    267 func Test_argdo_make_new_window()
    268  call s:reset_all_buffers()
    269 
    270  let [l:first, l:last] = s:make_args_list()
    271  let l:current = win_getid()
    272  let l:current_windows = s:get_windows_count()
    273 
    274  argdo echo ''
    275  call assert_notequal(l:current, win_getid())
    276  call assert_equal(l:last, bufnr())
    277  exe "normal \<C-w>j"
    278  call assert_equal(l:first, bufnr())
    279  call assert_equal(l:current_windows + 1, s:get_windows_count())
    280 endfunc
    281 
    282 " Fail :argedit but :argedit! is allowed
    283 func Test_argedit()
    284  call s:reset_all_buffers()
    285 
    286  args! first middle last
    287  enew
    288  file first
    289  let l:first = bufnr()
    290 
    291  enew
    292  file middle
    293  let l:middle = bufnr()
    294 
    295  enew
    296  file last
    297  let l:last = bufnr()
    298 
    299  set winfixbuf
    300 
    301  let l:current = bufnr()
    302  call assert_fails("argedit first middle last", "E1513:")
    303  call assert_equal(l:current, bufnr())
    304 
    305  argedit! first middle last
    306  call assert_equal(l:first, bufnr())
    307 endfunc
    308 
    309 " Fail :arglocal but :arglocal! is allowed
    310 func Test_arglocal()
    311  call s:reset_all_buffers()
    312 
    313  let l:other = s:make_buffer_pairs()
    314  let l:current = bufnr()
    315  argglobal! other
    316  exe $"buffer! {l:current}"
    317 
    318  call assert_fails("arglocal other", "E1513:")
    319  call assert_equal(l:current, bufnr())
    320 
    321  arglocal! other
    322  call assert_equal(l:other, bufnr())
    323 endfunc
    324 
    325 " Fail :argglobal but :argglobal! is allowed
    326 func Test_argglobal()
    327  call s:reset_all_buffers()
    328 
    329  let l:other = s:make_buffer_pairs()
    330  let l:current = bufnr()
    331 
    332  call assert_fails("argglobal other", "E1513:")
    333  call assert_equal(l:current, bufnr())
    334 
    335  argglobal! other
    336  call assert_equal(l:other, bufnr())
    337 endfunc
    338 
    339 " Fail :args but :args! is allowed
    340 func Test_args()
    341  call s:reset_all_buffers()
    342 
    343  let [l:first, _] = s:make_buffers_list()
    344  let l:current = bufnr()
    345 
    346  call assert_fails("args first middle last", "E1513:")
    347  call assert_equal(l:current, bufnr())
    348 
    349  args! first middle last
    350  call assert_equal(l:first, bufnr())
    351 endfunc
    352 
    353 " Fail :bNext but :bNext! is allowed
    354 func Test_bNext()
    355  call s:reset_all_buffers()
    356 
    357  let l:other = s:make_buffer_pairs()
    358  call assert_fails("bNext", "E1513:")
    359  let l:current = bufnr()
    360 
    361  call assert_equal(l:current, bufnr())
    362 
    363  bNext!
    364  call assert_equal(l:other, bufnr())
    365 endfunc
    366 
    367 " Allow :badd because it doesn't actually change the current window's buffer
    368 func Test_badd()
    369  call s:reset_all_buffers()
    370 
    371  call s:make_buffer_pairs()
    372  let l:current = bufnr()
    373 
    374  badd other
    375  call assert_equal(l:current, bufnr())
    376 endfunc
    377 
    378 " Allow :balt because it doesn't actually change the current window's buffer
    379 func Test_balt()
    380  call s:reset_all_buffers()
    381 
    382  call s:make_buffer_pairs()
    383  let l:current = bufnr()
    384 
    385  balt other
    386  call assert_equal(l:current, bufnr())
    387 endfunc
    388 
    389 " Fail :bfirst but :bfirst! is allowed
    390 func Test_bfirst()
    391  call s:reset_all_buffers()
    392 
    393  let l:other = s:make_buffer_pairs()
    394  let l:current = bufnr()
    395 
    396  call assert_fails("bfirst", "E1513:")
    397  call assert_equal(l:current, bufnr())
    398 
    399  bfirst!
    400  call assert_equal(l:other, bufnr())
    401 endfunc
    402 
    403 " Fail :blast but :blast! is allowed
    404 func Test_blast()
    405  call s:reset_all_buffers()
    406 
    407  let l:other = s:make_buffer_pairs(1)
    408  bfirst!
    409  let l:current = bufnr()
    410 
    411  call assert_fails("blast", "E1513:")
    412  call assert_equal(l:current, bufnr())
    413 
    414  blast!
    415  call assert_equal(l:other, bufnr())
    416 endfunc
    417 
    418 " Fail :bmodified but :bmodified! is allowed
    419 func Test_bmodified()
    420  call s:reset_all_buffers()
    421 
    422  let l:other = s:make_buffer_pairs()
    423  let l:current = bufnr()
    424 
    425  exe $"buffer! {l:other}"
    426  set modified
    427  exe $"buffer! {l:current}"
    428 
    429  call assert_fails("bmodified", "E1513:")
    430  call assert_equal(l:current, bufnr())
    431 
    432  bmodified!
    433  call assert_equal(l:other, bufnr())
    434 endfunc
    435 
    436 " Fail :bnext but :bnext! is allowed
    437 func Test_bnext()
    438  call s:reset_all_buffers()
    439 
    440  let l:other = s:make_buffer_pairs()
    441  let l:current = bufnr()
    442 
    443  call assert_fails("bnext", "E1513:")
    444  call assert_equal(l:current, bufnr())
    445 
    446  bnext!
    447  call assert_equal(l:other, bufnr())
    448 endfunc
    449 
    450 " Fail :bprevious but :bprevious! is allowed
    451 func Test_bprevious()
    452  call s:reset_all_buffers()
    453 
    454  let l:other = s:make_buffer_pairs()
    455  let l:current = bufnr()
    456 
    457  call assert_fails("bprevious", "E1513:")
    458  call assert_equal(l:current, bufnr())
    459 
    460  bprevious!
    461  call assert_equal(l:other, bufnr())
    462 endfunc
    463 
    464 " Fail :brewind but :brewind! is allowed
    465 func Test_brewind()
    466  call s:reset_all_buffers()
    467 
    468  let l:other = s:make_buffer_pairs()
    469  let l:current = bufnr()
    470 
    471  call assert_fails("brewind", "E1513:")
    472  call assert_equal(l:current, bufnr())
    473 
    474  brewind!
    475  call assert_equal(l:other, bufnr())
    476 endfunc
    477 
    478 " Fail :browse edit but :browse edit! is allowed
    479 func Test_browse_edit_fail()
    480  " A GUI dialog may stall the test.
    481  CheckNotGui
    482 
    483  call s:reset_all_buffers()
    484 
    485  let l:other = s:make_buffer_pairs()
    486  let l:current = bufnr()
    487 
    488  call assert_fails("browse edit other", "E1513:")
    489  call assert_equal(l:current, bufnr())
    490 
    491  try
    492    browse edit! other
    493    call assert_equal(l:other, bufnr())
    494  catch /^Vim\%((\a\+)\)\=:E338:/
    495    " Ignore E338, which occurs if console Vim is built with +browse.
    496    " Console Vim without +browse will treat this as a regular :edit.
    497  endtry
    498 endfunc
    499 
    500 " Allow :browse w because it doesn't change the buffer in the current file
    501 func Test_browse_edit_pass()
    502  " A GUI dialog may stall the test.
    503  CheckNotGui
    504 
    505  call s:reset_all_buffers()
    506 
    507  let l:other = s:make_buffer_pairs()
    508  let l:current = bufnr()
    509 
    510  try
    511    browse write other
    512  catch /^Vim\%((\a\+)\)\=:E338:/
    513    " Ignore E338, which occurs if console Vim is built with +browse.
    514    " Console Vim without +browse will treat this as a regular :write.
    515  endtry
    516 
    517  call delete("other")
    518 endfunc
    519 
    520 " Call :bufdo and choose the next available 'nowinfixbuf' window.
    521 func Test_bufdo_choose_available_window()
    522  call s:reset_all_buffers()
    523 
    524  let l:other = s:make_buffer_pairs()
    525 
    526  " Make a split window that is 'nowinfixbuf' but make it the second-to-last
    527  " window so that :bufdo will first try the 'winfixbuf' window, pass over it,
    528  " and prefer the other 'nowinfixbuf' window, instead.
    529  "
    530  " +-------------------+
    531  " |   'nowinfixbuf'   |
    532  " +-------------------+
    533  " |    'winfixbuf'    |  <-- Cursor is here
    534  " +-------------------+
    535  split
    536  let l:nowinfixbuf_window = win_getid()
    537  " Move to the 'winfixbuf' window now
    538  exe "normal \<C-w>j"
    539  let l:winfixbuf_window = win_getid()
    540 
    541  let l:current = bufnr()
    542  let l:expected_windows = s:get_windows_count()
    543 
    544  call assert_notequal(l:current, l:other)
    545 
    546  bufdo echo ''
    547  call assert_equal(l:nowinfixbuf_window, win_getid())
    548  call assert_notequal(l:other, bufnr())
    549  call assert_equal(l:expected_windows, s:get_windows_count())
    550 endfunc
    551 
    552 " Call :bufdo and create a new split window if all available windows are 'winfixbuf'.
    553 func Test_bufdo_make_new_window()
    554  call s:reset_all_buffers()
    555 
    556  let [l:first, l:last] = s:make_buffers_list()
    557  exe $"buffer! {l:first}"
    558  let l:current = win_getid()
    559  let l:current_windows = s:get_windows_count()
    560 
    561  bufdo echo ''
    562  call assert_notequal(l:current, win_getid())
    563  call assert_equal(l:last, bufnr())
    564  exe "normal \<C-w>j"
    565  call assert_equal(l:first, bufnr())
    566  call assert_equal(l:current_windows + 1, s:get_windows_count())
    567 endfunc
    568 
    569 " Fail :buffer but :buffer! is allowed
    570 func Test_buffer()
    571  call s:reset_all_buffers()
    572 
    573  let l:other = s:make_buffer_pairs()
    574  let l:current = bufnr()
    575 
    576  call assert_fails($"buffer {l:other}", "E1513:")
    577  call assert_equal(l:current, bufnr())
    578 
    579  exe $"buffer! {l:other}"
    580  call assert_equal(l:other, bufnr())
    581 endfunc
    582 
    583 " Allow :buffer on a 'winfixbuf' window if there is no change in buffer
    584 func Test_buffer_same_buffer()
    585  call s:reset_all_buffers()
    586 
    587  call s:make_buffer_pairs()
    588  let l:current = bufnr()
    589 
    590  exe $"buffer {l:current}"
    591  call assert_equal(l:current, bufnr())
    592 
    593  exe $"buffer! {l:current}"
    594  call assert_equal(l:current, bufnr())
    595 endfunc
    596 
    597 " Allow :cNext but the 'nowinfixbuf' window is selected, instead
    598 func Test_cNext()
    599  CheckFeature quickfix
    600  call s:reset_all_buffers()
    601 
    602  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    603 
    604  " The call to `:cNext` succeeds but it selects the window with 'nowinfixbuf' instead
    605  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    606 
    607  " Make sure the previous window has 'winfixbuf' so we can test that our
    608  " "skip 'winfixbuf' window" logic works.
    609  call win_gotoid(l:winfix_window)
    610  call win_gotoid(l:quickfix_window)
    611 
    612  cNext
    613  call assert_equal(l:first_window, win_getid())
    614 endfunc
    615 
    616 " Allow :cNfile but the 'nowinfixbuf' window is selected, instead
    617 func Test_cNfile()
    618  CheckFeature quickfix
    619  call s:reset_all_buffers()
    620 
    621  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    622 
    623  " The call to `:cNfile` succeeds but it selects the window with 'nowinfixbuf' instead
    624  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    625  cnext!
    626 
    627  " Make sure the previous window has 'winfixbuf' so we can test that our
    628  " "skip 'winfixbuf' window" logic works.
    629  call win_gotoid(l:winfix_window)
    630  call win_gotoid(l:quickfix_window)
    631 
    632  cNfile
    633  call assert_equal(l:first_window, win_getid())
    634 endfunc
    635 
    636 " Allow :caddexpr because it doesn't change the current buffer
    637 func Test_caddexpr()
    638  CheckFeature quickfix
    639  call s:reset_all_buffers()
    640 
    641  let l:file_path = tempname()
    642  call writefile(["Error - bad-thing-found"], l:file_path, 'D')
    643  exe $"edit {l:file_path}"
    644  let l:file_buffer = bufnr()
    645  let l:current = bufnr()
    646 
    647  edit first.unittest
    648  call append(0, ["some-search-term bad-thing-found"])
    649 
    650  edit! other.unittest
    651 
    652  set winfixbuf
    653 
    654  exe $"buffer! {l:file_buffer}"
    655 
    656  exe 'caddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")'
    657  call assert_equal(l:current, bufnr())
    658 endfunc
    659 
    660 " Fail :cbuffer but :cbuffer! is allowed
    661 func Test_cbuffer()
    662  CheckFeature quickfix
    663  call s:reset_all_buffers()
    664 
    665  let l:file_path = tempname()
    666  call writefile(["first.unittest:1:Error - bad-thing-found"], l:file_path, 'D')
    667  exe $"edit {l:file_path}"
    668  let l:file_buffer = bufnr()
    669  let l:current = bufnr()
    670 
    671  edit first.unittest
    672  call append(0, ["some-search-term bad-thing-found"])
    673 
    674  edit! other.unittest
    675 
    676  set winfixbuf
    677 
    678  exe $"buffer! {file_buffer}"
    679 
    680  call assert_fails($"cbuffer {file_buffer}", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
    681  call assert_equal(current, bufnr())
    682 
    683  exe $"cbuffer! {file_buffer}"
    684  call assert_equal("first.unittest", expand("%:t"))
    685 endfunc
    686 
    687 " Allow :cc but the 'nowinfixbuf' window is selected, instead
    688 func Test_cc()
    689  CheckFeature quickfix
    690  call s:reset_all_buffers()
    691 
    692  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    693 
    694  " The call to `:cnext` succeeds but it selects the window with 'nowinfixbuf' instead
    695  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    696 
    697  " Make sure the previous window has 'winfixbuf' so we can test that our
    698  " "skip 'winfixbuf' window" logic works.
    699  call win_gotoid(l:winfix_window)
    700  call win_gotoid(l:quickfix_window)
    701  " Go up one line in the quickfix window to an quickfix entry that doesn't
    702  " point to a winfixbuf buffer
    703  normal k
    704  " Attempt to make the previous window, winfixbuf buffer, to go to the
    705  " non-winfixbuf quickfix entry
    706  .cc
    707 
    708  " Confirm that :.cc did not change the winfixbuf-enabled window
    709  call assert_equal(l:first_window, win_getid())
    710 endfunc
    711 
    712 " Call :cdo and choose the next available 'nowinfixbuf' window.
    713 func Test_cdo_choose_available_window()
    714  CheckFeature quickfix
    715  call s:reset_all_buffers()
    716 
    717  let [l:current, l:last] = s:make_simple_quickfix()
    718  exe $"buffer! {l:current}"
    719 
    720  " Make a split window that is 'nowinfixbuf' but make it the second-to-last
    721  " window so that :cdo will first try the 'winfixbuf' window, pass over it,
    722  " and prefer the other 'nowinfixbuf' window, instead.
    723  "
    724  " +-------------------+
    725  " |   'nowinfixbuf'   |
    726  " +-------------------+
    727  " |    'winfixbuf'    |  <-- Cursor is here
    728  " +-------------------+
    729  split
    730  let l:nowinfixbuf_window = win_getid()
    731  " Move to the 'winfixbuf' window now
    732  exe "normal \<C-w>j"
    733  let l:winfixbuf_window = win_getid()
    734  let l:expected_windows = s:get_windows_count()
    735 
    736  cdo echo ''
    737 
    738  call assert_equal(l:nowinfixbuf_window, win_getid())
    739  call assert_equal(l:last, bufnr())
    740  exe "normal \<C-w>j"
    741  call assert_equal(l:current, bufnr())
    742  call assert_equal(l:expected_windows, s:get_windows_count())
    743 endfunc
    744 
    745 " Call :cdo and create a new split window if all available windows are 'winfixbuf'.
    746 func Test_cdo_make_new_window()
    747  CheckFeature quickfix
    748  call s:reset_all_buffers()
    749 
    750  let [l:current_buffer, l:last] = s:make_simple_quickfix()
    751  exe $"buffer! {l:current_buffer}"
    752 
    753  let l:current_window = win_getid()
    754  let l:current_windows = s:get_windows_count()
    755 
    756  cdo echo ''
    757  call assert_notequal(l:current_window, win_getid())
    758  call assert_equal(l:last, bufnr())
    759  exe "normal \<C-w>j"
    760  call assert_equal(l:current_buffer, bufnr())
    761  call assert_equal(l:current_windows + 1, s:get_windows_count())
    762 endfunc
    763 
    764 " Fail :cexpr but :cexpr! is allowed
    765 func Test_cexpr()
    766  CheckFeature quickfix
    767  call s:reset_all_buffers()
    768 
    769  let file = tempname()
    770  let entry = $'["{file}:1:bar"]'
    771  let current = bufnr()
    772 
    773  set winfixbuf
    774 
    775  call assert_fails($"cexpr {entry}", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
    776  call assert_equal(current, bufnr())
    777 
    778  exe $"cexpr! {entry}"
    779  call assert_equal(fnamemodify(file, ":t"), expand("%:t"))
    780 endfunc
    781 
    782 " Call :cfdo and choose the next available 'nowinfixbuf' window.
    783 func Test_cfdo_choose_available_window()
    784  CheckFeature quickfix
    785  call s:reset_all_buffers()
    786 
    787  let [l:current, l:last] = s:make_simple_quickfix()
    788  exe $"buffer! {l:current}"
    789 
    790  " Make a split window that is 'nowinfixbuf' but make it the second-to-last
    791  " window so that :cfdo will first try the 'winfixbuf' window, pass over it,
    792  " and prefer the other 'nowinfixbuf' window, instead.
    793  "
    794  " +-------------------+
    795  " |   'nowinfixbuf'   |
    796  " +-------------------+
    797  " |    'winfixbuf'    |  <-- Cursor is here
    798  " +-------------------+
    799  split
    800  let l:nowinfixbuf_window = win_getid()
    801  " Move to the 'winfixbuf' window now
    802  exe "normal \<C-w>j"
    803  let l:winfixbuf_window = win_getid()
    804  let l:expected_windows = s:get_windows_count()
    805 
    806  cfdo echo ''
    807 
    808  call assert_equal(l:nowinfixbuf_window, win_getid())
    809  call assert_equal(l:last, bufnr())
    810  exe "normal \<C-w>j"
    811  call assert_equal(l:current, bufnr())
    812  call assert_equal(l:expected_windows, s:get_windows_count())
    813 endfunc
    814 
    815 " Call :cfdo and create a new split window if all available windows are 'winfixbuf'.
    816 func Test_cfdo_make_new_window()
    817  CheckFeature quickfix
    818  call s:reset_all_buffers()
    819 
    820  let [l:current_buffer, l:last] = s:make_simple_quickfix()
    821  exe $"buffer! {l:current_buffer}"
    822 
    823  let l:current_window = win_getid()
    824  let l:current_windows = s:get_windows_count()
    825 
    826  cfdo echo ''
    827  call assert_notequal(l:current_window, win_getid())
    828  call assert_equal(l:last, bufnr())
    829  exe "normal \<C-w>j"
    830  call assert_equal(l:current_buffer, bufnr())
    831  call assert_equal(l:current_windows + 1, s:get_windows_count())
    832 endfunc
    833 
    834 " Fail :cfile but :cfile! is allowed
    835 func Test_cfile()
    836  CheckFeature quickfix
    837  call s:reset_all_buffers()
    838 
    839  edit first.unittest
    840  call append(0, ["some-search-term bad-thing-found"])
    841  write
    842  let first = bufnr()
    843 
    844  edit! second.unittest
    845  call append(0, ["some-search-term"])
    846  write
    847 
    848  let file = tempname()
    849  call writefile(["first.unittest:1:Error - bad-thing-found was detected"], file)
    850 
    851  let current = bufnr()
    852 
    853  set winfixbuf
    854 
    855  call assert_fails($":cfile {file}", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
    856  call assert_equal(current, bufnr())
    857 
    858  exe $":cfile! {file}"
    859  call assert_equal(first, bufnr())
    860 
    861  call delete(file)
    862  call delete("first.unittest")
    863  call delete("second.unittest")
    864 endfunc
    865 
    866 " Allow :cfirst but the 'nowinfixbuf' window is selected, instead
    867 func Test_cfirst()
    868  CheckFeature quickfix
    869  call s:reset_all_buffers()
    870 
    871  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    872 
    873  " The call to `:cfirst` succeeds but it selects the window with 'nowinfixbuf' instead
    874  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    875 
    876  " Make sure the previous window has 'winfixbuf' so we can test that our
    877  " "skip 'winfixbuf' window" logic works.
    878  call win_gotoid(l:winfix_window)
    879  call win_gotoid(l:quickfix_window)
    880 
    881  cfirst
    882  call assert_equal(l:first_window, win_getid())
    883 endfunc
    884 
    885 " Allow :clast but the 'nowinfixbuf' window is selected, instead
    886 func Test_clast()
    887  CheckFeature quickfix
    888  call s:reset_all_buffers()
    889 
    890  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    891 
    892  " The call to `:clast` succeeds but it selects the window with 'nowinfixbuf' instead
    893  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    894 
    895  " Make sure the previous window has 'winfixbuf' so we can test that our
    896  " "skip 'winfixbuf' window" logic works.
    897  call win_gotoid(l:winfix_window)
    898  call win_gotoid(l:quickfix_window)
    899 
    900  clast
    901  call assert_equal(l:first_window, win_getid())
    902 endfunc
    903 
    904 " Allow :cnext but the 'nowinfixbuf' window is selected, instead
    905 " Make sure no new windows are created and previous windows are reused
    906 func Test_cnext()
    907  CheckFeature quickfix
    908  call s:reset_all_buffers()
    909 
    910  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    911  let l:expected = s:get_windows_count()
    912 
    913  " The call to `:cnext` succeeds but it selects the window with 'nowinfixbuf' instead
    914  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    915 
    916  cnext!
    917  call assert_equal(l:expected, s:get_windows_count())
    918 
    919  " Make sure the previous window has 'winfixbuf' so we can test that our
    920  " "skip 'winfixbuf' window" logic works.
    921  call win_gotoid(l:winfix_window)
    922  call win_gotoid(l:quickfix_window)
    923 
    924  cnext
    925  call assert_equal(l:first_window, win_getid())
    926  call assert_equal(l:expected, s:get_windows_count())
    927 endfunc
    928 
    929 " Make sure :cnext creates a split window if no previous window exists
    930 func Test_cnext_no_previous_window()
    931  CheckFeature quickfix
    932  call s:reset_all_buffers()
    933 
    934  let [l:current, _] = s:make_simple_quickfix()
    935  exe $"buffer! {l:current}"
    936 
    937  let l:expected = s:get_windows_count()
    938 
    939  " Open the quickfix in a separate split and go to it
    940  copen
    941 
    942  call assert_equal(l:expected + 1, s:get_windows_count())
    943 endfunc
    944 
    945 " Allow :cnext and create a 'nowinfixbuf' window if none exists
    946 func Test_cnext_make_new_window()
    947  CheckFeature quickfix
    948  call s:reset_all_buffers()
    949 
    950  let [l:current, _] = s:make_simple_quickfix()
    951  let l:current = win_getid()
    952 
    953  cfirst!
    954 
    955  let l:windows = s:get_windows_count()
    956  let l:expected = l:windows + 1  " We're about to create a new split window
    957 
    958  cnext
    959  call assert_equal(l:expected, s:get_windows_count())
    960 
    961  cnext!
    962  call assert_equal(l:expected, s:get_windows_count())
    963 endfunc
    964 
    965 " Allow :cprevious but the 'nowinfixbuf' window is selected, instead
    966 func Test_cprevious()
    967  CheckFeature quickfix
    968  call s:reset_all_buffers()
    969 
    970  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    971 
    972  " The call to `:cprevious` succeeds but it selects the window with 'nowinfixbuf' instead
    973  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    974 
    975  " Make sure the previous window has 'winfixbuf' so we can test that our
    976  " "skip 'winfixbuf' window" logic works.
    977  call win_gotoid(l:winfix_window)
    978  call win_gotoid(l:quickfix_window)
    979 
    980  cprevious
    981  call assert_equal(l:first_window, win_getid())
    982 endfunc
    983 
    984 " Allow :cnfile but the 'nowinfixbuf' window is selected, instead
    985 func Test_cnfile()
    986  CheckFeature quickfix
    987  call s:reset_all_buffers()
    988 
    989  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
    990 
    991  " The call to `:cnfile` succeeds but it selects the window with 'nowinfixbuf' instead
    992  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
    993  cnext!
    994 
    995  " Make sure the previous window has 'winfixbuf' so we can test that our
    996  " "skip 'winfixbuf' window" logic works.
    997  call win_gotoid(l:winfix_window)
    998  call win_gotoid(l:quickfix_window)
    999 
   1000  cnfile
   1001  call assert_equal(l:first_window, win_getid())
   1002 endfunc
   1003 
   1004 " Allow :cpfile but the 'nowinfixbuf' window is selected, instead
   1005 func Test_cpfile()
   1006  CheckFeature quickfix
   1007  call s:reset_all_buffers()
   1008 
   1009  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
   1010 
   1011  " The call to `:cpfile` succeeds but it selects the window with 'nowinfixbuf' instead
   1012  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
   1013  cnext!
   1014 
   1015  " Make sure the previous window has 'winfixbuf' so we can test that our
   1016  " "skip 'winfixbuf' window" logic works.
   1017  call win_gotoid(l:winfix_window)
   1018  call win_gotoid(l:quickfix_window)
   1019 
   1020  cpfile
   1021  call assert_equal(l:first_window, win_getid())
   1022 endfunc
   1023 
   1024 " Allow :crewind but the 'nowinfixbuf' window is selected, instead
   1025 func Test_crewind()
   1026  CheckFeature quickfix
   1027  call s:reset_all_buffers()
   1028 
   1029  let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
   1030 
   1031  " The call to `:crewind` succeeds but it selects the window with 'nowinfixbuf' instead
   1032  call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
   1033  cnext!
   1034 
   1035  " Make sure the previous window has 'winfixbuf' so we can test that our
   1036  " "skip 'winfixbuf' window" logic works.
   1037  call win_gotoid(l:winfix_window)
   1038  call win_gotoid(l:quickfix_window)
   1039 
   1040  crewind
   1041  call assert_equal(l:first_window, win_getid())
   1042 endfunc
   1043 
   1044 " Allow <C-w>f because it opens in a new split
   1045 func Test_ctrl_w_f()
   1046  call s:reset_all_buffers()
   1047 
   1048  enew
   1049  let l:file_name = tempname()
   1050  call writefile([], l:file_name)
   1051  let l:file_buffer = bufnr()
   1052 
   1053  enew
   1054  file other
   1055  let l:other_buffer = bufnr()
   1056 
   1057  set winfixbuf
   1058 
   1059  call setline(1, l:file_name)
   1060  let l:current_windows = s:get_windows_count()
   1061  exe "normal \<C-w>f"
   1062 
   1063  call assert_equal(l:current_windows + 1, s:get_windows_count())
   1064 
   1065  call delete(l:file_name)
   1066 endfunc
   1067 
   1068 " Fail :djump but :djump! is allowed
   1069 func Test_djump()
   1070  call s:reset_all_buffers()
   1071 
   1072  let l:include_file = tempname() .. ".h"
   1073  call writefile(["min(1, 12);",
   1074        \ $'#include "{l:include_file}"'
   1075        \ ],
   1076        \ "main.c")
   1077  call writefile(["#define min(X, Y)  ((X) < (Y) ? (X) : (Y))"], l:include_file)
   1078  edit main.c
   1079 
   1080  set winfixbuf
   1081 
   1082  let l:current = bufnr()
   1083 
   1084  call assert_fails("djump 1 /min/", "E1513:")
   1085  call assert_equal(l:current, bufnr())
   1086 
   1087  djump! 1 /min/
   1088  call assert_notequal(l:current, bufnr())
   1089 
   1090  call delete("main.c")
   1091  call delete(l:include_file)
   1092 endfunc
   1093 
   1094 " Fail :drop but :drop! is allowed
   1095 func Test_drop()
   1096  call s:reset_all_buffers()
   1097 
   1098  let l:other = s:make_buffer_pairs()
   1099  let l:current = bufnr()
   1100 
   1101  call assert_fails("drop other", "E1513:")
   1102  call assert_equal(l:current, bufnr())
   1103 
   1104  drop! other
   1105  call assert_equal(l:other, bufnr())
   1106 endfunc
   1107 
   1108 " Fail :edit but :edit! is allowed
   1109 func Test_edit()
   1110  call s:reset_all_buffers()
   1111 
   1112  let l:other = s:make_buffer_pairs()
   1113  let l:current = bufnr()
   1114 
   1115  call assert_fails("edit other", "E1513:")
   1116  call assert_equal(l:current, bufnr())
   1117 
   1118  edit! other
   1119  call assert_equal(l:other, bufnr())
   1120 endfunc
   1121 
   1122 " Fail :e when selecting a buffer from a relative path if in a different folder
   1123 "
   1124 " In this tests there's 2 buffers
   1125 "
   1126 " foo - lives on disk, in some folder. e.g. /tmp/foo
   1127 " foo - an in-memory buffer that has not been saved to disk. If saved, it
   1128 "       would live in a different folder, /other/foo.
   1129 "
   1130 " The 'winfixbuf' is looking at the in-memory buffer and trying to switch to
   1131 " the buffer on-disk (and fails, because it's a different buffer)
   1132 func Test_edit_different_buffer_on_disk_and_relative_path_to_disk()
   1133  call s:reset_all_buffers()
   1134 
   1135  let l:file_on_disk = tempname()
   1136  let l:directory_on_disk1 = fnamemodify(l:file_on_disk, ":p:h")
   1137  let l:name = fnamemodify(l:file_on_disk, ":t")
   1138  exe $"edit {l:file_on_disk}"
   1139  write!
   1140 
   1141  let l:directory_on_disk2 = l:directory_on_disk1 .. "_something_else"
   1142 
   1143  if !isdirectory(l:directory_on_disk2)
   1144    call mkdir(l:directory_on_disk2)
   1145  endif
   1146 
   1147  exe $"cd {l:directory_on_disk2}"
   1148  exe $"edit {l:name}"
   1149 
   1150  let l:current = bufnr()
   1151 
   1152  call assert_equal(l:current, bufnr())
   1153  set winfixbuf
   1154  call assert_fails($"edit {l:file_on_disk}", "E1513:")
   1155  call assert_equal(l:current, bufnr())
   1156 
   1157  call delete(l:directory_on_disk1)
   1158  call delete(l:directory_on_disk2)
   1159 endfunc
   1160 
   1161 " Fail :e when selecting a buffer from a relative path if in a different folder
   1162 "
   1163 " In this tests there's 2 buffers
   1164 "
   1165 " foo - lives on disk, in some folder. e.g. /tmp/foo
   1166 " foo - an in-memory buffer that has not been saved to disk. If saved, it
   1167 "       would live in a different folder, /other/foo.
   1168 "
   1169 " The 'winfixbuf' is looking at the on-disk buffer and trying to switch to
   1170 " the in-memory buffer (and fails, because it's a different buffer)
   1171 func Test_edit_different_buffer_on_disk_and_relative_path_to_memory()
   1172  call s:reset_all_buffers()
   1173 
   1174  let l:file_on_disk = tempname()
   1175  let l:directory_on_disk1 = fnamemodify(l:file_on_disk, ":p:h")
   1176  let l:name = fnamemodify(l:file_on_disk, ":t")
   1177  exe $"edit {l:file_on_disk}"
   1178  write!
   1179 
   1180  let l:directory_on_disk2 = l:directory_on_disk1 .. "_something_else"
   1181 
   1182  if !isdirectory(l:directory_on_disk2)
   1183    call mkdir(l:directory_on_disk2)
   1184  endif
   1185 
   1186  exe $"cd {l:directory_on_disk2}"
   1187  exe $"edit {l:name}"
   1188  exe $"cd {l:directory_on_disk1}"
   1189  exe $"edit {l:file_on_disk}"
   1190  exe $"cd {l:directory_on_disk2}"
   1191 
   1192  let l:current = bufnr()
   1193 
   1194  call assert_equal(l:current, bufnr())
   1195  set winfixbuf
   1196  call assert_fails($"edit {l:name}", "E1513:")
   1197  call assert_equal(l:current, bufnr())
   1198 
   1199  call delete(l:directory_on_disk1)
   1200  call delete(l:directory_on_disk2)
   1201 endfunc
   1202 
   1203 " Fail to call `:e first` if called from a starting, in-memory buffer
   1204 func Test_edit_first_buffer()
   1205  call s:reset_all_buffers()
   1206 
   1207  set winfixbuf
   1208  let l:current = bufnr()
   1209 
   1210  call assert_fails("edit first", "E1513:")
   1211  call assert_equal(l:current, bufnr())
   1212 
   1213  edit! first
   1214  call assert_equal(l:current, bufnr())
   1215  edit! somewhere_else
   1216  call assert_notequal(l:current, bufnr())
   1217 endfunc
   1218 
   1219 " Allow reloading a buffer using :e
   1220 func Test_edit_no_arguments()
   1221  call s:reset_all_buffers()
   1222 
   1223  let l:current = bufnr()
   1224  file some_buffer
   1225 
   1226  call assert_equal(l:current, bufnr())
   1227  set winfixbuf
   1228  edit
   1229  call assert_equal(l:current, bufnr())
   1230 endfunc
   1231 
   1232 " Allow :e selecting the current buffer
   1233 func Test_edit_same_buffer_in_memory()
   1234  call s:reset_all_buffers()
   1235 
   1236  let current = bufnr()
   1237  file same_buffer
   1238 
   1239  call assert_equal(current, bufnr())
   1240  set winfixbuf
   1241  edit same_buffer
   1242  call assert_equal(current, bufnr())
   1243  set nowinfixbuf
   1244 endfunc
   1245 
   1246 " Allow :e selecting the current buffer as a full path
   1247 func Test_edit_same_buffer_on_disk_absolute_path()
   1248  call s:reset_all_buffers()
   1249 
   1250  let file = tempname()
   1251  " file must exist for expansion of 8.3 paths to succeed
   1252  call writefile([], file, 'D')
   1253  let file = fnamemodify(file, ':p')
   1254  let current = bufnr()
   1255  exe $"edit {file}"
   1256  write!
   1257 
   1258  call assert_equal(current, bufnr())
   1259  set winfixbuf
   1260  exe $"edit {file}"
   1261  call assert_equal(current, bufnr())
   1262 
   1263  set nowinfixbuf
   1264 endfunc
   1265 
   1266 " Fail :enew but :enew! is allowed
   1267 func Test_enew()
   1268  call s:reset_all_buffers()
   1269 
   1270  let l:other = s:make_buffer_pairs()
   1271  let l:current = bufnr()
   1272 
   1273  call assert_fails("enew", "E1513:")
   1274  call assert_equal(l:current, bufnr())
   1275 
   1276  enew!
   1277  call assert_notequal(l:other, bufnr())
   1278  call assert_notequal(3, bufnr())
   1279 endfunc
   1280 
   1281 " Fail :ex but :ex! is allowed
   1282 func Test_ex()
   1283  call s:reset_all_buffers()
   1284 
   1285  let l:other = s:make_buffer_pairs()
   1286  let l:current = bufnr()
   1287 
   1288  call assert_fails("ex other", "E1513:")
   1289  call assert_equal(l:current, bufnr())
   1290 
   1291  ex! other
   1292  call assert_equal(l:other, bufnr())
   1293 endfunc
   1294 
   1295 " Fail :find but :find! is allowed
   1296 func Test_find()
   1297  call s:reset_all_buffers()
   1298 
   1299  let l:current = bufnr()
   1300  let l:file = tempname()
   1301  call writefile([], l:file, 'D')
   1302  let l:file = fnamemodify(l:file, ':p')  " In case it's Windows 8.3-style.
   1303  let l:directory = fnamemodify(l:file, ":p:h")
   1304  let l:name = fnamemodify(l:file, ":p:t")
   1305 
   1306  let l:original_path = &path
   1307  exe $"set path={l:directory}"
   1308 
   1309  set winfixbuf
   1310 
   1311  call assert_fails($"exe 'find {l:name}'", "E1513:")
   1312  call assert_equal(l:current, bufnr())
   1313 
   1314  exe $"find! {l:name}"
   1315  call assert_equal(l:file, expand("%:p"))
   1316 
   1317  exe $"set path={l:original_path}"
   1318 endfunc
   1319 
   1320 " Fail :first but :first! is allowed
   1321 func Test_first()
   1322  call s:reset_all_buffers()
   1323 
   1324  let [l:first, _] = s:make_args_list()
   1325  next!
   1326 
   1327  call assert_fails("first", "E1513:")
   1328  call assert_notequal(l:first, bufnr())
   1329 
   1330  first!
   1331  call assert_equal(l:first, bufnr())
   1332 endfunc
   1333 
   1334 " Fail :grep but :grep! is allowed
   1335 func Test_grep()
   1336  CheckFeature quickfix
   1337  call s:reset_all_buffers()
   1338 
   1339  edit first.unittest
   1340  call append(0, ["some-search-term"])
   1341  write
   1342  let l:first = bufnr()
   1343 
   1344  edit current.unittest
   1345  call append(0, ["some-search-term"])
   1346  write
   1347  let l:current = bufnr()
   1348 
   1349  edit! last.unittest
   1350  call append(0, ["some-search-term"])
   1351  write
   1352  let l:last = bufnr()
   1353 
   1354  set winfixbuf
   1355 
   1356  buffer! current.unittest
   1357 
   1358  call assert_fails("silent! grep some-search-term *.unittest", "E1513:")
   1359  call assert_equal(l:current, bufnr())
   1360  exe $"edit! {l:first}"
   1361 
   1362  silent! grep! some-search-term *.unittest
   1363  call assert_notequal(l:first, bufnr())
   1364 
   1365  call delete("first.unittest")
   1366  call delete("current.unittest")
   1367  call delete("last.unittest")
   1368 endfunc
   1369 
   1370 " Fail :ijump but :ijump! is allowed
   1371 func Test_ijump()
   1372  call s:reset_all_buffers()
   1373 
   1374  let l:include_file = tempname() .. ".h"
   1375  call writefile([
   1376        \ $'#include "{l:include_file}"'
   1377        \ ],
   1378        \ "main.c", 'D')
   1379  call writefile(["#define min(X, Y)  ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
   1380  edit main.c
   1381 
   1382  set winfixbuf
   1383 
   1384  let l:current = bufnr()
   1385 
   1386  set define=^\\s*#\\s*define
   1387  set include=^\\s*#\\s*include
   1388  set path=.,/usr/include,,
   1389 
   1390  call assert_fails("ijump /min/", "E1513:")
   1391  call assert_equal(l:current, bufnr())
   1392 
   1393  set nowinfixbuf
   1394 
   1395  ijump! /min/
   1396  call assert_notequal(l:current, bufnr())
   1397 
   1398  set define&
   1399  set include&
   1400  set path&
   1401 endfunc
   1402 
   1403 " Fail :lNext but :lNext! is allowed
   1404 func Test_lNext()
   1405  CheckFeature quickfix
   1406  call s:reset_all_buffers()
   1407 
   1408  let [l:first, l:middle, _] = s:make_simple_location_list()
   1409  call assert_equal(1, getloclist(0, #{idx: 0}).idx)
   1410 
   1411  lnext!
   1412  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1413  call assert_equal(l:middle, bufnr())
   1414 
   1415  call assert_fails("lNext", "E1513:")
   1416  " Ensure the entry didn't change.
   1417  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1418  call assert_equal(l:middle, bufnr())
   1419 
   1420  lnext!
   1421  call assert_equal(3, getloclist(0, #{idx: 0}).idx)
   1422  call assert_equal(l:middle, bufnr())
   1423 
   1424  lNext!
   1425  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1426  call assert_equal(l:middle, bufnr())
   1427 
   1428  lNext!
   1429  call assert_equal(1, getloclist(0, #{idx: 0}).idx)
   1430  call assert_equal(l:first, bufnr())
   1431 endfunc
   1432 
   1433 " Fail :lNfile but :lNfile! is allowed
   1434 func Test_lNfile()
   1435  CheckFeature quickfix
   1436  call s:reset_all_buffers()
   1437 
   1438  let [l:first, l:current, _] = s:make_simple_location_list()
   1439  call assert_equal(1, getloclist(0, #{idx: 0}).idx)
   1440 
   1441  lnext!
   1442  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1443  call assert_equal(l:current, bufnr())
   1444 
   1445  call assert_fails("lNfile", "E1513:")
   1446  " Ensure the entry didn't change.
   1447  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1448  call assert_equal(l:current, bufnr())
   1449 
   1450  lnext!
   1451  call assert_equal(3, getloclist(0, #{idx: 0}).idx)
   1452  call assert_equal(l:current, bufnr())
   1453 
   1454  lNfile!
   1455  call assert_equal(1, getloclist(0, #{idx: 0}).idx)
   1456  call assert_equal(l:first, bufnr())
   1457 endfunc
   1458 
   1459 " Allow :laddexpr because it doesn't change the current buffer
   1460 func Test_laddexpr()
   1461  CheckFeature quickfix
   1462  call s:reset_all_buffers()
   1463 
   1464  let l:file_path = tempname()
   1465  call writefile(["Error - bad-thing-found"], l:file_path, 'D')
   1466  exe $"edit {l:file_path}"
   1467  let l:file_buffer = bufnr()
   1468  let l:current = bufnr()
   1469 
   1470  edit first.unittest
   1471  call append(0, ["some-search-term bad-thing-found"])
   1472 
   1473  edit! other.unittest
   1474 
   1475  set winfixbuf
   1476 
   1477  exe $"buffer! {l:file_buffer}"
   1478 
   1479  exe 'laddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")'
   1480  call assert_equal(l:current, bufnr())
   1481 endfunc
   1482 
   1483 " Fail :last but :last! is allowed
   1484 func Test_last()
   1485  call s:reset_all_buffers()
   1486 
   1487  let [_, l:last] = s:make_args_list()
   1488  next!
   1489 
   1490  call assert_fails("last", "E1513:")
   1491  call assert_notequal(l:last, bufnr())
   1492 
   1493  last!
   1494  call assert_equal(l:last, bufnr())
   1495 endfunc
   1496 
   1497 " Fail :lbuffer but :lbuffer! is allowed
   1498 func Test_lbuffer()
   1499  CheckFeature quickfix
   1500  call s:reset_all_buffers()
   1501 
   1502  let l:file_path = tempname()
   1503  call writefile(["first.unittest:1:Error - bad-thing-found"], l:file_path, 'D')
   1504  exe $"edit {l:file_path}"
   1505  let l:file_buffer = bufnr()
   1506  let l:current = bufnr()
   1507 
   1508  edit first.unittest
   1509  call append(0, ["some-search-term bad-thing-found"])
   1510 
   1511  edit! other.unittest
   1512 
   1513  set winfixbuf
   1514 
   1515  exe $"buffer! {file_buffer}"
   1516 
   1517  call assert_fails($"lbuffer {file_buffer}", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
   1518  call assert_equal(current, bufnr())
   1519 
   1520  exe $"lbuffer! {file_buffer}"
   1521  call assert_equal("first.unittest", expand("%:t"))
   1522 endfunc
   1523 
   1524 " Fail :ldo but :ldo! is allowed
   1525 func Test_ldo()
   1526  CheckFeature quickfix
   1527  call s:reset_all_buffers()
   1528 
   1529  let [l:first, l:middle, l:last] = s:make_simple_location_list()
   1530  lnext!
   1531 
   1532  call assert_fails($'exe "ldo buffer {l:first}"', "E1513:")
   1533  call assert_equal(l:middle, bufnr())
   1534  exe $"ldo! buffer {l:first}"
   1535  call assert_notequal(l:last, bufnr())
   1536 endfunc
   1537 
   1538 " Fail :lfdo but :lfdo! is allowed
   1539 func Test_lexpr()
   1540  CheckFeature quickfix
   1541  call s:reset_all_buffers()
   1542 
   1543  let file = tempname()
   1544  let entry = $'["{file}:1:bar"]'
   1545  let current = bufnr()
   1546 
   1547  set winfixbuf
   1548 
   1549  call assert_fails($"lexpr {entry}", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
   1550  call assert_equal(current, bufnr())
   1551 
   1552  exe $"lexpr! {entry}"
   1553  call assert_equal(fnamemodify(file, ":t"), expand("%:t"))
   1554 endfunc
   1555 
   1556 " Fail :lfdo but :lfdo! is allowed
   1557 func Test_lfdo()
   1558  CheckFeature quickfix
   1559  call s:reset_all_buffers()
   1560 
   1561  let [first, middle, last] = s:make_simple_location_list()
   1562  lnext!
   1563 
   1564  call assert_fails('exe "lfdo buffer ' .. first .. '"', "E1513:")
   1565  call assert_equal(middle, bufnr())
   1566  exe $"lfdo! buffer {first}"
   1567  call assert_notequal(last, bufnr())
   1568 endfunc
   1569 
   1570 " Fail :lfile but :lfile! is allowed
   1571 func Test_lfile()
   1572  CheckFeature quickfix
   1573  call s:reset_all_buffers()
   1574 
   1575  edit first.unittest
   1576  call append(0, ["some-search-term bad-thing-found"])
   1577  write
   1578  let l:first = bufnr()
   1579 
   1580  edit! second.unittest
   1581  call append(0, ["some-search-term"])
   1582  write
   1583 
   1584  let l:file = tempname()
   1585  call writefile(["first.unittest:1:Error - bad-thing-found was detected"], l:file, 'D')
   1586 
   1587  let l:current = bufnr()
   1588 
   1589  set winfixbuf
   1590 
   1591  call assert_fails($":lfile {l:file}", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
   1592  call assert_equal(l:current, bufnr())
   1593 
   1594  exe $":lfile! {l:file}"
   1595  call assert_equal(l:first, bufnr())
   1596 
   1597  call delete("first.unittest")
   1598  call delete("second.unittest")
   1599 endfunc
   1600 
   1601 " Fail :ll but :ll! is allowed
   1602 func Test_ll()
   1603  CheckFeature quickfix
   1604  call s:reset_all_buffers()
   1605 
   1606  let [l:first, l:middle, l:last] = s:make_simple_location_list()
   1607  lopen
   1608  lfirst!
   1609  exe "normal \<C-w>j"
   1610  normal j
   1611 
   1612  call assert_fails(".ll", "E1513:")
   1613  exe "normal \<C-w>k"
   1614  call assert_equal(l:first, bufnr())
   1615  exe "normal \<C-w>j"
   1616  .ll!
   1617  exe "normal \<C-w>k"
   1618  call assert_equal(l:middle, bufnr())
   1619 endfunc
   1620 
   1621 " Fail :llast but :llast! is allowed
   1622 func Test_llast()
   1623  CheckFeature quickfix
   1624  call s:reset_all_buffers()
   1625 
   1626  let [l:first, _, l:last] = s:make_simple_location_list()
   1627  lfirst!
   1628 
   1629  call assert_fails("llast", "E1513:")
   1630  call assert_equal(l:first, bufnr())
   1631 
   1632  llast!
   1633  call assert_equal(l:last, bufnr())
   1634 endfunc
   1635 
   1636 " Fail :lnext but :lnext! is allowed
   1637 func Test_lnext()
   1638  CheckFeature quickfix
   1639  call s:reset_all_buffers()
   1640 
   1641  let [l:first, l:middle, l:last] = s:make_simple_location_list()
   1642  ll!
   1643 
   1644  call assert_fails("lnext", "E1513:")
   1645  call assert_equal(l:first, bufnr())
   1646 
   1647  lnext!
   1648  call assert_equal(l:middle, bufnr())
   1649 endfunc
   1650 
   1651 " Fail :lnfile but :lnfile! is allowed
   1652 func Test_lnfile()
   1653  CheckFeature quickfix
   1654  call s:reset_all_buffers()
   1655 
   1656  let [_, l:current, l:last] = s:make_simple_location_list()
   1657  call assert_equal(1, getloclist(0, #{idx: 0}).idx)
   1658 
   1659  lnext!
   1660  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1661  call assert_equal(l:current, bufnr())
   1662 
   1663  call assert_fails("lnfile", "E1513:")
   1664  " Ensure the entry didn't change.
   1665  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1666  call assert_equal(l:current, bufnr())
   1667 
   1668  lnfile!
   1669  call assert_equal(4, getloclist(0, #{idx: 0}).idx)
   1670  call assert_equal(l:last, bufnr())
   1671 endfunc
   1672 
   1673 " Fail :lpfile but :lpfile! is allowed
   1674 func Test_lpfile()
   1675  CheckFeature quickfix
   1676  call s:reset_all_buffers()
   1677 
   1678  let [l:first, l:current, _] = s:make_simple_location_list()
   1679  lnext!
   1680 
   1681  call assert_fails("lpfile", "E1513:")
   1682  call assert_equal(l:current, bufnr())
   1683 
   1684  lnext!  " Reset for the next test call
   1685 
   1686  lpfile!
   1687  call assert_equal(l:first, bufnr())
   1688 endfunc
   1689 
   1690 " Fail :lprevious but :lprevious! is allowed
   1691 func Test_lprevious()
   1692  CheckFeature quickfix
   1693  call s:reset_all_buffers()
   1694 
   1695  let [l:first, l:middle, _] = s:make_simple_location_list()
   1696  call assert_equal(1, getloclist(0, #{idx: 0}).idx)
   1697 
   1698  lnext!
   1699  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1700  call assert_equal(l:middle, bufnr())
   1701 
   1702  call assert_fails("lprevious", "E1513:")
   1703  " Ensure the entry didn't change.
   1704  call assert_equal(2, getloclist(0, #{idx: 0}).idx)
   1705  call assert_equal(l:middle, bufnr())
   1706 
   1707  lprevious!
   1708  call assert_equal(1, getloclist(0, #{idx: 0}).idx)
   1709  call assert_equal(l:first, bufnr())
   1710 endfunc
   1711 
   1712 " Fail :lrewind but :lrewind! is allowed
   1713 func Test_lrewind()
   1714  CheckFeature quickfix
   1715  call s:reset_all_buffers()
   1716 
   1717  let [l:first, l:middle, _] = s:make_simple_location_list()
   1718  lnext!
   1719 
   1720  call assert_fails("lrewind", "E1513:")
   1721  call assert_equal(l:middle, bufnr())
   1722 
   1723  lrewind!
   1724  call assert_equal(l:first, bufnr())
   1725 endfunc
   1726 
   1727 " Fail :ltag but :ltag! is allowed
   1728 func Test_ltag()
   1729  call s:reset_all_buffers()
   1730 
   1731  set tags=Xtags
   1732  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   1733        \ "one\tXfile\t1",
   1734        \ "three\tXfile\t3",
   1735        \ "two\tXfile\t2"],
   1736        \ "Xtags", 'D')
   1737  call writefile(["one", "two", "three"], "Xfile", 'D')
   1738  call writefile(["one"], "Xother", 'D')
   1739  edit Xother
   1740  exe "normal \<C-]>"
   1741 
   1742  set winfixbuf
   1743 
   1744  let l:current = bufnr()
   1745 
   1746  call assert_fails("ltag one", "E1513:")
   1747 
   1748  ltag! one
   1749 
   1750  set tags&
   1751 endfunc
   1752 
   1753 " Fail vim.cmd if we try to change buffers while 'winfixbuf' is set
   1754 func Test_lua_command()
   1755  " CheckFeature lua
   1756  call s:reset_all_buffers()
   1757 
   1758  enew
   1759  file first
   1760  let l:previous = bufnr()
   1761 
   1762  enew
   1763  file second
   1764  let l:current = bufnr()
   1765 
   1766  set winfixbuf
   1767 
   1768  call assert_fails($'lua vim.cmd("buffer " .. {l:previous})')
   1769  call assert_equal(l:current, bufnr())
   1770 
   1771  exe $'lua vim.cmd("buffer! " .. {l:previous})'
   1772  call assert_equal(l:previous, bufnr())
   1773 endfunc
   1774 
   1775 " Fail :lvimgrep but :lvimgrep! is allowed
   1776 func Test_lvimgrep()
   1777  CheckFeature quickfix
   1778  call s:reset_all_buffers()
   1779 
   1780  edit first.unittest
   1781  call append(0, ["some-search-term"])
   1782  write
   1783 
   1784  edit winfix.unittest
   1785  call append(0, ["some-search-term"])
   1786  write
   1787  let l:current = bufnr()
   1788 
   1789  set winfixbuf
   1790 
   1791  edit! last.unittest
   1792  call append(0, ["some-search-term"])
   1793  write
   1794  let l:last = bufnr()
   1795 
   1796  buffer! winfix.unittest
   1797 
   1798  call assert_fails("lvimgrep /some-search-term/ *.unittest", "E1513:")
   1799  call assert_equal(l:current, bufnr())
   1800 
   1801  lvimgrep! /some-search-term/ *.unittest
   1802  call assert_notequal(l:current, bufnr())
   1803 
   1804  call delete("first.unittest")
   1805  call delete("winfix.unittest")
   1806  call delete("last.unittest")
   1807 endfunc
   1808 
   1809 " Fail :lvimgrepadd but :lvimgrepadd! is allowed
   1810 func Test_lvimgrepadd()
   1811  CheckFeature quickfix
   1812  call s:reset_all_buffers()
   1813 
   1814  edit first.unittest
   1815  call append(0, ["some-search-term"])
   1816  write
   1817 
   1818  edit winfix.unittest
   1819  call append(0, ["some-search-term"])
   1820  write
   1821  let l:current = bufnr()
   1822 
   1823  set winfixbuf
   1824 
   1825  edit! last.unittest
   1826  call append(0, ["some-search-term"])
   1827  write
   1828  let l:last = bufnr()
   1829 
   1830  buffer! winfix.unittest
   1831 
   1832  call assert_fails("lvimgrepadd /some-search-term/ *.unittest", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
   1833  call assert_equal(l:current, bufnr())
   1834 
   1835  lvimgrepadd! /some-search-term/ *.unittest
   1836  call assert_notequal(l:current, bufnr())
   1837 
   1838  call delete("first.unittest")
   1839  call delete("winfix.unittest")
   1840  call delete("last.unittest")
   1841 endfunc
   1842 
   1843 " Don't allow global marks to change the current 'winfixbuf' window
   1844 func Test_marks_mappings_fail()
   1845  call s:reset_all_buffers()
   1846 
   1847  let l:other = s:make_buffer_pairs()
   1848  let l:current = bufnr()
   1849  exe $"buffer! {l:other}"
   1850  normal mA
   1851  exe $"buffer! {l:current}"
   1852  normal mB
   1853 
   1854  call assert_fails("normal `A", "E1513:")
   1855  call assert_equal(l:current, bufnr())
   1856 
   1857  call assert_fails("normal 'A", "E1513:")
   1858  call assert_equal(l:current, bufnr())
   1859 
   1860  set nowinfixbuf
   1861 
   1862  normal `A
   1863  call assert_equal(l:other, bufnr())
   1864 endfunc
   1865 
   1866 " Allow global marks in a 'winfixbuf' window if the jump is the same buffer
   1867 func Test_marks_mappings_pass_intra_move()
   1868  call s:reset_all_buffers()
   1869 
   1870  let l:current = bufnr()
   1871  call append(0, ["some line", "another line"])
   1872  normal mA
   1873  normal j
   1874  normal mB
   1875 
   1876  set winfixbuf
   1877 
   1878  normal `A
   1879  call assert_equal(l:current, bufnr())
   1880 endfunc
   1881 
   1882 " Fail :next but :next! is allowed
   1883 func Test_next()
   1884  call s:reset_all_buffers()
   1885 
   1886  let [l:first, _] = s:make_args_list()
   1887  first!
   1888 
   1889  call assert_fails("next", "E1513:")
   1890  call assert_equal(l:first, bufnr())
   1891 
   1892  next!
   1893  call assert_notequal(l:first, bufnr())
   1894 endfunc
   1895 
   1896 " Ensure :mksession saves 'winfixbuf' details
   1897 func Test_mksession()
   1898  CheckFeature mksession
   1899  call s:reset_all_buffers()
   1900 
   1901  set sessionoptions+=options
   1902  set winfixbuf
   1903 
   1904  mksession test_winfixbuf_Test_mksession.vim
   1905 
   1906  call s:reset_all_buffers()
   1907  let l:winfixbuf = &winfixbuf
   1908  call assert_equal(0, l:winfixbuf)
   1909 
   1910  source test_winfixbuf_Test_mksession.vim
   1911 
   1912  let l:winfixbuf = &winfixbuf
   1913  call assert_equal(1, l:winfixbuf)
   1914 
   1915  set sessionoptions&
   1916  call delete("test_winfixbuf_Test_mksession.vim")
   1917 endfunc
   1918 
   1919 " Allow :next if the next index is the same as the current buffer
   1920 func Test_next_same_buffer()
   1921  call s:reset_all_buffers()
   1922 
   1923  enew
   1924  file foo
   1925  enew
   1926  file bar
   1927  enew
   1928  file fizz
   1929  enew
   1930  file buzz
   1931  args foo foo bar fizz buzz
   1932 
   1933  edit foo
   1934  set winfixbuf
   1935  let l:current = bufnr()
   1936 
   1937  " Allow :next because the args list is `[foo] foo bar fizz buzz
   1938  next
   1939  call assert_equal(l:current, bufnr())
   1940 
   1941  " Fail :next because the args list is `foo [foo] bar fizz buzz
   1942  " and the next buffer would be bar, which is a different buffer
   1943  call assert_fails("next", "E1513:")
   1944  call assert_equal(l:current, bufnr())
   1945 endfunc
   1946 
   1947 " Fail to jump to a tag with g<C-]> if 'winfixbuf' is enabled
   1948 func Test_normal_g_ctrl_square_bracket_right()
   1949  call s:reset_all_buffers()
   1950 
   1951  set tags=Xtags
   1952  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   1953        \ "one\tXfile\t1",
   1954        \ "three\tXfile\t3",
   1955        \ "two\tXfile\t2"],
   1956        \ "Xtags", 'D')
   1957  call writefile(["one", "two", "three"], "Xfile", 'D')
   1958  call writefile(["one"], "Xother", 'D')
   1959  edit Xother
   1960 
   1961  set winfixbuf
   1962 
   1963  let l:current = bufnr()
   1964 
   1965  call assert_fails("normal g\<C-]>", "E1513:")
   1966  call assert_equal(l:current, bufnr())
   1967 
   1968  set tags&
   1969 endfunc
   1970 
   1971 " Fail to jump to a tag with g<RightMouse> if 'winfixbuf' is enabled
   1972 func Test_normal_g_rightmouse()
   1973  call s:reset_all_buffers()
   1974  set mouse=n
   1975 
   1976  set tags=Xtags
   1977  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   1978        \ "one\tXfile\t1",
   1979        \ "three\tXfile\t3",
   1980        \ "two\tXfile\t2"],
   1981        \ "Xtags", 'D')
   1982  call writefile(["one", "two", "three"], "Xfile", 'D')
   1983  call writefile(["one"], "Xother", 'D')
   1984  edit Xother
   1985  exe "normal \<C-]>"
   1986 
   1987  set winfixbuf
   1988 
   1989  let l:current = bufnr()
   1990 
   1991  call assert_fails("normal g\<RightMouse>", "E1513:")
   1992  call assert_equal(l:current, bufnr())
   1993 
   1994  set tags&
   1995  set mouse&
   1996 endfunc
   1997 
   1998 " Fail to jump to a tag with g] if 'winfixbuf' is enabled
   1999 func Test_normal_g_square_bracket_right()
   2000  call s:reset_all_buffers()
   2001 
   2002  set tags=Xtags
   2003  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2004        \ "one\tXfile\t1",
   2005        \ "three\tXfile\t3",
   2006        \ "two\tXfile\t2"],
   2007        \ "Xtags", 'D')
   2008  call writefile(["one", "two", "three"], "Xfile", 'D')
   2009  call writefile(["one"], "Xother", 'D')
   2010  edit Xother
   2011 
   2012  set winfixbuf
   2013 
   2014  let l:current = bufnr()
   2015 
   2016  call assert_fails("normal g]", "E1513:")
   2017  call assert_equal(l:current, bufnr())
   2018 
   2019  set tags&
   2020 endfunc
   2021 
   2022 " Fail to jump to a tag with <C-RightMouse> if 'winfixbuf' is enabled
   2023 func Test_normal_ctrl_rightmouse()
   2024  call s:reset_all_buffers()
   2025  set mouse=n
   2026 
   2027  set tags=Xtags
   2028  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2029        \ "one\tXfile\t1",
   2030        \ "three\tXfile\t3",
   2031        \ "two\tXfile\t2"],
   2032        \ "Xtags", 'D')
   2033  call writefile(["one", "two", "three"], "Xfile", 'D')
   2034  call writefile(["one"], "Xother", 'D')
   2035  edit Xother
   2036  exe "normal \<C-]>"
   2037 
   2038  set winfixbuf
   2039 
   2040  let l:current = bufnr()
   2041 
   2042  call assert_fails("normal \<C-RightMouse>", "E1513:")
   2043  call assert_equal(l:current, bufnr())
   2044 
   2045  set tags&
   2046  set mouse&
   2047 endfunc
   2048 
   2049 " Fail to jump to a tag with <C-t> if 'winfixbuf' is enabled
   2050 func Test_normal_ctrl_t()
   2051  call s:reset_all_buffers()
   2052 
   2053  set tags=Xtags
   2054  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2055        \ "one\tXfile\t1",
   2056        \ "three\tXfile\t3",
   2057        \ "two\tXfile\t2"],
   2058        \ "Xtags", 'D')
   2059  call writefile(["one", "two", "three"], "Xfile", 'D')
   2060  call writefile(["one"], "Xother", 'D')
   2061  edit Xother
   2062  exe "normal \<C-]>"
   2063 
   2064  set winfixbuf
   2065 
   2066  let l:current = bufnr()
   2067 
   2068  call assert_fails("normal \<C-t>", "E1513:")
   2069  call assert_equal(l:current, bufnr())
   2070 
   2071  set tags&
   2072 endfunc
   2073 
   2074 " Disallow <C-^> in 'winfixbuf' windows
   2075 func Test_normal_ctrl_hat()
   2076  call s:reset_all_buffers()
   2077  clearjumps
   2078 
   2079  enew
   2080  file first
   2081  let l:first = bufnr()
   2082 
   2083  enew
   2084  file current
   2085  let l:current = bufnr()
   2086 
   2087  set winfixbuf
   2088 
   2089  call assert_fails("normal \<C-^>", "E1513:")
   2090  call assert_equal(l:current, bufnr())
   2091 endfunc
   2092 
   2093 " Allow <C-i> in 'winfixbuf' windows if the movement stays within the buffer
   2094 func Test_normal_ctrl_i_pass()
   2095  call s:reset_all_buffers()
   2096  clearjumps
   2097 
   2098  enew
   2099  file first
   2100  let l:first = bufnr()
   2101 
   2102  enew!
   2103  file current
   2104  let l:current = bufnr()
   2105  " Add some lines so we can populate a jumplist"
   2106  call append(0, ["some line", "another line"])
   2107  " Add an entry to the jump list
   2108  " Go up another line
   2109  normal m`
   2110  normal k
   2111  exe "normal \<C-o>"
   2112 
   2113  set winfixbuf
   2114 
   2115  let l:line = getcurpos()[1]
   2116  exe "normal 1\<C-i>"
   2117  call assert_notequal(l:line, getcurpos()[1])
   2118 endfunc
   2119 
   2120 " Disallow <C-o> in 'winfixbuf' windows if it would cause the buffer to switch
   2121 func Test_normal_ctrl_o_fail()
   2122  call s:reset_all_buffers()
   2123  clearjumps
   2124 
   2125  enew
   2126  file first
   2127  let l:first = bufnr()
   2128 
   2129  enew
   2130  file current
   2131  let l:current = bufnr()
   2132 
   2133  set winfixbuf
   2134 
   2135  call assert_fails("normal \<C-o>", "E1513:")
   2136  call assert_equal(l:current, bufnr())
   2137 endfunc
   2138 
   2139 " Allow <C-o> in 'winfixbuf' windows if the movement stays within the buffer
   2140 func Test_normal_ctrl_o_pass()
   2141  call s:reset_all_buffers()
   2142  clearjumps
   2143 
   2144  enew
   2145  file first
   2146  let l:first = bufnr()
   2147 
   2148  enew!
   2149  file current
   2150  let l:current = bufnr()
   2151  " Add some lines so we can populate a jumplist
   2152  call append(0, ["some line", "another line"])
   2153  " Add an entry to the jump list
   2154  " Go up another line
   2155  normal m`
   2156  normal k
   2157 
   2158  set winfixbuf
   2159 
   2160  exe "normal \<C-o>"
   2161  call assert_equal(l:current, bufnr())
   2162 endfunc
   2163 
   2164 " Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
   2165 func Test_normal_ctrl_square_bracket_right()
   2166  call s:reset_all_buffers()
   2167 
   2168  set tags=Xtags
   2169  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2170        \ "one\tXfile\t1",
   2171        \ "three\tXfile\t3",
   2172        \ "two\tXfile\t2"],
   2173        \ "Xtags", 'D')
   2174  call writefile(["one", "two", "three"], "Xfile", 'D')
   2175  call writefile(["one"], "Xother", 'D')
   2176  edit Xother
   2177 
   2178  set winfixbuf
   2179 
   2180  let l:current = bufnr()
   2181 
   2182  call assert_fails("normal \<C-]>", "E1513:")
   2183  call assert_equal(l:current, bufnr())
   2184 
   2185  set tags&
   2186 endfunc
   2187 
   2188 " Allow <C-w><C-]> with 'winfixbuf' enabled because it runs in a new, split window
   2189 func Test_normal_ctrl_w_ctrl_square_bracket_right()
   2190  call s:reset_all_buffers()
   2191 
   2192  set tags=Xtags
   2193  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2194        \ "one\tXfile\t1",
   2195        \ "three\tXfile\t3",
   2196        \ "two\tXfile\t2"],
   2197        \ "Xtags", 'D')
   2198  call writefile(["one", "two", "three"], "Xfile", 'D')
   2199  call writefile(["one"], "Xother", 'D')
   2200  edit Xother
   2201 
   2202  set winfixbuf
   2203 
   2204  let l:current_windows = s:get_windows_count()
   2205  exe "normal \<C-w>\<C-]>"
   2206  call assert_equal(l:current_windows + 1, s:get_windows_count())
   2207 
   2208  set tags&
   2209 endfunc
   2210 
   2211 " Allow <C-w>g<C-]> with 'winfixbuf' enabled because it runs in a new, split window
   2212 func Test_normal_ctrl_w_g_ctrl_square_bracket_right()
   2213  call s:reset_all_buffers()
   2214 
   2215  set tags=Xtags
   2216  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2217        \ "one\tXfile\t1",
   2218        \ "three\tXfile\t3",
   2219        \ "two\tXfile\t2"],
   2220        \ "Xtags", 'D')
   2221  call writefile(["one", "two", "three"], "Xfile", 'D')
   2222  call writefile(["one"], "Xother", 'D')
   2223  edit Xother
   2224 
   2225  set winfixbuf
   2226 
   2227  let l:current_windows = s:get_windows_count()
   2228  exe "normal \<C-w>g\<C-]>"
   2229  call assert_equal(l:current_windows + 1, s:get_windows_count())
   2230 
   2231  set tags&
   2232 endfunc
   2233 
   2234 " Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
   2235 func Test_normal_gt()
   2236  call s:reset_all_buffers()
   2237 
   2238  set tags=Xtags
   2239  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2240        \ "one\tXfile\t1",
   2241        \ "three\tXfile\t3",
   2242        \ "two\tXfile\t2"],
   2243        \ "Xtags", 'D')
   2244  call writefile(["one", "two", "three"], "Xfile", 'D')
   2245  call writefile(["one", "two", "three"], "Xother", 'D')
   2246  edit Xother
   2247 
   2248  set winfixbuf
   2249 
   2250  let l:current = bufnr()
   2251 
   2252  call assert_fails("normal \<C-]>", "E1513:")
   2253  call assert_equal(l:current, bufnr())
   2254 
   2255  set tags&
   2256 endfunc
   2257 
   2258 " Prevent gF from switching a 'winfixbuf' window's buffer
   2259 func Test_normal_gF()
   2260  call s:reset_all_buffers()
   2261 
   2262  let l:file = tempname()
   2263  call append(0, [l:file])
   2264  call writefile([], l:file, 'D')
   2265  " Place the cursor onto the line that has `l:file`
   2266  normal gg
   2267  " Prevent Vim from erroring with "No write since last change @ command
   2268  " line" when we try to call gF, later.
   2269  set hidden
   2270 
   2271  set winfixbuf
   2272 
   2273  let l:buffer = bufnr()
   2274 
   2275  call assert_fails("normal gF", "E1513:")
   2276  call assert_equal(l:buffer, bufnr())
   2277 
   2278  set nowinfixbuf
   2279 
   2280  normal gF
   2281  call assert_notequal(l:buffer, bufnr())
   2282 
   2283  set nohidden
   2284 endfunc
   2285 
   2286 " Prevent gf from switching a 'winfixbuf' window's buffer
   2287 func Test_normal_gf()
   2288  call s:reset_all_buffers()
   2289 
   2290  let l:file = tempname()
   2291  call append(0, [l:file])
   2292  call writefile([], l:file, 'D')
   2293  " Place the cursor onto the line that has `l:file`
   2294  normal gg
   2295  " Prevent Vim from erroring with "No write since last change @ command
   2296  " line" when we try to call gf, later.
   2297  set hidden
   2298 
   2299  set winfixbuf
   2300 
   2301  let l:buffer = bufnr()
   2302 
   2303  call assert_fails("normal gf", "E1513:")
   2304  call assert_equal(l:buffer, bufnr())
   2305 
   2306  set nowinfixbuf
   2307 
   2308  normal gf
   2309  call assert_notequal(l:buffer, bufnr())
   2310 
   2311  set nohidden
   2312 endfunc
   2313 
   2314 " Fail "goto file under the cursor" (using [f, which is the same as `:normal gf`)
   2315 func Test_normal_square_bracket_left_f()
   2316  call s:reset_all_buffers()
   2317 
   2318  let l:file = tempname()
   2319  call append(0, [l:file])
   2320  call writefile([], l:file, 'D')
   2321  " Place the cursor onto the line that has `l:file`
   2322  normal gg
   2323  " Prevent Vim from erroring with "No write since last change @ command
   2324  " line" when we try to call gf, later.
   2325  set hidden
   2326 
   2327  set winfixbuf
   2328 
   2329  let l:buffer = bufnr()
   2330 
   2331  call assert_fails("normal [f", "E1513:")
   2332  call assert_equal(l:buffer, bufnr())
   2333 
   2334  set nowinfixbuf
   2335 
   2336  normal [f
   2337  call assert_notequal(l:buffer, bufnr())
   2338 
   2339  set nohidden
   2340 endfunc
   2341 
   2342 " Fail to go to a C macro with [<C-d> if 'winfixbuf' is enabled
   2343 func Test_normal_square_bracket_left_ctrl_d()
   2344  call s:reset_all_buffers()
   2345 
   2346  let l:include_file = tempname() .. ".h"
   2347  call writefile(["min(1, 12);",
   2348        \ $'#include "{l:include_file}"'
   2349        \ ],
   2350        \ "main.c", 'D')
   2351  call writefile(["#define min(X, Y)  ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
   2352  edit main.c
   2353  normal ]\<C-d>
   2354 
   2355  set winfixbuf
   2356 
   2357  let l:current = bufnr()
   2358 
   2359  call assert_fails("normal [\<C-d>", "E1513:")
   2360  call assert_equal(l:current, bufnr())
   2361 
   2362  set nowinfixbuf
   2363 
   2364  exe "normal [\<C-d>"
   2365  call assert_notequal(l:current, bufnr())
   2366 endfunc
   2367 
   2368 " Fail to go to a C macro with ]<C-d> if 'winfixbuf' is enabled
   2369 func Test_normal_square_bracket_right_ctrl_d()
   2370  call s:reset_all_buffers()
   2371 
   2372  let l:include_file = tempname() .. ".h"
   2373  call writefile(["min(1, 12);",
   2374        \ $'#include "{l:include_file}"'
   2375        \ ],
   2376        \ "main.c", 'D')
   2377  call writefile(["#define min(X, Y)  ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
   2378  edit main.c
   2379 
   2380  set winfixbuf
   2381 
   2382  let l:current = bufnr()
   2383 
   2384  call assert_fails("normal ]\<C-d>", "E1513:")
   2385  call assert_equal(l:current, bufnr())
   2386 
   2387  set nowinfixbuf
   2388 
   2389  exe "normal ]\<C-d>"
   2390  call assert_notequal(l:current, bufnr())
   2391 endfunc
   2392 
   2393 " Fail to go to a C macro with [<C-i> if 'winfixbuf' is enabled
   2394 func Test_normal_square_bracket_left_ctrl_i()
   2395  call s:reset_all_buffers()
   2396 
   2397  let l:include_file = tempname() .. ".h"
   2398  call writefile([$'#include "{l:include_file}"',
   2399        \ "min(1, 12);",
   2400        \ ],
   2401        \ "main.c", 'D')
   2402  call writefile(["#define min(X, Y)  ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
   2403  edit main.c
   2404  " Move to the line with `min(1, 12);` on it"
   2405  normal j
   2406 
   2407  set define=^\\s*#\\s*define
   2408  set include=^\\s*#\\s*include
   2409  set path=.,/usr/include,,
   2410 
   2411  let l:current = bufnr()
   2412 
   2413  set winfixbuf
   2414 
   2415  call assert_fails("normal [\<C-i>", "E1513:")
   2416 
   2417  set nowinfixbuf
   2418 
   2419  exe "normal [\<C-i>"
   2420  call assert_notequal(l:current, bufnr())
   2421 
   2422  set define&
   2423  set include&
   2424  set path&
   2425 endfunc
   2426 
   2427 " Fail to go to a C macro with ]<C-i> if 'winfixbuf' is enabled
   2428 func Test_normal_square_bracket_right_ctrl_i()
   2429  call s:reset_all_buffers()
   2430 
   2431  let l:include_file = tempname() .. ".h"
   2432  call writefile(["min(1, 12);",
   2433        \ $'#include "{l:include_file}"'
   2434        \ ],
   2435        \ "main.c", 'D')
   2436  call writefile(["#define min(X, Y)  ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
   2437  edit main.c
   2438 
   2439  set winfixbuf
   2440 
   2441  set define=^\\s*#\\s*define
   2442  set include=^\\s*#\\s*include
   2443  set path=.,/usr/include,,
   2444 
   2445  let l:current = bufnr()
   2446 
   2447  call assert_fails("normal ]\<C-i>", "E1513:")
   2448  call assert_equal(l:current, bufnr())
   2449 
   2450  set nowinfixbuf
   2451 
   2452  exe "normal ]\<C-i>"
   2453  call assert_notequal(l:current, bufnr())
   2454 
   2455  set define&
   2456  set include&
   2457  set path&
   2458 endfunc
   2459 
   2460 " Fail "goto file under the cursor" (using ]f, which is the same as `:normal gf`)
   2461 func Test_normal_square_bracket_right_f()
   2462  call s:reset_all_buffers()
   2463 
   2464  let l:file = tempname()
   2465  call append(0, [l:file])
   2466  call writefile([], l:file, 'D')
   2467  " Place the cursor onto the line that has `l:file`
   2468  normal gg
   2469  " Prevent Vim from erroring with "No write since last change @ command
   2470  " line" when we try to call gf, later.
   2471  set hidden
   2472 
   2473  set winfixbuf
   2474 
   2475  let l:buffer = bufnr()
   2476 
   2477  call assert_fails("normal ]f", "E1513:")
   2478  call assert_equal(l:buffer, bufnr())
   2479 
   2480  set nowinfixbuf
   2481 
   2482  normal ]f
   2483  call assert_notequal(l:buffer, bufnr())
   2484 
   2485  set nohidden
   2486 endfunc
   2487 
   2488 " Fail to jump to a tag with v<C-]> if 'winfixbuf' is enabled
   2489 func Test_normal_v_ctrl_square_bracket_right()
   2490  call s:reset_all_buffers()
   2491 
   2492  set tags=Xtags
   2493  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2494        \ "one\tXfile\t1",
   2495        \ "three\tXfile\t3",
   2496        \ "two\tXfile\t2"],
   2497        \ "Xtags", 'D')
   2498  call writefile(["one", "two", "three"], "Xfile", 'D')
   2499  call writefile(["one"], "Xother", 'D')
   2500  edit Xother
   2501 
   2502  set winfixbuf
   2503 
   2504  let l:current = bufnr()
   2505 
   2506  call assert_fails("normal v\<C-]>", "E1513:")
   2507  call assert_equal(l:current, bufnr())
   2508 
   2509  set tags&
   2510 endfunc
   2511 
   2512 " Fail to jump to a tag with vg<C-]> if 'winfixbuf' is enabled
   2513 func Test_normal_v_g_ctrl_square_bracket_right()
   2514  call s:reset_all_buffers()
   2515 
   2516  set tags=Xtags
   2517  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2518        \ "one\tXfile\t1",
   2519        \ "three\tXfile\t3",
   2520        \ "two\tXfile\t2"],
   2521        \ "Xtags", 'D')
   2522  call writefile(["one", "two", "three"], "Xfile", 'D')
   2523  call writefile(["one"], "Xother", 'D')
   2524  edit Xother
   2525 
   2526  set winfixbuf
   2527 
   2528  let l:current = bufnr()
   2529 
   2530  call assert_fails("normal vg\<C-]>", "E1513:")
   2531  call assert_equal(l:current, bufnr())
   2532 
   2533  set tags&
   2534 endfunc
   2535 
   2536 " Allow :pedit because, unlike :edit, it uses a separate window
   2537 func Test_pedit()
   2538  call s:reset_all_buffers()
   2539 
   2540  let l:other = s:make_buffer_pairs()
   2541 
   2542  pedit other
   2543 
   2544  exe "normal \<C-w>w"
   2545  call assert_equal(l:other, bufnr())
   2546 endfunc
   2547 
   2548 " Allow :pbuffer because, unlike :buffer, it uses a separate window
   2549 func Test_pbuffer()
   2550  call s:reset_all_buffers()
   2551 
   2552  let l:other = s:make_buffer_pairs()
   2553 
   2554  exe $'pbuffer {l:other}'
   2555 
   2556  exe "normal \<C-w>w"
   2557  call assert_equal(l:other, bufnr())
   2558 endfunc
   2559 
   2560 " Fail :pop but :pop! is allowed
   2561 func Test_pop()
   2562  call s:reset_all_buffers()
   2563 
   2564  set tags=Xtags
   2565  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2566        \ "thesame\tXfile\t1;\"\td\tfile:",
   2567        \ "thesame\tXfile\t2;\"\td\tfile:",
   2568        \ "thesame\tXfile\t3;\"\td\tfile:",
   2569        \ ],
   2570        \ "Xtags", 'D')
   2571  call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
   2572  call writefile(["thesame one"], "Xother", 'D')
   2573  edit Xother
   2574 
   2575  tag thesame
   2576 
   2577  set winfixbuf
   2578 
   2579  let l:current = bufnr()
   2580 
   2581  call assert_fails("pop", "E1513:")
   2582  call assert_equal(l:current, bufnr())
   2583 
   2584  pop!
   2585  call assert_notequal(l:current, bufnr())
   2586 
   2587  set tags&
   2588 endfunc
   2589 
   2590 " Fail :previous but :previous! is allowed
   2591 func Test_previous()
   2592  call s:reset_all_buffers()
   2593 
   2594  let [l:first, _] = s:make_args_list()
   2595  next!
   2596 
   2597  call assert_fails("previous", "E1513:")
   2598  call assert_notequal(l:first, bufnr())
   2599 
   2600  previous!
   2601  call assert_equal(l:first, bufnr())
   2602 endfunc
   2603 
   2604 " Fail pyxdo if it changes a window with 'winfixbuf' is set
   2605 func Test_pythonx_pyxdo()
   2606  CheckFeature pythonx
   2607  call s:reset_all_buffers()
   2608 
   2609  enew
   2610  file first
   2611  let g:_previous_buffer = bufnr()
   2612 
   2613  enew
   2614  file second
   2615 
   2616  set winfixbuf
   2617 
   2618  pythonx << EOF
   2619 import vim
   2620 
   2621 def test_winfixbuf_Test_pythonx_pyxdo_set_buffer():
   2622    buffer = vim.vars['_previous_buffer']
   2623    vim.current.buffer = vim.buffers[buffer]
   2624 EOF
   2625 
   2626  try
   2627    pyxdo test_winfixbuf_Test_pythonx_pyxdo_set_buffer()
   2628  catch /pynvim\.api\.common\.NvimError: Vim:E1513:/
   2629    let l:caught = 1
   2630  endtry
   2631 
   2632  call assert_equal(1, l:caught)
   2633 
   2634  unlet g:_previous_buffer
   2635 endfunc
   2636 
   2637 " Fail pyxfile if it changes a window with 'winfixbuf' is set
   2638 func Test_pythonx_pyxfile()
   2639  CheckFeature pythonx
   2640  call s:reset_all_buffers()
   2641 
   2642  enew
   2643  file first
   2644  let g:_previous_buffer = bufnr()
   2645 
   2646  enew
   2647  file second
   2648 
   2649  set winfixbuf
   2650 
   2651  call writefile(["import vim",
   2652        \ "buffer = vim.vars['_previous_buffer']",
   2653        \ "vim.current.buffer = vim.buffers[buffer]",
   2654        \ ],
   2655        \ "file.py", 'D')
   2656 
   2657  try
   2658    pyxfile file.py
   2659  catch /pynvim\.api\.common\.NvimError: Vim:E1513:/
   2660    let l:caught = 1
   2661  endtry
   2662 
   2663  call assert_equal(1, l:caught)
   2664 
   2665  unlet g:_previous_buffer
   2666 endfunc
   2667 
   2668 " Fail vim.current.buffer if 'winfixbuf' is set
   2669 func Test_pythonx_vim_current_buffer()
   2670  CheckFeature pythonx
   2671  call s:reset_all_buffers()
   2672 
   2673  enew
   2674  file first
   2675  let g:_previous_buffer = bufnr()
   2676 
   2677  enew
   2678  file second
   2679 
   2680  let l:caught = 0
   2681 
   2682  set winfixbuf
   2683 
   2684  try
   2685    pythonx << EOF
   2686 import vim
   2687 
   2688 buffer = vim.vars["_previous_buffer"]
   2689 vim.current.buffer = vim.buffers[buffer]
   2690 EOF
   2691  catch /pynvim\.api\.common\.NvimError: Vim:E1513:/
   2692    let l:caught = 1
   2693  endtry
   2694 
   2695  call assert_equal(1, l:caught)
   2696  unlet g:_previous_buffer
   2697 endfunc
   2698 
   2699 " Ensure remapping to a disabled action still triggers failures
   2700 func Test_remap_key_fail()
   2701  call s:reset_all_buffers()
   2702 
   2703  enew
   2704  file first
   2705  let l:first = bufnr()
   2706 
   2707  enew
   2708  file current
   2709  let l:current = bufnr()
   2710 
   2711  set winfixbuf
   2712 
   2713  nnoremap g <C-^>
   2714 
   2715  call assert_fails("normal g", "E1513:")
   2716  call assert_equal(l:current, bufnr())
   2717 
   2718  nunmap g
   2719 endfunc
   2720 
   2721 " Ensure remapping a disabled key to something valid does trigger any failures
   2722 func Test_remap_key_pass()
   2723  call s:reset_all_buffers()
   2724 
   2725  enew
   2726  file first
   2727  let l:first = bufnr()
   2728 
   2729  enew
   2730  file current
   2731  let l:current = bufnr()
   2732 
   2733  set winfixbuf
   2734 
   2735  call assert_fails("normal \<C-^>", "E1513:")
   2736  call assert_equal(l:current, bufnr())
   2737 
   2738  " Disallow <C-^> by default but allow it if the command does something else
   2739  nnoremap <C-^> :echo "hello!"
   2740 
   2741  exe "normal \<C-^>"
   2742  call assert_equal(l:current, bufnr())
   2743 
   2744  nunmap <C-^>
   2745 endfunc
   2746 
   2747 " Fail :rewind but :rewind! is allowed
   2748 func Test_rewind()
   2749  call s:reset_all_buffers()
   2750 
   2751  let [l:first, _] = s:make_args_list()
   2752  next!
   2753 
   2754  call assert_fails("rewind", "E1513:")
   2755  call assert_notequal(l:first, bufnr())
   2756 
   2757  rewind!
   2758  call assert_equal(l:first, bufnr())
   2759 endfunc
   2760 
   2761 " Allow :sblast because it opens the buffer in a new, split window
   2762 func Test_sblast()
   2763  call s:reset_all_buffers()
   2764 
   2765  let l:other = s:make_buffer_pairs(1)
   2766  bfirst!
   2767  let l:current = bufnr()
   2768 
   2769  sblast
   2770  call assert_equal(l:other, bufnr())
   2771 endfunc
   2772 
   2773 " Fail :sbprevious but :sbprevious! is allowed
   2774 func Test_sbprevious()
   2775  call s:reset_all_buffers()
   2776 
   2777  let l:other = s:make_buffer_pairs()
   2778  let l:current = bufnr()
   2779 
   2780  sbprevious
   2781  call assert_equal(l:other, bufnr())
   2782 endfunc
   2783 
   2784 " Make sure 'winfixbuf' can be set using 'winfixbuf' or 'wfb'
   2785 func Test_short_option()
   2786  call s:reset_all_buffers()
   2787 
   2788  call s:make_buffer_pairs()
   2789 
   2790  set winfixbuf
   2791  call assert_fails("edit something_else", "E1513:")
   2792 
   2793  set nowinfixbuf
   2794  set wfb
   2795  call assert_fails("edit another_place", "E1513:")
   2796 
   2797  set nowfb
   2798  edit last_place
   2799 endfunc
   2800 
   2801 " Allow :snext because it makes a new window
   2802 func Test_snext()
   2803  call s:reset_all_buffers()
   2804 
   2805  let [l:first, _] = s:make_args_list()
   2806  first!
   2807 
   2808  let l:current_window = win_getid()
   2809 
   2810  snext
   2811  call assert_notequal(l:current_window, win_getid())
   2812  call assert_notequal(l:first, bufnr())
   2813 endfunc
   2814 
   2815 " Ensure the first has 'winfixbuf' and a new split window is 'nowinfixbuf'
   2816 func Test_split_window()
   2817  call s:reset_all_buffers()
   2818 
   2819  split
   2820  exe "normal \<C-w>j"
   2821 
   2822  set winfixbuf
   2823 
   2824  let l:winfix_window_1 = win_getid()
   2825  vsplit
   2826  let l:winfix_window_2 = win_getid()
   2827 
   2828  call assert_equal(1, getwinvar(l:winfix_window_1, "&winfixbuf"))
   2829  call assert_equal(0, getwinvar(l:winfix_window_2, "&winfixbuf"))
   2830 endfunc
   2831 
   2832 " Fail :tNext but :tNext! is allowed
   2833 func Test_tNext()
   2834  call s:reset_all_buffers()
   2835 
   2836  set tags=Xtags
   2837  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2838        \ "thesame\tXfile\t1;\"\td\tfile:",
   2839        \ "thesame\tXfile\t2;\"\td\tfile:",
   2840        \ "thesame\tXfile\t3;\"\td\tfile:",
   2841        \ ],
   2842        \ "Xtags", 'D')
   2843  call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
   2844  call writefile(["thesame one"], "Xother", 'D')
   2845  edit Xother
   2846 
   2847  tag thesame
   2848  exe "normal \<C-^>"
   2849  tnext!
   2850 
   2851  set winfixbuf
   2852 
   2853  let l:current = bufnr()
   2854 
   2855  call assert_fails("tNext", "E1513:")
   2856  call assert_equal(l:current, bufnr())
   2857 
   2858  tNext!
   2859 
   2860  set tags&
   2861 endfunc
   2862 
   2863 " Call :tabdo and choose the next available 'nowinfixbuf' window.
   2864 func Test_tabdo_choose_available_window()
   2865  call s:reset_all_buffers()
   2866 
   2867  let [l:first, _] = s:make_args_list()
   2868 
   2869  " Make a split window that is 'nowinfixbuf' but make it the second-to-last
   2870  " window so that :tabdo will first try the 'winfixbuf' window, pass over it,
   2871  " and prefer the other 'nowinfixbuf' window, instead.
   2872  "
   2873  " +-------------------+
   2874  " |   'nowinfixbuf'   |
   2875  " +-------------------+
   2876  " |    'winfixbuf'    |  <-- Cursor is here
   2877  " +-------------------+
   2878  split
   2879  let l:nowinfixbuf_window = win_getid()
   2880  " Move to the 'winfixbuf' window now
   2881  exe "normal \<C-w>j"
   2882  let l:winfixbuf_window = win_getid()
   2883 
   2884  let l:expected_windows = s:get_windows_count()
   2885  tabdo echo ''
   2886  call assert_equal(l:nowinfixbuf_window, win_getid())
   2887  call assert_equal(l:first, bufnr())
   2888  call assert_equal(l:expected_windows, s:get_windows_count())
   2889 endfunc
   2890 
   2891 " Call :tabdo and create a new split window if all available windows are 'winfixbuf'.
   2892 func Test_tabdo_make_new_window()
   2893  call s:reset_all_buffers()
   2894 
   2895  let [l:first, _] = s:make_buffers_list()
   2896  exe $"buffer! {l:first}"
   2897 
   2898  let l:current = win_getid()
   2899  let l:current_windows = s:get_windows_count()
   2900 
   2901  tabdo echo ''
   2902  call assert_notequal(l:current, win_getid())
   2903  call assert_equal(l:first, bufnr())
   2904  exe "normal \<C-w>j"
   2905  call assert_equal(l:first, bufnr())
   2906  call assert_equal(l:current_windows + 1, s:get_windows_count())
   2907 endfunc
   2908 
   2909 " Fail :tag but :tag! is allowed
   2910 func Test_tag()
   2911  call s:reset_all_buffers()
   2912 
   2913  set tags=Xtags
   2914  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2915        \ "one\tXfile\t1",
   2916        \ "three\tXfile\t3",
   2917        \ "two\tXfile\t2"],
   2918        \ "Xtags", 'D')
   2919  call writefile(["one", "two", "three"], "Xfile", 'D')
   2920  call writefile(["one"], "Xother", 'D')
   2921  edit Xother
   2922 
   2923  set winfixbuf
   2924 
   2925  let l:current = bufnr()
   2926 
   2927  call assert_fails("tag one", "E1513:")
   2928  call assert_equal(l:current, bufnr())
   2929 
   2930  tag! one
   2931  call assert_notequal(l:current, bufnr())
   2932 
   2933  set tags&
   2934 endfunc
   2935 
   2936 
   2937 " Fail :tfirst but :tfirst! is allowed
   2938 func Test_tfirst()
   2939  call s:reset_all_buffers()
   2940 
   2941  set tags=Xtags
   2942  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2943        \ "one\tXfile\t1",
   2944        \ "three\tXfile\t3",
   2945        \ "two\tXfile\t2"],
   2946        \ "Xtags", 'D')
   2947  call writefile(["one", "two", "three"], "Xfile", 'D')
   2948  call writefile(["one"], "Xother", 'D')
   2949  tag one
   2950  edit Xother
   2951 
   2952  set winfixbuf
   2953 
   2954  let l:current = bufnr()
   2955 
   2956  call assert_fails("tfirst", "E1513:")
   2957  call assert_equal(l:current, bufnr())
   2958 
   2959  tfirst!
   2960  call assert_notequal(l:current, bufnr())
   2961 
   2962  set tags&
   2963 endfunc
   2964 
   2965 " Fail :tjump but :tjump! is allowed
   2966 func Test_tjump()
   2967  call s:reset_all_buffers()
   2968 
   2969  set tags=Xtags
   2970  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2971        \ "one\tXfile\t1",
   2972        \ "three\tXfile\t3",
   2973        \ "two\tXfile\t2"],
   2974        \ "Xtags", 'D')
   2975  call writefile(["one", "two", "three"], "Xfile", 'D')
   2976  call writefile(["one"], "Xother", 'D')
   2977  edit Xother
   2978 
   2979  set winfixbuf
   2980 
   2981  let l:current = bufnr()
   2982 
   2983  call assert_fails("tjump one", "E1513:")
   2984  call assert_equal(l:current, bufnr())
   2985 
   2986  tjump! one
   2987  call assert_notequal(l:current, bufnr())
   2988 
   2989  set tags&
   2990 endfunc
   2991 
   2992 " Fail :tlast but :tlast! is allowed
   2993 func Test_tlast()
   2994  call s:reset_all_buffers()
   2995 
   2996  set tags=Xtags
   2997  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   2998        \ "one\tXfile\t1",
   2999        \ "three\tXfile\t3",
   3000        \ "two\tXfile\t2"],
   3001        \ "Xtags", 'D')
   3002  call writefile(["one", "two", "three"], "Xfile", 'D')
   3003  edit Xfile
   3004  tjump one
   3005  edit Xfile
   3006 
   3007  set winfixbuf
   3008 
   3009  let l:current = bufnr()
   3010 
   3011  call assert_fails("tlast", "E1513:")
   3012  call assert_equal(l:current, bufnr())
   3013 
   3014  tlast!
   3015  call assert_equal(l:current, bufnr())
   3016 
   3017  set tags&
   3018 endfunc
   3019 
   3020 " Fail :tnext but :tnext! is allowed
   3021 func Test_tnext()
   3022  call s:reset_all_buffers()
   3023 
   3024  set tags=Xtags
   3025  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   3026        \ "thesame\tXfile\t1;\"\td\tfile:",
   3027        \ "thesame\tXfile\t2;\"\td\tfile:",
   3028        \ "thesame\tXfile\t3;\"\td\tfile:",
   3029        \ ],
   3030        \ "Xtags", 'D')
   3031  call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
   3032  call writefile(["thesame one"], "Xother", 'D')
   3033  edit Xother
   3034 
   3035  tag thesame
   3036  exe "normal \<C-^>"
   3037 
   3038  set winfixbuf
   3039 
   3040  let l:current = bufnr()
   3041 
   3042  call assert_fails("tnext", "E1513:")
   3043  call assert_equal(l:current, bufnr())
   3044 
   3045  tnext!
   3046  call assert_notequal(l:current, bufnr())
   3047 
   3048  set tags&
   3049 endfunc
   3050 
   3051 " Fail :tprevious but :tprevious! is allowed
   3052 func Test_tprevious()
   3053  call s:reset_all_buffers()
   3054 
   3055  set tags=Xtags
   3056  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
   3057        \ "thesame\tXfile\t1;\"\td\tfile:",
   3058        \ "thesame\tXfile\t2;\"\td\tfile:",
   3059        \ "thesame\tXfile\t3;\"\td\tfile:",
   3060        \ ],
   3061        \ "Xtags", 'D')
   3062  call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
   3063  call writefile(["thesame one"], "Xother", 'D')
   3064  edit Xother
   3065 
   3066  tag thesame
   3067  exe "normal \<C-^>"
   3068  tnext!
   3069 
   3070  set winfixbuf
   3071 
   3072  let l:current = bufnr()
   3073 
   3074  call assert_fails("tprevious", "E1513:")
   3075  call assert_equal(l:current, bufnr())
   3076 
   3077  tprevious!
   3078 
   3079  set tags&
   3080 endfunc
   3081 
   3082 " Fail :view but :view! is allowed
   3083 func Test_view()
   3084  call s:reset_all_buffers()
   3085 
   3086  let l:other = s:make_buffer_pairs()
   3087  let l:current = bufnr()
   3088 
   3089  call assert_fails("view other", "E1513:")
   3090  call assert_equal(l:current, bufnr())
   3091 
   3092  view! other
   3093  call assert_equal(l:other, bufnr())
   3094 endfunc
   3095 
   3096 " Fail :visual but :visual! is allowed
   3097 func Test_visual()
   3098  call s:reset_all_buffers()
   3099 
   3100  let l:other = s:make_buffer_pairs()
   3101  let l:current = bufnr()
   3102 
   3103  call assert_fails("visual other", "E1513:")
   3104  call assert_equal(l:current, bufnr())
   3105 
   3106  visual! other
   3107  call assert_equal(l:other, bufnr())
   3108 endfunc
   3109 
   3110 " Fail :vimgrep but :vimgrep! is allowed
   3111 func Test_vimgrep()
   3112  CheckFeature quickfix
   3113  call s:reset_all_buffers()
   3114 
   3115  edit first.unittest
   3116  call append(0, ["some-search-term"])
   3117  write
   3118 
   3119  edit winfix.unittest
   3120  call append(0, ["some-search-term"])
   3121  write
   3122  let l:current = bufnr()
   3123 
   3124  set winfixbuf
   3125 
   3126  edit! last.unittest
   3127  call append(0, ["some-search-term"])
   3128  write
   3129  let l:last = bufnr()
   3130 
   3131  buffer! winfix.unittest
   3132 
   3133  call assert_fails("vimgrep /some-search-term/ *.unittest", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
   3134  call assert_equal(l:current, bufnr())
   3135 
   3136  " Don't error and also do swap to the first match because ! was included
   3137  vimgrep! /some-search-term/ *.unittest
   3138  call assert_notequal(l:current, bufnr())
   3139 
   3140  call delete("first.unittest")
   3141  call delete("winfix.unittest")
   3142  call delete("last.unittest")
   3143 endfunc
   3144 
   3145 " Fail :vimgrepadd but ::vimgrepadd! is allowed
   3146 func Test_vimgrepadd()
   3147  CheckFeature quickfix
   3148  call s:reset_all_buffers()
   3149 
   3150  edit first.unittest
   3151  call append(0, ["some-search-term"])
   3152  write
   3153 
   3154  edit winfix.unittest
   3155  call append(0, ["some-search-term"])
   3156  write
   3157  let l:current = bufnr()
   3158 
   3159  set winfixbuf
   3160 
   3161  edit! last.unittest
   3162  call append(0, ["some-search-term"])
   3163  write
   3164  let l:last = bufnr()
   3165 
   3166  buffer! winfix.unittest
   3167 
   3168  call assert_fails("vimgrepadd /some-search-term/ *.unittest", "E1513: Cannot switch buffer. 'winfixbuf' is enabled")
   3169  call assert_equal(l:current, bufnr())
   3170 
   3171  vimgrepadd! /some-search-term/ *.unittest
   3172  call assert_notequal(l:current, bufnr())
   3173  call delete("first.unittest")
   3174  call delete("winfix.unittest")
   3175  call delete("last.unittest")
   3176 endfunc
   3177 
   3178 " Fail :wNext but :wNext! is allowed
   3179 func Test_wNext()
   3180  call s:reset_all_buffers()
   3181 
   3182  let [l:first, _] = s:make_args_list()
   3183  next!
   3184 
   3185  call assert_fails("wNext", "E1513:")
   3186  call assert_notequal(l:first, bufnr())
   3187 
   3188  wNext!
   3189  call assert_equal(l:first, bufnr())
   3190 
   3191  call delete("first")
   3192  call delete("middle")
   3193  call delete("last")
   3194 endfunc
   3195 
   3196 " Allow :windo unless `:windo foo` would change a 'winfixbuf' window's buffer
   3197 func Test_windo()
   3198  call s:reset_all_buffers()
   3199 
   3200  let l:current_window = win_getid()
   3201  let l:current_buffer = bufnr()
   3202  split
   3203  enew
   3204  file some_other_buffer
   3205 
   3206  set winfixbuf
   3207 
   3208  let l:current = win_getid()
   3209 
   3210  windo echo ''
   3211  call assert_equal(l:current_window, win_getid())
   3212 
   3213  call assert_fails($'exe "windo buffer {l:current_buffer}"', "E1513:")
   3214  call assert_equal(l:current_window, win_getid())
   3215 
   3216  exe $"windo buffer! {l:current_buffer}"
   3217  call assert_equal(l:current_window, win_getid())
   3218 endfunc
   3219 
   3220 " Fail :wnext but :wnext! is allowed
   3221 func Test_wnext()
   3222  call s:reset_all_buffers()
   3223 
   3224  let [_, l:last] = s:make_args_list()
   3225  next!
   3226 
   3227  call assert_fails("wnext", "E1513:")
   3228  call assert_notequal(l:last, bufnr())
   3229 
   3230  wnext!
   3231  call assert_equal(l:last, bufnr())
   3232 
   3233  call delete("first")
   3234  call delete("middle")
   3235  call delete("last")
   3236 endfunc
   3237 
   3238 " Fail :wprevious but :wprevious! is allowed
   3239 func Test_wprevious()
   3240  call s:reset_all_buffers()
   3241 
   3242  let [l:first, _] = s:make_args_list()
   3243  next!
   3244 
   3245  call assert_fails("wprevious", "E1513:")
   3246  call assert_notequal(l:first, bufnr())
   3247 
   3248  wprevious!
   3249  call assert_equal(l:first, bufnr())
   3250 
   3251  call delete("first")
   3252  call delete("middle")
   3253  call delete("last")
   3254 endfunc
   3255 
   3256 func Test_quickfix_switchbuf_invalid_prevwin()
   3257  call s:reset_all_buffers()
   3258 
   3259  call s:make_simple_quickfix()
   3260  call assert_equal(1, getqflist(#{idx: 0}).idx)
   3261 
   3262  set switchbuf=uselast
   3263  split
   3264  copen
   3265  exe winnr('#') 'quit'
   3266  call assert_equal(2, winnr('$'))
   3267 
   3268  cnext  " Would've triggered a null pointer member access
   3269  call assert_equal(2, getqflist(#{idx: 0}).idx)
   3270 
   3271  set switchbuf&
   3272 endfunc
   3273 
   3274 func Test_listdo_goto_prevwin()
   3275  call s:reset_all_buffers()
   3276  call s:make_buffers_list()
   3277 
   3278  new
   3279  call assert_equal(0, &winfixbuf)
   3280  wincmd p
   3281  call assert_equal(1, &winfixbuf)
   3282  call assert_notequal(bufnr(), bufnr('#'))
   3283 
   3284  augroup ListDoGotoPrevwin
   3285    au!
   3286    au BufLeave * let s:triggered = 1
   3287          \| call assert_equal(bufnr(), winbufnr(winnr()))
   3288  augroup END
   3289  " Should correctly switch to the window without 'winfixbuf', and curbuf should
   3290  " be consistent with curwin->w_buffer for autocommands.
   3291  bufdo "
   3292  call assert_equal(0, &winfixbuf)
   3293  call assert_equal(1, s:triggered)
   3294  unlet! s:triggered
   3295  au! ListDoGotoPrevwin
   3296 
   3297  set winfixbuf
   3298  wincmd p
   3299  call assert_equal(2, winnr('$'))
   3300  " Both curwin and prevwin have 'winfixbuf' set, so should split a new window
   3301  " without it set.
   3302  bufdo "
   3303  call assert_equal(0, &winfixbuf)
   3304  call assert_equal(3, winnr('$'))
   3305 
   3306  quit
   3307  call assert_equal(2, winnr('$'))
   3308  call assert_equal(1, &winfixbuf)
   3309  augroup ListDoGotoPrevwin
   3310    au!
   3311    au WinEnter * ++once set winfixbuf
   3312  augroup END
   3313  " Same as before, but naughty autocommands set 'winfixbuf' for the new window.
   3314  " :bufdo should give up in this case.
   3315  call assert_fails('bufdo "', 'E1513:')
   3316 
   3317  au! ListDoGotoPrevwin
   3318  augroup! ListDoGotoPrevwin
   3319 endfunc
   3320 
   3321 func Test_quickfix_changed_split_failed()
   3322  call s:reset_all_buffers()
   3323 
   3324  call s:make_simple_quickfix()
   3325  call assert_equal(1, winnr('$'))
   3326 
   3327  " Quickfix code will open a split in an attempt to get a 'nowinfixbuf' window
   3328  " to switch buffers in.  Interfere with things by setting 'winfixbuf' in it.
   3329  augroup QfChanged
   3330    au!
   3331    au WinEnter * ++once call assert_equal(2, winnr('$'))
   3332          \| set winfixbuf | call setqflist([], 'f')
   3333  augroup END
   3334  call assert_fails('cnext', ['E1513:', 'E925:'])
   3335  " Check that the split was automatically closed.
   3336  call assert_equal(1, winnr('$'))
   3337 
   3338  au! QfChanged
   3339  augroup! QfChanged
   3340 endfunc
   3341 
   3342 func Test_bufdo_cnext_splitwin_fails()
   3343  call s:reset_all_buffers()
   3344  call s:make_simple_quickfix()
   3345  call assert_equal(1, getqflist(#{idx: 0}).idx)
   3346  " Make sure there is not enough room to
   3347  " split the winfixedbuf window
   3348  let &winheight=&lines
   3349  let &winminheight=&lines-2
   3350  " Still want E1513, or it may not be clear why a split was attempted and why
   3351  " it failing caused the commands to abort.
   3352  call assert_fails(':bufdo echo 1', ['E36:', 'E1513:'])
   3353  call assert_fails(':cnext', ['E36:', 'E1513:'])
   3354  " Ensure the entry didn't change.
   3355  call assert_equal(1, getqflist(#{idx: 0}).idx)
   3356  set winminheight&vim winheight&vim
   3357 endfunc
   3358 
   3359 " Test that exiting with 'winfixbuf' and EXITFREE doesn't cause an error.
   3360 func Test_exitfree_no_error()
   3361  let lines =<< trim END
   3362    set winfixbuf
   3363    qall!
   3364  END
   3365  call writefile(lines, 'Xwfb_exitfree', 'D')
   3366  call assert_notmatch('E1513:',
   3367        "\ system(GetVimCommandClean() .. ' --not-a-term -X -S Xwfb_exitfree'))
   3368        \ system(GetVimCommandClean() .. ' -X -S Xwfb_exitfree'))
   3369 endfunc
   3370 
   3371 " vim: shiftwidth=2 sts=2 expandtab