blob: 2d4eaf675eb08fb05a8e4b70ba8d09444e78e48a [file] [log] [blame]
Colin Kennedy21570352024-03-03 16:16:47 +01001" Test 'winfixbuf'
2
3source check.vim
zeertzjq620e8522024-03-28 10:11:57 +01004source shared.vim
Colin Kennedy21570352024-03-03 16:16:47 +01005
6" Find the number of open windows in the current tab
7func s:get_windows_count()
8 return tabpagewinnr(tabpagenr(), '$')
9endfunc
10
11" Create some unnamed buffers.
12func 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]
28endfunc
29
30" Create some unnamed buffers and add them to an args list
31func 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]
37endfunc
38
39" Create two buffers and then set the window to 'winfixbuf'
40func 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
66endfunc
67
68" Create 3 quick buffers and set the window to 'winfixbuf'
69func 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 execute ":buffer! " . l:second
81
82 return [l:first, l:second, l:third]
83endfunc
84
85" Create a location list with at least 2 entries + a 'winfixbuf' window.
86func 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]
131endfunc
132
133" Create a quickfix with at least 2 entries that are in the current 'winfixbuf' window.
134func 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]
178endfunc
179
180" Create a quickfix with at least 2 entries that are in the current 'winfixbuf' window.
181func s:make_quickfix_windows()
182 let [l:current, _] = s:make_simple_quickfix()
183 execute "buffer! " . l:current
184
185 split
186 let l:first_window = win_getid()
187 execute "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]
195endfunc
196
197" Revert all changes that occurred in any past test
198func s:reset_all_buffers()
199 %bwipeout!
200 set nowinfixbuf
201
202 call setqflist([])
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +0200203 call setloclist(0, [], 'f')
Colin Kennedy21570352024-03-03 16:16:47 +0100204
205 delmarks A-Z0-9
206endfunc
207
208" Find and set the first quickfix entry that points to `buffer`
209func 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 execute 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.'
222endfunc
223
224" Fail to call :Next on a 'winfixbuf' window unless :Next! is used.
225func 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())
236endfunc
237
238" Call :argdo and choose the next available 'nowinfixbuf' window.
239func 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 execute "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())
264endfunc
265
266" Call :argdo and create a new split window if all available windows are 'winfixbuf'.
267func 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 execute "normal \<C-w>j"
278 call assert_equal(l:first, bufnr())
279 call assert_equal(l:current_windows + 1, s:get_windows_count())
280endfunc
281
282" Fail :argedit but :argedit! is allowed
283func 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())
307endfunc
308
309" Fail :arglocal but :arglocal! is allowed
310func 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 execute "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())
323endfunc
324
325" Fail :argglobal but :argglobal! is allowed
326func 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())
337endfunc
338
339" Fail :args but :args! is allowed
340func 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())
351endfunc
352
353" Fail :bNext but :bNext! is allowed
354func 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())
365endfunc
366
367" Allow :badd because it doesn't actually change the current window's buffer
368func 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())
376endfunc
377
378" Allow :balt because it doesn't actually change the current window's buffer
379func 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())
387endfunc
388
389" Fail :bfirst but :bfirst! is allowed
390func 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())
401endfunc
402
403" Fail :blast but :blast! is allowed
404func 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())
416endfunc
417
418" Fail :bmodified but :bmodified! is allowed
419func Test_bmodified()
420 call s:reset_all_buffers()
421
422 let l:other = s:make_buffer_pairs()
423 let l:current = bufnr()
424
425 execute "buffer! " . l:other
426 set modified
427 execute "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())
434endfunc
435
436" Fail :bnext but :bnext! is allowed
437func 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())
448endfunc
449
450" Fail :bprevious but :bprevious! is allowed
451func 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())
462endfunc
463
464" Fail :brewind but :brewind! is allowed
465func 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())
476endfunc
477
478" Fail :browse edit but :browse edit! is allowed
479func Test_browse_edit_fail()
Sean Dewar769eb2d2024-03-07 21:37:50 +0100480 " A GUI dialog may stall the test.
481 CheckNotGui
482
Colin Kennedy21570352024-03-03 16:16:47 +0100483 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
Sean Dewar769eb2d2024-03-07 21:37:50 +0100491 try
492 browse edit! other
493 call assert_equal(l:other, bufnr())
Christian Brabandt0a32b882024-03-13 20:59:27 +0100494 catch /^Vim\%((\a\+)\)\=:E338:/
Sean Dewar769eb2d2024-03-07 21:37:50 +0100495 " 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
Colin Kennedy21570352024-03-03 16:16:47 +0100498endfunc
499
500" Allow :browse w because it doesn't change the buffer in the current file
501func Test_browse_edit_pass()
Sean Dewar769eb2d2024-03-07 21:37:50 +0100502 " A GUI dialog may stall the test.
503 CheckNotGui
504
Colin Kennedy21570352024-03-03 16:16:47 +0100505 call s:reset_all_buffers()
506
507 let l:other = s:make_buffer_pairs()
508 let l:current = bufnr()
509
Sean Dewar769eb2d2024-03-07 21:37:50 +0100510 try
511 browse write other
Christian Brabandt0a32b882024-03-13 20:59:27 +0100512 catch /^Vim\%((\a\+)\)\=:E338:/
Sean Dewar769eb2d2024-03-07 21:37:50 +0100513 " 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
Colin Kennedy21570352024-03-03 16:16:47 +0100516
517 call delete("other")
518endfunc
519
520" Call :bufdo and choose the next available 'nowinfixbuf' window.
521func 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 execute "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())
550endfunc
551
552" Call :bufdo and create a new split window if all available windows are 'winfixbuf'.
553func Test_bufdo_make_new_window()
554 call s:reset_all_buffers()
555
556 let [l:first, l:last] = s:make_buffers_list()
557 execute "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 execute "normal \<C-w>j"
565 call assert_equal(l:first, bufnr())
566 call assert_equal(l:current_windows + 1, s:get_windows_count())
567endfunc
568
569" Fail :buffer but :buffer! is allowed
570func 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 execute "buffer! " . l:other
580 call assert_equal(l:other, bufnr())
581endfunc
582
583" Allow :buffer on a 'winfixbuf' window if there is no change in buffer
584func Test_buffer_same_buffer()
585 call s:reset_all_buffers()
586
587 call s:make_buffer_pairs()
588 let l:current = bufnr()
589
590 execute "buffer " . l:current
591 call assert_equal(l:current, bufnr())
592
593 execute "buffer! " . l:current
594 call assert_equal(l:current, bufnr())
595endfunc
596
597" Allow :cNext but the 'nowinfixbuf' window is selected, instead
598func 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())
614endfunc
615
616" Allow :cNfile but the 'nowinfixbuf' window is selected, instead
617func 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())
634endfunc
635
636" Allow :caddexpr because it doesn't change the current buffer
637func Test_caddexpr()
638 CheckFeature quickfix
639 call s:reset_all_buffers()
640
641 let l:file_path = tempname()
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +0200642 call writefile(["Error - bad-thing-found"], l:file_path, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +0100643 execute "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 execute "buffer! " . l:file_buffer
655
656 execute 'caddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")'
657 call assert_equal(l:current, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +0100658endfunc
659
660" Fail :cbuffer but :cbuffer! is allowed
661func Test_cbuffer()
662 CheckFeature quickfix
663 call s:reset_all_buffers()
664
665 let l:file_path = tempname()
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +0200666 call writefile(["first.unittest:1:Error - bad-thing-found"], l:file_path, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +0100667 execute "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 execute "buffer! " . l:file_buffer
679
680 call assert_fails("cbuffer " . l:file_buffer)
681 call assert_equal(l:current, bufnr())
682
683 execute "cbuffer! " . l:file_buffer
684 call assert_equal("first.unittest", expand("%:t"))
Colin Kennedy21570352024-03-03 16:16:47 +0100685endfunc
686
687" Allow :cc but the 'nowinfixbuf' window is selected, instead
688func 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())
710endfunc
711
712" Call :cdo and choose the next available 'nowinfixbuf' window.
713func 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 execute "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 execute "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 execute "normal \<C-w>j"
741 call assert_equal(l:current, bufnr())
742 call assert_equal(l:expected_windows, s:get_windows_count())
743endfunc
744
745" Call :cdo and create a new split window if all available windows are 'winfixbuf'.
746func 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 execute "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 execute "normal \<C-w>j"
760 call assert_equal(l:current_buffer, bufnr())
761 call assert_equal(l:current_windows + 1, s:get_windows_count())
762endfunc
763
764" Fail :cexpr but :cexpr! is allowed
765func Test_cexpr()
766 CheckFeature quickfix
767 call s:reset_all_buffers()
768
769 let l:file = tempname()
770 let l:entry = '["' . l:file . ':1:bar"]'
771 let l:current = bufnr()
772
773 set winfixbuf
774
775 call assert_fails("cexpr " . l:entry)
776 call assert_equal(l:current, bufnr())
777
778 execute "cexpr! " . l:entry
779 call assert_equal(fnamemodify(l:file, ":t"), expand("%:t"))
780endfunc
781
782" Call :cfdo and choose the next available 'nowinfixbuf' window.
783func 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 execute "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 execute "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 execute "normal \<C-w>j"
811 call assert_equal(l:current, bufnr())
812 call assert_equal(l:expected_windows, s:get_windows_count())
813endfunc
814
815" Call :cfdo and create a new split window if all available windows are 'winfixbuf'.
816func 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 execute "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 execute "normal \<C-w>j"
830 call assert_equal(l:current_buffer, bufnr())
831 call assert_equal(l:current_windows + 1, s:get_windows_count())
832endfunc
833
834" Fail :cfile but :cfile! is allowed
835func 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 l:first = bufnr()
843
844 edit! second.unittest
845 call append(0, ["some-search-term"])
846 write
847
848 let l:file = tempname()
849 call writefile(["first.unittest:1:Error - bad-thing-found was detected"], l:file)
850
851 let l:current = bufnr()
852
853 set winfixbuf
854
855 call assert_fails(":cfile " . l:file)
856 call assert_equal(l:current, bufnr())
857
858 execute ":cfile! " . l:file
859 call assert_equal(l:first, bufnr())
860
861 call delete(l:file)
862 call delete("first.unittest")
863 call delete("second.unittest")
864endfunc
865
866" Allow :cfirst but the 'nowinfixbuf' window is selected, instead
867func 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())
883endfunc
884
885" Allow :clast but the 'nowinfixbuf' window is selected, instead
886func 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())
902endfunc
903
904" Allow :cnext but the 'nowinfixbuf' window is selected, instead
905" Make sure no new windows are created and previous windows are reused
906func 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())
927endfunc
928
929" Make sure :cnext creates a split window if no previous window exists
930func Test_cnext_no_previous_window()
931 CheckFeature quickfix
932 call s:reset_all_buffers()
933
934 let [l:current, _] = s:make_simple_quickfix()
935 execute "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())
943endfunc
944
945" Allow :cnext and create a 'nowinfixbuf' window if none exists
946func 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())
963endfunc
964
965" Allow :cprevious but the 'nowinfixbuf' window is selected, instead
966func 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())
982endfunc
983
984" Allow :cnfile but the 'nowinfixbuf' window is selected, instead
985func 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())
1002endfunc
1003
1004" Allow :cpfile but the 'nowinfixbuf' window is selected, instead
1005func 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())
1022endfunc
1023
1024" Allow :crewind but the 'nowinfixbuf' window is selected, instead
1025func 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())
1042endfunc
1043
1044" Allow <C-w>f because it opens in a new split
1045func 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 execute "normal \<C-w>f"
1062
1063 call assert_equal(l:current_windows + 1, s:get_windows_count())
1064
1065 call delete(l:file_name)
1066endfunc
1067
1068" Fail :djump but :djump! is allowed
1069func 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)
1092endfunc
1093
1094" Fail :drop but :drop! is allowed
1095func 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())
1106endfunc
1107
1108" Fail :edit but :edit! is allowed
1109func 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())
1120endfunc
1121
Colin Kennedy65e580b2024-03-26 18:29:30 +01001122" 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)
1132func 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 execute "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 execute "cd " . l:directory_on_disk2
1148 execute "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)
1159endfunc
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)
1171func 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 execute "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 execute "cd " . l:directory_on_disk2
1187 execute "edit " l:name
1188 execute "cd " . l:directory_on_disk1
1189 execute "edit " l:file_on_disk
1190 execute "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)
1201endfunc
1202
1203" Fail to call `:e first` if called from a starting, in-memory buffer
1204func 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())
1217endfunc
1218
1219" Allow reloading a buffer using :e
1220func 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())
1230endfunc
1231
1232" Allow :e selecting the current buffer
1233func Test_edit_same_buffer_in_memory()
1234 call s:reset_all_buffers()
1235
Christian Brabandt79b28672024-03-27 10:44:14 +01001236 let current = bufnr()
Colin Kennedy65e580b2024-03-26 18:29:30 +01001237 file same_buffer
1238
Christian Brabandt79b28672024-03-27 10:44:14 +01001239 call assert_equal(current, bufnr())
Colin Kennedy65e580b2024-03-26 18:29:30 +01001240 set winfixbuf
1241 edit same_buffer
Christian Brabandt79b28672024-03-27 10:44:14 +01001242 call assert_equal(current, bufnr())
1243 set nowinfixbuf
Colin Kennedy65e580b2024-03-26 18:29:30 +01001244endfunc
1245
1246" Allow :e selecting the current buffer as a full path
1247func Test_edit_same_buffer_on_disk_absolute_path()
1248 call s:reset_all_buffers()
1249
Christian Brabandt79b28672024-03-27 10:44:14 +01001250 let file = tempname()
Sean Dewaraed65542024-03-28 09:48:34 +01001251 " file must exist for expansion of 8.3 paths to succeed
1252 call writefile([], file, 'D')
1253 let file = fnamemodify(file, ':p')
Christian Brabandt79b28672024-03-27 10:44:14 +01001254 let current = bufnr()
1255 execute "edit " . file
Colin Kennedy65e580b2024-03-26 18:29:30 +01001256 write!
1257
Christian Brabandt79b28672024-03-27 10:44:14 +01001258 call assert_equal(current, bufnr())
Colin Kennedy65e580b2024-03-26 18:29:30 +01001259 set winfixbuf
Christian Brabandt79b28672024-03-27 10:44:14 +01001260 execute "edit " file
1261 call assert_equal(current, bufnr())
Colin Kennedy65e580b2024-03-26 18:29:30 +01001262
Christian Brabandt79b28672024-03-27 10:44:14 +01001263 set nowinfixbuf
Colin Kennedy65e580b2024-03-26 18:29:30 +01001264endfunc
1265
Colin Kennedy21570352024-03-03 16:16:47 +01001266" Fail :enew but :enew! is allowed
1267func 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())
1279endfunc
1280
1281" Fail :ex but :ex! is allowed
1282func 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())
1293endfunc
1294
1295" Fail :find but :find! is allowed
1296func Test_find()
1297 call s:reset_all_buffers()
1298
1299 let l:current = bufnr()
1300 let l:file = tempname()
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001301 call writefile([], l:file, 'D')
Sean Dewar769eb2d2024-03-07 21:37:50 +01001302 let l:file = fnamemodify(l:file, ':p') " In case it's Windows 8.3-style.
Colin Kennedy21570352024-03-03 16:16:47 +01001303 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 execute "set path=" . l:directory
1308
1309 set winfixbuf
1310
1311 call assert_fails("execute 'find " . l:name . "'", "E1513:")
1312 call assert_equal(l:current, bufnr())
1313
1314 execute "find! " . l:name
1315 call assert_equal(l:file, expand("%:p"))
1316
1317 execute "set path=" . l:original_path
Colin Kennedy21570352024-03-03 16:16:47 +01001318endfunc
1319
1320" Fail :first but :first! is allowed
1321func 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())
1332endfunc
1333
1334" Fail :grep but :grep! is allowed
1335func 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 execute "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")
1368endfunc
1369
1370" Fail :ijump but :ijump! is allowed
1371func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001378 \ "main.c", 'D')
1379 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01001380 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&
Colin Kennedy21570352024-03-03 16:16:47 +01001401endfunc
1402
1403" Fail :lNext but :lNext! is allowed
1404func Test_lNext()
1405 CheckFeature quickfix
1406 call s:reset_all_buffers()
1407
1408 let [l:first, l:middle, _] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001409 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001410
Sean Dewar4bb505e2024-03-05 20:39:07 +01001411 lnext!
1412 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001413 call assert_equal(l:middle, bufnr())
1414
Sean Dewar4bb505e2024-03-05 20:39:07 +01001415 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())
Colin Kennedy21570352024-03-03 16:16:47 +01001423
1424 lNext!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001425 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)
Colin Kennedy21570352024-03-03 16:16:47 +01001430 call assert_equal(l:first, bufnr())
1431endfunc
1432
1433" Fail :lNfile but :lNfile! is allowed
1434func Test_lNfile()
1435 CheckFeature quickfix
1436 call s:reset_all_buffers()
1437
1438 let [l:first, l:current, _] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001439 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001440
Sean Dewar4bb505e2024-03-05 20:39:07 +01001441 lnext!
1442 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001443 call assert_equal(l:current, bufnr())
1444
Sean Dewar4bb505e2024-03-05 20:39:07 +01001445 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())
Colin Kennedy21570352024-03-03 16:16:47 +01001453
1454 lNfile!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001455 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001456 call assert_equal(l:first, bufnr())
1457endfunc
1458
1459" Allow :laddexpr because it doesn't change the current buffer
1460func Test_laddexpr()
1461 CheckFeature quickfix
1462 call s:reset_all_buffers()
1463
1464 let l:file_path = tempname()
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001465 call writefile(["Error - bad-thing-found"], l:file_path, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01001466 execute "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 execute "buffer! " . l:file_buffer
1478
1479 execute 'laddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")'
1480 call assert_equal(l:current, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01001481endfunc
1482
1483" Fail :last but :last! is allowed
1484func 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())
1495endfunc
1496
1497" Fail :lbuffer but :lbuffer! is allowed
1498func Test_lbuffer()
1499 CheckFeature quickfix
1500 call s:reset_all_buffers()
1501
1502 let l:file_path = tempname()
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001503 call writefile(["first.unittest:1:Error - bad-thing-found"], l:file_path, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01001504 execute "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 execute "buffer! " . l:file_buffer
1516
1517 call assert_fails("lbuffer " . l:file_buffer)
1518 call assert_equal(l:current, bufnr())
1519
1520 execute "lbuffer! " . l:file_buffer
1521 call assert_equal("first.unittest", expand("%:t"))
Colin Kennedy21570352024-03-03 16:16:47 +01001522endfunc
1523
1524" Fail :ldo but :ldo! is allowed
1525func 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('execute "ldo buffer ' . l:first . '"', "E1513:")
1533 call assert_equal(l:middle, bufnr())
1534 execute "ldo! buffer " . l:first
1535 call assert_notequal(l:last, bufnr())
1536endfunc
1537
1538" Fail :lfdo but :lfdo! is allowed
1539func Test_lexpr()
1540 CheckFeature quickfix
1541 call s:reset_all_buffers()
1542
1543 let l:file = tempname()
1544 let l:entry = '["' . l:file . ':1:bar"]'
1545 let l:current = bufnr()
1546
1547 set winfixbuf
1548
1549 call assert_fails("lexpr " . l:entry)
1550 call assert_equal(l:current, bufnr())
1551
1552 execute "lexpr! " . l:entry
1553 call assert_equal(fnamemodify(l:file, ":t"), expand("%:t"))
1554endfunc
1555
1556" Fail :lfdo but :lfdo! is allowed
1557func Test_lfdo()
1558 CheckFeature quickfix
1559 call s:reset_all_buffers()
1560
1561 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1562 lnext!
1563
1564 call assert_fails('execute "lfdo buffer ' . l:first . '"', "E1513:")
1565 call assert_equal(l:middle, bufnr())
1566 execute "lfdo! buffer " . l:first
1567 call assert_notequal(l:last, bufnr())
1568endfunc
1569
1570" Fail :lfile but :lfile! is allowed
1571func 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()
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001585 call writefile(["first.unittest:1:Error - bad-thing-found was detected"], l:file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01001586
1587 let l:current = bufnr()
1588
1589 set winfixbuf
1590
1591 call assert_fails(":lfile " . l:file)
1592 call assert_equal(l:current, bufnr())
1593
1594 execute ":lfile! " . l:file
1595 call assert_equal(l:first, bufnr())
1596
Colin Kennedy21570352024-03-03 16:16:47 +01001597 call delete("first.unittest")
1598 call delete("second.unittest")
1599endfunc
1600
1601" Fail :ll but :ll! is allowed
1602func 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 execute "normal \<C-w>j"
1610 normal j
1611
1612 call assert_fails(".ll", "E1513:")
1613 execute "normal \<C-w>k"
1614 call assert_equal(l:first, bufnr())
1615 execute "normal \<C-w>j"
1616 .ll!
1617 execute "normal \<C-w>k"
1618 call assert_equal(l:middle, bufnr())
1619endfunc
1620
1621" Fail :llast but :llast! is allowed
1622func 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())
1634endfunc
1635
1636" Fail :lnext but :lnext! is allowed
1637func 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())
1649endfunc
1650
1651" Fail :lnfile but :lnfile! is allowed
1652func Test_lnfile()
1653 CheckFeature quickfix
1654 call s:reset_all_buffers()
1655
1656 let [_, l:current, l:last] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001657 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001658
Sean Dewar4bb505e2024-03-05 20:39:07 +01001659 lnext!
1660 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001661 call assert_equal(l:current, bufnr())
1662
Sean Dewar4bb505e2024-03-05 20:39:07 +01001663 call assert_fails("lnfile", "E1513:")
Sean Dewar769eb2d2024-03-07 21:37:50 +01001664 " Ensure the entry didn't change.
Sean Dewar4bb505e2024-03-05 20:39:07 +01001665 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
1666 call assert_equal(l:current, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01001667
1668 lnfile!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001669 call assert_equal(4, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001670 call assert_equal(l:last, bufnr())
1671endfunc
1672
1673" Fail :lpfile but :lpfile! is allowed
1674func 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())
1688endfunc
1689
1690" Fail :lprevious but :lprevious! is allowed
1691func Test_lprevious()
1692 CheckFeature quickfix
1693 call s:reset_all_buffers()
1694
1695 let [l:first, l:middle, _] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001696 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001697
Sean Dewar4bb505e2024-03-05 20:39:07 +01001698 lnext!
1699 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001700 call assert_equal(l:middle, bufnr())
1701
Sean Dewar4bb505e2024-03-05 20:39:07 +01001702 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())
Colin Kennedy21570352024-03-03 16:16:47 +01001706
1707 lprevious!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001708 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001709 call assert_equal(l:first, bufnr())
1710endfunc
1711
1712" Fail :lrewind but :lrewind! is allowed
1713func 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())
1725endfunc
1726
1727" Fail :ltag but :ltag! is allowed
1728func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001736 \ "Xtags", 'D')
1737 call writefile(["one", "two", "three"], "Xfile", 'D')
1738 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01001739 edit Xother
1740 execute "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&
Colin Kennedy21570352024-03-03 16:16:47 +01001751endfunc
1752
1753" Fail vim.command if we try to change buffers while 'winfixbuf' is set
1754func Test_lua_command()
Sean Dewar5131f222024-03-04 19:09:26 +01001755 CheckFeature lua
Colin Kennedy21570352024-03-03 16:16:47 +01001756 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.command("buffer " .. ' . l:previous . ')')
1769 call assert_equal(l:current, bufnr())
1770
1771 execute 'lua vim.command("buffer! " .. ' . l:previous . ')'
1772 call assert_equal(l:previous, bufnr())
1773endfunc
1774
1775" Fail :lvimgrep but :lvimgrep! is allowed
1776func 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")
1807endfunc
1808
1809" Fail :lvimgrepadd but :lvimgrepadd! is allowed
1810func 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")
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")
1841endfunc
1842
1843" Don't allow global marks to change the current 'winfixbuf' window
1844func 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 execute "buffer! " . l:other
1850 normal mA
1851 execute "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())
1864endfunc
1865
1866" Allow global marks in a 'winfixbuf' window if the jump is the same buffer
1867func 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())
1880endfunc
1881
1882" Fail :next but :next! is allowed
1883func 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())
1894endfunc
1895
1896" Ensure :mksession saves 'winfixbuf' details
1897func 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")
1917endfunc
1918
1919" Allow :next if the next index is the same as the current buffer
1920func 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())
1945endfunc
1946
1947" Fail to jump to a tag with g<C-]> if 'winfixbuf' is enabled
1948func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001956 \ "Xtags", 'D')
1957 call writefile(["one", "two", "three"], "Xfile", 'D')
1958 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01001959 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&
Colin Kennedy21570352024-03-03 16:16:47 +01001969endfunc
1970
1971" Fail to jump to a tag with g<RightMouse> if 'winfixbuf' is enabled
1972func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02001981 \ "Xtags", 'D')
1982 call writefile(["one", "two", "three"], "Xfile", 'D')
1983 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01001984 edit Xother
1985 execute "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&
Colin Kennedy21570352024-03-03 16:16:47 +01001996endfunc
1997
1998" Fail to jump to a tag with g] if 'winfixbuf' is enabled
1999func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002007 \ "Xtags", 'D')
2008 call writefile(["one", "two", "three"], "Xfile", 'D')
2009 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002010 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002020endfunc
2021
2022" Fail to jump to a tag with <C-RightMouse> if 'winfixbuf' is enabled
2023func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002032 \ "Xtags", 'D')
2033 call writefile(["one", "two", "three"], "Xfile", 'D')
2034 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002035 edit Xother
2036 execute "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&
Colin Kennedy21570352024-03-03 16:16:47 +01002047endfunc
2048
2049" Fail to jump to a tag with <C-t> if 'winfixbuf' is enabled
2050func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002058 \ "Xtags", 'D')
2059 call writefile(["one", "two", "three"], "Xfile", 'D')
2060 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002061 edit Xother
2062 execute "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&
Colin Kennedy21570352024-03-03 16:16:47 +01002072endfunc
2073
2074" Disallow <C-^> in 'winfixbuf' windows
2075func 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())
2091endfunc
2092
2093" Allow <C-i> in 'winfixbuf' windows if the movement stays within the buffer
2094func 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 execute "normal \<C-o>"
2112
2113 set winfixbuf
2114
2115 let l:line = getcurpos()[1]
2116 execute "normal 1\<C-i>"
2117 call assert_notequal(l:line, getcurpos()[1])
2118endfunc
2119
2120" Disallow <C-o> in 'winfixbuf' windows if it would cause the buffer to switch
2121func 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())
2137endfunc
2138
2139" Allow <C-o> in 'winfixbuf' windows if the movement stays within the buffer
2140func 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 execute "normal \<C-o>"
2161 call assert_equal(l:current, bufnr())
2162endfunc
2163
2164" Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
2165func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002173 \ "Xtags", 'D')
2174 call writefile(["one", "two", "three"], "Xfile", 'D')
2175 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002176 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002186endfunc
2187
2188" Allow <C-w><C-]> with 'winfixbuf' enabled because it runs in a new, split window
2189func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002197 \ "Xtags", 'D')
2198 call writefile(["one", "two", "three"], "Xfile", 'D')
2199 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002200 edit Xother
2201
2202 set winfixbuf
2203
2204 let l:current_windows = s:get_windows_count()
2205 execute "normal \<C-w>\<C-]>"
2206 call assert_equal(l:current_windows + 1, s:get_windows_count())
2207
2208 set tags&
Colin Kennedy21570352024-03-03 16:16:47 +01002209endfunc
2210
2211" Allow <C-w>g<C-]> with 'winfixbuf' enabled because it runs in a new, split window
2212func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002220 \ "Xtags", 'D')
2221 call writefile(["one", "two", "three"], "Xfile", 'D')
2222 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002223 edit Xother
2224
2225 set winfixbuf
2226
2227 let l:current_windows = s:get_windows_count()
2228 execute "normal \<C-w>g\<C-]>"
2229 call assert_equal(l:current_windows + 1, s:get_windows_count())
2230
2231 set tags&
Colin Kennedy21570352024-03-03 16:16:47 +01002232endfunc
2233
2234" Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
2235func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002243 \ "Xtags", 'D')
2244 call writefile(["one", "two", "three"], "Xfile", 'D')
2245 call writefile(["one", "two", "three"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002246 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002256endfunc
2257
2258" Prevent gF from switching a 'winfixbuf' window's buffer
2259func Test_normal_gF()
2260 call s:reset_all_buffers()
2261
2262 let l:file = tempname()
2263 call append(0, [l:file])
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002264 call writefile([], l:file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002265 " 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
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002283 set nohidden
Colin Kennedy21570352024-03-03 16:16:47 +01002284endfunc
2285
2286" Prevent gf from switching a 'winfixbuf' window's buffer
2287func Test_normal_gf()
2288 call s:reset_all_buffers()
2289
2290 let l:file = tempname()
2291 call append(0, [l:file])
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002292 call writefile([], l:file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002293 " 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
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002311 set nohidden
Colin Kennedy21570352024-03-03 16:16:47 +01002312endfunc
2313
2314" Fail "goto file under the cursor" (using [f, which is the same as `:normal gf`)
2315func Test_normal_square_bracket_left_f()
2316 call s:reset_all_buffers()
2317
2318 let l:file = tempname()
2319 call append(0, [l:file])
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002320 call writefile([], l:file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002321 " 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
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002339 set nohidden
Colin Kennedy21570352024-03-03 16:16:47 +01002340endfunc
2341
2342" Fail to go to a C macro with [<C-d> if 'winfixbuf' is enabled
2343func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002350 \ "main.c", 'D')
2351 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002352 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 execute "normal [\<C-d>"
2365 call assert_notequal(l:current, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01002366endfunc
2367
2368" Fail to go to a C macro with ]<C-d> if 'winfixbuf' is enabled
2369func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002376 \ "main.c", 'D')
2377 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002378 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 execute "normal ]\<C-d>"
2390 call assert_notequal(l:current, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01002391endfunc
2392
2393" Fail to go to a C macro with [<C-i> if 'winfixbuf' is enabled
2394func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002401 \ "main.c", 'D')
2402 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002403 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 execute "normal [\<C-i>"
2420 call assert_notequal(l:current, bufnr())
2421
2422 set define&
2423 set include&
2424 set path&
Colin Kennedy21570352024-03-03 16:16:47 +01002425endfunc
2426
2427" Fail to go to a C macro with ]<C-i> if 'winfixbuf' is enabled
2428func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002435 \ "main.c", 'D')
2436 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002437 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 execute "normal ]\<C-i>"
2453 call assert_notequal(l:current, bufnr())
2454
2455 set define&
2456 set include&
2457 set path&
Colin Kennedy21570352024-03-03 16:16:47 +01002458endfunc
2459
2460" Fail "goto file under the cursor" (using ]f, which is the same as `:normal gf`)
2461func Test_normal_square_bracket_right_f()
2462 call s:reset_all_buffers()
2463
2464 let l:file = tempname()
2465 call append(0, [l:file])
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002466 call writefile([], l:file, 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002467 " 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
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002485 set nohidden
Colin Kennedy21570352024-03-03 16:16:47 +01002486endfunc
2487
2488" Fail to jump to a tag with v<C-]> if 'winfixbuf' is enabled
2489func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002497 \ "Xtags", 'D')
2498 call writefile(["one", "two", "three"], "Xfile", 'D')
2499 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002500 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002510endfunc
2511
2512" Fail to jump to a tag with vg<C-]> if 'winfixbuf' is enabled
2513func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002521 \ "Xtags", 'D')
2522 call writefile(["one", "two", "three"], "Xfile", 'D')
2523 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002524 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002534endfunc
2535
2536" Allow :pedit because, unlike :edit, it uses a separate window
2537func Test_pedit()
2538 call s:reset_all_buffers()
2539
2540 let l:other = s:make_buffer_pairs()
2541
2542 pedit other
2543
2544 execute "normal \<C-w>w"
2545 call assert_equal(l:other, bufnr())
2546endfunc
2547
Yinzuo Jianga2a2fe82024-12-16 21:22:09 +01002548" Allow :pbuffer because, unlike :buffer, it uses a separate window
2549func 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 execute "normal \<C-w>w"
2557 call assert_equal(l:other, bufnr())
2558endfunc
2559
Colin Kennedy21570352024-03-03 16:16:47 +01002560" Fail :pop but :pop! is allowed
2561func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002570 \ "Xtags", 'D')
2571 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
2572 call writefile(["thesame one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002573 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002588endfunc
2589
2590" Fail :previous but :previous! is allowed
2591func 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())
2602endfunc
2603
Sean Dewar769eb2d2024-03-07 21:37:50 +01002604" Fail pyxdo if it changes a window with 'winfixbuf' is set
2605func Test_pythonx_pyxdo()
Colin Kennedy21570352024-03-03 16:16:47 +01002606 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
Sean Dewar769eb2d2024-03-07 21:37:50 +01002618 pythonx << EOF
Colin Kennedy21570352024-03-03 16:16:47 +01002619import vim
2620
Sean Dewar769eb2d2024-03-07 21:37:50 +01002621def test_winfixbuf_Test_pythonx_pyxdo_set_buffer():
Colin Kennedy21570352024-03-03 16:16:47 +01002622 buffer = vim.vars['_previous_buffer']
2623 vim.current.buffer = vim.buffers[buffer]
2624EOF
2625
2626 try
Sean Dewar769eb2d2024-03-07 21:37:50 +01002627 pyxdo test_winfixbuf_Test_pythonx_pyxdo_set_buffer()
Christian Brabandt0a32b882024-03-13 20:59:27 +01002628 catch /Vim\%((\a\+)\)\=:E1513:/
Colin Kennedy21570352024-03-03 16:16:47 +01002629 let l:caught = 1
2630 endtry
2631
2632 call assert_equal(1, l:caught)
2633
2634 unlet g:_previous_buffer
2635endfunc
2636
Sean Dewar769eb2d2024-03-07 21:37:50 +01002637" Fail pyxfile if it changes a window with 'winfixbuf' is set
2638func Test_pythonx_pyxfile()
Colin Kennedy21570352024-03-03 16:16:47 +01002639 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002655 \ "file.py", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002656
2657 try
Sean Dewar769eb2d2024-03-07 21:37:50 +01002658 pyxfile file.py
Christian Brabandt0a32b882024-03-13 20:59:27 +01002659 catch /Vim\%((\a\+)\)\=:E1513:/
Colin Kennedy21570352024-03-03 16:16:47 +01002660 let l:caught = 1
2661 endtry
2662
2663 call assert_equal(1, l:caught)
2664
Colin Kennedy21570352024-03-03 16:16:47 +01002665 unlet g:_previous_buffer
2666endfunc
2667
2668" Fail vim.current.buffer if 'winfixbuf' is set
Sean Dewar769eb2d2024-03-07 21:37:50 +01002669func Test_pythonx_vim_current_buffer()
Colin Kennedy21570352024-03-03 16:16:47 +01002670 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
Sean Dewar769eb2d2024-03-07 21:37:50 +01002685 pythonx << EOF
Colin Kennedy21570352024-03-03 16:16:47 +01002686import vim
2687
2688buffer = vim.vars["_previous_buffer"]
2689vim.current.buffer = vim.buffers[buffer]
2690EOF
Christian Brabandt0a32b882024-03-13 20:59:27 +01002691 catch /Vim\%((\a\+)\)\=:E1513:/
Colin Kennedy21570352024-03-03 16:16:47 +01002692 let l:caught = 1
2693 endtry
2694
2695 call assert_equal(1, l:caught)
2696 unlet g:_previous_buffer
2697endfunc
2698
2699" Ensure remapping to a disabled action still triggers failures
2700func 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
2719endfunc
2720
2721" Ensure remapping a disabled key to something valid does trigger any failures
2722func 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 execute "normal \<C-^>"
2742 call assert_equal(l:current, bufnr())
2743
2744 nunmap <C-^>
2745endfunc
2746
2747" Fail :rewind but :rewind! is allowed
2748func 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())
2759endfunc
2760
2761" Allow :sblast because it opens the buffer in a new, split window
2762func 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())
2771endfunc
2772
2773" Fail :sbprevious but :sbprevious! is allowed
2774func 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())
2782endfunc
2783
2784" Make sure 'winfixbuf' can be set using 'winfixbuf' or 'wfb'
2785func Test_short_option()
2786 call s:reset_all_buffers()
2787
2788 call s:make_buffer_pairs()
2789
2790 set winfixbuf
Yegappan Lakshmanan22697b62024-04-22 20:58:24 +02002791 call assert_fails("edit something_else", "E1513:")
Colin Kennedy21570352024-03-03 16:16:47 +01002792
2793 set nowinfixbuf
2794 set wfb
Yegappan Lakshmanan22697b62024-04-22 20:58:24 +02002795 call assert_fails("edit another_place", "E1513:")
Colin Kennedy21570352024-03-03 16:16:47 +01002796
2797 set nowfb
2798 edit last_place
2799endfunc
2800
2801" Allow :snext because it makes a new window
2802func 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())
2813endfunc
2814
2815" Ensure the first has 'winfixbuf' and a new split window is 'nowinfixbuf'
2816func Test_split_window()
2817 call s:reset_all_buffers()
2818
2819 split
2820 execute "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"))
2830endfunc
2831
2832" Fail :tNext but :tNext! is allowed
2833func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002842 \ "Xtags", 'D')
2843 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
2844 call writefile(["thesame one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002845 edit Xother
2846
2847 tag thesame
2848 execute "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&
Colin Kennedy21570352024-03-03 16:16:47 +01002861endfunc
2862
2863" Call :tabdo and choose the next available 'nowinfixbuf' window.
2864func 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 execute "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())
2889endfunc
2890
2891" Call :tabdo and create a new split window if all available windows are 'winfixbuf'.
2892func Test_tabdo_make_new_window()
2893 call s:reset_all_buffers()
2894
2895 let [l:first, _] = s:make_buffers_list()
2896 execute "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 execute "normal \<C-w>j"
2905 call assert_equal(l:first, bufnr())
2906 call assert_equal(l:current_windows + 1, s:get_windows_count())
2907endfunc
2908
2909" Fail :tag but :tag! is allowed
2910func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002918 \ "Xtags", 'D')
2919 call writefile(["one", "two", "three"], "Xfile", 'D')
2920 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002921 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002934endfunc
2935
2936
2937" Fail :tfirst but :tfirst! is allowed
2938func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002946 \ "Xtags", 'D')
2947 call writefile(["one", "two", "three"], "Xfile", 'D')
2948 call writefile(["one"], "Xother", 'D')
LemonBoy4ff3a9b2024-07-09 20:03:24 +02002949 tag one
Colin Kennedy21570352024-03-03 16:16:47 +01002950 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002963endfunc
2964
2965" Fail :tjump but :tjump! is allowed
2966func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02002974 \ "Xtags", 'D')
2975 call writefile(["one", "two", "three"], "Xfile", 'D')
2976 call writefile(["one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01002977 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&
Colin Kennedy21570352024-03-03 16:16:47 +01002990endfunc
2991
2992" Fail :tlast but :tlast! is allowed
2993func 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"],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02003001 \ "Xtags", 'D')
3002 call writefile(["one", "two", "three"], "Xfile", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01003003 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&
Colin Kennedy21570352024-03-03 16:16:47 +01003018endfunc
3019
3020" Fail :tnext but :tnext! is allowed
3021func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02003030 \ "Xtags", 'D')
3031 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
3032 call writefile(["thesame one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01003033 edit Xother
3034
3035 tag thesame
3036 execute "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&
Colin Kennedy21570352024-03-03 16:16:47 +01003049endfunc
3050
3051" Fail :tprevious but :tprevious! is allowed
3052func 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 \ ],
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02003061 \ "Xtags", 'D')
3062 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile", 'D')
3063 call writefile(["thesame one"], "Xother", 'D')
Colin Kennedy21570352024-03-03 16:16:47 +01003064 edit Xother
3065
3066 tag thesame
3067 execute "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&
Colin Kennedy21570352024-03-03 16:16:47 +01003080endfunc
3081
3082" Fail :view but :view! is allowed
3083func 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())
3094endfunc
3095
3096" Fail :visual but :visual! is allowed
3097func 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())
3108endfunc
3109
3110" Fail :vimgrep but :vimgrep! is allowed
3111func 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")
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")
3143endfunc
3144
3145" Fail :vimgrepadd but ::vimgrepadd! is allowed
3146func 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")
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")
3176endfunc
3177
3178" Fail :wNext but :wNext! is allowed
3179func 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")
3194endfunc
3195
3196" Allow :windo unless `:windo foo` would change a 'winfixbuf' window's buffer
3197func 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('execute "windo buffer ' . l:current_buffer . '"', "E1513:")
3214 call assert_equal(l:current_window, win_getid())
3215
3216 execute "windo buffer! " . l:current_buffer
3217 call assert_equal(l:current_window, win_getid())
3218endfunc
3219
3220" Fail :wnext but :wnext! is allowed
3221func 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")
3236endfunc
3237
3238" Fail :wprevious but :wprevious! is allowed
3239func 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")
3254endfunc
Sean Dewar5131f222024-03-04 19:09:26 +01003255
3256func Test_quickfix_switchbuf_invalid_prevwin()
3257 call s:reset_all_buffers()
3258
Sean Dewar4bb505e2024-03-05 20:39:07 +01003259 call s:make_simple_quickfix()
3260 call assert_equal(1, getqflist(#{idx: 0}).idx)
Sean Dewar5131f222024-03-04 19:09:26 +01003261
3262 set switchbuf=uselast
3263 split
3264 copen
3265 execute winnr('#') 'quit'
Sean Dewar4bb505e2024-03-05 20:39:07 +01003266 call assert_equal(2, winnr('$'))
Sean Dewar5131f222024-03-04 19:09:26 +01003267
Sean Dewar4bb505e2024-03-05 20:39:07 +01003268 cnext " Would've triggered a null pointer member access
3269 call assert_equal(2, getqflist(#{idx: 0}).idx)
3270
Sean Dewar5131f222024-03-04 19:09:26 +01003271 set switchbuf&
3272endfunc
3273
Sean Dewar4bb505e2024-03-05 20:39:07 +01003274func 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
3319endfunc
3320
3321func 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
3340endfunc
3341
Sean Dewar769eb2d2024-03-07 21:37:50 +01003342func Test_bufdo_cnext_splitwin_fails()
Christian Brabandtaf7ae812024-03-06 19:31:39 +01003343 call s:reset_all_buffers()
Sean Dewar769eb2d2024-03-07 21:37:50 +01003344 call s:make_simple_quickfix()
3345 call assert_equal(1, getqflist(#{idx: 0}).idx)
Christian Brabandtaf7ae812024-03-06 19:31:39 +01003346 " Make sure there is not enough room to
3347 " split the winfixedbuf window
3348 let &winheight=&lines
3349 let &winminheight=&lines-2
Sean Dewar769eb2d2024-03-07 21:37:50 +01003350 " 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)
Christian Brabandtaf7ae812024-03-06 19:31:39 +01003356 set winminheight&vim winheight&vim
3357endfunc
3358
zeertzjq620e8522024-03-28 10:11:57 +01003359" Test that exiting with 'winfixbuf' and EXITFREE doesn't cause an error.
3360func 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:',
Yegappan Lakshmanan4baf9082024-04-21 19:50:21 +02003367 \ system(GetVimCommandClean() .. ' --not-a-term -X -S Xwfb_exitfree'))
zeertzjq620e8522024-03-28 10:11:57 +01003368endfunc
3369
Sean Dewar5131f222024-03-04 19:09:26 +01003370" vim: shiftwidth=2 sts=2 expandtab