blob: 0b15983932ada2ba92eb4b5779847f5897d94bfd [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()
1257 lnext!
1258
1259 call assert_fails("lNext", "E1513:")
1260 call assert_equal(l:middle, bufnr())
1261
1262 lnext! " Reset for the next test
1263
1264 lNext!
1265 call assert_equal(l:first, bufnr())
1266endfunc
1267
1268" Fail :lNfile but :lNfile! is allowed
1269func Test_lNfile()
1270 CheckFeature quickfix
1271 call s:reset_all_buffers()
1272
1273 let [l:first, l:current, _] = s:make_simple_location_list()
1274 lnext!
1275
1276 call assert_fails("lNfile", "E1513:")
1277 call assert_equal(l:current, bufnr())
1278
1279 lnext! " Reset for the next test
1280
1281 lNfile!
1282 call assert_equal(l:first, bufnr())
1283endfunc
1284
1285" Allow :laddexpr because it doesn't change the current buffer
1286func Test_laddexpr()
1287 CheckFeature quickfix
1288 call s:reset_all_buffers()
1289
1290 let l:file_path = tempname()
1291 call writefile(["Error - bad-thing-found"], l:file_path)
1292 execute "edit " . l:file_path
1293 let l:file_buffer = bufnr()
1294 let l:current = bufnr()
1295
1296 edit first.unittest
1297 call append(0, ["some-search-term bad-thing-found"])
1298
1299 edit! other.unittest
1300
1301 set winfixbuf
1302
1303 execute "buffer! " . l:file_buffer
1304
1305 execute 'laddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")'
1306 call assert_equal(l:current, bufnr())
1307
1308 call delete(l:file_path)
1309endfunc
1310
1311" Fail :last but :last! is allowed
1312func Test_last()
1313 call s:reset_all_buffers()
1314
1315 let [_, l:last] = s:make_args_list()
1316 next!
1317
1318 call assert_fails("last", "E1513:")
1319 call assert_notequal(l:last, bufnr())
1320
1321 last!
1322 call assert_equal(l:last, bufnr())
1323endfunc
1324
1325" Fail :lbuffer but :lbuffer! is allowed
1326func Test_lbuffer()
1327 CheckFeature quickfix
1328 call s:reset_all_buffers()
1329
1330 let l:file_path = tempname()
1331 call writefile(["first.unittest:1:Error - bad-thing-found"], l:file_path)
1332 execute "edit " . l:file_path
1333 let l:file_buffer = bufnr()
1334 let l:current = bufnr()
1335
1336 edit first.unittest
1337 call append(0, ["some-search-term bad-thing-found"])
1338
1339 edit! other.unittest
1340
1341 set winfixbuf
1342
1343 execute "buffer! " . l:file_buffer
1344
1345 call assert_fails("lbuffer " . l:file_buffer)
1346 call assert_equal(l:current, bufnr())
1347
1348 execute "lbuffer! " . l:file_buffer
1349 call assert_equal("first.unittest", expand("%:t"))
1350
1351 call delete(l:file_path)
1352endfunc
1353
1354" Fail :ldo but :ldo! is allowed
1355func Test_ldo()
1356 CheckFeature quickfix
1357 call s:reset_all_buffers()
1358
1359 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1360 lnext!
1361
1362 call assert_fails('execute "ldo buffer ' . l:first . '"', "E1513:")
1363 call assert_equal(l:middle, bufnr())
1364 execute "ldo! buffer " . l:first
1365 call assert_notequal(l:last, bufnr())
1366endfunc
1367
1368" Fail :lfdo but :lfdo! is allowed
1369func Test_lexpr()
1370 CheckFeature quickfix
1371 call s:reset_all_buffers()
1372
1373 let l:file = tempname()
1374 let l:entry = '["' . l:file . ':1:bar"]'
1375 let l:current = bufnr()
1376
1377 set winfixbuf
1378
1379 call assert_fails("lexpr " . l:entry)
1380 call assert_equal(l:current, bufnr())
1381
1382 execute "lexpr! " . l:entry
1383 call assert_equal(fnamemodify(l:file, ":t"), expand("%:t"))
1384endfunc
1385
1386" Fail :lfdo but :lfdo! is allowed
1387func Test_lfdo()
1388 CheckFeature quickfix
1389 call s:reset_all_buffers()
1390
1391 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1392 lnext!
1393
1394 call assert_fails('execute "lfdo buffer ' . l:first . '"', "E1513:")
1395 call assert_equal(l:middle, bufnr())
1396 execute "lfdo! buffer " . l:first
1397 call assert_notequal(l:last, bufnr())
1398endfunc
1399
1400" Fail :lfile but :lfile! is allowed
1401func Test_lfile()
1402 CheckFeature quickfix
1403 call s:reset_all_buffers()
1404
1405 edit first.unittest
1406 call append(0, ["some-search-term bad-thing-found"])
1407 write
1408 let l:first = bufnr()
1409
1410 edit! second.unittest
1411 call append(0, ["some-search-term"])
1412 write
1413
1414 let l:file = tempname()
1415 call writefile(["first.unittest:1:Error - bad-thing-found was detected"], l:file)
1416
1417 let l:current = bufnr()
1418
1419 set winfixbuf
1420
1421 call assert_fails(":lfile " . l:file)
1422 call assert_equal(l:current, bufnr())
1423
1424 execute ":lfile! " . l:file
1425 call assert_equal(l:first, bufnr())
1426
1427 call delete(l:file)
1428 call delete("first.unittest")
1429 call delete("second.unittest")
1430endfunc
1431
1432" Fail :ll but :ll! is allowed
1433func Test_ll()
1434 CheckFeature quickfix
1435 call s:reset_all_buffers()
1436
1437 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1438 lopen
1439 lfirst!
1440 execute "normal \<C-w>j"
1441 normal j
1442
1443 call assert_fails(".ll", "E1513:")
1444 execute "normal \<C-w>k"
1445 call assert_equal(l:first, bufnr())
1446 execute "normal \<C-w>j"
1447 .ll!
1448 execute "normal \<C-w>k"
1449 call assert_equal(l:middle, bufnr())
1450endfunc
1451
1452" Fail :llast but :llast! is allowed
1453func Test_llast()
1454 CheckFeature quickfix
1455 call s:reset_all_buffers()
1456
1457 let [l:first, _, l:last] = s:make_simple_location_list()
1458 lfirst!
1459
1460 call assert_fails("llast", "E1513:")
1461 call assert_equal(l:first, bufnr())
1462
1463 llast!
1464 call assert_equal(l:last, bufnr())
1465endfunc
1466
1467" Fail :lnext but :lnext! is allowed
1468func Test_lnext()
1469 CheckFeature quickfix
1470 call s:reset_all_buffers()
1471
1472 let [l:first, l:middle, l:last] = s:make_simple_location_list()
1473 ll!
1474
1475 call assert_fails("lnext", "E1513:")
1476 call assert_equal(l:first, bufnr())
1477
1478 lnext!
1479 call assert_equal(l:middle, bufnr())
1480endfunc
1481
1482" Fail :lnfile but :lnfile! is allowed
1483func Test_lnfile()
1484 CheckFeature quickfix
1485 call s:reset_all_buffers()
1486
1487 let [_, l:current, l:last] = s:make_simple_location_list()
1488 lnext!
1489
1490 call assert_fails("lnfile", "E1513:")
1491 call assert_equal(l:current, bufnr())
1492
1493 lprevious! " Reset for the next test call
1494
1495 lnfile!
1496 call assert_equal(l:last, bufnr())
1497endfunc
1498
1499" Fail :lpfile but :lpfile! is allowed
1500func Test_lpfile()
1501 CheckFeature quickfix
1502 call s:reset_all_buffers()
1503
1504 let [l:first, l:current, _] = s:make_simple_location_list()
1505 lnext!
1506
1507 call assert_fails("lpfile", "E1513:")
1508 call assert_equal(l:current, bufnr())
1509
1510 lnext! " Reset for the next test call
1511
1512 lpfile!
1513 call assert_equal(l:first, bufnr())
1514endfunc
1515
1516" Fail :lprevious but :lprevious! is allowed
1517func Test_lprevious()
1518 CheckFeature quickfix
1519 call s:reset_all_buffers()
1520
1521 let [l:first, l:middle, _] = s:make_simple_location_list()
1522 lnext!
1523
1524 call assert_fails("lprevious", "E1513:")
1525 call assert_equal(l:middle, bufnr())
1526
1527 lnext! " Reset for the next test call
1528
1529 lprevious!
1530 call assert_equal(l:first, bufnr())
1531endfunc
1532
1533" Fail :lrewind but :lrewind! is allowed
1534func Test_lrewind()
1535 CheckFeature quickfix
1536 call s:reset_all_buffers()
1537
1538 let [l:first, l:middle, _] = s:make_simple_location_list()
1539 lnext!
1540
1541 call assert_fails("lrewind", "E1513:")
1542 call assert_equal(l:middle, bufnr())
1543
1544 lrewind!
1545 call assert_equal(l:first, bufnr())
1546endfunc
1547
1548" Fail :ltag but :ltag! is allowed
1549func Test_ltag()
1550 call s:reset_all_buffers()
1551
1552 set tags=Xtags
1553 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1554 \ "one\tXfile\t1",
1555 \ "three\tXfile\t3",
1556 \ "two\tXfile\t2"],
1557 \ "Xtags")
1558 call writefile(["one", "two", "three"], "Xfile")
1559 call writefile(["one"], "Xother")
1560 edit Xother
1561 execute "normal \<C-]>"
1562
1563 set winfixbuf
1564
1565 let l:current = bufnr()
1566
1567 call assert_fails("ltag one", "E1513:")
1568
1569 ltag! one
1570
1571 set tags&
1572 call delete("Xtags")
1573 call delete("Xfile")
1574 call delete("Xother")
1575endfunc
1576
1577" Fail vim.command if we try to change buffers while 'winfixbuf' is set
1578func Test_lua_command()
1579 call s:reset_all_buffers()
1580
1581 enew
1582 file first
1583 let l:previous = bufnr()
1584
1585 enew
1586 file second
1587 let l:current = bufnr()
1588
1589 set winfixbuf
1590
1591 call assert_fails('lua vim.command("buffer " .. ' . l:previous . ')')
1592 call assert_equal(l:current, bufnr())
1593
1594 execute 'lua vim.command("buffer! " .. ' . l:previous . ')'
1595 call assert_equal(l:previous, bufnr())
1596endfunc
1597
1598" Fail :lvimgrep but :lvimgrep! is allowed
1599func Test_lvimgrep()
1600 CheckFeature quickfix
1601 call s:reset_all_buffers()
1602
1603 edit first.unittest
1604 call append(0, ["some-search-term"])
1605 write
1606
1607 edit winfix.unittest
1608 call append(0, ["some-search-term"])
1609 write
1610 let l:current = bufnr()
1611
1612 set winfixbuf
1613
1614 edit! last.unittest
1615 call append(0, ["some-search-term"])
1616 write
1617 let l:last = bufnr()
1618
1619 buffer! winfix.unittest
1620
1621 call assert_fails("lvimgrep /some-search-term/ *.unittest", "E1513:")
1622 call assert_equal(l:current, bufnr())
1623
1624 lvimgrep! /some-search-term/ *.unittest
1625 call assert_notequal(l:current, bufnr())
1626
1627 call delete("first.unittest")
1628 call delete("winfix.unittest")
1629 call delete("last.unittest")
1630endfunc
1631
1632" Fail :lvimgrepadd but :lvimgrepadd! is allowed
1633func Test_lvimgrepadd()
1634 CheckFeature quickfix
1635 call s:reset_all_buffers()
1636
1637 edit first.unittest
1638 call append(0, ["some-search-term"])
1639 write
1640
1641 edit winfix.unittest
1642 call append(0, ["some-search-term"])
1643 write
1644 let l:current = bufnr()
1645
1646 set winfixbuf
1647
1648 edit! last.unittest
1649 call append(0, ["some-search-term"])
1650 write
1651 let l:last = bufnr()
1652
1653 buffer! winfix.unittest
1654
1655 call assert_fails("lvimgrepadd /some-search-term/ *.unittest")
1656 call assert_equal(l:current, bufnr())
1657
1658 lvimgrepadd! /some-search-term/ *.unittest
1659 call assert_notequal(l:current, bufnr())
1660
1661 call delete("first.unittest")
1662 call delete("winfix.unittest")
1663 call delete("last.unittest")
1664endfunc
1665
1666" Don't allow global marks to change the current 'winfixbuf' window
1667func Test_marks_mappings_fail()
1668 call s:reset_all_buffers()
1669
1670 let l:other = s:make_buffer_pairs()
1671 let l:current = bufnr()
1672 execute "buffer! " . l:other
1673 normal mA
1674 execute "buffer! " . l:current
1675 normal mB
1676
1677 call assert_fails("normal `A", "E1513:")
1678 call assert_equal(l:current, bufnr())
1679
1680 call assert_fails("normal 'A", "E1513:")
1681 call assert_equal(l:current, bufnr())
1682
1683 set nowinfixbuf
1684
1685 normal `A
1686 call assert_equal(l:other, bufnr())
1687endfunc
1688
1689" Allow global marks in a 'winfixbuf' window if the jump is the same buffer
1690func Test_marks_mappings_pass_intra_move()
1691 call s:reset_all_buffers()
1692
1693 let l:current = bufnr()
1694 call append(0, ["some line", "another line"])
1695 normal mA
1696 normal j
1697 normal mB
1698
1699 set winfixbuf
1700
1701 normal `A
1702 call assert_equal(l:current, bufnr())
1703endfunc
1704
1705" Fail :next but :next! is allowed
1706func Test_next()
1707 call s:reset_all_buffers()
1708
1709 let [l:first, _] = s:make_args_list()
1710 first!
1711
1712 call assert_fails("next", "E1513:")
1713 call assert_equal(l:first, bufnr())
1714
1715 next!
1716 call assert_notequal(l:first, bufnr())
1717endfunc
1718
1719" Ensure :mksession saves 'winfixbuf' details
1720func Test_mksession()
1721 CheckFeature mksession
1722 call s:reset_all_buffers()
1723
1724 set sessionoptions+=options
1725 set winfixbuf
1726
1727 mksession test_winfixbuf_Test_mksession.vim
1728
1729 call s:reset_all_buffers()
1730 let l:winfixbuf = &winfixbuf
1731 call assert_equal(0, l:winfixbuf)
1732
1733 source test_winfixbuf_Test_mksession.vim
1734
1735 let l:winfixbuf = &winfixbuf
1736 call assert_equal(1, l:winfixbuf)
1737
1738 set sessionoptions&
1739 call delete("test_winfixbuf_Test_mksession.vim")
1740endfunc
1741
1742" Allow :next if the next index is the same as the current buffer
1743func Test_next_same_buffer()
1744 call s:reset_all_buffers()
1745
1746 enew
1747 file foo
1748 enew
1749 file bar
1750 enew
1751 file fizz
1752 enew
1753 file buzz
1754 args foo foo bar fizz buzz
1755
1756 edit foo
1757 set winfixbuf
1758 let l:current = bufnr()
1759
1760 " Allow :next because the args list is `[foo] foo bar fizz buzz
1761 next
1762 call assert_equal(l:current, bufnr())
1763
1764 " Fail :next because the args list is `foo [foo] bar fizz buzz
1765 " and the next buffer would be bar, which is a different buffer
1766 call assert_fails("next", "E1513:")
1767 call assert_equal(l:current, bufnr())
1768endfunc
1769
1770" Fail to jump to a tag with g<C-]> if 'winfixbuf' is enabled
1771func Test_normal_g_ctrl_square_bracket_right()
1772 call s:reset_all_buffers()
1773
1774 set tags=Xtags
1775 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1776 \ "one\tXfile\t1",
1777 \ "three\tXfile\t3",
1778 \ "two\tXfile\t2"],
1779 \ "Xtags")
1780 call writefile(["one", "two", "three"], "Xfile")
1781 call writefile(["one"], "Xother")
1782 edit Xother
1783
1784 set winfixbuf
1785
1786 let l:current = bufnr()
1787
1788 call assert_fails("normal g\<C-]>", "E1513:")
1789 call assert_equal(l:current, bufnr())
1790
1791 set tags&
1792 call delete("Xtags")
1793 call delete("Xfile")
1794 call delete("Xother")
1795endfunc
1796
1797" Fail to jump to a tag with g<RightMouse> if 'winfixbuf' is enabled
1798func Test_normal_g_rightmouse()
1799 call s:reset_all_buffers()
1800 set mouse=n
1801
1802 set tags=Xtags
1803 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1804 \ "one\tXfile\t1",
1805 \ "three\tXfile\t3",
1806 \ "two\tXfile\t2"],
1807 \ "Xtags")
1808 call writefile(["one", "two", "three"], "Xfile")
1809 call writefile(["one"], "Xother")
1810 edit Xother
1811 execute "normal \<C-]>"
1812
1813 set winfixbuf
1814
1815 let l:current = bufnr()
1816
1817 call assert_fails("normal g\<RightMouse>", "E1513:")
1818 call assert_equal(l:current, bufnr())
1819
1820 set tags&
1821 set mouse&
1822 call delete("Xtags")
1823 call delete("Xfile")
1824 call delete("Xother")
1825endfunc
1826
1827" Fail to jump to a tag with g] if 'winfixbuf' is enabled
1828func Test_normal_g_square_bracket_right()
1829 call s:reset_all_buffers()
1830
1831 set tags=Xtags
1832 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1833 \ "one\tXfile\t1",
1834 \ "three\tXfile\t3",
1835 \ "two\tXfile\t2"],
1836 \ "Xtags")
1837 call writefile(["one", "two", "three"], "Xfile")
1838 call writefile(["one"], "Xother")
1839 edit Xother
1840
1841 set winfixbuf
1842
1843 let l:current = bufnr()
1844
1845 call assert_fails("normal g]", "E1513:")
1846 call assert_equal(l:current, bufnr())
1847
1848 set tags&
1849 call delete("Xtags")
1850 call delete("Xfile")
1851 call delete("Xother")
1852endfunc
1853
1854" Fail to jump to a tag with <C-RightMouse> if 'winfixbuf' is enabled
1855func Test_normal_ctrl_rightmouse()
1856 call s:reset_all_buffers()
1857 set mouse=n
1858
1859 set tags=Xtags
1860 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1861 \ "one\tXfile\t1",
1862 \ "three\tXfile\t3",
1863 \ "two\tXfile\t2"],
1864 \ "Xtags")
1865 call writefile(["one", "two", "three"], "Xfile")
1866 call writefile(["one"], "Xother")
1867 edit Xother
1868 execute "normal \<C-]>"
1869
1870 set winfixbuf
1871
1872 let l:current = bufnr()
1873
1874 call assert_fails("normal \<C-RightMouse>", "E1513:")
1875 call assert_equal(l:current, bufnr())
1876
1877 set tags&
1878 set mouse&
1879 call delete("Xtags")
1880 call delete("Xfile")
1881 call delete("Xother")
1882endfunc
1883
1884" Fail to jump to a tag with <C-t> if 'winfixbuf' is enabled
1885func Test_normal_ctrl_t()
1886 call s:reset_all_buffers()
1887
1888 set tags=Xtags
1889 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
1890 \ "one\tXfile\t1",
1891 \ "three\tXfile\t3",
1892 \ "two\tXfile\t2"],
1893 \ "Xtags")
1894 call writefile(["one", "two", "three"], "Xfile")
1895 call writefile(["one"], "Xother")
1896 edit Xother
1897 execute "normal \<C-]>"
1898
1899 set winfixbuf
1900
1901 let l:current = bufnr()
1902
1903 call assert_fails("normal \<C-t>", "E1513:")
1904 call assert_equal(l:current, bufnr())
1905
1906 set tags&
1907 call delete("Xtags")
1908 call delete("Xfile")
1909 call delete("Xother")
1910endfunc
1911
1912" Disallow <C-^> in 'winfixbuf' windows
1913func Test_normal_ctrl_hat()
1914 call s:reset_all_buffers()
1915 clearjumps
1916
1917 enew
1918 file first
1919 let l:first = bufnr()
1920
1921 enew
1922 file current
1923 let l:current = bufnr()
1924
1925 set winfixbuf
1926
1927 call assert_fails("normal \<C-^>", "E1513:")
1928 call assert_equal(l:current, bufnr())
1929endfunc
1930
1931" Allow <C-i> in 'winfixbuf' windows if the movement stays within the buffer
1932func Test_normal_ctrl_i_pass()
1933 call s:reset_all_buffers()
1934 clearjumps
1935
1936 enew
1937 file first
1938 let l:first = bufnr()
1939
1940 enew!
1941 file current
1942 let l:current = bufnr()
1943 " Add some lines so we can populate a jumplist"
1944 call append(0, ["some line", "another line"])
1945 " Add an entry to the jump list
1946 " Go up another line
1947 normal m`
1948 normal k
1949 execute "normal \<C-o>"
1950
1951 set winfixbuf
1952
1953 let l:line = getcurpos()[1]
1954 execute "normal 1\<C-i>"
1955 call assert_notequal(l:line, getcurpos()[1])
1956endfunc
1957
1958" Disallow <C-o> in 'winfixbuf' windows if it would cause the buffer to switch
1959func Test_normal_ctrl_o_fail()
1960 call s:reset_all_buffers()
1961 clearjumps
1962
1963 enew
1964 file first
1965 let l:first = bufnr()
1966
1967 enew
1968 file current
1969 let l:current = bufnr()
1970
1971 set winfixbuf
1972
1973 call assert_fails("normal \<C-o>", "E1513:")
1974 call assert_equal(l:current, bufnr())
1975endfunc
1976
1977" Allow <C-o> in 'winfixbuf' windows if the movement stays within the buffer
1978func Test_normal_ctrl_o_pass()
1979 call s:reset_all_buffers()
1980 clearjumps
1981
1982 enew
1983 file first
1984 let l:first = bufnr()
1985
1986 enew!
1987 file current
1988 let l:current = bufnr()
1989 " Add some lines so we can populate a jumplist
1990 call append(0, ["some line", "another line"])
1991 " Add an entry to the jump list
1992 " Go up another line
1993 normal m`
1994 normal k
1995
1996 set winfixbuf
1997
1998 execute "normal \<C-o>"
1999 call assert_equal(l:current, bufnr())
2000endfunc
2001
2002" Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
2003func Test_normal_ctrl_square_bracket_right()
2004 call s:reset_all_buffers()
2005
2006 set tags=Xtags
2007 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2008 \ "one\tXfile\t1",
2009 \ "three\tXfile\t3",
2010 \ "two\tXfile\t2"],
2011 \ "Xtags")
2012 call writefile(["one", "two", "three"], "Xfile")
2013 call writefile(["one"], "Xother")
2014 edit Xother
2015
2016 set winfixbuf
2017
2018 let l:current = bufnr()
2019
2020 call assert_fails("normal \<C-]>", "E1513:")
2021 call assert_equal(l:current, bufnr())
2022
2023 set tags&
2024 call delete("Xtags")
2025 call delete("Xfile")
2026 call delete("Xother")
2027endfunc
2028
2029" Allow <C-w><C-]> with 'winfixbuf' enabled because it runs in a new, split window
2030func Test_normal_ctrl_w_ctrl_square_bracket_right()
2031 call s:reset_all_buffers()
2032
2033 set tags=Xtags
2034 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2035 \ "one\tXfile\t1",
2036 \ "three\tXfile\t3",
2037 \ "two\tXfile\t2"],
2038 \ "Xtags")
2039 call writefile(["one", "two", "three"], "Xfile")
2040 call writefile(["one"], "Xother")
2041 edit Xother
2042
2043 set winfixbuf
2044
2045 let l:current_windows = s:get_windows_count()
2046 execute "normal \<C-w>\<C-]>"
2047 call assert_equal(l:current_windows + 1, s:get_windows_count())
2048
2049 set tags&
2050 call delete("Xtags")
2051 call delete("Xfile")
2052 call delete("Xother")
2053endfunc
2054
2055" Allow <C-w>g<C-]> with 'winfixbuf' enabled because it runs in a new, split window
2056func Test_normal_ctrl_w_g_ctrl_square_bracket_right()
2057 call s:reset_all_buffers()
2058
2059 set tags=Xtags
2060 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2061 \ "one\tXfile\t1",
2062 \ "three\tXfile\t3",
2063 \ "two\tXfile\t2"],
2064 \ "Xtags")
2065 call writefile(["one", "two", "three"], "Xfile")
2066 call writefile(["one"], "Xother")
2067 edit Xother
2068
2069 set winfixbuf
2070
2071 let l:current_windows = s:get_windows_count()
2072 execute "normal \<C-w>g\<C-]>"
2073 call assert_equal(l:current_windows + 1, s:get_windows_count())
2074
2075 set tags&
2076 call delete("Xtags")
2077 call delete("Xfile")
2078 call delete("Xother")
2079endfunc
2080
2081" Fail to jump to a tag with <C-]> if 'winfixbuf' is enabled
2082func Test_normal_gt()
2083 call s:reset_all_buffers()
2084
2085 set tags=Xtags
2086 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2087 \ "one\tXfile\t1",
2088 \ "three\tXfile\t3",
2089 \ "two\tXfile\t2"],
2090 \ "Xtags")
2091 call writefile(["one", "two", "three"], "Xfile")
2092 call writefile(["one", "two", "three"], "Xother")
2093 edit Xother
2094
2095 set winfixbuf
2096
2097 let l:current = bufnr()
2098
2099 call assert_fails("normal \<C-]>", "E1513:")
2100 call assert_equal(l:current, bufnr())
2101
2102 set tags&
2103 call delete("Xtags")
2104 call delete("Xfile")
2105 call delete("Xother")
2106endfunc
2107
2108" Prevent gF from switching a 'winfixbuf' window's buffer
2109func Test_normal_gF()
2110 call s:reset_all_buffers()
2111
2112 let l:file = tempname()
2113 call append(0, [l:file])
2114 call writefile([], l:file)
2115 " Place the cursor onto the line that has `l:file`
2116 normal gg
2117 " Prevent Vim from erroring with "No write since last change @ command
2118 " line" when we try to call gF, later.
2119 set hidden
2120
2121 set winfixbuf
2122
2123 let l:buffer = bufnr()
2124
2125 call assert_fails("normal gF", "E1513:")
2126 call assert_equal(l:buffer, bufnr())
2127
2128 set nowinfixbuf
2129
2130 normal gF
2131 call assert_notequal(l:buffer, bufnr())
2132
2133 call delete(l:file)
2134endfunc
2135
2136" Prevent gf from switching a 'winfixbuf' window's buffer
2137func Test_normal_gf()
2138 call s:reset_all_buffers()
2139
2140 let l:file = tempname()
2141 call append(0, [l:file])
2142 call writefile([], l:file)
2143 " Place the cursor onto the line that has `l:file`
2144 normal gg
2145 " Prevent Vim from erroring with "No write since last change @ command
2146 " line" when we try to call gf, later.
2147 set hidden
2148
2149 set winfixbuf
2150
2151 let l:buffer = bufnr()
2152
2153 call assert_fails("normal gf", "E1513:")
2154 call assert_equal(l:buffer, bufnr())
2155
2156 set nowinfixbuf
2157
2158 normal gf
2159 call assert_notequal(l:buffer, bufnr())
2160
2161 call delete(l:file)
2162endfunc
2163
2164" Fail "goto file under the cursor" (using [f, which is the same as `:normal gf`)
2165func Test_normal_square_bracket_left_f()
2166 call s:reset_all_buffers()
2167
2168 let l:file = tempname()
2169 call append(0, [l:file])
2170 call writefile([], l:file)
2171 " Place the cursor onto the line that has `l:file`
2172 normal gg
2173 " Prevent Vim from erroring with "No write since last change @ command
2174 " line" when we try to call gf, later.
2175 set hidden
2176
2177 set winfixbuf
2178
2179 let l:buffer = bufnr()
2180
2181 call assert_fails("normal [f", "E1513:")
2182 call assert_equal(l:buffer, bufnr())
2183
2184 set nowinfixbuf
2185
2186 normal [f
2187 call assert_notequal(l:buffer, bufnr())
2188
2189 call delete(l:file)
2190endfunc
2191
2192" Fail to go to a C macro with [<C-d> if 'winfixbuf' is enabled
2193func Test_normal_square_bracket_left_ctrl_d()
2194 call s:reset_all_buffers()
2195
2196 let l:include_file = tempname() . ".h"
2197 call writefile(["min(1, 12);",
2198 \ '#include "' . l:include_file . '"'
2199 \ ],
2200 \ "main.c")
2201 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2202 edit main.c
2203 normal ]\<C-d>
2204
2205 set winfixbuf
2206
2207 let l:current = bufnr()
2208
2209 call assert_fails("normal [\<C-d>", "E1513:")
2210 call assert_equal(l:current, bufnr())
2211
2212 set nowinfixbuf
2213
2214 execute "normal [\<C-d>"
2215 call assert_notequal(l:current, bufnr())
2216
2217 call delete("main.c")
2218 call delete(l:include_file)
2219endfunc
2220
2221" Fail to go to a C macro with ]<C-d> if 'winfixbuf' is enabled
2222func Test_normal_square_bracket_right_ctrl_d()
2223 call s:reset_all_buffers()
2224
2225 let l:include_file = tempname() . ".h"
2226 call writefile(["min(1, 12);",
2227 \ '#include "' . l:include_file . '"'
2228 \ ],
2229 \ "main.c")
2230 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2231 edit main.c
2232
2233 set winfixbuf
2234
2235 let l:current = bufnr()
2236
2237 call assert_fails("normal ]\<C-d>", "E1513:")
2238 call assert_equal(l:current, bufnr())
2239
2240 set nowinfixbuf
2241
2242 execute "normal ]\<C-d>"
2243 call assert_notequal(l:current, bufnr())
2244
2245 call delete("main.c")
2246 call delete(l:include_file)
2247endfunc
2248
2249" Fail to go to a C macro with [<C-i> if 'winfixbuf' is enabled
2250func Test_normal_square_bracket_left_ctrl_i()
2251 call s:reset_all_buffers()
2252
2253 let l:include_file = tempname() . ".h"
2254 call writefile(['#include "' . l:include_file . '"',
2255 \ "min(1, 12);",
2256 \ ],
2257 \ "main.c")
2258 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2259 edit main.c
2260 " Move to the line with `min(1, 12);` on it"
2261 normal j
2262
2263 set define=^\\s*#\\s*define
2264 set include=^\\s*#\\s*include
2265 set path=.,/usr/include,,
2266
2267 let l:current = bufnr()
2268
2269 set winfixbuf
2270
2271 call assert_fails("normal [\<C-i>", "E1513:")
2272
2273 set nowinfixbuf
2274
2275 execute "normal [\<C-i>"
2276 call assert_notequal(l:current, bufnr())
2277
2278 set define&
2279 set include&
2280 set path&
2281 call delete("main.c")
2282 call delete(l:include_file)
2283endfunc
2284
2285" Fail to go to a C macro with ]<C-i> if 'winfixbuf' is enabled
2286func Test_normal_square_bracket_right_ctrl_i()
2287 call s:reset_all_buffers()
2288
2289 let l:include_file = tempname() . ".h"
2290 call writefile(["min(1, 12);",
2291 \ '#include "' . l:include_file . '"'
2292 \ ],
2293 \ "main.c")
2294 call writefile(["#define min(X, Y) ((X) < (Y) ? (X) : (Y))"], l:include_file)
2295 edit main.c
2296
2297 set winfixbuf
2298
2299 set define=^\\s*#\\s*define
2300 set include=^\\s*#\\s*include
2301 set path=.,/usr/include,,
2302
2303 let l:current = bufnr()
2304
2305 call assert_fails("normal ]\<C-i>", "E1513:")
2306 call assert_equal(l:current, bufnr())
2307
2308 set nowinfixbuf
2309
2310 execute "normal ]\<C-i>"
2311 call assert_notequal(l:current, bufnr())
2312
2313 set define&
2314 set include&
2315 set path&
2316 call delete("main.c")
2317 call delete(l:include_file)
2318endfunc
2319
2320" Fail "goto file under the cursor" (using ]f, which is the same as `:normal gf`)
2321func Test_normal_square_bracket_right_f()
2322 call s:reset_all_buffers()
2323
2324 let l:file = tempname()
2325 call append(0, [l:file])
2326 call writefile([], l:file)
2327 " Place the cursor onto the line that has `l:file`
2328 normal gg
2329 " Prevent Vim from erroring with "No write since last change @ command
2330 " line" when we try to call gf, later.
2331 set hidden
2332
2333 set winfixbuf
2334
2335 let l:buffer = bufnr()
2336
2337 call assert_fails("normal ]f", "E1513:")
2338 call assert_equal(l:buffer, bufnr())
2339
2340 set nowinfixbuf
2341
2342 normal ]f
2343 call assert_notequal(l:buffer, bufnr())
2344
2345 call delete(l:file)
2346endfunc
2347
2348" Fail to jump to a tag with v<C-]> if 'winfixbuf' is enabled
2349func Test_normal_v_ctrl_square_bracket_right()
2350 call s:reset_all_buffers()
2351
2352 set tags=Xtags
2353 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2354 \ "one\tXfile\t1",
2355 \ "three\tXfile\t3",
2356 \ "two\tXfile\t2"],
2357 \ "Xtags")
2358 call writefile(["one", "two", "three"], "Xfile")
2359 call writefile(["one"], "Xother")
2360 edit Xother
2361
2362 set winfixbuf
2363
2364 let l:current = bufnr()
2365
2366 call assert_fails("normal v\<C-]>", "E1513:")
2367 call assert_equal(l:current, bufnr())
2368
2369 set tags&
2370 call delete("Xtags")
2371 call delete("Xfile")
2372 call delete("Xother")
2373endfunc
2374
2375" Fail to jump to a tag with vg<C-]> if 'winfixbuf' is enabled
2376func Test_normal_v_g_ctrl_square_bracket_right()
2377 call s:reset_all_buffers()
2378
2379 set tags=Xtags
2380 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2381 \ "one\tXfile\t1",
2382 \ "three\tXfile\t3",
2383 \ "two\tXfile\t2"],
2384 \ "Xtags")
2385 call writefile(["one", "two", "three"], "Xfile")
2386 call writefile(["one"], "Xother")
2387 edit Xother
2388
2389 set winfixbuf
2390
2391 let l:current = bufnr()
2392
2393 call assert_fails("normal vg\<C-]>", "E1513:")
2394 call assert_equal(l:current, bufnr())
2395
2396 set tags&
2397 call delete("Xtags")
2398 call delete("Xfile")
2399 call delete("Xother")
2400endfunc
2401
2402" Allow :pedit because, unlike :edit, it uses a separate window
2403func Test_pedit()
2404 call s:reset_all_buffers()
2405
2406 let l:other = s:make_buffer_pairs()
2407
2408 pedit other
2409
2410 execute "normal \<C-w>w"
2411 call assert_equal(l:other, bufnr())
2412endfunc
2413
2414" Fail :pop but :pop! is allowed
2415func Test_pop()
2416 call s:reset_all_buffers()
2417
2418 set tags=Xtags
2419 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2420 \ "thesame\tXfile\t1;\"\td\tfile:",
2421 \ "thesame\tXfile\t2;\"\td\tfile:",
2422 \ "thesame\tXfile\t3;\"\td\tfile:",
2423 \ ],
2424 \ "Xtags")
2425 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2426 call writefile(["thesame one"], "Xother")
2427 edit Xother
2428
2429 tag thesame
2430
2431 set winfixbuf
2432
2433 let l:current = bufnr()
2434
2435 call assert_fails("pop", "E1513:")
2436 call assert_equal(l:current, bufnr())
2437
2438 pop!
2439 call assert_notequal(l:current, bufnr())
2440
2441 set tags&
2442 call delete("Xtags")
2443 call delete("Xfile")
2444 call delete("Xother")
2445endfunc
2446
2447" Fail :previous but :previous! is allowed
2448func Test_previous()
2449 call s:reset_all_buffers()
2450
2451 let [l:first, _] = s:make_args_list()
2452 next!
2453
2454 call assert_fails("previous", "E1513:")
2455 call assert_notequal(l:first, bufnr())
2456
2457 previous!
2458 call assert_equal(l:first, bufnr())
2459endfunc
2460
2461" Fail pydo if it changes a window with 'winfixbuf' is set
2462func Test_python_pydo()
2463 CheckFeature pythonx
2464 call s:reset_all_buffers()
2465
2466 enew
2467 file first
2468 let g:_previous_buffer = bufnr()
2469
2470 enew
2471 file second
2472
2473 set winfixbuf
2474
2475 python << EOF
2476import vim
2477
2478def test_winfixbuf_Test_python_pydo_set_buffer():
2479 buffer = vim.vars['_previous_buffer']
2480 vim.current.buffer = vim.buffers[buffer]
2481EOF
2482
2483 try
2484 pydo test_winfixbuf_Test_python_pydo_set_buffer()
2485 catch /Vim(pydo):vim.error: Vim:E1513: Cannot edit buffer. 'winfixbuf' is enabled/
2486 let l:caught = 1
2487 endtry
2488
2489 call assert_equal(1, l:caught)
2490
2491 unlet g:_previous_buffer
2492endfunc
2493
2494" Fail pyfile if it changes a window with 'winfixbuf' is set
2495func Test_python_pyfile()
2496 CheckFeature pythonx
2497 call s:reset_all_buffers()
2498
2499 enew
2500 file first
2501 let g:_previous_buffer = bufnr()
2502
2503 enew
2504 file second
2505
2506 set winfixbuf
2507
2508 call writefile(["import vim",
2509 \ "buffer = vim.vars['_previous_buffer']",
2510 \ "vim.current.buffer = vim.buffers[buffer]",
2511 \ ],
2512 \ "file.py")
2513
2514 try
2515 pyfile file.py
2516 catch /Vim(pyfile):vim.error: Vim:E1513: Cannot edit buffer. 'winfixbuf' is enabled/
2517 let l:caught = 1
2518 endtry
2519
2520 call assert_equal(1, l:caught)
2521
2522 call delete("file.py")
2523 unlet g:_previous_buffer
2524endfunc
2525
2526" Fail vim.current.buffer if 'winfixbuf' is set
2527func Test_python_vim_current_buffer()
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 let l:caught = 0
2539
2540 set winfixbuf
2541
2542 try
2543 python << EOF
2544import vim
2545
2546buffer = vim.vars["_previous_buffer"]
2547vim.current.buffer = vim.buffers[buffer]
2548EOF
2549 catch /Vim(python):vim\.error: Vim:E1513: Cannot edit buffer. 'winfixbuf' is enabled/
2550 let l:caught = 1
2551 endtry
2552
2553 call assert_equal(1, l:caught)
2554 unlet g:_previous_buffer
2555endfunc
2556
2557" Ensure remapping to a disabled action still triggers failures
2558func Test_remap_key_fail()
2559 call s:reset_all_buffers()
2560
2561 enew
2562 file first
2563 let l:first = bufnr()
2564
2565 enew
2566 file current
2567 let l:current = bufnr()
2568
2569 set winfixbuf
2570
2571 nnoremap g <C-^>
2572
2573 call assert_fails("normal g", "E1513:")
2574 call assert_equal(l:current, bufnr())
2575
2576 nunmap g
2577endfunc
2578
2579" Ensure remapping a disabled key to something valid does trigger any failures
2580func Test_remap_key_pass()
2581 call s:reset_all_buffers()
2582
2583 enew
2584 file first
2585 let l:first = bufnr()
2586
2587 enew
2588 file current
2589 let l:current = bufnr()
2590
2591 set winfixbuf
2592
2593 call assert_fails("normal \<C-^>", "E1513:")
2594 call assert_equal(l:current, bufnr())
2595
2596 " Disallow <C-^> by default but allow it if the command does something else
2597 nnoremap <C-^> :echo "hello!"
2598
2599 execute "normal \<C-^>"
2600 call assert_equal(l:current, bufnr())
2601
2602 nunmap <C-^>
2603endfunc
2604
2605" Fail :rewind but :rewind! is allowed
2606func Test_rewind()
2607 call s:reset_all_buffers()
2608
2609 let [l:first, _] = s:make_args_list()
2610 next!
2611
2612 call assert_fails("rewind", "E1513:")
2613 call assert_notequal(l:first, bufnr())
2614
2615 rewind!
2616 call assert_equal(l:first, bufnr())
2617endfunc
2618
2619" Allow :sblast because it opens the buffer in a new, split window
2620func Test_sblast()
2621 call s:reset_all_buffers()
2622
2623 let l:other = s:make_buffer_pairs(1)
2624 bfirst!
2625 let l:current = bufnr()
2626
2627 sblast
2628 call assert_equal(l:other, bufnr())
2629endfunc
2630
2631" Fail :sbprevious but :sbprevious! is allowed
2632func Test_sbprevious()
2633 call s:reset_all_buffers()
2634
2635 let l:other = s:make_buffer_pairs()
2636 let l:current = bufnr()
2637
2638 sbprevious
2639 call assert_equal(l:other, bufnr())
2640endfunc
2641
2642" Make sure 'winfixbuf' can be set using 'winfixbuf' or 'wfb'
2643func Test_short_option()
2644 call s:reset_all_buffers()
2645
2646 call s:make_buffer_pairs()
2647
2648 set winfixbuf
2649 call assert_fails("edit something_else", "E1513")
2650
2651 set nowinfixbuf
2652 set wfb
2653 call assert_fails("edit another_place", "E1513")
2654
2655 set nowfb
2656 edit last_place
2657endfunc
2658
2659" Allow :snext because it makes a new window
2660func Test_snext()
2661 call s:reset_all_buffers()
2662
2663 let [l:first, _] = s:make_args_list()
2664 first!
2665
2666 let l:current_window = win_getid()
2667
2668 snext
2669 call assert_notequal(l:current_window, win_getid())
2670 call assert_notequal(l:first, bufnr())
2671endfunc
2672
2673" Ensure the first has 'winfixbuf' and a new split window is 'nowinfixbuf'
2674func Test_split_window()
2675 call s:reset_all_buffers()
2676
2677 split
2678 execute "normal \<C-w>j"
2679
2680 set winfixbuf
2681
2682 let l:winfix_window_1 = win_getid()
2683 vsplit
2684 let l:winfix_window_2 = win_getid()
2685
2686 call assert_equal(1, getwinvar(l:winfix_window_1, "&winfixbuf"))
2687 call assert_equal(0, getwinvar(l:winfix_window_2, "&winfixbuf"))
2688endfunc
2689
2690" Fail :tNext but :tNext! is allowed
2691func Test_tNext()
2692 call s:reset_all_buffers()
2693
2694 set tags=Xtags
2695 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2696 \ "thesame\tXfile\t1;\"\td\tfile:",
2697 \ "thesame\tXfile\t2;\"\td\tfile:",
2698 \ "thesame\tXfile\t3;\"\td\tfile:",
2699 \ ],
2700 \ "Xtags")
2701 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2702 call writefile(["thesame one"], "Xother")
2703 edit Xother
2704
2705 tag thesame
2706 execute "normal \<C-^>"
2707 tnext!
2708
2709 set winfixbuf
2710
2711 let l:current = bufnr()
2712
2713 call assert_fails("tNext", "E1513:")
2714 call assert_equal(l:current, bufnr())
2715
2716 tNext!
2717
2718 set tags&
2719 call delete("Xtags")
2720 call delete("Xfile")
2721 call delete("Xother")
2722endfunc
2723
2724" Call :tabdo and choose the next available 'nowinfixbuf' window.
2725func Test_tabdo_choose_available_window()
2726 call s:reset_all_buffers()
2727
2728 let [l:first, _] = s:make_args_list()
2729
2730 " Make a split window that is 'nowinfixbuf' but make it the second-to-last
2731 " window so that :tabdo will first try the 'winfixbuf' window, pass over it,
2732 " and prefer the other 'nowinfixbuf' window, instead.
2733 "
2734 " +-------------------+
2735 " | 'nowinfixbuf' |
2736 " +-------------------+
2737 " | 'winfixbuf' | <-- Cursor is here
2738 " +-------------------+
2739 split
2740 let l:nowinfixbuf_window = win_getid()
2741 " Move to the 'winfixbuf' window now
2742 execute "normal \<C-w>j"
2743 let l:winfixbuf_window = win_getid()
2744
2745 let l:expected_windows = s:get_windows_count()
2746 tabdo echo ''
2747 call assert_equal(l:nowinfixbuf_window, win_getid())
2748 call assert_equal(l:first, bufnr())
2749 call assert_equal(l:expected_windows, s:get_windows_count())
2750endfunc
2751
2752" Call :tabdo and create a new split window if all available windows are 'winfixbuf'.
2753func Test_tabdo_make_new_window()
2754 call s:reset_all_buffers()
2755
2756 let [l:first, _] = s:make_buffers_list()
2757 execute "buffer! " . l:first
2758
2759 let l:current = win_getid()
2760 let l:current_windows = s:get_windows_count()
2761
2762 tabdo echo ''
2763 call assert_notequal(l:current, win_getid())
2764 call assert_equal(l:first, bufnr())
2765 execute "normal \<C-w>j"
2766 call assert_equal(l:first, bufnr())
2767 call assert_equal(l:current_windows + 1, s:get_windows_count())
2768endfunc
2769
2770" Fail :tag but :tag! is allowed
2771func Test_tag()
2772 call s:reset_all_buffers()
2773
2774 set tags=Xtags
2775 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2776 \ "one\tXfile\t1",
2777 \ "three\tXfile\t3",
2778 \ "two\tXfile\t2"],
2779 \ "Xtags")
2780 call writefile(["one", "two", "three"], "Xfile")
2781 call writefile(["one"], "Xother")
2782 edit Xother
2783
2784 set winfixbuf
2785
2786 let l:current = bufnr()
2787
2788 call assert_fails("tag one", "E1513:")
2789 call assert_equal(l:current, bufnr())
2790
2791 tag! one
2792 call assert_notequal(l:current, bufnr())
2793
2794 set tags&
2795 call delete("Xtags")
2796 call delete("Xfile")
2797 call delete("Xother")
2798endfunc
2799
2800
2801" Fail :tfirst but :tfirst! is allowed
2802func Test_tfirst()
2803 call s:reset_all_buffers()
2804
2805 set tags=Xtags
2806 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2807 \ "one\tXfile\t1",
2808 \ "three\tXfile\t3",
2809 \ "two\tXfile\t2"],
2810 \ "Xtags")
2811 call writefile(["one", "two", "three"], "Xfile")
2812 call writefile(["one"], "Xother")
2813 edit Xother
2814
2815 set winfixbuf
2816
2817 let l:current = bufnr()
2818
2819 call assert_fails("tfirst", "E1513:")
2820 call assert_equal(l:current, bufnr())
2821
2822 tfirst!
2823 call assert_notequal(l:current, bufnr())
2824
2825 set tags&
2826 call delete("Xtags")
2827 call delete("Xfile")
2828 call delete("Xother")
2829endfunc
2830
2831" Fail :tjump but :tjump! is allowed
2832func Test_tjump()
2833 call s:reset_all_buffers()
2834
2835 set tags=Xtags
2836 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2837 \ "one\tXfile\t1",
2838 \ "three\tXfile\t3",
2839 \ "two\tXfile\t2"],
2840 \ "Xtags")
2841 call writefile(["one", "two", "three"], "Xfile")
2842 call writefile(["one"], "Xother")
2843 edit Xother
2844
2845 set winfixbuf
2846
2847 let l:current = bufnr()
2848
2849 call assert_fails("tjump one", "E1513:")
2850 call assert_equal(l:current, bufnr())
2851
2852 tjump! one
2853 call assert_notequal(l:current, bufnr())
2854
2855 set tags&
2856 call delete("Xtags")
2857 call delete("Xfile")
2858 call delete("Xother")
2859endfunc
2860
2861" Fail :tlast but :tlast! is allowed
2862func Test_tlast()
2863 call s:reset_all_buffers()
2864
2865 set tags=Xtags
2866 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2867 \ "one\tXfile\t1",
2868 \ "three\tXfile\t3",
2869 \ "two\tXfile\t2"],
2870 \ "Xtags")
2871 call writefile(["one", "two", "three"], "Xfile")
2872 edit Xfile
2873 tjump one
2874 edit Xfile
2875
2876 set winfixbuf
2877
2878 let l:current = bufnr()
2879
2880 call assert_fails("tlast", "E1513:")
2881 call assert_equal(l:current, bufnr())
2882
2883 tlast!
2884 call assert_equal(l:current, bufnr())
2885
2886 set tags&
2887 call delete("Xtags")
2888 call delete("Xfile")
2889endfunc
2890
2891" Fail :tnext but :tnext! is allowed
2892func Test_tnext()
2893 call s:reset_all_buffers()
2894
2895 set tags=Xtags
2896 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2897 \ "thesame\tXfile\t1;\"\td\tfile:",
2898 \ "thesame\tXfile\t2;\"\td\tfile:",
2899 \ "thesame\tXfile\t3;\"\td\tfile:",
2900 \ ],
2901 \ "Xtags")
2902 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2903 call writefile(["thesame one"], "Xother")
2904 edit Xother
2905
2906 tag thesame
2907 execute "normal \<C-^>"
2908
2909 set winfixbuf
2910
2911 let l:current = bufnr()
2912
2913 call assert_fails("tnext", "E1513:")
2914 call assert_equal(l:current, bufnr())
2915
2916 tnext!
2917 call assert_notequal(l:current, bufnr())
2918
2919 set tags&
2920 call delete("Xtags")
2921 call delete("Xfile")
2922 call delete("Xother")
2923endfunc
2924
2925" Fail :tprevious but :tprevious! is allowed
2926func Test_tprevious()
2927 call s:reset_all_buffers()
2928
2929 set tags=Xtags
2930 call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
2931 \ "thesame\tXfile\t1;\"\td\tfile:",
2932 \ "thesame\tXfile\t2;\"\td\tfile:",
2933 \ "thesame\tXfile\t3;\"\td\tfile:",
2934 \ ],
2935 \ "Xtags")
2936 call writefile(["thesame one", "thesame two", "thesame three"], "Xfile")
2937 call writefile(["thesame one"], "Xother")
2938 edit Xother
2939
2940 tag thesame
2941 execute "normal \<C-^>"
2942 tnext!
2943
2944 set winfixbuf
2945
2946 let l:current = bufnr()
2947
2948 call assert_fails("tprevious", "E1513:")
2949 call assert_equal(l:current, bufnr())
2950
2951 tprevious!
2952
2953 set tags&
2954 call delete("Xtags")
2955 call delete("Xfile")
2956 call delete("Xother")
2957endfunc
2958
2959" Fail :view but :view! is allowed
2960func Test_view()
2961 call s:reset_all_buffers()
2962
2963 let l:other = s:make_buffer_pairs()
2964 let l:current = bufnr()
2965
2966 call assert_fails("view other", "E1513:")
2967 call assert_equal(l:current, bufnr())
2968
2969 view! other
2970 call assert_equal(l:other, bufnr())
2971endfunc
2972
2973" Fail :visual but :visual! is allowed
2974func Test_visual()
2975 call s:reset_all_buffers()
2976
2977 let l:other = s:make_buffer_pairs()
2978 let l:current = bufnr()
2979
2980 call assert_fails("visual other", "E1513:")
2981 call assert_equal(l:current, bufnr())
2982
2983 visual! other
2984 call assert_equal(l:other, bufnr())
2985endfunc
2986
2987" Fail :vimgrep but :vimgrep! is allowed
2988func Test_vimgrep()
2989 CheckFeature quickfix
2990 call s:reset_all_buffers()
2991
2992 edit first.unittest
2993 call append(0, ["some-search-term"])
2994 write
2995
2996 edit winfix.unittest
2997 call append(0, ["some-search-term"])
2998 write
2999 let l:current = bufnr()
3000
3001 set winfixbuf
3002
3003 edit! last.unittest
3004 call append(0, ["some-search-term"])
3005 write
3006 let l:last = bufnr()
3007
3008 buffer! winfix.unittest
3009
3010 call assert_fails("vimgrep /some-search-term/ *.unittest")
3011 call assert_equal(l:current, bufnr())
3012
3013 " Don't error and also do swap to the first match because ! was included
3014 vimgrep! /some-search-term/ *.unittest
3015 call assert_notequal(l:current, bufnr())
3016
3017 call delete("first.unittest")
3018 call delete("winfix.unittest")
3019 call delete("last.unittest")
3020endfunc
3021
3022" Fail :vimgrepadd but ::vimgrepadd! is allowed
3023func Test_vimgrepadd()
3024 CheckFeature quickfix
3025 call s:reset_all_buffers()
3026
3027 edit first.unittest
3028 call append(0, ["some-search-term"])
3029 write
3030
3031 edit winfix.unittest
3032 call append(0, ["some-search-term"])
3033 write
3034 let l:current = bufnr()
3035
3036 set winfixbuf
3037
3038 edit! last.unittest
3039 call append(0, ["some-search-term"])
3040 write
3041 let l:last = bufnr()
3042
3043 buffer! winfix.unittest
3044
3045 call assert_fails("vimgrepadd /some-search-term/ *.unittest")
3046 call assert_equal(l:current, bufnr())
3047
3048 vimgrepadd! /some-search-term/ *.unittest
3049 call assert_notequal(l:current, bufnr())
3050 call delete("first.unittest")
3051 call delete("winfix.unittest")
3052 call delete("last.unittest")
3053endfunc
3054
3055" Fail :wNext but :wNext! is allowed
3056func Test_wNext()
3057 call s:reset_all_buffers()
3058
3059 let [l:first, _] = s:make_args_list()
3060 next!
3061
3062 call assert_fails("wNext", "E1513:")
3063 call assert_notequal(l:first, bufnr())
3064
3065 wNext!
3066 call assert_equal(l:first, bufnr())
3067
3068 call delete("first")
3069 call delete("middle")
3070 call delete("last")
3071endfunc
3072
3073" Allow :windo unless `:windo foo` would change a 'winfixbuf' window's buffer
3074func Test_windo()
3075 call s:reset_all_buffers()
3076
3077 let l:current_window = win_getid()
3078 let l:current_buffer = bufnr()
3079 split
3080 enew
3081 file some_other_buffer
3082
3083 set winfixbuf
3084
3085 let l:current = win_getid()
3086
3087 windo echo ''
3088 call assert_equal(l:current_window, win_getid())
3089
3090 call assert_fails('execute "windo buffer ' . l:current_buffer . '"', "E1513:")
3091 call assert_equal(l:current_window, win_getid())
3092
3093 execute "windo buffer! " . l:current_buffer
3094 call assert_equal(l:current_window, win_getid())
3095endfunc
3096
3097" Fail :wnext but :wnext! is allowed
3098func Test_wnext()
3099 call s:reset_all_buffers()
3100
3101 let [_, l:last] = s:make_args_list()
3102 next!
3103
3104 call assert_fails("wnext", "E1513:")
3105 call assert_notequal(l:last, bufnr())
3106
3107 wnext!
3108 call assert_equal(l:last, bufnr())
3109
3110 call delete("first")
3111 call delete("middle")
3112 call delete("last")
3113endfunc
3114
3115" Fail :wprevious but :wprevious! is allowed
3116func Test_wprevious()
3117 call s:reset_all_buffers()
3118
3119 let [l:first, _] = s:make_args_list()
3120 next!
3121
3122 call assert_fails("wprevious", "E1513:")
3123 call assert_notequal(l:first, bufnr())
3124
3125 wprevious!
3126 call assert_equal(l:first, bufnr())
3127
3128 call delete("first")
3129 call delete("middle")
3130 call delete("last")
3131endfunc