xref: /vim-8.2.3635/src/testdir/test_search.vim (revision 81ea1dfb)
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', 0, 99, 100)", 'E475: Invalid argument: 0')
378  call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
379  call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
380  call assert_fails("call searchpair('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e')
381  call assert_fails("call searchpair('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn')
382endfunc
383
384func Test_searchpairpos_errors()
385  call assert_fails("call searchpairpos([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
386  call assert_fails("call searchpairpos('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
387  call assert_fails("call searchpairpos('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
388  call assert_fails("call searchpairpos('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
389  call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0')
390  call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
391  call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
392  call assert_fails("call searchpairpos('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e')
393  call assert_fails("call searchpairpos('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn')
394endfunc
395
396func Test_searchpair_skip()
397    func Zero()
398      return 0
399    endfunc
400    func Partial(x)
401      return a:x
402    endfunc
403    new
404    call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
405    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', ''))
406    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0'))
407    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0}))
408    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero')))
409    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0])))
410    bw!
411endfunc
412
413func Test_searchpair_leak()
414  new
415  call setline(1, 'if one else another endif')
416
417  " The error in the skip expression caused memory to leak.
418  call assert_fails("call searchpair('\\<if\\>', '\\<else\\>', '\\<endif\\>', '', '\"foo\" 2')", 'E15:')
419
420  bwipe!
421endfunc
422
423func Test_searchc()
424  " These commands used to cause memory overflow in searchc().
425  new
426  norm ixx
427  exe "norm 0t\u93cf"
428  bw!
429endfunc
430
431func Cmdline3_prep()
432  " need to disable char_avail,
433  " so that expansion of commandline works
434  call test_override("char_avail", 1)
435  new
436  call setline(1, ['  1', '  2 the~e', '  3 the theother'])
437  set incsearch
438endfunc
439
440func Incsearch_cleanup()
441  set noincsearch
442  call test_override("char_avail", 0)
443  bw!
444endfunc
445
446func Test_search_cmdline3()
447  CheckOption incsearch
448
449  call Cmdline3_prep()
450  1
451  " first match
452  call feedkeys("/the\<c-l>\<cr>", 'tx')
453  call assert_equal('  2 the~e', getline('.'))
454
455  call Incsearch_cleanup()
456endfunc
457
458func Test_search_cmdline3s()
459  CheckOption incsearch
460
461  call Cmdline3_prep()
462  1
463  call feedkeys(":%s/the\<c-l>/xxx\<cr>", 'tx')
464  call assert_equal('  2 xxxe', getline('.'))
465  undo
466  call feedkeys(":%subs/the\<c-l>/xxx\<cr>", 'tx')
467  call assert_equal('  2 xxxe', getline('.'))
468  undo
469  call feedkeys(":%substitute/the\<c-l>/xxx\<cr>", 'tx')
470  call assert_equal('  2 xxxe', getline('.'))
471  undo
472  call feedkeys(":%smagic/the.e/xxx\<cr>", 'tx')
473  call assert_equal('  2 xxx', getline('.'))
474  undo
475  call assert_fails(":%snomagic/the.e/xxx\<cr>", 'E486')
476  "
477  call feedkeys(":%snomagic/the\\.e/xxx\<cr>", 'tx')
478  call assert_equal('  2 xxx', getline('.'))
479
480  call Incsearch_cleanup()
481endfunc
482
483func Test_search_cmdline3g()
484  CheckOption incsearch
485
486  call Cmdline3_prep()
487  1
488  call feedkeys(":g/the\<c-l>/d\<cr>", 'tx')
489  call assert_equal('  3 the theother', getline(2))
490  undo
491  call feedkeys(":global/the\<c-l>/d\<cr>", 'tx')
492  call assert_equal('  3 the theother', getline(2))
493  undo
494  call feedkeys(":g!/the\<c-l>/d\<cr>", 'tx')
495  call assert_equal(1, line('$'))
496  call assert_equal('  2 the~e', getline(1))
497  undo
498  call feedkeys(":global!/the\<c-l>/d\<cr>", 'tx')
499  call assert_equal(1, line('$'))
500  call assert_equal('  2 the~e', getline(1))
501
502  call Incsearch_cleanup()
503endfunc
504
505func Test_search_cmdline3v()
506  CheckOption incsearch
507
508  call Cmdline3_prep()
509  1
510  call feedkeys(":v/the\<c-l>/d\<cr>", 'tx')
511  call assert_equal(1, line('$'))
512  call assert_equal('  2 the~e', getline(1))
513  undo
514  call feedkeys(":vglobal/the\<c-l>/d\<cr>", 'tx')
515  call assert_equal(1, line('$'))
516  call assert_equal('  2 the~e', getline(1))
517
518  call Incsearch_cleanup()
519endfunc
520
521func Test_search_cmdline4()
522  CheckOption incsearch
523
524  " need to disable char_avail,
525  " so that expansion of commandline works
526  call test_override("char_avail", 1)
527  new
528  call setline(1, ['  1 the first', '  2 the second', '  3 the third'])
529  set incsearch
530  $
531  call feedkeys("?the\<c-g>\<cr>", 'tx')
532  call assert_equal('  3 the third', getline('.'))
533  $
534  call feedkeys("?the\<c-g>\<c-g>\<cr>", 'tx')
535  call assert_equal('  1 the first', getline('.'))
536  $
537  call feedkeys("?the\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
538  call assert_equal('  2 the second', getline('.'))
539  $
540  call feedkeys("?the\<c-t>\<cr>", 'tx')
541  call assert_equal('  1 the first', getline('.'))
542  $
543  call feedkeys("?the\<c-t>\<c-t>\<cr>", 'tx')
544  call assert_equal('  3 the third', getline('.'))
545  $
546  call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
547  call assert_equal('  2 the second', getline('.'))
548  " clean up
549  set noincsearch
550  call test_override("char_avail", 0)
551  bw!
552endfunc
553
554func Test_search_cmdline5()
555  CheckOption incsearch
556
557  " Do not call test_override("char_avail", 1) so that <C-g> and <C-t> work
558  " regardless char_avail.
559  new
560  call setline(1, ['  1 the first', '  2 the second', '  3 the third', ''])
561  set incsearch
562  1
563  call feedkeys("/the\<c-g>\<c-g>\<cr>", 'tx')
564  call assert_equal('  3 the third', getline('.'))
565  $
566  call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
567  call assert_equal('  1 the first', getline('.'))
568  " clean up
569  set noincsearch
570  bw!
571endfunc
572
573func Test_search_cmdline6()
574  " Test that consecutive matches
575  " are caught by <c-g>/<c-t>
576  CheckOption incsearch
577
578  " need to disable char_avail,
579  " so that expansion of commandline works
580  call test_override("char_avail", 1)
581  new
582  call setline(1, [' bbvimb', ''])
583  set incsearch
584  " first match
585  norm! gg0
586  call feedkeys("/b\<cr>", 'tx')
587  call assert_equal([0,1,2,0], getpos('.'))
588  " second match
589  norm! gg0
590  call feedkeys("/b\<c-g>\<cr>", 'tx')
591  call assert_equal([0,1,3,0], getpos('.'))
592  " third match
593  norm! gg0
594  call feedkeys("/b\<c-g>\<c-g>\<cr>", 'tx')
595  call assert_equal([0,1,7,0], getpos('.'))
596  " first match again
597  norm! gg0
598  call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
599  call assert_equal([0,1,2,0], getpos('.'))
600  set nowrapscan
601  " last match
602  norm! gg0
603  call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
604  call assert_equal([0,1,7,0], getpos('.'))
605  " clean up
606  set wrapscan&vim
607  set noincsearch
608  call test_override("char_avail", 0)
609  bw!
610endfunc
611
612func Test_search_cmdline7()
613  " Test that an pressing <c-g> in an empty command line
614  " does not move the cursor
615  CheckOption incsearch
616
617  " need to disable char_avail,
618  " so that expansion of commandline works
619  call test_override("char_avail", 1)
620  new
621  let @/ = 'b'
622  call setline(1, [' bbvimb', ''])
623  set incsearch
624  " first match
625  norm! gg0
626  " moves to next match of previous search pattern, just like /<cr>
627  call feedkeys("/\<c-g>\<cr>", 'tx')
628  call assert_equal([0,1,2,0], getpos('.'))
629  " moves to next match of previous search pattern, just like /<cr>
630  call feedkeys("/\<cr>", 'tx')
631  call assert_equal([0,1,3,0], getpos('.'))
632  " moves to next match of previous search pattern, just like /<cr>
633  call feedkeys("/\<c-t>\<cr>", 'tx')
634  call assert_equal([0,1,7,0], getpos('.'))
635
636  " using an offset uses the last search pattern
637  call cursor(1, 1)
638  call setline(1, ['1 bbvimb', ' 2 bbvimb'])
639  let @/ = 'b'
640  call feedkeys("//e\<c-g>\<cr>", 'tx')
641  call assert_equal('1 bbvimb', getline('.'))
642  call assert_equal(4, col('.'))
643
644  set noincsearch
645  call test_override("char_avail", 0)
646  bw!
647endfunc
648
649func Test_search_cmdline8()
650  " Highlighting is cleared in all windows
651  " since hls applies to all windows
652  CheckOption incsearch
653  CheckFeature terminal
654  CheckNotGui
655  if has("win32")
656    throw "Skipped: Bug with sending <ESC> to terminal window not fixed yet"
657  endif
658
659  let h = winheight(0)
660  if h < 3
661    return
662  endif
663  " Prepare buffer text
664  let lines = ['abb vim vim vi', 'vimvivim']
665  call writefile(lines, 'Xsearch.txt')
666  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
667
668  call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
669
670  call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
671  call term_sendkeys(buf, ":14vsp\<cr>")
672  call term_sendkeys(buf, "/vim\<cr>")
673  call term_sendkeys(buf, "/b\<esc>")
674  call term_sendkeys(buf, "gg0")
675  call TermWait(buf, 250)
676  let screen_line = term_scrape(buf, 1)
677  let [a0,a1,a2,a3] = [screen_line[3].attr, screen_line[4].attr,
678        \ screen_line[18].attr, screen_line[19].attr]
679  call assert_notequal(a0, a1)
680  call assert_notequal(a0, a3)
681  call assert_notequal(a1, a2)
682  call assert_equal(a0, a2)
683  call assert_equal(a1, a3)
684  " clean up
685  call delete('Xsearch.txt')
686
687  bwipe!
688endfunc
689
690" Tests for regexp with various magic settings
691func Run_search_regexp_magic_opt()
692  put ='1 a aa abb abbccc'
693  exe 'normal! /a*b\{2}c\+/e' . "\<CR>"
694  call assert_equal([0, 2, 17, 0], getpos('.'))
695
696  put ='2 d dd dee deefff'
697  exe 'normal! /\Md\*e\{2}f\+/e' . "\<CR>"
698  call assert_equal([0, 3, 17, 0], getpos('.'))
699
700  set nomagic
701  put ='3 g gg ghh ghhiii'
702  exe 'normal! /g\*h\{2}i\+/e' . "\<CR>"
703  call assert_equal([0, 4, 17, 0], getpos('.'))
704
705  put ='4 j jj jkk jkklll'
706  exe 'normal! /\mj*k\{2}l\+/e' . "\<CR>"
707  call assert_equal([0, 5, 17, 0], getpos('.'))
708
709  put ='5 m mm mnn mnnooo'
710  exe 'normal! /\vm*n{2}o+/e' . "\<CR>"
711  call assert_equal([0, 6, 17, 0], getpos('.'))
712
713  put ='6 x ^aa$ x'
714  exe 'normal! /\V^aa$' . "\<CR>"
715  call assert_equal([0, 7, 5, 0], getpos('.'))
716
717  set magic
718  put ='7 (a)(b) abbaa'
719  exe 'normal! /\v(a)(b)\2\1\1/e' . "\<CR>"
720  call assert_equal([0, 8, 14, 0], getpos('.'))
721
722  put ='8 axx [ab]xx'
723  exe 'normal! /\V[ab]\(\[xy]\)\1' . "\<CR>"
724  call assert_equal([0, 9, 7, 0], getpos('.'))
725
726  %d
727endfunc
728
729func Test_search_regexp()
730  enew!
731
732  set regexpengine=1
733  call Run_search_regexp_magic_opt()
734  set regexpengine=2
735  call Run_search_regexp_magic_opt()
736  set regexpengine&
737
738  set undolevels=100
739  put ='9 foobar'
740  put =''
741  exe "normal! a\<C-G>u\<Esc>"
742  normal G
743  exe 'normal! dv?bar?' . "\<CR>"
744  call assert_equal('9 foo', getline('.'))
745  call assert_equal([0, 2, 5, 0], getpos('.'))
746  call assert_equal(2, line('$'))
747  normal u
748  call assert_equal('9 foobar', getline('.'))
749  call assert_equal([0, 2, 6, 0], getpos('.'))
750  call assert_equal(3, line('$'))
751
752  set undolevels&
753  enew!
754endfunc
755
756func Test_search_cmdline_incsearch_highlight()
757  CheckOption incsearch
758
759  set incsearch hlsearch
760  " need to disable char_avail,
761  " so that expansion of commandline works
762  call test_override("char_avail", 1)
763  new
764  call setline(1, ['aaa  1 the first', '  2 the second', '  3 the third'])
765
766  1
767  call feedkeys("/second\<cr>", 'tx')
768  call assert_equal('second', @/)
769  call assert_equal('  2 the second', getline('.'))
770
771  " Canceling search won't change @/
772  1
773  let @/ = 'last pattern'
774  call feedkeys("/third\<C-c>", 'tx')
775  call assert_equal('last pattern', @/)
776  call feedkeys("/third\<Esc>", 'tx')
777  call assert_equal('last pattern', @/)
778  call feedkeys("/3\<bs>\<bs>", 'tx')
779  call assert_equal('last pattern', @/)
780  call feedkeys("/third\<c-g>\<c-t>\<Esc>", 'tx')
781  call assert_equal('last pattern', @/)
782
783  " clean up
784  set noincsearch nohlsearch
785  bw!
786endfunc
787
788func Test_search_cmdline_incsearch_highlight_attr()
789  CheckOption incsearch
790  CheckFeature terminal
791  CheckNotGui
792
793  let h = winheight(0)
794  if h < 3
795    return
796  endif
797
798  " Prepare buffer text
799  let lines = ['abb vim vim vi', 'vimvivim']
800  call writefile(lines, 'Xsearch.txt')
801  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
802
803  call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
804  " wait for vim to complete initialization
805  call TermWait(buf)
806
807  " Get attr of normal(a0), incsearch(a1), hlsearch(a2) highlight
808  call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
809  call term_sendkeys(buf, '/b')
810  call TermWait(buf, 100)
811  let screen_line1 = term_scrape(buf, 1)
812  call assert_true(len(screen_line1) > 2)
813  " a0: attr_normal
814  let a0 = screen_line1[0].attr
815  " a1: attr_incsearch
816  let a1 = screen_line1[1].attr
817  " a2: attr_hlsearch
818  let a2 = screen_line1[2].attr
819  call assert_notequal(a0, a1)
820  call assert_notequal(a0, a2)
821  call assert_notequal(a1, a2)
822  call term_sendkeys(buf, "\<cr>gg0")
823
824  " Test incremental highlight search
825  call term_sendkeys(buf, "/vim")
826  call TermWait(buf, 100)
827  " Buffer:
828  " abb vim vim vi
829  " vimvivim
830  " Search: /vim
831  let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a2,a2,a2,a0,a0,a0]
832  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
833  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
834  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
835
836  " Test <C-g>
837  call term_sendkeys(buf, "\<C-g>\<C-g>")
838  call TermWait(buf, 100)
839  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
840  let attr_line2 = [a1,a1,a1,a0,a0,a2,a2,a2]
841  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
842  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
843
844  " Test <C-t>
845  call term_sendkeys(buf, "\<C-t>")
846  call TermWait(buf, 100)
847  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a1,a1,a1,a0,a0,a0]
848  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
849  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
850  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
851
852  " Type Enter and a1(incsearch highlight) should become a2(hlsearch highlight)
853  call term_sendkeys(buf, "\<cr>")
854  call TermWait(buf, 100)
855  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
856  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
857  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
858  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
859
860  " Test nohlsearch. a2(hlsearch highlight) should become a0(normal highlight)
861  call term_sendkeys(buf, ":1\<cr>")
862  call term_sendkeys(buf, ":set nohlsearch\<cr>")
863  call term_sendkeys(buf, "/vim")
864  call TermWait(buf, 100)
865  let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a0,a0,a0,a0,a0,a0]
866  let attr_line2 = [a0,a0,a0,a0,a0,a0,a0,a0]
867  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
868  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
869  call delete('Xsearch.txt')
870
871  call delete('Xsearch.txt')
872  bwipe!
873endfunc
874
875func Test_incsearch_cmdline_modifier()
876  CheckOption incsearch
877
878  call test_override("char_avail", 1)
879  new
880  call setline(1, ['foo'])
881  set incsearch
882  " Test that error E14 does not occur in parsing command modifier.
883  call feedkeys("V:tab", 'tx')
884
885  call Incsearch_cleanup()
886endfunc
887
888func Test_incsearch_scrolling()
889  if !CanRunVimInTerminal()
890    throw 'Skipped: cannot make screendumps'
891  endif
892  call assert_equal(0, &scrolloff)
893  call writefile([
894	\ 'let dots = repeat(".", 120)',
895	\ 'set incsearch cmdheight=2 scrolloff=0',
896	\ 'call setline(1, [dots, dots, dots, "", "target", dots, dots])',
897	\ 'normal gg',
898	\ 'redraw',
899	\ ], 'Xscript')
900  let buf = RunVimInTerminal('-S Xscript', {'rows': 9, 'cols': 70})
901  " Need to send one key at a time to force a redraw
902  call term_sendkeys(buf, '/')
903  sleep 100m
904  call term_sendkeys(buf, 't')
905  sleep 100m
906  call term_sendkeys(buf, 'a')
907  sleep 100m
908  call term_sendkeys(buf, 'r')
909  sleep 100m
910  call term_sendkeys(buf, 'g')
911  call VerifyScreenDump(buf, 'Test_incsearch_scrolling_01', {})
912
913  call term_sendkeys(buf, "\<Esc>")
914  call StopVimInTerminal(buf)
915  call delete('Xscript')
916endfunc
917
918func Test_incsearch_search_dump()
919  CheckOption incsearch
920  CheckScreendump
921
922  call writefile([
923	\ 'set incsearch hlsearch scrolloff=0',
924	\ 'for n in range(1, 8)',
925	\ '  call setline(n, "foo " . n)',
926	\ 'endfor',
927	\ '3',
928	\ ], 'Xis_search_script')
929  let buf = RunVimInTerminal('-S Xis_search_script', {'rows': 9, 'cols': 70})
930  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
931  " the 'ambiwidth' check.
932  sleep 100m
933
934  " Need to send one key at a time to force a redraw.
935  call term_sendkeys(buf, '/fo')
936  call VerifyScreenDump(buf, 'Test_incsearch_search_01', {})
937  call term_sendkeys(buf, "\<Esc>")
938  sleep 100m
939
940  call term_sendkeys(buf, '/\v')
941  call VerifyScreenDump(buf, 'Test_incsearch_search_02', {})
942  call term_sendkeys(buf, "\<Esc>")
943
944  call StopVimInTerminal(buf)
945  call delete('Xis_search_script')
946endfunc
947
948func Test_incsearch_substitute()
949  CheckOption incsearch
950
951  call test_override("char_avail", 1)
952  new
953  set incsearch
954  for n in range(1, 10)
955    call setline(n, 'foo ' . n)
956  endfor
957  4
958  call feedkeys(":.,.+2s/foo\<BS>o\<BS>o/xxx\<cr>", 'tx')
959  call assert_equal('foo 3', getline(3))
960  call assert_equal('xxx 4', getline(4))
961  call assert_equal('xxx 5', getline(5))
962  call assert_equal('xxx 6', getline(6))
963  call assert_equal('foo 7', getline(7))
964
965  call Incsearch_cleanup()
966endfunc
967
968" Similar to Test_incsearch_substitute() but with a screendump halfway.
969func Test_incsearch_substitute_dump()
970  CheckOption incsearch
971  CheckScreendump
972
973  call writefile([
974	\ 'set incsearch hlsearch scrolloff=0',
975	\ 'for n in range(1, 10)',
976	\ '  call setline(n, "foo " . n)',
977	\ 'endfor',
978	\ 'call setline(11, "bar 11")',
979	\ '3',
980	\ ], 'Xis_subst_script')
981  let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70})
982  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
983  " the 'ambiwidth' check.
984  sleep 100m
985
986  " Need to send one key at a time to force a redraw.
987  " Select three lines at the cursor with typed pattern.
988  call term_sendkeys(buf, ':.,.+2s/')
989  sleep 100m
990  call term_sendkeys(buf, 'f')
991  sleep 100m
992  call term_sendkeys(buf, 'o')
993  sleep 100m
994  call term_sendkeys(buf, 'o')
995  call VerifyScreenDump(buf, 'Test_incsearch_substitute_01', {})
996  call term_sendkeys(buf, "\<Esc>")
997
998  " Select three lines at the cursor using previous pattern.
999  call term_sendkeys(buf, "/foo\<CR>")
1000  sleep 100m
1001  call term_sendkeys(buf, ':.,.+2s//')
1002  call VerifyScreenDump(buf, 'Test_incsearch_substitute_02', {})
1003
1004  " Deleting last slash should remove the match.
1005  call term_sendkeys(buf, "\<BS>")
1006  call VerifyScreenDump(buf, 'Test_incsearch_substitute_03', {})
1007  call term_sendkeys(buf, "\<Esc>")
1008
1009  " Reverse range is accepted
1010  call term_sendkeys(buf, ':5,2s/foo')
1011  call VerifyScreenDump(buf, 'Test_incsearch_substitute_04', {})
1012  call term_sendkeys(buf, "\<Esc>")
1013
1014  " White space after the command is skipped
1015  call term_sendkeys(buf, ':2,3sub  /fo')
1016  call VerifyScreenDump(buf, 'Test_incsearch_substitute_05', {})
1017  call term_sendkeys(buf, "\<Esc>")
1018
1019  " Command modifiers are skipped
1020  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.')
1021  call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {})
1022  call term_sendkeys(buf, "\<Esc>")
1023
1024  " Cursorline highlighting at match
1025  call term_sendkeys(buf, ":set cursorline\<CR>")
1026  call term_sendkeys(buf, 'G9G')
1027  call term_sendkeys(buf, ':9,11s/bar')
1028  call VerifyScreenDump(buf, 'Test_incsearch_substitute_07', {})
1029  call term_sendkeys(buf, "\<Esc>")
1030
1031  " Cursorline highlighting at cursor when no match
1032  call term_sendkeys(buf, ':9,10s/bar')
1033  call VerifyScreenDump(buf, 'Test_incsearch_substitute_08', {})
1034  call term_sendkeys(buf, "\<Esc>")
1035
1036  " Only \v handled as empty pattern, does not move cursor
1037  call term_sendkeys(buf, '3G4G')
1038  call term_sendkeys(buf, ":nohlsearch\<CR>")
1039  call term_sendkeys(buf, ':6,7s/\v')
1040  call VerifyScreenDump(buf, 'Test_incsearch_substitute_09', {})
1041  call term_sendkeys(buf, "\<Esc>")
1042
1043  call term_sendkeys(buf, ":set nocursorline\<CR>")
1044
1045  " All matches are highlighted for 'hlsearch' after the incsearch canceled
1046  call term_sendkeys(buf, "1G*")
1047  call term_sendkeys(buf, ":2,5s/foo")
1048  sleep 100m
1049  call term_sendkeys(buf, "\<Esc>")
1050  call VerifyScreenDump(buf, 'Test_incsearch_substitute_10', {})
1051
1052  call term_sendkeys(buf, ":split\<CR>")
1053  call term_sendkeys(buf, ":let @/ = 'xyz'\<CR>")
1054  call term_sendkeys(buf, ":%s/.")
1055  call VerifyScreenDump(buf, 'Test_incsearch_substitute_11', {})
1056  call term_sendkeys(buf, "\<BS>")
1057  call VerifyScreenDump(buf, 'Test_incsearch_substitute_12', {})
1058  call term_sendkeys(buf, "\<Esc>")
1059  call VerifyScreenDump(buf, 'Test_incsearch_substitute_13', {})
1060  call term_sendkeys(buf, ":%bwipe!\<CR>")
1061  call term_sendkeys(buf, ":only!\<CR>")
1062
1063  "  get :'<,'>s command in history
1064  call term_sendkeys(buf, ":set cmdheight=2\<CR>")
1065  call term_sendkeys(buf, "aasdfasdf\<Esc>")
1066  call term_sendkeys(buf, "V:s/a/b/g\<CR>")
1067  " Using '<,'> does not give E20
1068  call term_sendkeys(buf, ":new\<CR>")
1069  call term_sendkeys(buf, "aasdfasdf\<Esc>")
1070  call term_sendkeys(buf, ":\<Up>\<Up>")
1071  call VerifyScreenDump(buf, 'Test_incsearch_substitute_14', {})
1072  call term_sendkeys(buf, "<Esc>")
1073
1074  call StopVimInTerminal(buf)
1075  call delete('Xis_subst_script')
1076endfunc
1077
1078func Test_incsearch_highlighting()
1079  CheckOption incsearch
1080  CheckScreendump
1081
1082  call writefile([
1083	\ 'set incsearch hlsearch',
1084	\ 'call setline(1, "hello/there")',
1085	\ ], 'Xis_subst_hl_script')
1086  let buf = RunVimInTerminal('-S Xis_subst_hl_script', {'rows': 4, 'cols': 20})
1087  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1088  " the 'ambiwidth' check.
1089  sleep 300m
1090
1091  " Using a different search delimiter should still highlight matches
1092  " that contain a '/'.
1093  call term_sendkeys(buf, ":%s;ello/the")
1094  call VerifyScreenDump(buf, 'Test_incsearch_substitute_15', {})
1095  call term_sendkeys(buf, "<Esc>")
1096
1097  call StopVimInTerminal(buf)
1098  call delete('Xis_subst_hl_script')
1099endfunc
1100
1101func Test_incsearch_with_change()
1102  CheckFeature timers
1103  CheckOption incsearch
1104  CheckScreendump
1105
1106  call writefile([
1107	\ 'set incsearch hlsearch scrolloff=0',
1108	\ 'call setline(1, ["one", "two ------ X", "three"])',
1109	\ 'call timer_start(200, { _ -> setline(2, "x")})',
1110	\ ], 'Xis_change_script')
1111  let buf = RunVimInTerminal('-S Xis_change_script', {'rows': 9, 'cols': 70})
1112  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1113  " the 'ambiwidth' check.
1114  sleep 300m
1115
1116  " Highlight X, it will be deleted by the timer callback.
1117  call term_sendkeys(buf, ':%s/X')
1118  call VerifyScreenDump(buf, 'Test_incsearch_change_01', {})
1119  call term_sendkeys(buf, "\<Esc>")
1120
1121  call StopVimInTerminal(buf)
1122  call delete('Xis_change_script')
1123endfunc
1124
1125" Similar to Test_incsearch_substitute_dump() for :sort
1126func Test_incsearch_sort_dump()
1127  CheckOption incsearch
1128  CheckScreendump
1129
1130  call writefile([
1131	\ 'set incsearch hlsearch scrolloff=0',
1132	\ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
1133	\ ], 'Xis_sort_script')
1134  let buf = RunVimInTerminal('-S Xis_sort_script', {'rows': 9, 'cols': 70})
1135  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1136  " the 'ambiwidth' check.
1137  sleep 100m
1138
1139  " Need to send one key at a time to force a redraw.
1140  call term_sendkeys(buf, ':sort ni u /on')
1141  call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {})
1142  call term_sendkeys(buf, "\<Esc>")
1143
1144  call StopVimInTerminal(buf)
1145  call delete('Xis_sort_script')
1146endfunc
1147
1148" Similar to Test_incsearch_substitute_dump() for :vimgrep famiry
1149func Test_incsearch_vimgrep_dump()
1150  CheckOption incsearch
1151  CheckScreendump
1152
1153  call writefile([
1154	\ 'set incsearch hlsearch scrolloff=0',
1155	\ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
1156	\ ], 'Xis_vimgrep_script')
1157  let buf = RunVimInTerminal('-S Xis_vimgrep_script', {'rows': 9, 'cols': 70})
1158  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1159  " the 'ambiwidth' check.
1160  sleep 100m
1161
1162  " Need to send one key at a time to force a redraw.
1163  call term_sendkeys(buf, ':vimgrep on')
1164  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_01', {})
1165  call term_sendkeys(buf, "\<Esc>")
1166
1167  call term_sendkeys(buf, ':vimg /on/ *.txt')
1168  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_02', {})
1169  call term_sendkeys(buf, "\<Esc>")
1170
1171  call term_sendkeys(buf, ':vimgrepadd "\<on')
1172  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_03', {})
1173  call term_sendkeys(buf, "\<Esc>")
1174
1175  call term_sendkeys(buf, ':lv "tha')
1176  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_04', {})
1177  call term_sendkeys(buf, "\<Esc>")
1178
1179  call term_sendkeys(buf, ':lvimgrepa "the" **/*.txt')
1180  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_05', {})
1181  call term_sendkeys(buf, "\<Esc>")
1182
1183  call StopVimInTerminal(buf)
1184  call delete('Xis_vimgrep_script')
1185endfunc
1186
1187func Test_keep_last_search_pattern()
1188  CheckOption incsearch
1189
1190  new
1191  call setline(1, ['foo', 'foo', 'foo'])
1192  set incsearch
1193  call test_override("char_avail", 1)
1194  let @/ = 'bar'
1195  call feedkeys(":/foo/s//\<Esc>", 'ntx')
1196  call assert_equal('bar', @/)
1197
1198  " no error message if pattern not found
1199  call feedkeys(":/xyz/s//\<Esc>", 'ntx')
1200  call assert_equal('bar', @/)
1201
1202  bwipe!
1203  call test_override("ALL", 0)
1204  set noincsearch
1205endfunc
1206
1207func Test_word_under_cursor_after_match()
1208  CheckOption incsearch
1209
1210  new
1211  call setline(1, 'foo bar')
1212  set incsearch
1213  call test_override("char_avail", 1)
1214  try
1215    call feedkeys("/foo\<C-R>\<C-W>\<CR>", 'ntx')
1216  catch /E486:/
1217  endtry
1218  call assert_equal('foobar', @/)
1219
1220  bwipe!
1221  call test_override("ALL", 0)
1222  set noincsearch
1223endfunc
1224
1225func Test_subst_word_under_cursor()
1226  CheckOption incsearch
1227
1228  new
1229  call setline(1, ['int SomeLongName;', 'for (xxx = 1; xxx < len; ++xxx)'])
1230  set incsearch
1231  call test_override("char_avail", 1)
1232  call feedkeys("/LongName\<CR>", 'ntx')
1233  call feedkeys(":%s/xxx/\<C-R>\<C-W>/g\<CR>", 'ntx')
1234  call assert_equal('for (SomeLongName = 1; SomeLongName < len; ++SomeLongName)', getline(2))
1235
1236  bwipe!
1237  call test_override("ALL", 0)
1238  set noincsearch
1239endfunc
1240
1241func Test_search_undefined_behaviour()
1242  CheckFeature terminal
1243
1244  let h = winheight(0)
1245  if h < 3
1246    return
1247  endif
1248  " did cause an undefined left shift
1249  let g:buf = term_start([GetVimProg(), '--clean', '-e', '-s', '-c', 'call search(getline("."))', 'samples/test000'], {'term_rows': 3})
1250  call assert_equal([''], getline(1, '$'))
1251  call term_sendkeys(g:buf, ":qa!\<cr>")
1252  bwipe!
1253endfunc
1254
1255func Test_search_undefined_behaviour2()
1256  call search("\%UC0000000")
1257endfunc
1258
1259" Test for search('multi-byte char', 'bce')
1260func Test_search_multibyte()
1261  let save_enc = &encoding
1262  set encoding=utf8
1263  enew!
1264  call append('$', 'A')
1265  call cursor(2, 1)
1266  call assert_equal(2, search('A', 'bce', line('.')))
1267  enew!
1268  let &encoding = save_enc
1269endfunc
1270
1271" This was causing E874.  Also causes an invalid read?
1272func Test_look_behind()
1273  new
1274  call setline(1, '0\|\&\n\@<=')
1275  call search(getline("."))
1276  bwipe!
1277endfunc
1278
1279func Test_search_sentence()
1280  new
1281  " this used to cause a crash
1282  call assert_fails("/\\%')", 'E486')
1283  call assert_fails("/", 'E486')
1284  /\%'(
1285  /
1286endfunc
1287
1288" Test that there is no crash when there is a last search pattern but no last
1289" substitute pattern.
1290func Test_no_last_substitute_pat()
1291  " Use viminfo to set the last search pattern to a string and make the last
1292  " substitute pattern the most recent used and make it empty (NULL).
1293  call writefile(['~MSle0/bar', '~MSle0~&'], 'Xviminfo')
1294  rviminfo! Xviminfo
1295  call assert_fails('normal n', 'E35:')
1296
1297  call delete('Xviminfo')
1298endfunc
1299
1300func Test_search_Ctrl_L_combining()
1301  " Make sure, that Ctrl-L works correctly with combining characters.
1302  " It uses an artificial example of an 'a' with 4 combining chars:
1303    " 'a' U+0061 Dec:97 LATIN SMALL LETTER A &#x61; /\%u61\Z "\u0061"
1304    " ' ̀' U+0300 Dec:768 COMBINING GRAVE ACCENT &#x300; /\%u300\Z "\u0300"
1305    " ' ́' U+0301 Dec:769 COMBINING ACUTE ACCENT &#x301; /\%u301\Z "\u0301"
1306    " ' ̇' U+0307 Dec:775 COMBINING DOT ABOVE &#x307; /\%u307\Z "\u0307"
1307    " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW &#x323; /\%u323 "\u0323"
1308  " Those should also appear on the commandline
1309  CheckOption incsearch
1310
1311  call Cmdline3_prep()
1312  1
1313  let bufcontent = ['', 'Miạ̀́̇m']
1314  call append('$', bufcontent)
1315  call feedkeys("/Mi\<c-l>\<c-l>\<cr>", 'tx')
1316  call assert_equal(5, line('.'))
1317  call assert_equal(bufcontent[1], @/)
1318  call Incsearch_cleanup()
1319endfunc
1320
1321func Test_large_hex_chars1()
1322  " This used to cause a crash, the character becomes an NFA state.
1323  try
1324    /\%Ufffffc23
1325  catch
1326    call assert_match('E678:', v:exception)
1327  endtry
1328  try
1329    set re=1
1330    /\%Ufffffc23
1331  catch
1332    call assert_match('E678:', v:exception)
1333  endtry
1334  set re&
1335endfunc
1336
1337func Test_large_hex_chars2()
1338  " This used to cause a crash, the character becomes an NFA state.
1339  try
1340    /[\Ufffffc1f]
1341  catch
1342    call assert_match('E486:', v:exception)
1343  endtry
1344  try
1345    set re=1
1346    /[\Ufffffc1f]
1347  catch
1348    call assert_match('E486:', v:exception)
1349  endtry
1350  set re&
1351endfunc
1352
1353func Test_one_error_msg()
1354  " This  was also giving an internal error
1355  call assert_fails('call search(" \\((\\v[[=P=]]){185}+             ")', 'E871:')
1356endfunc
1357
1358func Test_incsearch_add_char_under_cursor()
1359  CheckOption incsearch
1360
1361  set incsearch
1362  new
1363  call setline(1, ['find match', 'anything'])
1364  1
1365  call test_override('char_avail', 1)
1366  call feedkeys("fc/m\<C-L>\<C-L>\<C-L>\<C-L>\<C-L>\<CR>", 'tx')
1367  call assert_equal('match', @/)
1368  call test_override('char_avail', 0)
1369
1370  set incsearch&
1371  bwipe!
1372endfunc
1373
1374" Test for the search() function with match at the cursor position
1375func Test_search_match_at_curpos()
1376  new
1377  call append(0, ['foobar', '', 'one two', ''])
1378
1379  normal gg
1380
1381  eval 'foobar'->search('c')
1382  call assert_equal([1, 1], [line('.'), col('.')])
1383
1384  normal j
1385  call search('^$', 'c')
1386  call assert_equal([2, 1], [line('.'), col('.')])
1387
1388  call search('^$', 'bc')
1389  call assert_equal([2, 1], [line('.'), col('.')])
1390
1391  exe "normal /two\<CR>"
1392  call search('.', 'c')
1393  call assert_equal([3, 5], [line('.'), col('.')])
1394
1395  close!
1396endfunc
1397
1398" Test for error cases with the search() function
1399func Test_search_errors()
1400  call assert_fails("call search('pat', [])", 'E730:')
1401  call assert_fails("call search('pat', 'b', {})", 'E728:')
1402  call assert_fails("call search('pat', 'b', 1, [])", 'E745:')
1403  call assert_fails("call search('pat', 'ns')", 'E475:')
1404  call assert_fails("call search('pat', 'mr')", 'E475:')
1405endfunc
1406
1407func Test_search_display_pattern()
1408  new
1409  call setline(1, ['foo', 'bar', 'foobar'])
1410
1411  call cursor(1, 1)
1412  let @/ = 'foo'
1413  let pat = @/->escape('()*?'. '\s\+')
1414  let g:a = execute(':unsilent :norm! n')
1415  call assert_match(pat, g:a)
1416
1417  " right-left
1418  if exists("+rightleft")
1419    set rl
1420    call cursor(1, 1)
1421    let @/ = 'foo'
1422    let pat = 'oof/\s\+'
1423    let g:a = execute(':unsilent :norm! n')
1424    call assert_match(pat, g:a)
1425    set norl
1426  endif
1427endfunc
1428
1429func Test_searchdecl()
1430  let lines =<< trim END
1431     int global;
1432
1433     func()
1434     {
1435       int global;
1436       if (cond) {
1437	 int local;
1438       }
1439       int local;
1440       // comment
1441     }
1442  END
1443  new
1444  call setline(1, lines)
1445  10
1446  call assert_equal(0, searchdecl('local', 0, 0))
1447  call assert_equal(7, getcurpos()[1])
1448
1449  10
1450  call assert_equal(0, 'local'->searchdecl(0, 1))
1451  call assert_equal(9, getcurpos()[1])
1452
1453  10
1454  call assert_equal(0, searchdecl('global'))
1455  call assert_equal(5, getcurpos()[1])
1456
1457  10
1458  call assert_equal(0, searchdecl('global', 1))
1459  call assert_equal(1, getcurpos()[1])
1460
1461  bwipe!
1462endfunc
1463
1464func Test_search_special()
1465  " this was causing illegal memory access and an endless loop
1466  set t_PE=
1467  exe "norm /\x80PS"
1468endfunc
1469
1470" Test for command failures when the last search pattern is not set.
1471" Need to run this in a new vim instance where last search pattern is not set.
1472func Test_search_with_no_last_pat()
1473  let lines =<< trim [SCRIPT]
1474    call assert_fails("normal i\<C-R>/\e", 'E35:')
1475    call assert_fails("exe '/'", 'E35:')
1476    call assert_fails("exe '?'", 'E35:')
1477    call assert_fails("/", 'E35:')
1478    call assert_fails("?", 'E35:')
1479    call assert_fails("normal n", 'E35:')
1480    call assert_fails("normal N", 'E35:')
1481    call assert_fails("normal gn", 'E35:')
1482    call assert_fails("normal gN", 'E35:')
1483    call assert_fails("normal cgn", 'E35:')
1484    call assert_fails("normal cgN", 'E35:')
1485    let p = []
1486    let p = @/
1487    call assert_equal('', p)
1488    call assert_fails("normal :\<C-R>/", 'E35:')
1489    call assert_fails("//p", 'E35:')
1490    call assert_fails(";//p", 'E35:')
1491    call assert_fails("??p", 'E35:')
1492    call assert_fails(";??p", 'E35:')
1493    call assert_fails('g//p', 'E476:')
1494    call assert_fails('v//p', 'E476:')
1495    call writefile(v:errors, 'Xresult')
1496    qall!
1497  [SCRIPT]
1498  call writefile(lines, 'Xscript')
1499
1500  if RunVim([], [], '--clean -S Xscript')
1501    call assert_equal([], readfile('Xresult'))
1502  endif
1503  call delete('Xscript')
1504  call delete('Xresult')
1505endfunc
1506
1507" Test for using tilde (~) atom in search. This should use the last used
1508" substitute pattern
1509func Test_search_tilde_pat()
1510  let lines =<< trim [SCRIPT]
1511    set regexpengine=1
1512    call assert_fails('exe "normal /~\<CR>"', 'E33:')
1513    call assert_fails('exe "normal ?~\<CR>"', 'E33:')
1514    set regexpengine=2
1515    call assert_fails('exe "normal /~\<CR>"', 'E383:')
1516    call assert_fails('exe "normal ?~\<CR>"', 'E383:')
1517    set regexpengine&
1518    call writefile(v:errors, 'Xresult')
1519    qall!
1520  [SCRIPT]
1521  call writefile(lines, 'Xscript')
1522  if RunVim([], [], '--clean -S Xscript')
1523    call assert_equal([], readfile('Xresult'))
1524  endif
1525  call delete('Xscript')
1526  call delete('Xresult')
1527endfunc
1528
1529" Test for searching a pattern that is not present with 'nowrapscan'
1530func Test_search_pat_not_found()
1531  new
1532  set nowrapscan
1533  let @/ = '1abcxyz2'
1534  call assert_fails('normal n', 'E385:')
1535  call assert_fails('normal N', 'E384:')
1536  set wrapscan&
1537  close
1538endfunc
1539
1540" Test for v:searchforward variable
1541func Test_searchforward_var()
1542  new
1543  call setline(1, ['foo', '', 'foo'])
1544  call cursor(2, 1)
1545  let @/ = 'foo'
1546  let v:searchforward = 0
1547  normal N
1548  call assert_equal(3, line('.'))
1549  call cursor(2, 1)
1550  let v:searchforward = 1
1551  normal N
1552  call assert_equal(1, line('.'))
1553  close!
1554endfunc
1555
1556" Test for invalid regular expressions
1557func Test_invalid_regexp()
1558  set regexpengine=1
1559  call assert_fails("call search(repeat('\\(.\\)', 10))", 'E51:')
1560  call assert_fails("call search('\\%(')", 'E53:')
1561  call assert_fails("call search('\\(')", 'E54:')
1562  call assert_fails("call search('\\)')", 'E55:')
1563  call assert_fails("call search('x\\@#')", 'E59:')
1564  call assert_fails('call search(''\v%(%(%(%(%(%(%(%(%(%(%(a){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}'')', 'E60:')
1565  call assert_fails("call search('a\\+*')", 'E61:')
1566  call assert_fails("call search('\\_m')", 'E63:')
1567  call assert_fails("call search('\\+')", 'E64:')
1568  call assert_fails("call search('\\1')", 'E65:')
1569  call assert_fails("call search('\\z\\(\\)')", 'E66:')
1570  call assert_fails("call search('\\z2')", 'E67:')
1571  call assert_fails("call search('\\zx')", 'E68:')
1572  call assert_fails("call search('\\%[ab')", 'E69:')
1573  call assert_fails("call search('\\%[]')", 'E70:')
1574  call assert_fails("call search('\\%a')", 'E71:')
1575  call assert_fails("call search('ab\\%[\\(cd\\)]')", 'E369:')
1576  call assert_fails("call search('ab\\%[\\%(cd\\)]')", 'E369:')
1577  set regexpengine=2
1578  call assert_fails("call search('\\_')", 'E865:')
1579  call assert_fails("call search('\\+')", 'E866:')
1580  call assert_fails("call search('\\zx')", 'E867:')
1581  call assert_fails("call search('\\%a')", 'E867:')
1582  call assert_fails("call search('x\\@#')", 'E869:')
1583  call assert_fails("call search(repeat('\\(.\\)', 10))", 'E872:')
1584  call assert_fails("call search('\\_m')", 'E877:')
1585  call assert_fails("call search('\\%(')", 'E53:')
1586  call assert_fails("call search('\\(')", 'E54:')
1587  call assert_fails("call search('\\)')", 'E55:')
1588  call assert_fails("call search('\\z\\(\\)')", 'E66:')
1589  call assert_fails("call search('\\%[ab')", 'E69:')
1590  call assert_fails("call search('\\%[]')", 'E70:')
1591  call assert_fails("call search('\\%9999999999999999999999999999v')", 'E951:')
1592  set regexpengine&
1593  call assert_fails("call search('\\%#=3ab')", 'E864:')
1594endfunc
1595
1596" Test for searching a very complex pattern in a string. Should switch the
1597" regexp engine from NFA to the old engine.
1598func Test_regexp_switch_engine()
1599  let l = readfile('samples/re.freeze.txt')
1600  let v = substitute(l[4], '..\@<!', '', '')
1601  call assert_equal(l[4], v)
1602endfunc
1603
1604" Test for the \%V atom to search within visually selected text
1605func Test_search_in_visual_area()
1606  new
1607  call setline(1, ['foo bar1', 'foo bar2', 'foo bar3', 'foo bar4'])
1608  exe "normal 2GVjo/\\%Vbar\<CR>\<Esc>"
1609  call assert_equal([2, 5], [line('.'), col('.')])
1610  exe "normal 2GVj$?\\%Vbar\<CR>\<Esc>"
1611  call assert_equal([3, 5], [line('.'), col('.')])
1612  close!
1613endfunc
1614
1615" vim: shiftwidth=2 sts=2 expandtab
1616