blob: 8a1862c3e521f8ebb9e41aae5e4625ddae929c10 [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()
482 call s:reset_all_buffers()
483
484 let l:other = s:make_buffer_pairs()
485 let l:current = bufnr()
486
487 call assert_fails("browse edit other", "E1513:")
488 call assert_equal(l:current, bufnr())
489
490 browse edit! other
491 call assert_equal(l:other, bufnr())
492endfunc
493
494" Allow :browse w because it doesn't change the buffer in the current file
495func Test_browse_edit_pass()
496 call s:reset_all_buffers()
497
498 let l:other = s:make_buffer_pairs()
499 let l:current = bufnr()
500
501 browse write other
502
503 call delete("other")
504endfunc
505
506" Call :bufdo and choose the next available 'nowinfixbuf' window.
507func Test_bufdo_choose_available_window()
508 call s:reset_all_buffers()
509
510 let l:other = s:make_buffer_pairs()
511
512 " Make a split window that is 'nowinfixbuf' but make it the second-to-last
513 " window so that :bufdo will first try the 'winfixbuf' window, pass over it,
514 " and prefer the other 'nowinfixbuf' window, instead.
515 "
516 " +-------------------+
517 " | 'nowinfixbuf' |
518 " +-------------------+
519 " | 'winfixbuf' | <-- Cursor is here
520 " +-------------------+
521 split
522 let l:nowinfixbuf_window = win_getid()
523 " Move to the 'winfixbuf' window now
524 execute "normal \<C-w>j"
525 let l:winfixbuf_window = win_getid()
526
527 let l:current = bufnr()
528 let l:expected_windows = s:get_windows_count()
529
530 call assert_notequal(l:current, l:other)
531
532 bufdo echo ''
533 call assert_equal(l:nowinfixbuf_window, win_getid())
534 call assert_notequal(l:other, bufnr())
535 call assert_equal(l:expected_windows, s:get_windows_count())
536endfunc
537
538" Call :bufdo and create a new split window if all available windows are 'winfixbuf'.
539func Test_bufdo_make_new_window()
540 call s:reset_all_buffers()
541
542 let [l:first, l:last] = s:make_buffers_list()
543 execute "buffer! " . l:first
544 let l:current = win_getid()
545 let l:current_windows = s:get_windows_count()
546
547 bufdo echo ''
548 call assert_notequal(l:current, win_getid())
549 call assert_equal(l:last, bufnr())
550 execute "normal \<C-w>j"
551 call assert_equal(l:first, bufnr())
552 call assert_equal(l:current_windows + 1, s:get_windows_count())
553endfunc
554
555" Fail :buffer but :buffer! is allowed
556func Test_buffer()
557 call s:reset_all_buffers()
558
559 let l:other = s:make_buffer_pairs()
560 let l:current = bufnr()
561
562 call assert_fails("buffer " . l:other, "E1513:")
563 call assert_equal(l:current, bufnr())
564
565 execute "buffer! " . l:other
566 call assert_equal(l:other, bufnr())
567endfunc
568
569" Allow :buffer on a 'winfixbuf' window if there is no change in buffer
570func Test_buffer_same_buffer()
571 call s:reset_all_buffers()
572
573 call s:make_buffer_pairs()
574 let l:current = bufnr()
575
576 execute "buffer " . l:current
577 call assert_equal(l:current, bufnr())
578
579 execute "buffer! " . l:current
580 call assert_equal(l:current, bufnr())
581endfunc
582
583" Allow :cNext but the 'nowinfixbuf' window is selected, instead
584func Test_cNext()
585 CheckFeature quickfix
586 call s:reset_all_buffers()
587
588 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
589
590 " The call to `:cNext` succeeds but it selects the window with 'nowinfixbuf' instead
591 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
592
593 " Make sure the previous window has 'winfixbuf' so we can test that our
594 " "skip 'winfixbuf' window" logic works.
595 call win_gotoid(l:winfix_window)
596 call win_gotoid(l:quickfix_window)
597
598 cNext
599 call assert_equal(l:first_window, win_getid())
600endfunc
601
602" Allow :cNfile but the 'nowinfixbuf' window is selected, instead
603func Test_cNfile()
604 CheckFeature quickfix
605 call s:reset_all_buffers()
606
607 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
608
609 " The call to `:cNfile` succeeds but it selects the window with 'nowinfixbuf' instead
610 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
611 cnext!
612
613 " Make sure the previous window has 'winfixbuf' so we can test that our
614 " "skip 'winfixbuf' window" logic works.
615 call win_gotoid(l:winfix_window)
616 call win_gotoid(l:quickfix_window)
617
618 cNfile
619 call assert_equal(l:first_window, win_getid())
620endfunc
621
622" Allow :caddexpr because it doesn't change the current buffer
623func Test_caddexpr()
624 CheckFeature quickfix
625 call s:reset_all_buffers()
626
627 let l:file_path = tempname()
628 call writefile(["Error - bad-thing-found"], l:file_path)
629 execute "edit " . l:file_path
630 let l:file_buffer = bufnr()
631 let l:current = bufnr()
632
633 edit first.unittest
634 call append(0, ["some-search-term bad-thing-found"])
635
636 edit! other.unittest
637
638 set winfixbuf
639
640 execute "buffer! " . l:file_buffer
641
642 execute 'caddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")'
643 call assert_equal(l:current, bufnr())
644
645 call delete(l:file_path)
646endfunc
647
648" Fail :cbuffer but :cbuffer! is allowed
649func Test_cbuffer()
650 CheckFeature quickfix
651 call s:reset_all_buffers()
652
653 let l:file_path = tempname()
654 call writefile(["first.unittest:1:Error - bad-thing-found"], l:file_path)
655 execute "edit " . l:file_path
656 let l:file_buffer = bufnr()
657 let l:current = bufnr()
658
659 edit first.unittest
660 call append(0, ["some-search-term bad-thing-found"])
661
662 edit! other.unittest
663
664 set winfixbuf
665
666 execute "buffer! " . l:file_buffer
667
668 call assert_fails("cbuffer " . l:file_buffer)
669 call assert_equal(l:current, bufnr())
670
671 execute "cbuffer! " . l:file_buffer
672 call assert_equal("first.unittest", expand("%:t"))
673
674 call delete(l:file_path)
675endfunc
676
677" Allow :cc but the 'nowinfixbuf' window is selected, instead
678func Test_cc()
679 CheckFeature quickfix
680 call s:reset_all_buffers()
681
682 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
683
684 " The call to `:cnext` succeeds but it selects the window with 'nowinfixbuf' instead
685 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
686
687 " Make sure the previous window has 'winfixbuf' so we can test that our
688 " "skip 'winfixbuf' window" logic works.
689 call win_gotoid(l:winfix_window)
690 call win_gotoid(l:quickfix_window)
691 " Go up one line in the quickfix window to an quickfix entry that doesn't
692 " point to a winfixbuf buffer
693 normal k
694 " Attempt to make the previous window, winfixbuf buffer, to go to the
695 " non-winfixbuf quickfix entry
696 .cc
697
698 " Confirm that :.cc did not change the winfixbuf-enabled window
699 call assert_equal(l:first_window, win_getid())
700endfunc
701
702" Call :cdo and choose the next available 'nowinfixbuf' window.
703func Test_cdo_choose_available_window()
704 CheckFeature quickfix
705 call s:reset_all_buffers()
706
707 let [l:current, l:last] = s:make_simple_quickfix()
708 execute "buffer! " . l:current
709
710 " Make a split window that is 'nowinfixbuf' but make it the second-to-last
711 " window so that :cdo will first try the 'winfixbuf' window, pass over it,
712 " and prefer the other 'nowinfixbuf' window, instead.
713 "
714 " +-------------------+
715 " | 'nowinfixbuf' |
716 " +-------------------+
717 " | 'winfixbuf' | <-- Cursor is here
718 " +-------------------+
719 split
720 let l:nowinfixbuf_window = win_getid()
721 " Move to the 'winfixbuf' window now
722 execute "normal \<C-w>j"
723 let l:winfixbuf_window = win_getid()
724 let l:expected_windows = s:get_windows_count()
725
726 cdo echo ''
727
728 call assert_equal(l:nowinfixbuf_window, win_getid())
729 call assert_equal(l:last, bufnr())
730 execute "normal \<C-w>j"
731 call assert_equal(l:current, bufnr())
732 call assert_equal(l:expected_windows, s:get_windows_count())
733endfunc
734
735" Call :cdo and create a new split window if all available windows are 'winfixbuf'.
736func Test_cdo_make_new_window()
737 CheckFeature quickfix
738 call s:reset_all_buffers()
739
740 let [l:current_buffer, l:last] = s:make_simple_quickfix()
741 execute "buffer! " . l:current_buffer
742
743 let l:current_window = win_getid()
744 let l:current_windows = s:get_windows_count()
745
746 cdo echo ''
747 call assert_notequal(l:current_window, win_getid())
748 call assert_equal(l:last, bufnr())
749 execute "normal \<C-w>j"
750 call assert_equal(l:current_buffer, bufnr())
751 call assert_equal(l:current_windows + 1, s:get_windows_count())
752endfunc
753
754" Fail :cexpr but :cexpr! is allowed
755func Test_cexpr()
756 CheckFeature quickfix
757 call s:reset_all_buffers()
758
759 let l:file = tempname()
760 let l:entry = '["' . l:file . ':1:bar"]'
761 let l:current = bufnr()
762
763 set winfixbuf
764
765 call assert_fails("cexpr " . l:entry)
766 call assert_equal(l:current, bufnr())
767
768 execute "cexpr! " . l:entry
769 call assert_equal(fnamemodify(l:file, ":t"), expand("%:t"))
770endfunc
771
772" Call :cfdo and choose the next available 'nowinfixbuf' window.
773func Test_cfdo_choose_available_window()
774 CheckFeature quickfix
775 call s:reset_all_buffers()
776
777 let [l:current, l:last] = s:make_simple_quickfix()
778 execute "buffer! " . l:current
779
780 " Make a split window that is 'nowinfixbuf' but make it the second-to-last
781 " window so that :cfdo will first try the 'winfixbuf' window, pass over it,
782 " and prefer the other 'nowinfixbuf' window, instead.
783 "
784 " +-------------------+
785 " | 'nowinfixbuf' |
786 " +-------------------+
787 " | 'winfixbuf' | <-- Cursor is here
788 " +-------------------+
789 split
790 let l:nowinfixbuf_window = win_getid()
791 " Move to the 'winfixbuf' window now
792 execute "normal \<C-w>j"
793 let l:winfixbuf_window = win_getid()
794 let l:expected_windows = s:get_windows_count()
795
796 cfdo echo ''
797
798 call assert_equal(l:nowinfixbuf_window, win_getid())
799 call assert_equal(l:last, bufnr())
800 execute "normal \<C-w>j"
801 call assert_equal(l:current, bufnr())
802 call assert_equal(l:expected_windows, s:get_windows_count())
803endfunc
804
805" Call :cfdo and create a new split window if all available windows are 'winfixbuf'.
806func Test_cfdo_make_new_window()
807 CheckFeature quickfix
808 call s:reset_all_buffers()
809
810 let [l:current_buffer, l:last] = s:make_simple_quickfix()
811 execute "buffer! " . l:current_buffer
812
813 let l:current_window = win_getid()
814 let l:current_windows = s:get_windows_count()
815
816 cfdo echo ''
817 call assert_notequal(l:current_window, win_getid())
818 call assert_equal(l:last, bufnr())
819 execute "normal \<C-w>j"
820 call assert_equal(l:current_buffer, bufnr())
821 call assert_equal(l:current_windows + 1, s:get_windows_count())
822endfunc
823
824" Fail :cfile but :cfile! is allowed
825func Test_cfile()
826 CheckFeature quickfix
827 call s:reset_all_buffers()
828
829 edit first.unittest
830 call append(0, ["some-search-term bad-thing-found"])
831 write
832 let l:first = bufnr()
833
834 edit! second.unittest
835 call append(0, ["some-search-term"])
836 write
837
838 let l:file = tempname()
839 call writefile(["first.unittest:1:Error - bad-thing-found was detected"], l:file)
840
841 let l:current = bufnr()
842
843 set winfixbuf
844
845 call assert_fails(":cfile " . l:file)
846 call assert_equal(l:current, bufnr())
847
848 execute ":cfile! " . l:file
849 call assert_equal(l:first, bufnr())
850
851 call delete(l:file)
852 call delete("first.unittest")
853 call delete("second.unittest")
854endfunc
855
856" Allow :cfirst but the 'nowinfixbuf' window is selected, instead
857func Test_cfirst()
858 CheckFeature quickfix
859 call s:reset_all_buffers()
860
861 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
862
863 " The call to `:cfirst` succeeds but it selects the window with 'nowinfixbuf' instead
864 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
865
866 " Make sure the previous window has 'winfixbuf' so we can test that our
867 " "skip 'winfixbuf' window" logic works.
868 call win_gotoid(l:winfix_window)
869 call win_gotoid(l:quickfix_window)
870
871 cfirst
872 call assert_equal(l:first_window, win_getid())
873endfunc
874
875" Allow :clast but the 'nowinfixbuf' window is selected, instead
876func Test_clast()
877 CheckFeature quickfix
878 call s:reset_all_buffers()
879
880 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
881
882 " The call to `:clast` succeeds but it selects the window with 'nowinfixbuf' instead
883 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
884
885 " Make sure the previous window has 'winfixbuf' so we can test that our
886 " "skip 'winfixbuf' window" logic works.
887 call win_gotoid(l:winfix_window)
888 call win_gotoid(l:quickfix_window)
889
890 clast
891 call assert_equal(l:first_window, win_getid())
892endfunc
893
894" Allow :cnext but the 'nowinfixbuf' window is selected, instead
895" Make sure no new windows are created and previous windows are reused
896func Test_cnext()
897 CheckFeature quickfix
898 call s:reset_all_buffers()
899
900 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
901 let l:expected = s:get_windows_count()
902
903 " The call to `:cnext` succeeds but it selects the window with 'nowinfixbuf' instead
904 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
905
906 cnext!
907 call assert_equal(l:expected, s:get_windows_count())
908
909 " Make sure the previous window has 'winfixbuf' so we can test that our
910 " "skip 'winfixbuf' window" logic works.
911 call win_gotoid(l:winfix_window)
912 call win_gotoid(l:quickfix_window)
913
914 cnext
915 call assert_equal(l:first_window, win_getid())
916 call assert_equal(l:expected, s:get_windows_count())
917endfunc
918
919" Make sure :cnext creates a split window if no previous window exists
920func Test_cnext_no_previous_window()
921 CheckFeature quickfix
922 call s:reset_all_buffers()
923
924 let [l:current, _] = s:make_simple_quickfix()
925 execute "buffer! " . l:current
926
927 let l:expected = s:get_windows_count()
928
929 " Open the quickfix in a separate split and go to it
930 copen
931
932 call assert_equal(l:expected + 1, s:get_windows_count())
933endfunc
934
935" Allow :cnext and create a 'nowinfixbuf' window if none exists
936func Test_cnext_make_new_window()
937 CheckFeature quickfix
938 call s:reset_all_buffers()
939
940 let [l:current, _] = s:make_simple_quickfix()
941 let l:current = win_getid()
942
943 cfirst!
944
945 let l:windows = s:get_windows_count()
946 let l:expected = l:windows + 1 " We're about to create a new split window
947
948 cnext
949 call assert_equal(l:expected, s:get_windows_count())
950
951 cnext!
952 call assert_equal(l:expected, s:get_windows_count())
953endfunc
954
955" Allow :cprevious but the 'nowinfixbuf' window is selected, instead
956func Test_cprevious()
957 CheckFeature quickfix
958 call s:reset_all_buffers()
959
960 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
961
962 " The call to `:cprevious` succeeds but it selects the window with 'nowinfixbuf' instead
963 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
964
965 " Make sure the previous window has 'winfixbuf' so we can test that our
966 " "skip 'winfixbuf' window" logic works.
967 call win_gotoid(l:winfix_window)
968 call win_gotoid(l:quickfix_window)
969
970 cprevious
971 call assert_equal(l:first_window, win_getid())
972endfunc
973
974" Allow :cnfile but the 'nowinfixbuf' window is selected, instead
975func Test_cnfile()
976 CheckFeature quickfix
977 call s:reset_all_buffers()
978
979 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
980
981 " The call to `:cnfile` succeeds but it selects the window with 'nowinfixbuf' instead
982 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
983 cnext!
984
985 " Make sure the previous window has 'winfixbuf' so we can test that our
986 " "skip 'winfixbuf' window" logic works.
987 call win_gotoid(l:winfix_window)
988 call win_gotoid(l:quickfix_window)
989
990 cnfile
991 call assert_equal(l:first_window, win_getid())
992endfunc
993
994" Allow :cpfile but the 'nowinfixbuf' window is selected, instead
995func Test_cpfile()
996 CheckFeature quickfix
997 call s:reset_all_buffers()
998
999 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
1000
1001 " The call to `:cpfile` succeeds but it selects the window with 'nowinfixbuf' instead
1002 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
1003 cnext!
1004
1005 " Make sure the previous window has 'winfixbuf' so we can test that our
1006 " "skip 'winfixbuf' window" logic works.
1007 call win_gotoid(l:winfix_window)
1008 call win_gotoid(l:quickfix_window)
1009
1010 cpfile
1011 call assert_equal(l:first_window, win_getid())
1012endfunc
1013
1014" Allow :crewind but the 'nowinfixbuf' window is selected, instead
1015func Test_crewind()
1016 CheckFeature quickfix
1017 call s:reset_all_buffers()
1018
1019 let [l:first_window, l:winfix_window, l:quickfix_window] = s:make_quickfix_windows()
1020
1021 " The call to `:crewind` succeeds but it selects the window with 'nowinfixbuf' instead
1022 call s:set_quickfix_by_buffer(winbufnr(l:winfix_window))
1023 cnext!
1024
1025 " Make sure the previous window has 'winfixbuf' so we can test that our
1026 " "skip 'winfixbuf' window" logic works.
1027 call win_gotoid(l:winfix_window)
1028 call win_gotoid(l:quickfix_window)
1029
1030 crewind
1031 call assert_equal(l:first_window, win_getid())
1032endfunc
1033
1034" Allow <C-w>f because it opens in a new split
1035func Test_ctrl_w_f()
1036 call s:reset_all_buffers()
1037
1038 enew
1039 let l:file_name = tempname()
1040 call writefile([], l:file_name)
1041 let l:file_buffer = bufnr()
1042
1043 enew
1044 file other
1045 let l:other_buffer = bufnr()
1046
1047 set winfixbuf
1048
1049 call setline(1, l:file_name)
1050 let l:current_windows = s:get_windows_count()
1051 execute "normal \<C-w>f"
1052
1053 call assert_equal(l:current_windows + 1, s:get_windows_count())
1054
1055 call delete(l:file_name)
1056endfunc
1057
1058" Fail :djump but :djump! is allowed
1059func Test_djump()
1060 call s:reset_all_buffers()
1061
1062 let l:include_file = tempname() . ".h"
1063 call writefile(["min(1, 12);",
1064 \ '#include "' . l:include_file . '"'
1065 \ ],
1066 \ "main.c")
1067 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
1068 edit main.c
1069
1070 set winfixbuf
1071
1072 let l:current = bufnr()
1073
1074 call assert_fails("djump 1 /min/", "E1513:")
1075 call assert_equal(l:current, bufnr())
1076
1077 djump! 1 /min/
1078 call assert_notequal(l:current, bufnr())
1079
1080 call delete("main.c")
1081 call delete(l:include_file)
1082endfunc
1083
1084" Fail :drop but :drop! is allowed
1085func Test_drop()
1086 call s:reset_all_buffers()
1087
1088 let l:other = s:make_buffer_pairs()
1089 let l:current = bufnr()
1090
1091 call assert_fails("drop other", "E1513:")
1092 call assert_equal(l:current, bufnr())
1093
1094 drop! other
1095 call assert_equal(l:other, bufnr())
1096endfunc
1097
1098" Fail :edit but :edit! is allowed
1099func Test_edit()
1100 call s:reset_all_buffers()
1101
1102 let l:other = s:make_buffer_pairs()
1103 let l:current = bufnr()
1104
1105 call assert_fails("edit other", "E1513:")
1106 call assert_equal(l:current, bufnr())
1107
1108 edit! other
1109 call assert_equal(l:other, bufnr())
1110endfunc
1111
1112" Fail :enew but :enew! is allowed
1113func Test_enew()
1114 call s:reset_all_buffers()
1115
1116 let l:other = s:make_buffer_pairs()
1117 let l:current = bufnr()
1118
1119 call assert_fails("enew", "E1513:")
1120 call assert_equal(l:current, bufnr())
1121
1122 enew!
1123 call assert_notequal(l:other, bufnr())
1124 call assert_notequal(3, bufnr())
1125endfunc
1126
1127" Fail :ex but :ex! is allowed
1128func Test_ex()
1129 call s:reset_all_buffers()
1130
1131 let l:other = s:make_buffer_pairs()
1132 let l:current = bufnr()
1133
1134 call assert_fails("ex other", "E1513:")
1135 call assert_equal(l:current, bufnr())
1136
1137 ex! other
1138 call assert_equal(l:other, bufnr())
1139endfunc
1140
1141" Fail :find but :find! is allowed
1142func Test_find()
1143 call s:reset_all_buffers()
1144
1145 let l:current = bufnr()
1146 let l:file = tempname()
1147 call writefile([], l:file)
1148 let l:directory = fnamemodify(l:file, ":p:h")
1149 let l:name = fnamemodify(l:file, ":p:t")
1150
1151 let l:original_path = &path
1152 execute "set path=" . l:directory
1153
1154 set winfixbuf
1155
1156 call assert_fails("execute 'find " . l:name . "'", "E1513:")
1157 call assert_equal(l:current, bufnr())
1158
1159 execute "find! " . l:name
1160 call assert_equal(l:file, expand("%:p"))
1161
1162 execute "set path=" . l:original_path
1163 call delete(l:file)
1164endfunc
1165
1166" Fail :first but :first! is allowed
1167func Test_first()
1168 call s:reset_all_buffers()
1169
1170 let [l:first, _] = s:make_args_list()
1171 next!
1172
1173 call assert_fails("first", "E1513:")
1174 call assert_notequal(l:first, bufnr())
1175
1176 first!
1177 call assert_equal(l:first, bufnr())
1178endfunc
1179
1180" Fail :grep but :grep! is allowed
1181func Test_grep()
1182 CheckFeature quickfix
1183 call s:reset_all_buffers()
1184
1185 edit first.unittest
1186 call append(0, ["some-search-term"])
1187 write
1188 let l:first = bufnr()
1189
1190 edit current.unittest
1191 call append(0, ["some-search-term"])
1192 write
1193 let l:current = bufnr()
1194
1195 edit! last.unittest
1196 call append(0, ["some-search-term"])
1197 write
1198 let l:last = bufnr()
1199
1200 set winfixbuf
1201
1202 buffer! current.unittest
1203
1204 call assert_fails("silent! grep some-search-term *.unittest", "E1513:")
1205 call assert_equal(l:current, bufnr())
1206 execute "edit! " . l:first
1207
1208 silent! grep! some-search-term *.unittest
1209 call assert_notequal(l:first, bufnr())
1210
1211 call delete("first.unittest")
1212 call delete("current.unittest")
1213 call delete("last.unittest")
1214endfunc
1215
1216" Fail :ijump but :ijump! is allowed
1217func Test_ijump()
1218 call s:reset_all_buffers()
1219
1220 let l:include_file = tempname() . ".h"
1221 call writefile([
1222 \ '#include "' . l:include_file . '"'
1223 \ ],
1224 \ "main.c")
1225 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
1226 edit main.c
1227
1228 set winfixbuf
1229
1230 let l:current = bufnr()
1231
1232 set define=^\\s*#\\s*define
1233 set include=^\\s*#\\s*include
1234 set path=.,/usr/include,,
1235
1236 call assert_fails("ijump /min/", "E1513:")
1237 call assert_equal(l:current, bufnr())
1238
1239 set nowinfixbuf
1240
1241 ijump! /min/
1242 call assert_notequal(l:current, bufnr())
1243
1244 set define&
1245 set include&
1246 set path&
1247 call delete("main.c")
1248 call delete(l:include_file)
1249endfunc
1250
1251" Fail :lNext but :lNext! is allowed
1252func Test_lNext()
1253 CheckFeature quickfix
1254 call s:reset_all_buffers()
1255
1256 let [l:first, l:middle, _] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001257 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001258
Sean Dewar4bb505e2024-03-05 20:39:07 +01001259 lnext!
1260 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001261 call assert_equal(l:middle, bufnr())
1262
Sean Dewar4bb505e2024-03-05 20:39:07 +01001263 call assert_fails("lNext", "E1513:")
1264 " Ensure the entry didn't change.
1265 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
1266 call assert_equal(l:middle, bufnr())
1267
1268 lnext!
1269 call assert_equal(3, getloclist(0, #{idx: 0}).idx)
1270 call assert_equal(l:middle, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01001271
1272 lNext!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001273 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
1274 call assert_equal(l:middle, bufnr())
1275
1276 lNext!
1277 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001278 call assert_equal(l:first, bufnr())
1279endfunc
1280
1281" Fail :lNfile but :lNfile! is allowed
1282func Test_lNfile()
1283 CheckFeature quickfix
1284 call s:reset_all_buffers()
1285
1286 let [l:first, l:current, _] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001287 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001288
Sean Dewar4bb505e2024-03-05 20:39:07 +01001289 lnext!
1290 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001291 call assert_equal(l:current, bufnr())
1292
Sean Dewar4bb505e2024-03-05 20:39:07 +01001293 call assert_fails("lNfile", "E1513:")
1294 " Ensure the entry didn't change.
1295 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
1296 call assert_equal(l:current, bufnr())
1297
1298 lnext!
1299 call assert_equal(3, getloclist(0, #{idx: 0}).idx)
1300 call assert_equal(l:current, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01001301
1302 lNfile!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001303 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001304 call assert_equal(l:first, bufnr())
1305endfunc
1306
1307" Allow :laddexpr because it doesn't change the current buffer
1308func Test_laddexpr()
1309 CheckFeature quickfix
1310 call s:reset_all_buffers()
1311
1312 let l:file_path = tempname()
1313 call writefile(["Error - bad-thing-found"], l:file_path)
1314 execute "edit " . l:file_path
1315 let l:file_buffer = bufnr()
1316 let l:current = bufnr()
1317
1318 edit first.unittest
1319 call append(0, ["some-search-term bad-thing-found"])
1320
1321 edit! other.unittest
1322
1323 set winfixbuf
1324
1325 execute "buffer! " . l:file_buffer
1326
1327 execute 'laddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")'
1328 call assert_equal(l:current, bufnr())
1329
1330 call delete(l:file_path)
1331endfunc
1332
1333" Fail :last but :last! is allowed
1334func Test_last()
1335 call s:reset_all_buffers()
1336
1337 let [_, l:last] = s:make_args_list()
1338 next!
1339
1340 call assert_fails("last", "E1513:")
1341 call assert_notequal(l:last, bufnr())
1342
1343 last!
1344 call assert_equal(l:last, bufnr())
1345endfunc
1346
1347" Fail :lbuffer but :lbuffer! is allowed
1348func Test_lbuffer()
1349 CheckFeature quickfix
1350 call s:reset_all_buffers()
1351
1352 let l:file_path = tempname()
1353 call writefile(["first.unittest:1:Error - bad-thing-found"], l:file_path)
1354 execute "edit " . l:file_path
1355 let l:file_buffer = bufnr()
1356 let l:current = bufnr()
1357
1358 edit first.unittest
1359 call append(0, ["some-search-term bad-thing-found"])
1360
1361 edit! other.unittest
1362
1363 set winfixbuf
1364
1365 execute "buffer! " . l:file_buffer
1366
1367 call assert_fails("lbuffer " . l:file_buffer)
1368 call assert_equal(l:current, bufnr())
1369
1370 execute "lbuffer! " . l:file_buffer
1371 call assert_equal("first.unittest", expand("%:t"))
1372
1373 call delete(l:file_path)
1374endfunc
1375
1376" Fail :ldo but :ldo! is allowed
1377func Test_ldo()
1378 CheckFeature quickfix
1379 call s:reset_all_buffers()
1380
1381 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1382 lnext!
1383
1384 call assert_fails('execute "ldo buffer ' . l:first . '"', "E1513:")
1385 call assert_equal(l:middle, bufnr())
1386 execute "ldo! buffer " . l:first
1387 call assert_notequal(l:last, bufnr())
1388endfunc
1389
1390" Fail :lfdo but :lfdo! is allowed
1391func Test_lexpr()
1392 CheckFeature quickfix
1393 call s:reset_all_buffers()
1394
1395 let l:file = tempname()
1396 let l:entry = '["' . l:file . ':1:bar"]'
1397 let l:current = bufnr()
1398
1399 set winfixbuf
1400
1401 call assert_fails("lexpr " . l:entry)
1402 call assert_equal(l:current, bufnr())
1403
1404 execute "lexpr! " . l:entry
1405 call assert_equal(fnamemodify(l:file, ":t"), expand("%:t"))
1406endfunc
1407
1408" Fail :lfdo but :lfdo! is allowed
1409func Test_lfdo()
1410 CheckFeature quickfix
1411 call s:reset_all_buffers()
1412
1413 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1414 lnext!
1415
1416 call assert_fails('execute "lfdo buffer ' . l:first . '"', "E1513:")
1417 call assert_equal(l:middle, bufnr())
1418 execute "lfdo! buffer " . l:first
1419 call assert_notequal(l:last, bufnr())
1420endfunc
1421
1422" Fail :lfile but :lfile! is allowed
1423func Test_lfile()
1424 CheckFeature quickfix
1425 call s:reset_all_buffers()
1426
1427 edit first.unittest
1428 call append(0, ["some-search-term bad-thing-found"])
1429 write
1430 let l:first = bufnr()
1431
1432 edit! second.unittest
1433 call append(0, ["some-search-term"])
1434 write
1435
1436 let l:file = tempname()
1437 call writefile(["first.unittest:1:Error - bad-thing-found was detected"], l:file)
1438
1439 let l:current = bufnr()
1440
1441 set winfixbuf
1442
1443 call assert_fails(":lfile " . l:file)
1444 call assert_equal(l:current, bufnr())
1445
1446 execute ":lfile! " . l:file
1447 call assert_equal(l:first, bufnr())
1448
1449 call delete(l:file)
1450 call delete("first.unittest")
1451 call delete("second.unittest")
1452endfunc
1453
1454" Fail :ll but :ll! is allowed
1455func Test_ll()
1456 CheckFeature quickfix
1457 call s:reset_all_buffers()
1458
1459 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1460 lopen
1461 lfirst!
1462 execute "normal \<C-w>j"
1463 normal j
1464
1465 call assert_fails(".ll", "E1513:")
1466 execute "normal \<C-w>k"
1467 call assert_equal(l:first, bufnr())
1468 execute "normal \<C-w>j"
1469 .ll!
1470 execute "normal \<C-w>k"
1471 call assert_equal(l:middle, bufnr())
1472endfunc
1473
1474" Fail :llast but :llast! is allowed
1475func Test_llast()
1476 CheckFeature quickfix
1477 call s:reset_all_buffers()
1478
1479 let [l:first, _, l:last] = s:make_simple_location_list()
1480 lfirst!
1481
1482 call assert_fails("llast", "E1513:")
1483 call assert_equal(l:first, bufnr())
1484
1485 llast!
1486 call assert_equal(l:last, bufnr())
1487endfunc
1488
1489" Fail :lnext but :lnext! is allowed
1490func Test_lnext()
1491 CheckFeature quickfix
1492 call s:reset_all_buffers()
1493
1494 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1495 ll!
1496
1497 call assert_fails("lnext", "E1513:")
1498 call assert_equal(l:first, bufnr())
1499
1500 lnext!
1501 call assert_equal(l:middle, bufnr())
1502endfunc
1503
1504" Fail :lnfile but :lnfile! is allowed
1505func Test_lnfile()
1506 CheckFeature quickfix
1507 call s:reset_all_buffers()
1508
1509 let [_, l:current, l:last] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001510 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001511
Sean Dewar4bb505e2024-03-05 20:39:07 +01001512 lnext!
1513 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001514 call assert_equal(l:current, bufnr())
1515
Sean Dewar4bb505e2024-03-05 20:39:07 +01001516 call assert_fails("lnfile", "E1513:")
1517 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
1518 call assert_equal(l:current, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01001519
1520 lnfile!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001521 call assert_equal(4, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001522 call assert_equal(l:last, bufnr())
1523endfunc
1524
1525" Fail :lpfile but :lpfile! is allowed
1526func Test_lpfile()
1527 CheckFeature quickfix
1528 call s:reset_all_buffers()
1529
1530 let [l:first, l:current, _] = s:make_simple_location_list()
1531 lnext!
1532
1533 call assert_fails("lpfile", "E1513:")
1534 call assert_equal(l:current, bufnr())
1535
1536 lnext! " Reset for the next test call
1537
1538 lpfile!
1539 call assert_equal(l:first, bufnr())
1540endfunc
1541
1542" Fail :lprevious but :lprevious! is allowed
1543func Test_lprevious()
1544 CheckFeature quickfix
1545 call s:reset_all_buffers()
1546
1547 let [l:first, l:middle, _] = s:make_simple_location_list()
Sean Dewar4bb505e2024-03-05 20:39:07 +01001548 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001549
Sean Dewar4bb505e2024-03-05 20:39:07 +01001550 lnext!
1551 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001552 call assert_equal(l:middle, bufnr())
1553
Sean Dewar4bb505e2024-03-05 20:39:07 +01001554 call assert_fails("lprevious", "E1513:")
1555 " Ensure the entry didn't change.
1556 call assert_equal(2, getloclist(0, #{idx: 0}).idx)
1557 call assert_equal(l:middle, bufnr())
Colin Kennedy21570352024-03-03 16:16:47 +01001558
1559 lprevious!
Sean Dewar4bb505e2024-03-05 20:39:07 +01001560 call assert_equal(1, getloclist(0, #{idx: 0}).idx)
Colin Kennedy21570352024-03-03 16:16:47 +01001561 call assert_equal(l:first, bufnr())
1562endfunc
1563
1564" Fail :lrewind but :lrewind! is allowed
1565func Test_lrewind()
1566 CheckFeature quickfix
1567 call s:reset_all_buffers()
1568
1569 let [l:first, l:middle, _] = s:make_simple_location_list()
1570 lnext!
1571
1572 call assert_fails("lrewind", "E1513:")
1573 call assert_equal(l:middle, bufnr())
1574
1575 lrewind!
1576 call assert_equal(l:first, bufnr())
1577endfunc
1578
1579" Fail :ltag but :ltag! is allowed
1580func Test_ltag()
1581 call s:reset_all_buffers()
1582
1583 set tags=Xtags
1584 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1585 \ "one\tXfile\t1",
1586 \ "three\tXfile\t3",
1587 \ "two\tXfile\t2"],
1588 \ "Xtags")
1589 call writefile(["one", "two", "three"], "Xfile")
1590 call writefile(["one"], "Xother")
1591 edit Xother
1592 execute "normal \<C-]>"
1593
1594 set winfixbuf
1595
1596 let l:current = bufnr()
1597
1598 call assert_fails("ltag one", "E1513:")
1599
1600 ltag! one
1601
1602 set tags&
1603 call delete("Xtags")
1604 call delete("Xfile")
1605 call delete("Xother")
1606endfunc
1607
1608" Fail vim.command if we try to change buffers while 'winfixbuf' is set
1609func Test_lua_command()
Sean Dewar5131f222024-03-04 19:09:26 +01001610 CheckFeature lua
Colin Kennedy21570352024-03-03 16:16:47 +01001611 call s:reset_all_buffers()
1612
1613 enew
1614 file first
1615 let l:previous = bufnr()
1616
1617 enew
1618 file second
1619 let l:current = bufnr()
1620
1621 set winfixbuf
1622
1623 call assert_fails('lua vim.command("buffer " .. ' . l:previous . ')')
1624 call assert_equal(l:current, bufnr())
1625
1626 execute 'lua vim.command("buffer! " .. ' . l:previous . ')'
1627 call assert_equal(l:previous, bufnr())
1628endfunc
1629
1630" Fail :lvimgrep but :lvimgrep! is allowed
1631func Test_lvimgrep()
1632 CheckFeature quickfix
1633 call s:reset_all_buffers()
1634
1635 edit first.unittest
1636 call append(0, ["some-search-term"])
1637 write
1638
1639 edit winfix.unittest
1640 call append(0, ["some-search-term"])
1641 write
1642 let l:current = bufnr()
1643
1644 set winfixbuf
1645
1646 edit! last.unittest
1647 call append(0, ["some-search-term"])
1648 write
1649 let l:last = bufnr()
1650
1651 buffer! winfix.unittest
1652
1653 call assert_fails("lvimgrep /some-search-term/ *.unittest", "E1513:")
1654 call assert_equal(l:current, bufnr())
1655
1656 lvimgrep! /some-search-term/ *.unittest
1657 call assert_notequal(l:current, bufnr())
1658
1659 call delete("first.unittest")
1660 call delete("winfix.unittest")
1661 call delete("last.unittest")
1662endfunc
1663
1664" Fail :lvimgrepadd but :lvimgrepadd! is allowed
1665func Test_lvimgrepadd()
1666 CheckFeature quickfix
1667 call s:reset_all_buffers()
1668
1669 edit first.unittest
1670 call append(0, ["some-search-term"])
1671 write
1672
1673 edit winfix.unittest
1674 call append(0, ["some-search-term"])
1675 write
1676 let l:current = bufnr()
1677
1678 set winfixbuf
1679
1680 edit! last.unittest
1681 call append(0, ["some-search-term"])
1682 write
1683 let l:last = bufnr()
1684
1685 buffer! winfix.unittest
1686
1687 call assert_fails("lvimgrepadd /some-search-term/ *.unittest")
1688 call assert_equal(l:current, bufnr())
1689
1690 lvimgrepadd! /some-search-term/ *.unittest
1691 call assert_notequal(l:current, bufnr())
1692
1693 call delete("first.unittest")
1694 call delete("winfix.unittest")
1695 call delete("last.unittest")
1696endfunc
1697
1698" Don't allow global marks to change the current 'winfixbuf' window
1699func Test_marks_mappings_fail()
1700 call s:reset_all_buffers()
1701
1702 let l:other = s:make_buffer_pairs()
1703 let l:current = bufnr()
1704 execute "buffer! " . l:other
1705 normal mA
1706 execute "buffer! " . l:current
1707 normal mB
1708
1709 call assert_fails("normal `A", "E1513:")
1710 call assert_equal(l:current, bufnr())
1711
1712 call assert_fails("normal 'A", "E1513:")
1713 call assert_equal(l:current, bufnr())
1714
1715 set nowinfixbuf
1716
1717 normal `A
1718 call assert_equal(l:other, bufnr())
1719endfunc
1720
1721" Allow global marks in a 'winfixbuf' window if the jump is the same buffer
1722func Test_marks_mappings_pass_intra_move()
1723 call s:reset_all_buffers()
1724
1725 let l:current = bufnr()
1726 call append(0, ["some line", "another line"])
1727 normal mA
1728 normal j
1729 normal mB
1730
1731 set winfixbuf
1732
1733 normal `A
1734 call assert_equal(l:current, bufnr())
1735endfunc
1736
1737" Fail :next but :next! is allowed
1738func Test_next()
1739 call s:reset_all_buffers()
1740
1741 let [l:first, _] = s:make_args_list()
1742 first!
1743
1744 call assert_fails("next", "E1513:")
1745 call assert_equal(l:first, bufnr())
1746
1747 next!
1748 call assert_notequal(l:first, bufnr())
1749endfunc
1750
1751" Ensure :mksession saves 'winfixbuf' details
1752func Test_mksession()
1753 CheckFeature mksession
1754 call s:reset_all_buffers()
1755
1756 set sessionoptions+=options
1757 set winfixbuf
1758
1759 mksession test_winfixbuf_Test_mksession.vim
1760
1761 call s:reset_all_buffers()
1762 let l:winfixbuf = &winfixbuf
1763 call assert_equal(0, l:winfixbuf)
1764
1765 source test_winfixbuf_Test_mksession.vim
1766
1767 let l:winfixbuf = &winfixbuf
1768 call assert_equal(1, l:winfixbuf)
1769
1770 set sessionoptions&
1771 call delete("test_winfixbuf_Test_mksession.vim")
1772endfunc
1773
1774" Allow :next if the next index is the same as the current buffer
1775func Test_next_same_buffer()
1776 call s:reset_all_buffers()
1777
1778 enew
1779 file foo
1780 enew
1781 file bar
1782 enew
1783 file fizz
1784 enew
1785 file buzz
1786 args foo foo bar fizz buzz
1787
1788 edit foo
1789 set winfixbuf
1790 let l:current = bufnr()
1791
1792 " Allow :next because the args list is `[foo] foo bar fizz buzz
1793 next
1794 call assert_equal(l:current, bufnr())
1795
1796 " Fail :next because the args list is `foo [foo] bar fizz buzz
1797 " and the next buffer would be bar, which is a different buffer
1798 call assert_fails("next", "E1513:")
1799 call assert_equal(l:current, bufnr())
1800endfunc
1801
1802" Fail to jump to a tag with g<C-]> if 'winfixbuf' is enabled
1803func Test_normal_g_ctrl_square_bracket_right()
1804 call s:reset_all_buffers()
1805
1806 set tags=Xtags
1807 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1808 \ "one\tXfile\t1",
1809 \ "three\tXfile\t3",
1810 \ "two\tXfile\t2"],
1811 \ "Xtags")
1812 call writefile(["one", "two", "three"], "Xfile")
1813 call writefile(["one"], "Xother")
1814 edit Xother
1815
1816 set winfixbuf
1817
1818 let l:current = bufnr()
1819
1820 call assert_fails("normal g\<C-]>", "E1513:")
1821 call assert_equal(l:current, bufnr())
1822
1823 set tags&
1824 call delete("Xtags")
1825 call delete("Xfile")
1826 call delete("Xother")
1827endfunc
1828
1829" Fail to jump to a tag with g<RightMouse> if 'winfixbuf' is enabled
1830func Test_normal_g_rightmouse()
1831 call s:reset_all_buffers()
1832 set mouse=n
1833
1834 set tags=Xtags
1835 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1836 \ "one\tXfile\t1",
1837 \ "three\tXfile\t3",
1838 \ "two\tXfile\t2"],
1839 \ "Xtags")
1840 call writefile(["one", "two", "three"], "Xfile")
1841 call writefile(["one"], "Xother")
1842 edit Xother
1843 execute "normal \<C-]>"
1844
1845 set winfixbuf
1846
1847 let l:current = bufnr()
1848
1849 call assert_fails("normal g\<RightMouse>", "E1513:")
1850 call assert_equal(l:current, bufnr())
1851
1852 set tags&
1853 set mouse&
1854 call delete("Xtags")
1855 call delete("Xfile")
1856 call delete("Xother")
1857endfunc
1858
1859" Fail to jump to a tag with g] if 'winfixbuf' is enabled
1860func Test_normal_g_square_bracket_right()
1861 call s:reset_all_buffers()
1862
1863 set tags=Xtags
1864 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1865 \ "one\tXfile\t1",
1866 \ "three\tXfile\t3",
1867 \ "two\tXfile\t2"],
1868 \ "Xtags")
1869 call writefile(["one", "two", "three"], "Xfile")
1870 call writefile(["one"], "Xother")
1871 edit Xother
1872
1873 set winfixbuf
1874
1875 let l:current = bufnr()
1876
1877 call assert_fails("normal g]", "E1513:")
1878 call assert_equal(l:current, bufnr())
1879
1880 set tags&
1881 call delete("Xtags")
1882 call delete("Xfile")
1883 call delete("Xother")
1884endfunc
1885
1886" Fail to jump to a tag with <C-RightMouse> if 'winfixbuf' is enabled
1887func Test_normal_ctrl_rightmouse()
1888 call s:reset_all_buffers()
1889 set mouse=n
1890
1891 set tags=Xtags
1892 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1893 \ "one\tXfile\t1",
1894 \ "three\tXfile\t3",
1895 \ "two\tXfile\t2"],
1896 \ "Xtags")
1897 call writefile(["one", "two", "three"], "Xfile")
1898 call writefile(["one"], "Xother")
1899 edit Xother
1900 execute "normal \<C-]>"
1901
1902 set winfixbuf
1903
1904 let l:current = bufnr()
1905
1906 call assert_fails("normal \<C-RightMouse>", "E1513:")
1907 call assert_equal(l:current, bufnr())
1908
1909 set tags&
1910 set mouse&
1911 call delete("Xtags")
1912 call delete("Xfile")
1913 call delete("Xother")
1914endfunc
1915
1916" Fail to jump to a tag with <C-t> if 'winfixbuf' is enabled
1917func Test_normal_ctrl_t()
1918 call s:reset_all_buffers()
1919
1920 set tags=Xtags
1921 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1922 \ "one\tXfile\t1",
1923 \ "three\tXfile\t3",
1924 \ "two\tXfile\t2"],
1925 \ "Xtags")
1926 call writefile(["one", "two", "three"], "Xfile")
1927 call writefile(["one"], "Xother")
1928 edit Xother
1929 execute "normal \<C-]>"
1930
1931 set winfixbuf
1932
1933 let l:current = bufnr()
1934
1935 call assert_fails("normal \<C-t>", "E1513:")
1936 call assert_equal(l:current, bufnr())
1937
1938 set tags&
1939 call delete("Xtags")
1940 call delete("Xfile")
1941 call delete("Xother")
1942endfunc
1943
1944" Disallow <C-^> in 'winfixbuf' windows
1945func Test_normal_ctrl_hat()
1946 call s:reset_all_buffers()
1947 clearjumps
1948
1949 enew
1950 file first
1951 let l:first = bufnr()
1952
1953 enew
1954 file current
1955 let l:current = bufnr()
1956
1957 set winfixbuf
1958
1959 call assert_fails("normal \<C-^>", "E1513:")
1960 call assert_equal(l:current, bufnr())
1961endfunc
1962
1963" Allow <C-i> in 'winfixbuf' windows if the movement stays within the buffer
1964func Test_normal_ctrl_i_pass()
1965 call s:reset_all_buffers()
1966 clearjumps
1967
1968 enew
1969 file first
1970 let l:first = bufnr()
1971
1972 enew!
1973 file current
1974 let l:current = bufnr()
1975 " Add some lines so we can populate a jumplist"
1976 call append(0, ["some line", "another line"])
1977 " Add an entry to the jump list
1978 " Go up another line
1979 normal m`
1980 normal k
1981 execute "normal \<C-o>"
1982
1983 set winfixbuf
1984
1985 let l:line = getcurpos()[1]
1986 execute "normal 1\<C-i>"
1987 call assert_notequal(l:line, getcurpos()[1])
1988endfunc
1989
1990" Disallow <C-o> in 'winfixbuf' windows if it would cause the buffer to switch
1991func Test_normal_ctrl_o_fail()
1992 call s:reset_all_buffers()
1993 clearjumps
1994
1995 enew
1996 file first
1997 let l:first = bufnr()
1998
1999 enew
2000 file current
2001 let l:current = bufnr()
2002
2003 set winfixbuf
2004
2005 call assert_fails("normal \<C-o>", "E1513:")
2006 call assert_equal(l:current, bufnr())
2007endfunc
2008
2009" Allow <C-o> in 'winfixbuf' windows if the movement stays within the buffer
2010func Test_normal_ctrl_o_pass()
2011 call s:reset_all_buffers()
2012 clearjumps
2013
2014 enew
2015 file first
2016 let l:first = bufnr()
2017
2018 enew!
2019 file current
2020 let l:current = bufnr()
2021 " Add some lines so we can populate a jumplist
2022 call append(0, ["some line", "another line"])
2023 " Add an entry to the jump list
2024 " Go up another line
2025 normal m`
2026 normal k
2027
2028 set winfixbuf
2029
2030 execute "normal \<C-o>"
2031 call assert_equal(l:current, bufnr())
2032endfunc
2033
2034" Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
2035func Test_normal_ctrl_square_bracket_right()
2036 call s:reset_all_buffers()
2037
2038 set tags=Xtags
2039 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2040 \ "one\tXfile\t1",
2041 \ "three\tXfile\t3",
2042 \ "two\tXfile\t2"],
2043 \ "Xtags")
2044 call writefile(["one", "two", "three"], "Xfile")
2045 call writefile(["one"], "Xother")
2046 edit Xother
2047
2048 set winfixbuf
2049
2050 let l:current = bufnr()
2051
2052 call assert_fails("normal \<C-]>", "E1513:")
2053 call assert_equal(l:current, bufnr())
2054
2055 set tags&
2056 call delete("Xtags")
2057 call delete("Xfile")
2058 call delete("Xother")
2059endfunc
2060
2061" Allow <C-w><C-]> with 'winfixbuf' enabled because it runs in a new, split window
2062func Test_normal_ctrl_w_ctrl_square_bracket_right()
2063 call s:reset_all_buffers()
2064
2065 set tags=Xtags
2066 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2067 \ "one\tXfile\t1",
2068 \ "three\tXfile\t3",
2069 \ "two\tXfile\t2"],
2070 \ "Xtags")
2071 call writefile(["one", "two", "three"], "Xfile")
2072 call writefile(["one"], "Xother")
2073 edit Xother
2074
2075 set winfixbuf
2076
2077 let l:current_windows = s:get_windows_count()
2078 execute "normal \<C-w>\<C-]>"
2079 call assert_equal(l:current_windows + 1, s:get_windows_count())
2080
2081 set tags&
2082 call delete("Xtags")
2083 call delete("Xfile")
2084 call delete("Xother")
2085endfunc
2086
2087" Allow <C-w>g<C-]> with 'winfixbuf' enabled because it runs in a new, split window
2088func Test_normal_ctrl_w_g_ctrl_square_bracket_right()
2089 call s:reset_all_buffers()
2090
2091 set tags=Xtags
2092 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2093 \ "one\tXfile\t1",
2094 \ "three\tXfile\t3",
2095 \ "two\tXfile\t2"],
2096 \ "Xtags")
2097 call writefile(["one", "two", "three"], "Xfile")
2098 call writefile(["one"], "Xother")
2099 edit Xother
2100
2101 set winfixbuf
2102
2103 let l:current_windows = s:get_windows_count()
2104 execute "normal \<C-w>g\<C-]>"
2105 call assert_equal(l:current_windows + 1, s:get_windows_count())
2106
2107 set tags&
2108 call delete("Xtags")
2109 call delete("Xfile")
2110 call delete("Xother")
2111endfunc
2112
2113" Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
2114func Test_normal_gt()
2115 call s:reset_all_buffers()
2116
2117 set tags=Xtags
2118 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2119 \ "one\tXfile\t1",
2120 \ "three\tXfile\t3",
2121 \ "two\tXfile\t2"],
2122 \ "Xtags")
2123 call writefile(["one", "two", "three"], "Xfile")
2124 call writefile(["one", "two", "three"], "Xother")
2125 edit Xother
2126
2127 set winfixbuf
2128
2129 let l:current = bufnr()
2130
2131 call assert_fails("normal \<C-]>", "E1513:")
2132 call assert_equal(l:current, bufnr())
2133
2134 set tags&
2135 call delete("Xtags")
2136 call delete("Xfile")
2137 call delete("Xother")
2138endfunc
2139
2140" Prevent gF from switching a 'winfixbuf' window's buffer
2141func Test_normal_gF()
2142 call s:reset_all_buffers()
2143
2144 let l:file = tempname()
2145 call append(0, [l:file])
2146 call writefile([], l:file)
2147 " Place the cursor onto the line that has `l:file`
2148 normal gg
2149 " Prevent Vim from erroring with "No write since last change @ command
2150 " line" when we try to call gF, later.
2151 set hidden
2152
2153 set winfixbuf
2154
2155 let l:buffer = bufnr()
2156
2157 call assert_fails("normal gF", "E1513:")
2158 call assert_equal(l:buffer, bufnr())
2159
2160 set nowinfixbuf
2161
2162 normal gF
2163 call assert_notequal(l:buffer, bufnr())
2164
2165 call delete(l:file)
2166endfunc
2167
2168" Prevent gf from switching a 'winfixbuf' window's buffer
2169func Test_normal_gf()
2170 call s:reset_all_buffers()
2171
2172 let l:file = tempname()
2173 call append(0, [l:file])
2174 call writefile([], l:file)
2175 " Place the cursor onto the line that has `l:file`
2176 normal gg
2177 " Prevent Vim from erroring with "No write since last change @ command
2178 " line" when we try to call gf, later.
2179 set hidden
2180
2181 set winfixbuf
2182
2183 let l:buffer = bufnr()
2184
2185 call assert_fails("normal gf", "E1513:")
2186 call assert_equal(l:buffer, bufnr())
2187
2188 set nowinfixbuf
2189
2190 normal gf
2191 call assert_notequal(l:buffer, bufnr())
2192
2193 call delete(l:file)
2194endfunc
2195
2196" Fail "goto file under the cursor" (using [f, which is the same as `:normal gf`)
2197func Test_normal_square_bracket_left_f()
2198 call s:reset_all_buffers()
2199
2200 let l:file = tempname()
2201 call append(0, [l:file])
2202 call writefile([], l:file)
2203 " Place the cursor onto the line that has `l:file`
2204 normal gg
2205 " Prevent Vim from erroring with "No write since last change @ command
2206 " line" when we try to call gf, later.
2207 set hidden
2208
2209 set winfixbuf
2210
2211 let l:buffer = bufnr()
2212
2213 call assert_fails("normal [f", "E1513:")
2214 call assert_equal(l:buffer, bufnr())
2215
2216 set nowinfixbuf
2217
2218 normal [f
2219 call assert_notequal(l:buffer, bufnr())
2220
2221 call delete(l:file)
2222endfunc
2223
2224" Fail to go to a C macro with [<C-d> if 'winfixbuf' is enabled
2225func Test_normal_square_bracket_left_ctrl_d()
2226 call s:reset_all_buffers()
2227
2228 let l:include_file = tempname() . ".h"
2229 call writefile(["min(1, 12);",
2230 \ '#include "' . l:include_file . '"'
2231 \ ],
2232 \ "main.c")
2233 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2234 edit main.c
2235 normal ]\<C-d>
2236
2237 set winfixbuf
2238
2239 let l:current = bufnr()
2240
2241 call assert_fails("normal [\<C-d>", "E1513:")
2242 call assert_equal(l:current, bufnr())
2243
2244 set nowinfixbuf
2245
2246 execute "normal [\<C-d>"
2247 call assert_notequal(l:current, bufnr())
2248
2249 call delete("main.c")
2250 call delete(l:include_file)
2251endfunc
2252
2253" Fail to go to a C macro with ]<C-d> if 'winfixbuf' is enabled
2254func Test_normal_square_bracket_right_ctrl_d()
2255 call s:reset_all_buffers()
2256
2257 let l:include_file = tempname() . ".h"
2258 call writefile(["min(1, 12);",
2259 \ '#include "' . l:include_file . '"'
2260 \ ],
2261 \ "main.c")
2262 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2263 edit main.c
2264
2265 set winfixbuf
2266
2267 let l:current = bufnr()
2268
2269 call assert_fails("normal ]\<C-d>", "E1513:")
2270 call assert_equal(l:current, bufnr())
2271
2272 set nowinfixbuf
2273
2274 execute "normal ]\<C-d>"
2275 call assert_notequal(l:current, bufnr())
2276
2277 call delete("main.c")
2278 call delete(l:include_file)
2279endfunc
2280
2281" Fail to go to a C macro with [<C-i> if 'winfixbuf' is enabled
2282func Test_normal_square_bracket_left_ctrl_i()
2283 call s:reset_all_buffers()
2284
2285 let l:include_file = tempname() . ".h"
2286 call writefile(['#include "' . l:include_file . '"',
2287 \ "min(1, 12);",
2288 \ ],
2289 \ "main.c")
2290 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2291 edit main.c
2292 " Move to the line with `min(1, 12);` on it"
2293 normal j
2294
2295 set define=^\\s*#\\s*define
2296 set include=^\\s*#\\s*include
2297 set path=.,/usr/include,,
2298
2299 let l:current = bufnr()
2300
2301 set winfixbuf
2302
2303 call assert_fails("normal [\<C-i>", "E1513:")
2304
2305 set nowinfixbuf
2306
2307 execute "normal [\<C-i>"
2308 call assert_notequal(l:current, bufnr())
2309
2310 set define&
2311 set include&
2312 set path&
2313 call delete("main.c")
2314 call delete(l:include_file)
2315endfunc
2316
2317" Fail to go to a C macro with ]<C-i> if 'winfixbuf' is enabled
2318func Test_normal_square_bracket_right_ctrl_i()
2319 call s:reset_all_buffers()
2320
2321 let l:include_file = tempname() . ".h"
2322 call writefile(["min(1, 12);",
2323 \ '#include "' . l:include_file . '"'
2324 \ ],
2325 \ "main.c")
2326 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2327 edit main.c
2328
2329 set winfixbuf
2330
2331 set define=^\\s*#\\s*define
2332 set include=^\\s*#\\s*include
2333 set path=.,/usr/include,,
2334
2335 let l:current = bufnr()
2336
2337 call assert_fails("normal ]\<C-i>", "E1513:")
2338 call assert_equal(l:current, bufnr())
2339
2340 set nowinfixbuf
2341
2342 execute "normal ]\<C-i>"
2343 call assert_notequal(l:current, bufnr())
2344
2345 set define&
2346 set include&
2347 set path&
2348 call delete("main.c")
2349 call delete(l:include_file)
2350endfunc
2351
2352" Fail "goto file under the cursor" (using ]f, which is the same as `:normal gf`)
2353func Test_normal_square_bracket_right_f()
2354 call s:reset_all_buffers()
2355
2356 let l:file = tempname()
2357 call append(0, [l:file])
2358 call writefile([], l:file)
2359 " Place the cursor onto the line that has `l:file`
2360 normal gg
2361 " Prevent Vim from erroring with "No write since last change @ command
2362 " line" when we try to call gf, later.
2363 set hidden
2364
2365 set winfixbuf
2366
2367 let l:buffer = bufnr()
2368
2369 call assert_fails("normal ]f", "E1513:")
2370 call assert_equal(l:buffer, bufnr())
2371
2372 set nowinfixbuf
2373
2374 normal ]f
2375 call assert_notequal(l:buffer, bufnr())
2376
2377 call delete(l:file)
2378endfunc
2379
2380" Fail to jump to a tag with v<C-]> if 'winfixbuf' is enabled
2381func Test_normal_v_ctrl_square_bracket_right()
2382 call s:reset_all_buffers()
2383
2384 set tags=Xtags
2385 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2386 \ "one\tXfile\t1",
2387 \ "three\tXfile\t3",
2388 \ "two\tXfile\t2"],
2389 \ "Xtags")
2390 call writefile(["one", "two", "three"], "Xfile")
2391 call writefile(["one"], "Xother")
2392 edit Xother
2393
2394 set winfixbuf
2395
2396 let l:current = bufnr()
2397
2398 call assert_fails("normal v\<C-]>", "E1513:")
2399 call assert_equal(l:current, bufnr())
2400
2401 set tags&
2402 call delete("Xtags")
2403 call delete("Xfile")
2404 call delete("Xother")
2405endfunc
2406
2407" Fail to jump to a tag with vg<C-]> if 'winfixbuf' is enabled
2408func Test_normal_v_g_ctrl_square_bracket_right()
2409 call s:reset_all_buffers()
2410
2411 set tags=Xtags
2412 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2413 \ "one\tXfile\t1",
2414 \ "three\tXfile\t3",
2415 \ "two\tXfile\t2"],
2416 \ "Xtags")
2417 call writefile(["one", "two", "three"], "Xfile")
2418 call writefile(["one"], "Xother")
2419 edit Xother
2420
2421 set winfixbuf
2422
2423 let l:current = bufnr()
2424
2425 call assert_fails("normal vg\<C-]>", "E1513:")
2426 call assert_equal(l:current, bufnr())
2427
2428 set tags&
2429 call delete("Xtags")
2430 call delete("Xfile")
2431 call delete("Xother")
2432endfunc
2433
2434" Allow :pedit because, unlike :edit, it uses a separate window
2435func Test_pedit()
2436 call s:reset_all_buffers()
2437
2438 let l:other = s:make_buffer_pairs()
2439
2440 pedit other
2441
2442 execute "normal \<C-w>w"
2443 call assert_equal(l:other, bufnr())
2444endfunc
2445
2446" Fail :pop but :pop! is allowed
2447func Test_pop()
2448 call s:reset_all_buffers()
2449
2450 set tags=Xtags
2451 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2452 \ "thesame\tXfile\t1;\"\td\tfile:",
2453 \ "thesame\tXfile\t2;\"\td\tfile:",
2454 \ "thesame\tXfile\t3;\"\td\tfile:",
2455 \ ],
2456 \ "Xtags")
2457 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2458 call writefile(["thesame one"], "Xother")
2459 edit Xother
2460
2461 tag thesame
2462
2463 set winfixbuf
2464
2465 let l:current = bufnr()
2466
2467 call assert_fails("pop", "E1513:")
2468 call assert_equal(l:current, bufnr())
2469
2470 pop!
2471 call assert_notequal(l:current, bufnr())
2472
2473 set tags&
2474 call delete("Xtags")
2475 call delete("Xfile")
2476 call delete("Xother")
2477endfunc
2478
2479" Fail :previous but :previous! is allowed
2480func Test_previous()
2481 call s:reset_all_buffers()
2482
2483 let [l:first, _] = s:make_args_list()
2484 next!
2485
2486 call assert_fails("previous", "E1513:")
2487 call assert_notequal(l:first, bufnr())
2488
2489 previous!
2490 call assert_equal(l:first, bufnr())
2491endfunc
2492
2493" Fail pydo if it changes a window with 'winfixbuf' is set
2494func Test_python_pydo()
2495 CheckFeature pythonx
2496 call s:reset_all_buffers()
2497
2498 enew
2499 file first
2500 let g:_previous_buffer = bufnr()
2501
2502 enew
2503 file second
2504
2505 set winfixbuf
2506
2507 python << EOF
2508import vim
2509
2510def test_winfixbuf_Test_python_pydo_set_buffer():
2511 buffer = vim.vars['_previous_buffer']
2512 vim.current.buffer = vim.buffers[buffer]
2513EOF
2514
2515 try
2516 pydo test_winfixbuf_Test_python_pydo_set_buffer()
2517 catch /Vim(pydo):vim.error: Vim:E1513: Cannot edit buffer. 'winfixbuf' is enabled/
2518 let l:caught = 1
2519 endtry
2520
2521 call assert_equal(1, l:caught)
2522
2523 unlet g:_previous_buffer
2524endfunc
2525
2526" Fail pyfile if it changes a window with 'winfixbuf' is set
2527func Test_python_pyfile()
2528 CheckFeature pythonx
2529 call s:reset_all_buffers()
2530
2531 enew
2532 file first
2533 let g:_previous_buffer = bufnr()
2534
2535 enew
2536 file second
2537
2538 set winfixbuf
2539
2540 call writefile(["import vim",
2541 \ "buffer = vim.vars['_previous_buffer']",
2542 \ "vim.current.buffer = vim.buffers[buffer]",
2543 \ ],
2544 \ "file.py")
2545
2546 try
2547 pyfile file.py
2548 catch /Vim(pyfile):vim.error: Vim:E1513: Cannot edit buffer. 'winfixbuf' is enabled/
2549 let l:caught = 1
2550 endtry
2551
2552 call assert_equal(1, l:caught)
2553
2554 call delete("file.py")
2555 unlet g:_previous_buffer
2556endfunc
2557
2558" Fail vim.current.buffer if 'winfixbuf' is set
2559func Test_python_vim_current_buffer()
2560 CheckFeature pythonx
2561 call s:reset_all_buffers()
2562
2563 enew
2564 file first
2565 let g:_previous_buffer = bufnr()
2566
2567 enew
2568 file second
2569
2570 let l:caught = 0
2571
2572 set winfixbuf
2573
2574 try
2575 python << EOF
2576import vim
2577
2578buffer = vim.vars["_previous_buffer"]
2579vim.current.buffer = vim.buffers[buffer]
2580EOF
2581 catch /Vim(python):vim\.error: Vim:E1513: Cannot edit buffer. 'winfixbuf' is enabled/
2582 let l:caught = 1
2583 endtry
2584
2585 call assert_equal(1, l:caught)
2586 unlet g:_previous_buffer
2587endfunc
2588
2589" Ensure remapping to a disabled action still triggers failures
2590func Test_remap_key_fail()
2591 call s:reset_all_buffers()
2592
2593 enew
2594 file first
2595 let l:first = bufnr()
2596
2597 enew
2598 file current
2599 let l:current = bufnr()
2600
2601 set winfixbuf
2602
2603 nnoremap g <C-^>
2604
2605 call assert_fails("normal g", "E1513:")
2606 call assert_equal(l:current, bufnr())
2607
2608 nunmap g
2609endfunc
2610
2611" Ensure remapping a disabled key to something valid does trigger any failures
2612func Test_remap_key_pass()
2613 call s:reset_all_buffers()
2614
2615 enew
2616 file first
2617 let l:first = bufnr()
2618
2619 enew
2620 file current
2621 let l:current = bufnr()
2622
2623 set winfixbuf
2624
2625 call assert_fails("normal \<C-^>", "E1513:")
2626 call assert_equal(l:current, bufnr())
2627
2628 " Disallow <C-^> by default but allow it if the command does something else
2629 nnoremap <C-^> :echo "hello!"
2630
2631 execute "normal \<C-^>"
2632 call assert_equal(l:current, bufnr())
2633
2634 nunmap <C-^>
2635endfunc
2636
2637" Fail :rewind but :rewind! is allowed
2638func Test_rewind()
2639 call s:reset_all_buffers()
2640
2641 let [l:first, _] = s:make_args_list()
2642 next!
2643
2644 call assert_fails("rewind", "E1513:")
2645 call assert_notequal(l:first, bufnr())
2646
2647 rewind!
2648 call assert_equal(l:first, bufnr())
2649endfunc
2650
2651" Allow :sblast because it opens the buffer in a new, split window
2652func Test_sblast()
2653 call s:reset_all_buffers()
2654
2655 let l:other = s:make_buffer_pairs(1)
2656 bfirst!
2657 let l:current = bufnr()
2658
2659 sblast
2660 call assert_equal(l:other, bufnr())
2661endfunc
2662
2663" Fail :sbprevious but :sbprevious! is allowed
2664func Test_sbprevious()
2665 call s:reset_all_buffers()
2666
2667 let l:other = s:make_buffer_pairs()
2668 let l:current = bufnr()
2669
2670 sbprevious
2671 call assert_equal(l:other, bufnr())
2672endfunc
2673
2674" Make sure 'winfixbuf' can be set using 'winfixbuf' or 'wfb'
2675func Test_short_option()
2676 call s:reset_all_buffers()
2677
2678 call s:make_buffer_pairs()
2679
2680 set winfixbuf
2681 call assert_fails("edit something_else", "E1513")
2682
2683 set nowinfixbuf
2684 set wfb
2685 call assert_fails("edit another_place", "E1513")
2686
2687 set nowfb
2688 edit last_place
2689endfunc
2690
2691" Allow :snext because it makes a new window
2692func Test_snext()
2693 call s:reset_all_buffers()
2694
2695 let [l:first, _] = s:make_args_list()
2696 first!
2697
2698 let l:current_window = win_getid()
2699
2700 snext
2701 call assert_notequal(l:current_window, win_getid())
2702 call assert_notequal(l:first, bufnr())
2703endfunc
2704
2705" Ensure the first has 'winfixbuf' and a new split window is 'nowinfixbuf'
2706func Test_split_window()
2707 call s:reset_all_buffers()
2708
2709 split
2710 execute "normal \<C-w>j"
2711
2712 set winfixbuf
2713
2714 let l:winfix_window_1 = win_getid()
2715 vsplit
2716 let l:winfix_window_2 = win_getid()
2717
2718 call assert_equal(1, getwinvar(l:winfix_window_1, "&winfixbuf"))
2719 call assert_equal(0, getwinvar(l:winfix_window_2, "&winfixbuf"))
2720endfunc
2721
2722" Fail :tNext but :tNext! is allowed
2723func Test_tNext()
2724 call s:reset_all_buffers()
2725
2726 set tags=Xtags
2727 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2728 \ "thesame\tXfile\t1;\"\td\tfile:",
2729 \ "thesame\tXfile\t2;\"\td\tfile:",
2730 \ "thesame\tXfile\t3;\"\td\tfile:",
2731 \ ],
2732 \ "Xtags")
2733 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2734 call writefile(["thesame one"], "Xother")
2735 edit Xother
2736
2737 tag thesame
2738 execute "normal \<C-^>"
2739 tnext!
2740
2741 set winfixbuf
2742
2743 let l:current = bufnr()
2744
2745 call assert_fails("tNext", "E1513:")
2746 call assert_equal(l:current, bufnr())
2747
2748 tNext!
2749
2750 set tags&
2751 call delete("Xtags")
2752 call delete("Xfile")
2753 call delete("Xother")
2754endfunc
2755
2756" Call :tabdo and choose the next available 'nowinfixbuf' window.
2757func Test_tabdo_choose_available_window()
2758 call s:reset_all_buffers()
2759
2760 let [l:first, _] = s:make_args_list()
2761
2762 " Make a split window that is 'nowinfixbuf' but make it the second-to-last
2763 " window so that :tabdo will first try the 'winfixbuf' window, pass over it,
2764 " and prefer the other 'nowinfixbuf' window, instead.
2765 "
2766 " +-------------------+
2767 " | 'nowinfixbuf' |
2768 " +-------------------+
2769 " | 'winfixbuf' | <-- Cursor is here
2770 " +-------------------+
2771 split
2772 let l:nowinfixbuf_window = win_getid()
2773 " Move to the 'winfixbuf' window now
2774 execute "normal \<C-w>j"
2775 let l:winfixbuf_window = win_getid()
2776
2777 let l:expected_windows = s:get_windows_count()
2778 tabdo echo ''
2779 call assert_equal(l:nowinfixbuf_window, win_getid())
2780 call assert_equal(l:first, bufnr())
2781 call assert_equal(l:expected_windows, s:get_windows_count())
2782endfunc
2783
2784" Call :tabdo and create a new split window if all available windows are 'winfixbuf'.
2785func Test_tabdo_make_new_window()
2786 call s:reset_all_buffers()
2787
2788 let [l:first, _] = s:make_buffers_list()
2789 execute "buffer! " . l:first
2790
2791 let l:current = win_getid()
2792 let l:current_windows = s:get_windows_count()
2793
2794 tabdo echo ''
2795 call assert_notequal(l:current, win_getid())
2796 call assert_equal(l:first, bufnr())
2797 execute "normal \<C-w>j"
2798 call assert_equal(l:first, bufnr())
2799 call assert_equal(l:current_windows + 1, s:get_windows_count())
2800endfunc
2801
2802" Fail :tag but :tag! is allowed
2803func Test_tag()
2804 call s:reset_all_buffers()
2805
2806 set tags=Xtags
2807 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2808 \ "one\tXfile\t1",
2809 \ "three\tXfile\t3",
2810 \ "two\tXfile\t2"],
2811 \ "Xtags")
2812 call writefile(["one", "two", "three"], "Xfile")
2813 call writefile(["one"], "Xother")
2814 edit Xother
2815
2816 set winfixbuf
2817
2818 let l:current = bufnr()
2819
2820 call assert_fails("tag one", "E1513:")
2821 call assert_equal(l:current, bufnr())
2822
2823 tag! one
2824 call assert_notequal(l:current, bufnr())
2825
2826 set tags&
2827 call delete("Xtags")
2828 call delete("Xfile")
2829 call delete("Xother")
2830endfunc
2831
2832
2833" Fail :tfirst but :tfirst! is allowed
2834func Test_tfirst()
2835 call s:reset_all_buffers()
2836
2837 set tags=Xtags
2838 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2839 \ "one\tXfile\t1",
2840 \ "three\tXfile\t3",
2841 \ "two\tXfile\t2"],
2842 \ "Xtags")
2843 call writefile(["one", "two", "three"], "Xfile")
2844 call writefile(["one"], "Xother")
2845 edit Xother
2846
2847 set winfixbuf
2848
2849 let l:current = bufnr()
2850
2851 call assert_fails("tfirst", "E1513:")
2852 call assert_equal(l:current, bufnr())
2853
2854 tfirst!
2855 call assert_notequal(l:current, bufnr())
2856
2857 set tags&
2858 call delete("Xtags")
2859 call delete("Xfile")
2860 call delete("Xother")
2861endfunc
2862
2863" Fail :tjump but :tjump! is allowed
2864func Test_tjump()
2865 call s:reset_all_buffers()
2866
2867 set tags=Xtags
2868 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2869 \ "one\tXfile\t1",
2870 \ "three\tXfile\t3",
2871 \ "two\tXfile\t2"],
2872 \ "Xtags")
2873 call writefile(["one", "two", "three"], "Xfile")
2874 call writefile(["one"], "Xother")
2875 edit Xother
2876
2877 set winfixbuf
2878
2879 let l:current = bufnr()
2880
2881 call assert_fails("tjump one", "E1513:")
2882 call assert_equal(l:current, bufnr())
2883
2884 tjump! one
2885 call assert_notequal(l:current, bufnr())
2886
2887 set tags&
2888 call delete("Xtags")
2889 call delete("Xfile")
2890 call delete("Xother")
2891endfunc
2892
2893" Fail :tlast but :tlast! is allowed
2894func Test_tlast()
2895 call s:reset_all_buffers()
2896
2897 set tags=Xtags
2898 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2899 \ "one\tXfile\t1",
2900 \ "three\tXfile\t3",
2901 \ "two\tXfile\t2"],
2902 \ "Xtags")
2903 call writefile(["one", "two", "three"], "Xfile")
2904 edit Xfile
2905 tjump one
2906 edit Xfile
2907
2908 set winfixbuf
2909
2910 let l:current = bufnr()
2911
2912 call assert_fails("tlast", "E1513:")
2913 call assert_equal(l:current, bufnr())
2914
2915 tlast!
2916 call assert_equal(l:current, bufnr())
2917
2918 set tags&
2919 call delete("Xtags")
2920 call delete("Xfile")
2921endfunc
2922
2923" Fail :tnext but :tnext! is allowed
2924func Test_tnext()
2925 call s:reset_all_buffers()
2926
2927 set tags=Xtags
2928 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2929 \ "thesame\tXfile\t1;\"\td\tfile:",
2930 \ "thesame\tXfile\t2;\"\td\tfile:",
2931 \ "thesame\tXfile\t3;\"\td\tfile:",
2932 \ ],
2933 \ "Xtags")
2934 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2935 call writefile(["thesame one"], "Xother")
2936 edit Xother
2937
2938 tag thesame
2939 execute "normal \<C-^>"
2940
2941 set winfixbuf
2942
2943 let l:current = bufnr()
2944
2945 call assert_fails("tnext", "E1513:")
2946 call assert_equal(l:current, bufnr())
2947
2948 tnext!
2949 call assert_notequal(l:current, bufnr())
2950
2951 set tags&
2952 call delete("Xtags")
2953 call delete("Xfile")
2954 call delete("Xother")
2955endfunc
2956
2957" Fail :tprevious but :tprevious! is allowed
2958func Test_tprevious()
2959 call s:reset_all_buffers()
2960
2961 set tags=Xtags
2962 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2963 \ "thesame\tXfile\t1;\"\td\tfile:",
2964 \ "thesame\tXfile\t2;\"\td\tfile:",
2965 \ "thesame\tXfile\t3;\"\td\tfile:",
2966 \ ],
2967 \ "Xtags")
2968 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2969 call writefile(["thesame one"], "Xother")
2970 edit Xother
2971
2972 tag thesame
2973 execute "normal \<C-^>"
2974 tnext!
2975
2976 set winfixbuf
2977
2978 let l:current = bufnr()
2979
2980 call assert_fails("tprevious", "E1513:")
2981 call assert_equal(l:current, bufnr())
2982
2983 tprevious!
2984
2985 set tags&
2986 call delete("Xtags")
2987 call delete("Xfile")
2988 call delete("Xother")
2989endfunc
2990
2991" Fail :view but :view! is allowed
2992func Test_view()
2993 call s:reset_all_buffers()
2994
2995 let l:other = s:make_buffer_pairs()
2996 let l:current = bufnr()
2997
2998 call assert_fails("view other", "E1513:")
2999 call assert_equal(l:current, bufnr())
3000
3001 view! other
3002 call assert_equal(l:other, bufnr())
3003endfunc
3004
3005" Fail :visual but :visual! is allowed
3006func Test_visual()
3007 call s:reset_all_buffers()
3008
3009 let l:other = s:make_buffer_pairs()
3010 let l:current = bufnr()
3011
3012 call assert_fails("visual other", "E1513:")
3013 call assert_equal(l:current, bufnr())
3014
3015 visual! other
3016 call assert_equal(l:other, bufnr())
3017endfunc
3018
3019" Fail :vimgrep but :vimgrep! is allowed
3020func Test_vimgrep()
3021 CheckFeature quickfix
3022 call s:reset_all_buffers()
3023
3024 edit first.unittest
3025 call append(0, ["some-search-term"])
3026 write
3027
3028 edit winfix.unittest
3029 call append(0, ["some-search-term"])
3030 write
3031 let l:current = bufnr()
3032
3033 set winfixbuf
3034
3035 edit! last.unittest
3036 call append(0, ["some-search-term"])
3037 write
3038 let l:last = bufnr()
3039
3040 buffer! winfix.unittest
3041
3042 call assert_fails("vimgrep /some-search-term/ *.unittest")
3043 call assert_equal(l:current, bufnr())
3044
3045 " Don't error and also do swap to the first match because ! was included
3046 vimgrep! /some-search-term/ *.unittest
3047 call assert_notequal(l:current, bufnr())
3048
3049 call delete("first.unittest")
3050 call delete("winfix.unittest")
3051 call delete("last.unittest")
3052endfunc
3053
3054" Fail :vimgrepadd but ::vimgrepadd! is allowed
3055func Test_vimgrepadd()
3056 CheckFeature quickfix
3057 call s:reset_all_buffers()
3058
3059 edit first.unittest
3060 call append(0, ["some-search-term"])
3061 write
3062
3063 edit winfix.unittest
3064 call append(0, ["some-search-term"])
3065 write
3066 let l:current = bufnr()
3067
3068 set winfixbuf
3069
3070 edit! last.unittest
3071 call append(0, ["some-search-term"])
3072 write
3073 let l:last = bufnr()
3074
3075 buffer! winfix.unittest
3076
3077 call assert_fails("vimgrepadd /some-search-term/ *.unittest")
3078 call assert_equal(l:current, bufnr())
3079
3080 vimgrepadd! /some-search-term/ *.unittest
3081 call assert_notequal(l:current, bufnr())
3082 call delete("first.unittest")
3083 call delete("winfix.unittest")
3084 call delete("last.unittest")
3085endfunc
3086
3087" Fail :wNext but :wNext! is allowed
3088func Test_wNext()
3089 call s:reset_all_buffers()
3090
3091 let [l:first, _] = s:make_args_list()
3092 next!
3093
3094 call assert_fails("wNext", "E1513:")
3095 call assert_notequal(l:first, bufnr())
3096
3097 wNext!
3098 call assert_equal(l:first, bufnr())
3099
3100 call delete("first")
3101 call delete("middle")
3102 call delete("last")
3103endfunc
3104
3105" Allow :windo unless `:windo foo` would change a 'winfixbuf' window's buffer
3106func Test_windo()
3107 call s:reset_all_buffers()
3108
3109 let l:current_window = win_getid()
3110 let l:current_buffer = bufnr()
3111 split
3112 enew
3113 file some_other_buffer
3114
3115 set winfixbuf
3116
3117 let l:current = win_getid()
3118
3119 windo echo ''
3120 call assert_equal(l:current_window, win_getid())
3121
3122 call assert_fails('execute "windo buffer ' . l:current_buffer . '"', "E1513:")
3123 call assert_equal(l:current_window, win_getid())
3124
3125 execute "windo buffer! " . l:current_buffer
3126 call assert_equal(l:current_window, win_getid())
3127endfunc
3128
3129" Fail :wnext but :wnext! is allowed
3130func Test_wnext()
3131 call s:reset_all_buffers()
3132
3133 let [_, l:last] = s:make_args_list()
3134 next!
3135
3136 call assert_fails("wnext", "E1513:")
3137 call assert_notequal(l:last, bufnr())
3138
3139 wnext!
3140 call assert_equal(l:last, bufnr())
3141
3142 call delete("first")
3143 call delete("middle")
3144 call delete("last")
3145endfunc
3146
3147" Fail :wprevious but :wprevious! is allowed
3148func Test_wprevious()
3149 call s:reset_all_buffers()
3150
3151 let [l:first, _] = s:make_args_list()
3152 next!
3153
3154 call assert_fails("wprevious", "E1513:")
3155 call assert_notequal(l:first, bufnr())
3156
3157 wprevious!
3158 call assert_equal(l:first, bufnr())
3159
3160 call delete("first")
3161 call delete("middle")
3162 call delete("last")
3163endfunc
Sean Dewar5131f222024-03-04 19:09:26 +01003164
3165func Test_quickfix_switchbuf_invalid_prevwin()
3166 call s:reset_all_buffers()
3167
Sean Dewar4bb505e2024-03-05 20:39:07 +01003168 call s:make_simple_quickfix()
3169 call assert_equal(1, getqflist(#{idx: 0}).idx)
Sean Dewar5131f222024-03-04 19:09:26 +01003170
3171 set switchbuf=uselast
3172 split
3173 copen
3174 execute winnr('#') 'quit'
Sean Dewar4bb505e2024-03-05 20:39:07 +01003175 call assert_equal(2, winnr('$'))
Sean Dewar5131f222024-03-04 19:09:26 +01003176
Sean Dewar4bb505e2024-03-05 20:39:07 +01003177 cnext " Would've triggered a null pointer member access
3178 call assert_equal(2, getqflist(#{idx: 0}).idx)
3179
Sean Dewar5131f222024-03-04 19:09:26 +01003180 set switchbuf&
3181endfunc
3182
Sean Dewar4bb505e2024-03-05 20:39:07 +01003183func Test_listdo_goto_prevwin()
3184 call s:reset_all_buffers()
3185 call s:make_buffers_list()
3186
3187 new
3188 call assert_equal(0, &winfixbuf)
3189 wincmd p
3190 call assert_equal(1, &winfixbuf)
3191 call assert_notequal(bufnr(), bufnr('#'))
3192
3193 augroup ListDoGotoPrevwin
3194 au!
3195 au BufLeave * let s:triggered = 1
3196 \| call assert_equal(bufnr(), winbufnr(winnr()))
3197 augroup END
3198 " Should correctly switch to the window without 'winfixbuf', and curbuf should
3199 " be consistent with curwin->w_buffer for autocommands.
3200 bufdo "
3201 call assert_equal(0, &winfixbuf)
3202 call assert_equal(1, s:triggered)
3203 unlet! s:triggered
3204 au! ListDoGotoPrevwin
3205
3206 set winfixbuf
3207 wincmd p
3208 call assert_equal(2, winnr('$'))
3209 " Both curwin and prevwin have 'winfixbuf' set, so should split a new window
3210 " without it set.
3211 bufdo "
3212 call assert_equal(0, &winfixbuf)
3213 call assert_equal(3, winnr('$'))
3214
3215 quit
3216 call assert_equal(2, winnr('$'))
3217 call assert_equal(1, &winfixbuf)
3218 augroup ListDoGotoPrevwin
3219 au!
3220 au WinEnter * ++once set winfixbuf
3221 augroup END
3222 " Same as before, but naughty autocommands set 'winfixbuf' for the new window.
3223 " :bufdo should give up in this case.
3224 call assert_fails('bufdo "', 'E1513:')
3225
3226 au! ListDoGotoPrevwin
3227 augroup! ListDoGotoPrevwin
3228endfunc
3229
3230func Test_quickfix_changed_split_failed()
3231 call s:reset_all_buffers()
3232
3233 call s:make_simple_quickfix()
3234 call assert_equal(1, winnr('$'))
3235
3236 " Quickfix code will open a split in an attempt to get a 'nowinfixbuf' window
3237 " to switch buffers in. Interfere with things by setting 'winfixbuf' in it.
3238 augroup QfChanged
3239 au!
3240 au WinEnter * ++once call assert_equal(2, winnr('$'))
3241 \| set winfixbuf | call setqflist([], 'f')
3242 augroup END
3243 call assert_fails('cnext', ['E1513:', 'E925:'])
3244 " Check that the split was automatically closed.
3245 call assert_equal(1, winnr('$'))
3246
3247 au! QfChanged
3248 augroup! QfChanged
3249endfunc
3250
Sean Dewar5131f222024-03-04 19:09:26 +01003251" vim: shiftwidth=2 sts=2 expandtab