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