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