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