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