xref: /vim-8.2.3635/src/testdir/test_search.vim (revision d66cdcd4)
1" Test for the search command
2
3source shared.vim
4source screendump.vim
5source check.vim
6
7func Test_search_cmdline()
8  CheckOption incsearch
9
10  " need to disable char_avail,
11  " so that expansion of commandline works
12  call test_override("char_avail", 1)
13  new
14  call setline(1, ['  1', '  2 these', '  3 the', '  4 their', '  5 there', '  6 their', '  7 the', '  8 them', '  9 these', ' 10 foobar'])
15  " Test 1
16  " CTRL-N / CTRL-P skips through the previous search history
17  set noincsearch
18  :1
19  call feedkeys("/foobar\<cr>", 'tx')
20  call feedkeys("/the\<cr>", 'tx')
21  call assert_equal('the', @/)
22  call feedkeys("/thes\<C-P>\<C-P>\<cr>", 'tx')
23  call assert_equal('foobar', @/)
24
25  " Test 2
26  " Ctrl-G goes from one match to the next
27  " until the end of the buffer
28  set incsearch nowrapscan
29  :1
30  " first match
31  call feedkeys("/the\<cr>", 'tx')
32  call assert_equal('  2 these', getline('.'))
33  :1
34  " second match
35  call feedkeys("/the\<C-G>\<cr>", 'tx')
36  call assert_equal('  3 the', getline('.'))
37  call assert_equal([0, 0, 0, 0], getpos('"'))
38  :1
39  " third match
40  call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
41  call assert_equal('  4 their', getline('.'))
42  :1
43  " fourth match
44  call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
45  call assert_equal('  5 there', getline('.'))
46  :1
47  " fifth match
48  call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
49  call assert_equal('  6 their', getline('.'))
50  :1
51  " sixth match
52  call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
53  call assert_equal('  7 the', getline('.'))
54  :1
55  " seventh match
56  call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
57  call assert_equal('  8 them', getline('.'))
58  :1
59  " eighth match
60  call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
61  call assert_equal('  9 these', getline('.'))
62  :1
63  " no further match
64  call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
65  call assert_equal('  9 these', getline('.'))
66  call assert_equal([0, 0, 0, 0], getpos('"'))
67
68  " Test 3
69  " Ctrl-G goes from one match to the next
70  " and continues back at the top
71  set incsearch wrapscan
72  :1
73  " first match
74  call feedkeys("/the\<cr>", 'tx')
75  call assert_equal('  2 these', getline('.'))
76  :1
77  " second match
78  call feedkeys("/the\<C-G>\<cr>", 'tx')
79  call assert_equal('  3 the', getline('.'))
80  :1
81  " third match
82  call feedkeys("/the".repeat("\<C-G>", 2)."\<cr>", 'tx')
83  call assert_equal('  4 their', getline('.'))
84  :1
85  " fourth match
86  call feedkeys("/the".repeat("\<C-G>", 3)."\<cr>", 'tx')
87  call assert_equal('  5 there', getline('.'))
88  :1
89  " fifth match
90  call feedkeys("/the".repeat("\<C-G>", 4)."\<cr>", 'tx')
91  call assert_equal('  6 their', getline('.'))
92  :1
93  " sixth match
94  call feedkeys("/the".repeat("\<C-G>", 5)."\<cr>", 'tx')
95  call assert_equal('  7 the', getline('.'))
96  :1
97  " seventh match
98  call feedkeys("/the".repeat("\<C-G>", 6)."\<cr>", 'tx')
99  call assert_equal('  8 them', getline('.'))
100  :1
101  " eighth match
102  call feedkeys("/the".repeat("\<C-G>", 7)."\<cr>", 'tx')
103  call assert_equal('  9 these', getline('.'))
104  :1
105  " back at first match
106  call feedkeys("/the".repeat("\<C-G>", 8)."\<cr>", 'tx')
107  call assert_equal('  2 these', getline('.'))
108
109  " Test 4
110  " CTRL-T goes to the previous match
111  set incsearch nowrapscan
112  $
113  " first match
114  call feedkeys("?the\<cr>", 'tx')
115  call assert_equal('  9 these', getline('.'))
116  $
117  " first match
118  call feedkeys("?the\<C-G>\<cr>", 'tx')
119  call assert_equal('  9 these', getline('.'))
120  $
121  " second match
122  call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
123  call assert_equal('  8 them', getline('.'))
124  $
125  " last match
126  call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
127  call assert_equal('  2 these', getline('.'))
128  $
129  " last match
130  call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
131  call assert_equal('  2 these', getline('.'))
132
133  " Test 5
134  " CTRL-T goes to the previous match
135  set incsearch wrapscan
136  $
137  " first match
138  call feedkeys("?the\<cr>", 'tx')
139  call assert_equal('  9 these', getline('.'))
140  $
141  " first match at the top
142  call feedkeys("?the\<C-G>\<cr>", 'tx')
143  call assert_equal('  2 these', getline('.'))
144  $
145  " second match
146  call feedkeys("?the".repeat("\<C-T>", 1)."\<cr>", 'tx')
147  call assert_equal('  8 them', getline('.'))
148  $
149  " last match
150  call feedkeys("?the".repeat("\<C-T>", 7)."\<cr>", 'tx')
151  call assert_equal('  2 these', getline('.'))
152  $
153  " back at the bottom of the buffer
154  call feedkeys("?the".repeat("\<C-T>", 8)."\<cr>", 'tx')
155  call assert_equal('  9 these', getline('.'))
156
157  " Test 6
158  " CTRL-L adds to the search pattern
159  set incsearch wrapscan
160  1
161  " first match
162  call feedkeys("/the\<c-l>\<cr>", 'tx')
163  call assert_equal('  2 these', getline('.'))
164  1
165  " go to next match of 'thes'
166  call feedkeys("/the\<c-l>\<C-G>\<cr>", 'tx')
167  call assert_equal('  9 these', getline('.'))
168  1
169  " wrap around
170  call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
171  call assert_equal('  2 these', getline('.'))
172  1
173  " wrap around
174  set nowrapscan
175  call feedkeys("/the\<c-l>\<C-G>\<C-G>\<cr>", 'tx')
176  call assert_equal('  9 these', getline('.'))
177
178  " Test 7
179  " <bs> remove from match, but stay at current match
180  set incsearch wrapscan
181  1
182  " first match
183  call feedkeys("/thei\<cr>", 'tx')
184  call assert_equal('  4 their', getline('.'))
185  1
186  " delete one char, add another
187  call feedkeys("/thei\<bs>s\<cr>", 'tx')
188  call assert_equal('  2 these', getline('.'))
189  1
190  " delete one char, add another,  go to previous match, add one char
191  call feedkeys("/thei\<bs>s\<bs>\<C-T>\<c-l>\<cr>", 'tx')
192  call assert_equal('  9 these', getline('.'))
193  1
194  " delete all chars, start from the beginning again
195  call feedkeys("/them". repeat("\<bs>",4).'the\>'."\<cr>", 'tx')
196  call assert_equal('  3 the', getline('.'))
197
198  " clean up
199  call test_override("char_avail", 0)
200  bw!
201endfunc
202
203func Test_search_cmdline2()
204  CheckOption incsearch
205
206  " need to disable char_avail,
207  " so that expansion of commandline works
208  call test_override("char_avail", 1)
209  new
210  call setline(1, ['  1', '  2 these', '  3 the theother'])
211  " Test 1
212  " Ctrl-T goes correctly back and forth
213  set incsearch
214  1
215  " first match
216  call feedkeys("/the\<cr>", 'tx')
217  call assert_equal('  2 these', getline('.'))
218  1
219  " go to next match (on next line)
220  call feedkeys("/the\<C-G>\<cr>", 'tx')
221  call assert_equal('  3 the theother', getline('.'))
222  1
223  " go to next match (still on line 3)
224  call feedkeys("/the\<C-G>\<C-G>\<cr>", 'tx')
225  call assert_equal('  3 the theother', getline('.'))
226  1
227  " go to next match (still on line 3)
228  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<cr>", 'tx')
229  call assert_equal('  3 the theother', getline('.'))
230  1
231  " go to previous match (on line 3)
232  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<cr>", 'tx')
233  call assert_equal('  3 the theother', getline('.'))
234  1
235  " go to previous match (on line 3)
236  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<cr>", 'tx')
237  call assert_equal('  3 the theother', getline('.'))
238  1
239  " go to previous match (on line 2)
240  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<C-T>\<cr>", 'tx')
241  call assert_equal('  2 these', getline('.'))
242  1
243  " go to previous match (on line 2)
244  call feedkeys("/the\<C-G>\<C-R>\<C-W>\<cr>", 'tx')
245  call assert_equal('theother', @/)
246
247  " Test 2: keep the view,
248  " after deleting a character from the search cmd
249  call setline(1, ['  1', '  2 these', '  3 the', '  4 their', '  5 there', '  6 their', '  7 the', '  8 them', '  9 these', ' 10 foobar'])
250  resize 5
251  1
252  call feedkeys("/foo\<bs>\<cr>", 'tx')
253  redraw
254  call assert_equal({'lnum': 10, 'leftcol': 0, 'col': 4, 'topfill': 0, 'topline': 6, 'coladd': 0, 'skipcol': 0, 'curswant': 4}, winsaveview())
255
256  " remove all history entries
257  for i in range(11)
258      call histdel('/')
259  endfor
260
261  " Test 3: reset the view,
262  " after deleting all characters from the search cmd
263  norm! 1gg0
264  " unfortunately, neither "/foo\<c-w>\<cr>", nor "/foo\<bs>\<bs>\<bs>\<cr>",
265  " nor "/foo\<c-u>\<cr>" works to delete the commandline.
266  " In that case Vim should return "E35 no previous regular expression",
267  " but it looks like Vim still sees /foo and therefore the test fails.
268  " Therefore, disabling this test
269  "call assert_fails(feedkeys("/foo\<c-w>\<cr>", 'tx'), 'E35')
270  "call assert_equal({'lnum': 1, 'leftcol': 0, 'col': 0, 'topfill': 0, 'topline': 1, 'coladd': 0, 'skipcol': 0, 'curswant': 0}, winsaveview())
271
272  " clean up
273  set noincsearch
274  call test_override("char_avail", 0)
275  bw!
276endfunc
277
278func Test_use_sub_pat()
279  split
280  let @/ = ''
281  func X()
282    s/^/a/
283    /
284  endfunc
285  call X()
286  bwipe!
287endfunc
288
289func Test_searchpair()
290  new
291  call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]'])
292
293  4
294  call assert_equal(3, searchpair('\[', '', ']', 'bW'))
295  call assert_equal([0, 3, 2, 0], getpos('.'))
296  4
297  call assert_equal(2, searchpair('\[', '', ']', 'bWr'))
298  call assert_equal([0, 2, 6, 0], getpos('.'))
299  4
300  call assert_equal(1, searchpair('\[', '', ']', 'bWm'))
301  call assert_equal([0, 3, 2, 0], getpos('.'))
302  4|norm ^
303  call assert_equal(5, searchpair('\[', '', ']', 'Wn'))
304  call assert_equal([0, 4, 2, 0], getpos('.'))
305  4
306  call assert_equal(2, searchpair('\[', '', ']', 'bW',
307        \                         'getline(".") =~ "^\\s*\["'))
308  call assert_equal([0, 2, 6, 0], getpos('.'))
309  set nomagic
310  4
311  call assert_equal(3, searchpair('\[', '', ']', 'bW'))
312  call assert_equal([0, 3, 2, 0], getpos('.'))
313  set magic
314  4|norm ^
315  call assert_equal(0, searchpair('{', '', '}', 'bW'))
316  call assert_equal([0, 4, 2, 0], getpos('.'))
317
318  %d
319  call setline(1, ['if 1', '  if 2', '  else', '  endif 2', 'endif 1'])
320
321  /\<if 1
322  call assert_equal(5, searchpair('\<if\>', '\<else\>', '\<endif\>', 'W'))
323  call assert_equal([0, 5, 1, 0], getpos('.'))
324  /\<if 2
325  call assert_equal(3, searchpair('\<if\>', '\<else\>', '\<endif\>', 'W'))
326  call assert_equal([0, 3, 3, 0], getpos('.'))
327
328  q!
329endfunc
330
331func Test_searchpairpos()
332  new
333  call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]'])
334
335  4
336  call assert_equal([3, 2], searchpairpos('\[', '', ']', 'bW'))
337  call assert_equal([0, 3, 2, 0], getpos('.'))
338  4
339  call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bWr'))
340  call assert_equal([0, 2, 6, 0], getpos('.'))
341  4|norm ^
342  call assert_equal([5, 2], searchpairpos('\[', '', ']', 'Wn'))
343  call assert_equal([0, 4, 2, 0], getpos('.'))
344  4
345  call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bW',
346        \                                 'getline(".") =~ "^\\s*\["'))
347  call assert_equal([0, 2, 6, 0], getpos('.'))
348  4
349  call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bWr'))
350  call assert_equal([0, 2, 6, 0], getpos('.'))
351  set nomagic
352  4
353  call assert_equal([3, 2], searchpairpos('\[', '', ']', 'bW'))
354  call assert_equal([0, 3, 2, 0], getpos('.'))
355  set magic
356  4|norm ^
357  call assert_equal([0, 0], searchpairpos('{', '', '}', 'bW'))
358  call assert_equal([0, 4, 2, 0], getpos('.'))
359
360  %d
361  call setline(1, ['if 1', '  if 2', '  else', '  endif 2', 'endif 1'])
362  /\<if 1
363  call assert_equal([5, 1], searchpairpos('\<if\>', '\<else\>', '\<endif\>', 'W'))
364  call assert_equal([0, 5, 1, 0], getpos('.'))
365  /\<if 2
366  call assert_equal([3, 3], searchpairpos('\<if\>', '\<else\>', '\<endif\>', 'W'))
367  call assert_equal([0, 3, 3, 0], getpos('.'))
368
369  q!
370endfunc
371
372func Test_searchpair_errors()
373  call assert_fails("call searchpair([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
374  call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
375  call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
376  call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
377  call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
378  call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
379  call assert_fails("call searchpair('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e')
380  call assert_fails("call searchpair('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn')
381endfunc
382
383func Test_searchpairpos_errors()
384  call assert_fails("call searchpairpos([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
385  call assert_fails("call searchpairpos('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
386  call assert_fails("call searchpairpos('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
387  call assert_fails("call searchpairpos('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
388  call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
389  call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
390  call assert_fails("call searchpairpos('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e')
391  call assert_fails("call searchpairpos('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn')
392endfunc
393
394func Test_searchpair_skip()
395    func Zero()
396      return 0
397    endfunc
398    func Partial(x)
399      return a:x
400    endfunc
401    new
402    call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
403    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', ''))
404    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0'))
405    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0}))
406    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero')))
407    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0])))
408    bw!
409endfunc
410
411func Test_searchpair_leak()
412  new
413  call setline(1, 'if one else another endif')
414
415  " The error in the skip expression caused memory to leak.
416  call assert_fails("call searchpair('\\<if\\>', '\\<else\\>', '\\<endif\\>', '', '\"foo\" 2')", 'E15:')
417
418  bwipe!
419endfunc
420
421func Test_searchc()
422  " These commands used to cause memory overflow in searchc().
423  new
424  norm ixx
425  exe "norm 0t\u93cf"
426  bw!
427endfunc
428
429func Cmdline3_prep()
430  " need to disable char_avail,
431  " so that expansion of commandline works
432  call test_override("char_avail", 1)
433  new
434  call setline(1, ['  1', '  2 the~e', '  3 the theother'])
435  set incsearch
436endfunc
437
438func Incsearch_cleanup()
439  set noincsearch
440  call test_override("char_avail", 0)
441  bw!
442endfunc
443
444func Test_search_cmdline3()
445  CheckOption incsearch
446
447  call Cmdline3_prep()
448  1
449  " first match
450  call feedkeys("/the\<c-l>\<cr>", 'tx')
451  call assert_equal('  2 the~e', getline('.'))
452
453  call Incsearch_cleanup()
454endfunc
455
456func Test_search_cmdline3s()
457  CheckOption incsearch
458
459  call Cmdline3_prep()
460  1
461  call feedkeys(":%s/the\<c-l>/xxx\<cr>", 'tx')
462  call assert_equal('  2 xxxe', getline('.'))
463  undo
464  call feedkeys(":%subs/the\<c-l>/xxx\<cr>", 'tx')
465  call assert_equal('  2 xxxe', getline('.'))
466  undo
467  call feedkeys(":%substitute/the\<c-l>/xxx\<cr>", 'tx')
468  call assert_equal('  2 xxxe', getline('.'))
469  undo
470  call feedkeys(":%smagic/the.e/xxx\<cr>", 'tx')
471  call assert_equal('  2 xxx', getline('.'))
472  undo
473  call assert_fails(":%snomagic/the.e/xxx\<cr>", 'E486')
474  "
475  call feedkeys(":%snomagic/the\\.e/xxx\<cr>", 'tx')
476  call assert_equal('  2 xxx', getline('.'))
477
478  call Incsearch_cleanup()
479endfunc
480
481func Test_search_cmdline3g()
482  CheckOption incsearch
483
484  call Cmdline3_prep()
485  1
486  call feedkeys(":g/the\<c-l>/d\<cr>", 'tx')
487  call assert_equal('  3 the theother', getline(2))
488  undo
489  call feedkeys(":global/the\<c-l>/d\<cr>", 'tx')
490  call assert_equal('  3 the theother', getline(2))
491  undo
492  call feedkeys(":g!/the\<c-l>/d\<cr>", 'tx')
493  call assert_equal(1, line('$'))
494  call assert_equal('  2 the~e', getline(1))
495  undo
496  call feedkeys(":global!/the\<c-l>/d\<cr>", 'tx')
497  call assert_equal(1, line('$'))
498  call assert_equal('  2 the~e', getline(1))
499
500  call Incsearch_cleanup()
501endfunc
502
503func Test_search_cmdline3v()
504  CheckOption incsearch
505
506  call Cmdline3_prep()
507  1
508  call feedkeys(":v/the\<c-l>/d\<cr>", 'tx')
509  call assert_equal(1, line('$'))
510  call assert_equal('  2 the~e', getline(1))
511  undo
512  call feedkeys(":vglobal/the\<c-l>/d\<cr>", 'tx')
513  call assert_equal(1, line('$'))
514  call assert_equal('  2 the~e', getline(1))
515
516  call Incsearch_cleanup()
517endfunc
518
519func Test_search_cmdline4()
520  CheckOption incsearch
521
522  " need to disable char_avail,
523  " so that expansion of commandline works
524  call test_override("char_avail", 1)
525  new
526  call setline(1, ['  1 the first', '  2 the second', '  3 the third'])
527  set incsearch
528  $
529  call feedkeys("?the\<c-g>\<cr>", 'tx')
530  call assert_equal('  3 the third', getline('.'))
531  $
532  call feedkeys("?the\<c-g>\<c-g>\<cr>", 'tx')
533  call assert_equal('  1 the first', getline('.'))
534  $
535  call feedkeys("?the\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
536  call assert_equal('  2 the second', getline('.'))
537  $
538  call feedkeys("?the\<c-t>\<cr>", 'tx')
539  call assert_equal('  1 the first', getline('.'))
540  $
541  call feedkeys("?the\<c-t>\<c-t>\<cr>", 'tx')
542  call assert_equal('  3 the third', getline('.'))
543  $
544  call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
545  call assert_equal('  2 the second', getline('.'))
546  " clean up
547  set noincsearch
548  call test_override("char_avail", 0)
549  bw!
550endfunc
551
552func Test_search_cmdline5()
553  CheckOption incsearch
554
555  " Do not call test_override("char_avail", 1) so that <C-g> and <C-t> work
556  " regardless char_avail.
557  new
558  call setline(1, ['  1 the first', '  2 the second', '  3 the third', ''])
559  set incsearch
560  1
561  call feedkeys("/the\<c-g>\<c-g>\<cr>", 'tx')
562  call assert_equal('  3 the third', getline('.'))
563  $
564  call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
565  call assert_equal('  1 the first', getline('.'))
566  " clean up
567  set noincsearch
568  bw!
569endfunc
570
571func Test_search_cmdline6()
572  " Test that consecutive matches
573  " are caught by <c-g>/<c-t>
574  CheckOption incsearch
575
576  " need to disable char_avail,
577  " so that expansion of commandline works
578  call test_override("char_avail", 1)
579  new
580  call setline(1, [' bbvimb', ''])
581  set incsearch
582  " first match
583  norm! gg0
584  call feedkeys("/b\<cr>", 'tx')
585  call assert_equal([0,1,2,0], getpos('.'))
586  " second match
587  norm! gg0
588  call feedkeys("/b\<c-g>\<cr>", 'tx')
589  call assert_equal([0,1,3,0], getpos('.'))
590  " third match
591  norm! gg0
592  call feedkeys("/b\<c-g>\<c-g>\<cr>", 'tx')
593  call assert_equal([0,1,7,0], getpos('.'))
594  " first match again
595  norm! gg0
596  call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
597  call assert_equal([0,1,2,0], getpos('.'))
598  set nowrapscan
599  " last match
600  norm! gg0
601  call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
602  call assert_equal([0,1,7,0], getpos('.'))
603  " clean up
604  set wrapscan&vim
605  set noincsearch
606  call test_override("char_avail", 0)
607  bw!
608endfunc
609
610func Test_search_cmdline7()
611  " Test that pressing <c-g> in an empty command line
612  " does not move the cursor
613  CheckOption incsearch
614
615  " need to disable char_avail,
616  " so that expansion of commandline works
617  call test_override("char_avail", 1)
618  new
619  let @/ = 'b'
620  call setline(1, [' bbvimb', ''])
621  set incsearch
622  " first match
623  norm! gg0
624  " moves to next match of previous search pattern, just like /<cr>
625  call feedkeys("/\<c-g>\<cr>", 'tx')
626  call assert_equal([0,1,2,0], getpos('.'))
627  " moves to next match of previous search pattern, just like /<cr>
628  call feedkeys("/\<cr>", 'tx')
629  call assert_equal([0,1,3,0], getpos('.'))
630  " moves to next match of previous search pattern, just like /<cr>
631  call feedkeys("/\<c-t>\<cr>", 'tx')
632  call assert_equal([0,1,7,0], getpos('.'))
633
634  " using an offset uses the last search pattern
635  call cursor(1, 1)
636  call setline(1, ['1 bbvimb', ' 2 bbvimb'])
637  let @/ = 'b'
638  call feedkeys("//e\<c-g>\<cr>", 'tx')
639  call assert_equal('1 bbvimb', getline('.'))
640  call assert_equal(4, col('.'))
641
642  set noincsearch
643  call test_override("char_avail", 0)
644  bw!
645endfunc
646
647func Test_search_cmdline8()
648  " Highlighting is cleared in all windows
649  " since hls applies to all windows
650  CheckOption incsearch
651  CheckFeature terminal
652  CheckNotGui
653  if has("win32")
654    throw "Skipped: Bug with sending <ESC> to terminal window not fixed yet"
655  endif
656
657  let h = winheight(0)
658  if h < 3
659    return
660  endif
661  " Prepare buffer text
662  let lines = ['abb vim vim vi', 'vimvivim']
663  call writefile(lines, 'Xsearch.txt')
664  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
665
666  call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
667
668  call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
669  call term_sendkeys(buf, ":14vsp\<cr>")
670  call term_sendkeys(buf, "/vim\<cr>")
671  call term_sendkeys(buf, "/b\<esc>")
672  call term_sendkeys(buf, "gg0")
673  call TermWait(buf, 250)
674  let screen_line = term_scrape(buf, 1)
675  let [a0,a1,a2,a3] = [screen_line[3].attr, screen_line[4].attr,
676        \ screen_line[18].attr, screen_line[19].attr]
677  call assert_notequal(a0, a1)
678  call assert_notequal(a0, a3)
679  call assert_notequal(a1, a2)
680  call assert_equal(a0, a2)
681  call assert_equal(a1, a3)
682  " clean up
683  call delete('Xsearch.txt')
684
685  bwipe!
686endfunc
687
688" Tests for regexp with various magic settings
689func Run_search_regexp_magic_opt()
690  put ='1 a aa abb abbccc'
691  exe 'normal! /a*b\{2}c\+/e' . "\<CR>"
692  call assert_equal([0, 2, 17, 0], getpos('.'))
693
694  put ='2 d dd dee deefff'
695  exe 'normal! /\Md\*e\{2}f\+/e' . "\<CR>"
696  call assert_equal([0, 3, 17, 0], getpos('.'))
697
698  set nomagic
699  put ='3 g gg ghh ghhiii'
700  exe 'normal! /g\*h\{2}i\+/e' . "\<CR>"
701  call assert_equal([0, 4, 17, 0], getpos('.'))
702
703  put ='4 j jj jkk jkklll'
704  exe 'normal! /\mj*k\{2}l\+/e' . "\<CR>"
705  call assert_equal([0, 5, 17, 0], getpos('.'))
706
707  put ='5 m mm mnn mnnooo'
708  exe 'normal! /\vm*n{2}o+/e' . "\<CR>"
709  call assert_equal([0, 6, 17, 0], getpos('.'))
710
711  put ='6 x ^aa$ x'
712  exe 'normal! /\V^aa$' . "\<CR>"
713  call assert_equal([0, 7, 5, 0], getpos('.'))
714
715  set magic
716  put ='7 (a)(b) abbaa'
717  exe 'normal! /\v(a)(b)\2\1\1/e' . "\<CR>"
718  call assert_equal([0, 8, 14, 0], getpos('.'))
719
720  put ='8 axx [ab]xx'
721  exe 'normal! /\V[ab]\(\[xy]\)\1' . "\<CR>"
722  call assert_equal([0, 9, 7, 0], getpos('.'))
723
724  %d
725endfunc
726
727func Test_search_regexp()
728  enew!
729
730  set regexpengine=1
731  call Run_search_regexp_magic_opt()
732  set regexpengine=2
733  call Run_search_regexp_magic_opt()
734  set regexpengine&
735
736  set undolevels=100
737  put ='9 foobar'
738  put =''
739  exe "normal! a\<C-G>u\<Esc>"
740  normal G
741  exe 'normal! dv?bar?' . "\<CR>"
742  call assert_equal('9 foo', getline('.'))
743  call assert_equal([0, 2, 5, 0], getpos('.'))
744  call assert_equal(2, line('$'))
745  normal u
746  call assert_equal('9 foobar', getline('.'))
747  call assert_equal([0, 2, 6, 0], getpos('.'))
748  call assert_equal(3, line('$'))
749
750  set undolevels&
751  enew!
752endfunc
753
754func Test_search_cmdline_incsearch_highlight()
755  CheckOption incsearch
756
757  set incsearch hlsearch
758  " need to disable char_avail,
759  " so that expansion of commandline works
760  call test_override("char_avail", 1)
761  new
762  call setline(1, ['aaa  1 the first', '  2 the second', '  3 the third'])
763
764  1
765  call feedkeys("/second\<cr>", 'tx')
766  call assert_equal('second', @/)
767  call assert_equal('  2 the second', getline('.'))
768
769  " Canceling search won't change @/
770  1
771  let @/ = 'last pattern'
772  call feedkeys("/third\<C-c>", 'tx')
773  call assert_equal('last pattern', @/)
774  call feedkeys("/third\<Esc>", 'tx')
775  call assert_equal('last pattern', @/)
776  call feedkeys("/3\<bs>\<bs>", 'tx')
777  call assert_equal('last pattern', @/)
778  call feedkeys("/third\<c-g>\<c-t>\<Esc>", 'tx')
779  call assert_equal('last pattern', @/)
780
781  " clean up
782  set noincsearch nohlsearch
783  bw!
784endfunc
785
786func Test_search_cmdline_incsearch_highlight_attr()
787  CheckOption incsearch
788  CheckFeature terminal
789  CheckNotGui
790
791  let h = winheight(0)
792  if h < 3
793    return
794  endif
795
796  " Prepare buffer text
797  let lines = ['abb vim vim vi', 'vimvivim']
798  call writefile(lines, 'Xsearch.txt')
799  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
800
801  call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
802  " wait for vim to complete initialization
803  call TermWait(buf)
804
805  " Get attr of normal(a0), incsearch(a1), hlsearch(a2) highlight
806  call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
807  call term_sendkeys(buf, '/b')
808  call TermWait(buf, 100)
809  let screen_line1 = term_scrape(buf, 1)
810  call assert_true(len(screen_line1) > 2)
811  " a0: attr_normal
812  let a0 = screen_line1[0].attr
813  " a1: attr_incsearch
814  let a1 = screen_line1[1].attr
815  " a2: attr_hlsearch
816  let a2 = screen_line1[2].attr
817  call assert_notequal(a0, a1)
818  call assert_notequal(a0, a2)
819  call assert_notequal(a1, a2)
820  call term_sendkeys(buf, "\<cr>gg0")
821
822  " Test incremental highlight search
823  call term_sendkeys(buf, "/vim")
824  call TermWait(buf, 100)
825  " Buffer:
826  " abb vim vim vi
827  " vimvivim
828  " Search: /vim
829  let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a2,a2,a2,a0,a0,a0]
830  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
831  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
832  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
833
834  " Test <C-g>
835  call term_sendkeys(buf, "\<C-g>\<C-g>")
836  call TermWait(buf, 100)
837  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
838  let attr_line2 = [a1,a1,a1,a0,a0,a2,a2,a2]
839  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
840  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
841
842  " Test <C-t>
843  call term_sendkeys(buf, "\<C-t>")
844  call TermWait(buf, 100)
845  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a1,a1,a1,a0,a0,a0]
846  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
847  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
848  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
849
850  " Type Enter and a1(incsearch highlight) should become a2(hlsearch highlight)
851  call term_sendkeys(buf, "\<cr>")
852  call TermWait(buf, 100)
853  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
854  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
855  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
856  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
857
858  " Test nohlsearch. a2(hlsearch highlight) should become a0(normal highlight)
859  call term_sendkeys(buf, ":1\<cr>")
860  call term_sendkeys(buf, ":set nohlsearch\<cr>")
861  call term_sendkeys(buf, "/vim")
862  call TermWait(buf, 100)
863  let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a0,a0,a0,a0,a0,a0]
864  let attr_line2 = [a0,a0,a0,a0,a0,a0,a0,a0]
865  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
866  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
867  call delete('Xsearch.txt')
868
869  call delete('Xsearch.txt')
870  bwipe!
871endfunc
872
873func Test_incsearch_cmdline_modifier()
874  CheckOption incsearch
875
876  call test_override("char_avail", 1)
877  new
878  call setline(1, ['foo'])
879  set incsearch
880  " Test that error E14 does not occur in parsing command modifier.
881  call feedkeys("V:tab", 'tx')
882
883  call Incsearch_cleanup()
884endfunc
885
886func Test_incsearch_scrolling()
887  CheckRunVimInTerminal
888  call assert_equal(0, &scrolloff)
889  call writefile([
890	\ 'let dots = repeat(".", 120)',
891	\ 'set incsearch cmdheight=2 scrolloff=0',
892	\ 'call setline(1, [dots, dots, dots, "", "target", dots, dots])',
893	\ 'normal gg',
894	\ 'redraw',
895	\ ], 'Xscript')
896  let buf = RunVimInTerminal('-S Xscript', {'rows': 9, 'cols': 70})
897  " Need to send one key at a time to force a redraw
898  call term_sendkeys(buf, '/')
899  sleep 100m
900  call term_sendkeys(buf, 't')
901  sleep 100m
902  call term_sendkeys(buf, 'a')
903  sleep 100m
904  call term_sendkeys(buf, 'r')
905  sleep 100m
906  call term_sendkeys(buf, 'g')
907  call VerifyScreenDump(buf, 'Test_incsearch_scrolling_01', {})
908
909  call term_sendkeys(buf, "\<Esc>")
910  call StopVimInTerminal(buf)
911  call delete('Xscript')
912endfunc
913
914func Test_incsearch_search_dump()
915  CheckOption incsearch
916  CheckScreendump
917
918  call writefile([
919	\ 'set incsearch hlsearch scrolloff=0',
920	\ 'for n in range(1, 8)',
921	\ '  call setline(n, "foo " . n)',
922	\ 'endfor',
923	\ '3',
924	\ ], 'Xis_search_script')
925  let buf = RunVimInTerminal('-S Xis_search_script', {'rows': 9, 'cols': 70})
926  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
927  " the 'ambiwidth' check.
928  sleep 100m
929
930  " Need to send one key at a time to force a redraw.
931  call term_sendkeys(buf, '/fo')
932  call VerifyScreenDump(buf, 'Test_incsearch_search_01', {})
933  call term_sendkeys(buf, "\<Esc>")
934  sleep 100m
935
936  call term_sendkeys(buf, '/\v')
937  call VerifyScreenDump(buf, 'Test_incsearch_search_02', {})
938  call term_sendkeys(buf, "\<Esc>")
939
940  call StopVimInTerminal(buf)
941  call delete('Xis_search_script')
942endfunc
943
944func Test_incsearch_substitute()
945  CheckOption incsearch
946
947  call test_override("char_avail", 1)
948  new
949  set incsearch
950  for n in range(1, 10)
951    call setline(n, 'foo ' . n)
952  endfor
953  4
954  call feedkeys(":.,.+2s/foo\<BS>o\<BS>o/xxx\<cr>", 'tx')
955  call assert_equal('foo 3', getline(3))
956  call assert_equal('xxx 4', getline(4))
957  call assert_equal('xxx 5', getline(5))
958  call assert_equal('xxx 6', getline(6))
959  call assert_equal('foo 7', getline(7))
960
961  call Incsearch_cleanup()
962endfunc
963
964" Similar to Test_incsearch_substitute() but with a screendump halfway.
965func Test_incsearch_substitute_dump()
966  CheckOption incsearch
967  CheckScreendump
968
969  call writefile([
970	\ 'set incsearch hlsearch scrolloff=0',
971	\ 'for n in range(1, 10)',
972	\ '  call setline(n, "foo " . n)',
973	\ 'endfor',
974	\ 'call setline(11, "bar 11")',
975	\ '3',
976	\ ], 'Xis_subst_script')
977  let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70})
978  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
979  " the 'ambiwidth' check.
980  sleep 100m
981
982  " Need to send one key at a time to force a redraw.
983  " Select three lines at the cursor with typed pattern.
984  call term_sendkeys(buf, ':.,.+2s/')
985  sleep 100m
986  call term_sendkeys(buf, 'f')
987  sleep 100m
988  call term_sendkeys(buf, 'o')
989  sleep 100m
990  call term_sendkeys(buf, 'o')
991  call VerifyScreenDump(buf, 'Test_incsearch_substitute_01', {})
992  call term_sendkeys(buf, "\<Esc>")
993
994  " Select three lines at the cursor using previous pattern.
995  call term_sendkeys(buf, "/foo\<CR>")
996  sleep 100m
997  call term_sendkeys(buf, ':.,.+2s//')
998  call VerifyScreenDump(buf, 'Test_incsearch_substitute_02', {})
999
1000  " Deleting last slash should remove the match.
1001  call term_sendkeys(buf, "\<BS>")
1002  call VerifyScreenDump(buf, 'Test_incsearch_substitute_03', {})
1003  call term_sendkeys(buf, "\<Esc>")
1004
1005  " Reverse range is accepted
1006  call term_sendkeys(buf, ':5,2s/foo')
1007  call VerifyScreenDump(buf, 'Test_incsearch_substitute_04', {})
1008  call term_sendkeys(buf, "\<Esc>")
1009
1010  " White space after the command is skipped
1011  call term_sendkeys(buf, ':2,3sub  /fo')
1012  call VerifyScreenDump(buf, 'Test_incsearch_substitute_05', {})
1013  call term_sendkeys(buf, "\<Esc>")
1014
1015  " Command modifiers are skipped
1016  call term_sendkeys(buf, ':above below browse botr confirm keepmar keepalt keeppat keepjum filter xxx hide lockm leftabove noau noswap rightbel sandbox silent silent! $tab top unsil vert verbose 4,5s/fo.')
1017  call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {})
1018  call term_sendkeys(buf, "\<Esc>")
1019
1020  " Cursorline highlighting at match
1021  call term_sendkeys(buf, ":set cursorline\<CR>")
1022  call term_sendkeys(buf, 'G9G')
1023  call term_sendkeys(buf, ':9,11s/bar')
1024  call VerifyScreenDump(buf, 'Test_incsearch_substitute_07', {})
1025  call term_sendkeys(buf, "\<Esc>")
1026
1027  " Cursorline highlighting at cursor when no match
1028  call term_sendkeys(buf, ':9,10s/bar')
1029  call VerifyScreenDump(buf, 'Test_incsearch_substitute_08', {})
1030  call term_sendkeys(buf, "\<Esc>")
1031
1032  " Only \v handled as empty pattern, does not move cursor
1033  call term_sendkeys(buf, '3G4G')
1034  call term_sendkeys(buf, ":nohlsearch\<CR>")
1035  call term_sendkeys(buf, ':6,7s/\v')
1036  call VerifyScreenDump(buf, 'Test_incsearch_substitute_09', {})
1037  call term_sendkeys(buf, "\<Esc>")
1038
1039  call term_sendkeys(buf, ":set nocursorline\<CR>")
1040
1041  " All matches are highlighted for 'hlsearch' after the incsearch canceled
1042  call term_sendkeys(buf, "1G*")
1043  call term_sendkeys(buf, ":2,5s/foo")
1044  sleep 100m
1045  call term_sendkeys(buf, "\<Esc>")
1046  call VerifyScreenDump(buf, 'Test_incsearch_substitute_10', {})
1047
1048  call term_sendkeys(buf, ":split\<CR>")
1049  call term_sendkeys(buf, ":let @/ = 'xyz'\<CR>")
1050  call term_sendkeys(buf, ":%s/.")
1051  call VerifyScreenDump(buf, 'Test_incsearch_substitute_11', {})
1052  call term_sendkeys(buf, "\<BS>")
1053  call VerifyScreenDump(buf, 'Test_incsearch_substitute_12', {})
1054  call term_sendkeys(buf, "\<Esc>")
1055  call VerifyScreenDump(buf, 'Test_incsearch_substitute_13', {})
1056  call term_sendkeys(buf, ":%bwipe!\<CR>")
1057  call term_sendkeys(buf, ":only!\<CR>")
1058
1059  "  get :'<,'>s command in history
1060  call term_sendkeys(buf, ":set cmdheight=2\<CR>")
1061  call term_sendkeys(buf, "aasdfasdf\<Esc>")
1062  call term_sendkeys(buf, "V:s/a/b/g\<CR>")
1063  " Using '<,'> does not give E20
1064  call term_sendkeys(buf, ":new\<CR>")
1065  call term_sendkeys(buf, "aasdfasdf\<Esc>")
1066  call term_sendkeys(buf, ":\<Up>\<Up>")
1067  call VerifyScreenDump(buf, 'Test_incsearch_substitute_14', {})
1068  call term_sendkeys(buf, "<Esc>")
1069
1070  call StopVimInTerminal(buf)
1071  call delete('Xis_subst_script')
1072endfunc
1073
1074func Test_incsearch_highlighting()
1075  CheckOption incsearch
1076  CheckScreendump
1077
1078  call writefile([
1079	\ 'set incsearch hlsearch',
1080	\ 'call setline(1, "hello/there")',
1081	\ ], 'Xis_subst_hl_script')
1082  let buf = RunVimInTerminal('-S Xis_subst_hl_script', {'rows': 4, 'cols': 20})
1083  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1084  " the 'ambiwidth' check.
1085  sleep 300m
1086
1087  " Using a different search delimiter should still highlight matches
1088  " that contain a '/'.
1089  call term_sendkeys(buf, ":%s;ello/the")
1090  call VerifyScreenDump(buf, 'Test_incsearch_substitute_15', {})
1091  call term_sendkeys(buf, "<Esc>")
1092
1093  call StopVimInTerminal(buf)
1094  call delete('Xis_subst_hl_script')
1095endfunc
1096
1097func Test_incsearch_with_change()
1098  CheckFeature timers
1099  CheckOption incsearch
1100  CheckScreendump
1101
1102  call writefile([
1103	\ 'set incsearch hlsearch scrolloff=0',
1104	\ 'call setline(1, ["one", "two ------ X", "three"])',
1105	\ 'call timer_start(200, { _ -> setline(2, "x")})',
1106	\ ], 'Xis_change_script')
1107  let buf = RunVimInTerminal('-S Xis_change_script', {'rows': 9, 'cols': 70})
1108  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1109  " the 'ambiwidth' check.
1110  sleep 300m
1111
1112  " Highlight X, it will be deleted by the timer callback.
1113  call term_sendkeys(buf, ':%s/X')
1114  call VerifyScreenDump(buf, 'Test_incsearch_change_01', {})
1115  call term_sendkeys(buf, "\<Esc>")
1116
1117  call StopVimInTerminal(buf)
1118  call delete('Xis_change_script')
1119endfunc
1120
1121" Similar to Test_incsearch_substitute_dump() for :sort
1122func Test_incsearch_sort_dump()
1123  CheckOption incsearch
1124  CheckScreendump
1125
1126  call writefile([
1127	\ 'set incsearch hlsearch scrolloff=0',
1128	\ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
1129	\ ], 'Xis_sort_script')
1130  let buf = RunVimInTerminal('-S Xis_sort_script', {'rows': 9, 'cols': 70})
1131  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1132  " the 'ambiwidth' check.
1133  sleep 100m
1134
1135  call term_sendkeys(buf, ':sort ni u /on')
1136  call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {})
1137  call term_sendkeys(buf, "\<Esc>")
1138
1139  call term_sendkeys(buf, ':sort! /on')
1140  call VerifyScreenDump(buf, 'Test_incsearch_sort_02', {})
1141  call term_sendkeys(buf, "\<Esc>")
1142
1143  call StopVimInTerminal(buf)
1144  call delete('Xis_sort_script')
1145endfunc
1146
1147" Similar to Test_incsearch_substitute_dump() for :vimgrep famiry
1148func Test_incsearch_vimgrep_dump()
1149  CheckOption incsearch
1150  CheckScreendump
1151
1152  call writefile([
1153	\ 'set incsearch hlsearch scrolloff=0',
1154	\ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
1155	\ ], 'Xis_vimgrep_script')
1156  let buf = RunVimInTerminal('-S Xis_vimgrep_script', {'rows': 9, 'cols': 70})
1157  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1158  " the 'ambiwidth' check.
1159  sleep 100m
1160
1161  " Need to send one key at a time to force a redraw.
1162  call term_sendkeys(buf, ':vimgrep on')
1163  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_01', {})
1164  call term_sendkeys(buf, "\<Esc>")
1165
1166  call term_sendkeys(buf, ':vimg /on/ *.txt')
1167  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_02', {})
1168  call term_sendkeys(buf, "\<Esc>")
1169
1170  call term_sendkeys(buf, ':vimgrepadd "\<on')
1171  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_03', {})
1172  call term_sendkeys(buf, "\<Esc>")
1173
1174  call term_sendkeys(buf, ':lv "tha')
1175  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_04', {})
1176  call term_sendkeys(buf, "\<Esc>")
1177
1178  call term_sendkeys(buf, ':lvimgrepa "the" **/*.txt')
1179  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_05', {})
1180  call term_sendkeys(buf, "\<Esc>")
1181
1182  call StopVimInTerminal(buf)
1183  call delete('Xis_vimgrep_script')
1184endfunc
1185
1186func Test_keep_last_search_pattern()
1187  CheckOption incsearch
1188
1189  new
1190  call setline(1, ['foo', 'foo', 'foo'])
1191  set incsearch
1192  call test_override("char_avail", 1)
1193  let @/ = 'bar'
1194  call feedkeys(":/foo/s//\<Esc>", 'ntx')
1195  call assert_equal('bar', @/)
1196
1197  " no error message if pattern not found
1198  call feedkeys(":/xyz/s//\<Esc>", 'ntx')
1199  call assert_equal('bar', @/)
1200
1201  bwipe!
1202  call test_override("ALL", 0)
1203  set noincsearch
1204endfunc
1205
1206func Test_word_under_cursor_after_match()
1207  CheckOption incsearch
1208
1209  new
1210  call setline(1, 'foo bar')
1211  set incsearch
1212  call test_override("char_avail", 1)
1213  try
1214    call feedkeys("/foo\<C-R>\<C-W>\<CR>", 'ntx')
1215  catch /E486:/
1216  endtry
1217  call assert_equal('foobar', @/)
1218
1219  bwipe!
1220  call test_override("ALL", 0)
1221  set noincsearch
1222endfunc
1223
1224func Test_subst_word_under_cursor()
1225  CheckOption incsearch
1226
1227  new
1228  call setline(1, ['int SomeLongName;', 'for (xxx = 1; xxx < len; ++xxx)'])
1229  set incsearch
1230  call test_override("char_avail", 1)
1231  call feedkeys("/LongName\<CR>", 'ntx')
1232  call feedkeys(":%s/xxx/\<C-R>\<C-W>/g\<CR>", 'ntx')
1233  call assert_equal('for (SomeLongName = 1; SomeLongName < len; ++SomeLongName)', getline(2))
1234
1235  bwipe!
1236  call test_override("ALL", 0)
1237  set noincsearch
1238endfunc
1239
1240func Test_search_undefined_behaviour()
1241  CheckFeature terminal
1242
1243  let h = winheight(0)
1244  if h < 3
1245    return
1246  endif
1247  " did cause an undefined left shift
1248  let g:buf = term_start([GetVimProg(), '--clean', '-e', '-s', '-c', 'call search(getline("."))', 'samples/test000'], {'term_rows': 3})
1249  call assert_equal([''], getline(1, '$'))
1250  call term_sendkeys(g:buf, ":qa!\<cr>")
1251  bwipe!
1252endfunc
1253
1254func Test_search_undefined_behaviour2()
1255  call search("\%UC0000000")
1256endfunc
1257
1258" Test for search('multi-byte char', 'bce')
1259func Test_search_multibyte()
1260  let save_enc = &encoding
1261  set encoding=utf8
1262  enew!
1263  call append('$', 'A')
1264  call cursor(2, 1)
1265  call assert_equal(2, search('A', 'bce', line('.')))
1266  enew!
1267  let &encoding = save_enc
1268endfunc
1269
1270" This was causing E874.  Also causes an invalid read?
1271func Test_look_behind()
1272  new
1273  call setline(1, '0\|\&\n\@<=')
1274  call search(getline("."))
1275  bwipe!
1276endfunc
1277
1278func Test_search_sentence()
1279  new
1280  " this used to cause a crash
1281  call assert_fails("/\\%')", 'E486')
1282  call assert_fails("/", 'E486')
1283  /\%'(
1284  /
1285endfunc
1286
1287" Test that there is no crash when there is a last search pattern but no last
1288" substitute pattern.
1289func Test_no_last_substitute_pat()
1290  " Use viminfo to set the last search pattern to a string and make the last
1291  " substitute pattern the most recent used and make it empty (NULL).
1292  call writefile(['~MSle0/bar', '~MSle0~&'], 'Xviminfo')
1293  rviminfo! Xviminfo
1294  call assert_fails('normal n', 'E35:')
1295
1296  call delete('Xviminfo')
1297endfunc
1298
1299func Test_search_Ctrl_L_combining()
1300  " Make sure, that Ctrl-L works correctly with combining characters.
1301  " It uses an artificial example of an 'a' with 4 combining chars:
1302    " 'a' U+0061 Dec:97 LATIN SMALL LETTER A &#x61; /\%u61\Z "\u0061"
1303    " ' ̀' U+0300 Dec:768 COMBINING GRAVE ACCENT &#x300; /\%u300\Z "\u0300"
1304    " ' ́' U+0301 Dec:769 COMBINING ACUTE ACCENT &#x301; /\%u301\Z "\u0301"
1305    " ' ̇' U+0307 Dec:775 COMBINING DOT ABOVE &#x307; /\%u307\Z "\u0307"
1306    " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW &#x323; /\%u323 "\u0323"
1307  " Those should also appear on the commandline
1308  CheckOption incsearch
1309
1310  call Cmdline3_prep()
1311  1
1312  let bufcontent = ['', 'Miạ̀́̇m']
1313  call append('$', bufcontent)
1314  call feedkeys("/Mi\<c-l>\<c-l>\<cr>", 'tx')
1315  call assert_equal(5, line('.'))
1316  call assert_equal(bufcontent[1], @/)
1317  call Incsearch_cleanup()
1318endfunc
1319
1320func Test_large_hex_chars1()
1321  " This used to cause a crash, the character becomes an NFA state.
1322  try
1323    /\%Ufffffc23
1324  catch
1325    call assert_match('E678:', v:exception)
1326  endtry
1327  try
1328    set re=1
1329    /\%Ufffffc23
1330  catch
1331    call assert_match('E678:', v:exception)
1332  endtry
1333  set re&
1334endfunc
1335
1336func Test_large_hex_chars2()
1337  " This used to cause a crash, the character becomes an NFA state.
1338  try
1339    /[\Ufffffc1f]
1340  catch
1341    call assert_match('E486:', v:exception)
1342  endtry
1343  try
1344    set re=1
1345    /[\Ufffffc1f]
1346  catch
1347    call assert_match('E486:', v:exception)
1348  endtry
1349  set re&
1350endfunc
1351
1352func Test_one_error_msg()
1353  " This was also giving an internal error
1354  call assert_fails('call search(" \\((\\v[[=P=]]){185}+             ")', 'E871:')
1355endfunc
1356
1357func Test_incsearch_add_char_under_cursor()
1358  CheckOption incsearch
1359
1360  set incsearch
1361  new
1362  call setline(1, ['find match', 'anything'])
1363  1
1364  call test_override('char_avail', 1)
1365  call feedkeys("fc/m\<C-L>\<C-L>\<C-L>\<C-L>\<C-L>\<CR>", 'tx')
1366  call assert_equal('match', @/)
1367  call test_override('char_avail', 0)
1368
1369  set incsearch&
1370  bwipe!
1371endfunc
1372
1373" Test for the search() function with match at the cursor position
1374func Test_search_match_at_curpos()
1375  new
1376  call append(0, ['foobar', '', 'one two', ''])
1377
1378  normal gg
1379
1380  eval 'foobar'->search('c')
1381  call assert_equal([1, 1], [line('.'), col('.')])
1382
1383  normal j
1384  call search('^$', 'c')
1385  call assert_equal([2, 1], [line('.'), col('.')])
1386
1387  call search('^$', 'bc')
1388  call assert_equal([2, 1], [line('.'), col('.')])
1389
1390  exe "normal /two\<CR>"
1391  call search('.', 'c')
1392  call assert_equal([3, 5], [line('.'), col('.')])
1393
1394  close!
1395endfunc
1396
1397" Test for error cases with the search() function
1398func Test_search_errors()
1399  call assert_fails("call search('pat', [])", 'E730:')
1400  call assert_fails("call search('pat', 'b', {})", 'E728:')
1401  call assert_fails("call search('pat', 'b', 1, [])", 'E745:')
1402  call assert_fails("call search('pat', 'ns')", 'E475:')
1403  call assert_fails("call search('pat', 'mr')", 'E475:')
1404
1405  new
1406  call setline(1, ['foo', 'bar'])
1407  call assert_fails('call feedkeys("/foo/;/bar/;\<CR>", "tx")', 'E386:')
1408  bwipe!
1409endfunc
1410
1411func Test_search_display_pattern()
1412  new
1413  call setline(1, ['foo', 'bar', 'foobar'])
1414
1415  call cursor(1, 1)
1416  let @/ = 'foo'
1417  let pat = @/->escape('()*?'. '\s\+')
1418  let g:a = execute(':unsilent :norm! n')
1419  call assert_match(pat, g:a)
1420
1421  " right-left
1422  if exists("+rightleft")
1423    set rl
1424    call cursor(1, 1)
1425    let @/ = 'foo'
1426    let pat = 'oof/\s\+'
1427    let g:a = execute(':unsilent :norm! n')
1428    call assert_match(pat, g:a)
1429    set norl
1430  endif
1431endfunc
1432
1433func Test_searchdecl()
1434  let lines =<< trim END
1435     int global;
1436
1437     func()
1438     {
1439       int global;
1440       if (cond) {
1441	 int local;
1442       }
1443       int local;
1444       // comment
1445     }
1446  END
1447  new
1448  call setline(1, lines)
1449  10
1450  call assert_equal(0, searchdecl('local', 0, 0))
1451  call assert_equal(7, getcurpos()[1])
1452
1453  10
1454  call assert_equal(0, 'local'->searchdecl(0, 1))
1455  call assert_equal(9, getcurpos()[1])
1456
1457  10
1458  call assert_equal(0, searchdecl('global'))
1459  call assert_equal(5, getcurpos()[1])
1460
1461  10
1462  call assert_equal(0, searchdecl('global', 1))
1463  call assert_equal(1, getcurpos()[1])
1464
1465  bwipe!
1466endfunc
1467
1468func Test_search_special()
1469  " this was causing illegal memory access and an endless loop
1470  set t_PE=
1471  exe "norm /\x80PS"
1472endfunc
1473
1474" Test for command failures when the last search pattern is not set.
1475" Need to run this in a new vim instance where last search pattern is not set.
1476func Test_search_with_no_last_pat()
1477  let lines =<< trim [SCRIPT]
1478    call assert_fails("normal i\<C-R>/\e", 'E35:')
1479    call assert_fails("exe '/'", 'E35:')
1480    call assert_fails("exe '?'", 'E35:')
1481    call assert_fails("/", 'E35:')
1482    call assert_fails("?", 'E35:')
1483    call assert_fails("normal n", 'E35:')
1484    call assert_fails("normal N", 'E35:')
1485    call assert_fails("normal gn", 'E35:')
1486    call assert_fails("normal gN", 'E35:')
1487    call assert_fails("normal cgn", 'E35:')
1488    call assert_fails("normal cgN", 'E35:')
1489    let p = []
1490    let p = @/
1491    call assert_equal('', p)
1492    call assert_fails("normal :\<C-R>/", 'E35:')
1493    call assert_fails("//p", 'E35:')
1494    call assert_fails(";//p", 'E35:')
1495    call assert_fails("??p", 'E35:')
1496    call assert_fails(";??p", 'E35:')
1497    call assert_fails('g//p', ['E35:', 'E476:'])
1498    call assert_fails('v//p', ['E35:', 'E476:'])
1499    call writefile(v:errors, 'Xresult')
1500    qall!
1501  [SCRIPT]
1502  call writefile(lines, 'Xscript')
1503
1504  if RunVim([], [], '--clean -S Xscript')
1505    call assert_equal([], readfile('Xresult'))
1506  endif
1507  call delete('Xscript')
1508  call delete('Xresult')
1509endfunc
1510
1511" Test for using tilde (~) atom in search. This should use the last used
1512" substitute pattern
1513func Test_search_tilde_pat()
1514  let lines =<< trim [SCRIPT]
1515    set regexpengine=1
1516    call assert_fails('exe "normal /~\<CR>"', 'E33:')
1517    call assert_fails('exe "normal ?~\<CR>"', 'E33:')
1518    set regexpengine=2
1519    call assert_fails('exe "normal /~\<CR>"', ['E33:', 'E383:'])
1520    call assert_fails('exe "normal ?~\<CR>"', ['E33:', 'E383:'])
1521    set regexpengine&
1522    call writefile(v:errors, 'Xresult')
1523    qall!
1524  [SCRIPT]
1525  call writefile(lines, 'Xscript')
1526  if RunVim([], [], '--clean -S Xscript')
1527    call assert_equal([], readfile('Xresult'))
1528  endif
1529  call delete('Xscript')
1530  call delete('Xresult')
1531endfunc
1532
1533" Test for searching a pattern that is not present with 'nowrapscan'
1534func Test_search_pat_not_found()
1535  new
1536  set nowrapscan
1537  let @/ = '1abcxyz2'
1538  call assert_fails('normal n', 'E385:')
1539  call assert_fails('normal N', 'E384:')
1540  set wrapscan&
1541  close
1542endfunc
1543
1544" Test for v:searchforward variable
1545func Test_searchforward_var()
1546  new
1547  call setline(1, ['foo', '', 'foo'])
1548  call cursor(2, 1)
1549  let @/ = 'foo'
1550  let v:searchforward = 0
1551  normal N
1552  call assert_equal(3, line('.'))
1553  call cursor(2, 1)
1554  let v:searchforward = 1
1555  normal N
1556  call assert_equal(1, line('.'))
1557  close!
1558endfunc
1559
1560" Test for invalid regular expressions
1561func Test_invalid_regexp()
1562  set regexpengine=1
1563  call assert_fails("call search(repeat('\\(.\\)', 10))", 'E51:')
1564  call assert_fails("call search('\\%(')", 'E53:')
1565  call assert_fails("call search('\\(')", 'E54:')
1566  call assert_fails("call search('\\)')", 'E55:')
1567  call assert_fails("call search('x\\@#')", 'E59:')
1568  call assert_fails('call search(''\v%(%(%(%(%(%(%(%(%(%(%(a){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}'')', 'E60:')
1569  call assert_fails("call search('a\\+*')", 'E61:')
1570  call assert_fails("call search('\\_m')", 'E63:')
1571  call assert_fails("call search('\\+')", 'E64:')
1572  call assert_fails("call search('\\1')", 'E65:')
1573  call assert_fails("call search('\\z\\(\\)')", 'E66:')
1574  call assert_fails("call search('\\z2')", 'E67:')
1575  call assert_fails("call search('\\zx')", 'E68:')
1576  call assert_fails("call search('\\%[ab')", 'E69:')
1577  call assert_fails("call search('\\%[]')", 'E70:')
1578  call assert_fails("call search('\\%a')", 'E71:')
1579  call assert_fails("call search('ab\\%[\\(cd\\)]')", 'E369:')
1580  call assert_fails("call search('ab\\%[\\%(cd\\)]')", 'E369:')
1581  set regexpengine=2
1582  call assert_fails("call search('\\_')", 'E865:')
1583  call assert_fails("call search('\\+')", 'E866:')
1584  call assert_fails("call search('\\zx')", 'E867:')
1585  call assert_fails("call search('\\%a')", 'E867:')
1586  call assert_fails("call search('x\\@#')", 'E869:')
1587  call assert_fails("call search(repeat('\\(.\\)', 10))", 'E872:')
1588  call assert_fails("call search('\\_m')", 'E877:')
1589  call assert_fails("call search('\\%(')", 'E53:')
1590  call assert_fails("call search('\\(')", 'E54:')
1591  call assert_fails("call search('\\)')", 'E55:')
1592  call assert_fails("call search('\\z\\(\\)')", 'E66:')
1593  call assert_fails("call search('\\%[ab')", 'E69:')
1594  call assert_fails("call search('\\%[]')", 'E70:')
1595  call assert_fails("call search('\\%9999999999999999999999999999v')", 'E951:')
1596  set regexpengine&
1597  call assert_fails("call search('\\%#=3ab')", 'E864:')
1598endfunc
1599
1600" Test for searching a very complex pattern in a string. Should switch the
1601" regexp engine from NFA to the old engine.
1602func Test_regexp_switch_engine()
1603  let l = readfile('samples/re.freeze.txt')
1604  let v = substitute(l[4], '..\@<!', '', '')
1605  call assert_equal(l[4], v)
1606endfunc
1607
1608" Test for the \%V atom to search within visually selected text
1609func Test_search_in_visual_area()
1610  new
1611  call setline(1, ['foo bar1', 'foo bar2', 'foo bar3', 'foo bar4'])
1612  exe "normal 2GVjo/\\%Vbar\<CR>\<Esc>"
1613  call assert_equal([2, 5], [line('.'), col('.')])
1614  exe "normal 2GVj$?\\%Vbar\<CR>\<Esc>"
1615  call assert_equal([3, 5], [line('.'), col('.')])
1616  close!
1617endfunc
1618
1619" Test for searching with 'smartcase' and 'ignorecase'
1620func Test_search_smartcase()
1621  new
1622  call setline(1, ['', 'Hello'])
1623  set noignorecase nosmartcase
1624  call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
1625
1626  set ignorecase nosmartcase
1627  exe "normal /\\a\\_.\\(.*\\)O\<CR>"
1628  call assert_equal([2, 1], [line('.'), col('.')])
1629
1630  call cursor(1, 1)
1631  set ignorecase smartcase
1632  call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
1633
1634  exe "normal /\\a\\_.\\(.*\\)o\<CR>"
1635  call assert_equal([2, 1], [line('.'), col('.')])
1636
1637  " Test for using special atoms with 'smartcase'
1638  call setline(1, ['', '    Hello\ '])
1639  call cursor(1, 1)
1640  call feedkeys('/\_.\%(\uello\)\' .. "\<CR>", 'xt')
1641  call assert_equal([2, 4], [line('.'), col('.')])
1642
1643  set ignorecase& smartcase&
1644  close!
1645endfun
1646
1647" Test 'smartcase' with utf-8.
1648func Test_search_smartcase_utf8()
1649  new
1650  let save_enc = &encoding
1651  set encoding=utf8 ignorecase smartcase
1652
1653  call setline(1, 'Café cafÉ')
1654  1s/café/x/g
1655  call assert_equal('x x', getline(1))
1656
1657  call setline(1, 'Café cafÉ')
1658  1s/cafÉ/x/g
1659  call assert_equal('Café x', getline(1))
1660
1661  set ignorecase& smartcase&
1662  let &encoding = save_enc
1663  close!
1664endfunc
1665
1666" Test searching past the end of a file
1667func Test_search_past_eof()
1668  new
1669  call setline(1, ['Line'])
1670  exe "normal /\\n\\zs\<CR>"
1671  call assert_equal([1, 4], [line('.'), col('.')])
1672  close!
1673endfunc
1674
1675" Test for various search offsets
1676func Test_search_offset()
1677  " With /e, for a match in the first column of a line, the cursor should be
1678  " placed at the end of the previous line.
1679  new
1680  call setline(1, ['one two', 'three four'])
1681  call search('two\_.', 'e')
1682  call assert_equal([1, 7], [line('.'), col('.')])
1683
1684  " with cursor at the beginning of the file, use /s+1
1685  call cursor(1, 1)
1686  exe "normal /two/s+1\<CR>"
1687  call assert_equal([1, 6], [line('.'), col('.')])
1688
1689  " with cursor at the end of the file, use /e-1
1690  call cursor(2, 10)
1691  exe "normal ?three?e-1\<CR>"
1692  call assert_equal([2, 4], [line('.'), col('.')])
1693
1694  " line offset - after the last line
1695  call cursor(1, 1)
1696  exe "normal /three/+1\<CR>"
1697  call assert_equal([2, 1], [line('.'), col('.')])
1698
1699  " line offset - before the first line
1700  call cursor(2, 1)
1701  exe "normal ?one?-1\<CR>"
1702  call assert_equal([1, 1], [line('.'), col('.')])
1703
1704  " character offset - before the first character in the file
1705  call cursor(2, 1)
1706  exe "normal ?one?s-1\<CR>"
1707  call assert_equal([1, 1], [line('.'), col('.')])
1708  call cursor(2, 1)
1709  exe "normal ?one?e-3\<CR>"
1710  call assert_equal([1, 1], [line('.'), col('.')])
1711
1712  " character offset - after the last character in the file
1713  call cursor(1, 1)
1714  exe "normal /four/s+4\<CR>"
1715  call assert_equal([2, 10], [line('.'), col('.')])
1716  call cursor(1, 1)
1717  exe "normal /four/e+1\<CR>"
1718  call assert_equal([2, 10], [line('.'), col('.')])
1719
1720  close!
1721endfunc
1722
1723" Test for searching for matching parenthesis using %
1724func Test_search_match_paren()
1725  new
1726  call setline(1, "abc(def')'ghi'('jk'\\t'lm)no")
1727  " searching for a matching parenthesis should skip single quoted characters
1728  call cursor(1, 4)
1729  normal %
1730  call assert_equal([1, 25], [line('.'), col('.')])
1731  normal %
1732  call assert_equal([1, 4], [line('.'), col('.')])
1733  call cursor(1, 5)
1734  normal ])
1735  call assert_equal([1, 25], [line('.'), col('.')])
1736  call cursor(1, 24)
1737  normal [(
1738  call assert_equal([1, 4], [line('.'), col('.')])
1739
1740  " matching parenthesis in 'virtualedit' mode with cursor after the eol
1741  call setline(1, 'abc(defgh)')
1742  set virtualedit=all
1743  normal 20|%
1744  call assert_equal(4, col('.'))
1745  set virtualedit&
1746  close!
1747endfunc
1748
1749" Test for searching a pattern and stopping before a specified line
1750func Test_search_stopline()
1751  new
1752  call setline(1, ['', '', '', 'vim'])
1753  call assert_equal(0, search('vim', 'n', 3))
1754  call assert_equal(4, search('vim', 'n', 4))
1755  call setline(1, ['vim', '', '', ''])
1756  call cursor(4, 1)
1757  call assert_equal(0, search('vim', 'bn', 2))
1758  call assert_equal(1, search('vim', 'bn', 1))
1759  close!
1760endfunc
1761
1762" vim: shiftwidth=2 sts=2 expandtab
1763