xref: /vim-8.2.3635/src/testdir/test_search.vim (revision fc65cabb)
1" Test for the search command
2
3source shared.vim
4source screendump.vim
5
6func Test_search_cmdline()
7  if !exists('+incsearch')
8    return
9  endif
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  " eigth 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  " eigth 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  if !exists('+incsearch')
205    return
206  endif
207  " need to disable char_avail,
208  " so that expansion of commandline works
209  call test_override("char_avail", 1)
210  new
211  call setline(1, ['  1', '  2 these', '  3 the theother'])
212  " Test 1
213  " Ctrl-T goes correctly back and forth
214  set incsearch
215  1
216  " first match
217  call feedkeys("/the\<cr>", 'tx')
218  call assert_equal('  2 these', getline('.'))
219  1
220  " go to next match (on next line)
221  call feedkeys("/the\<C-G>\<cr>", 'tx')
222  call assert_equal('  3 the theother', getline('.'))
223  1
224  " go to next match (still on line 3)
225  call feedkeys("/the\<C-G>\<C-G>\<cr>", 'tx')
226  call assert_equal('  3 the theother', getline('.'))
227  1
228  " go to next match (still on line 3)
229  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<cr>", 'tx')
230  call assert_equal('  3 the theother', getline('.'))
231  1
232  " go to previous match (on line 3)
233  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<cr>", 'tx')
234  call assert_equal('  3 the theother', getline('.'))
235  1
236  " go to previous match (on line 3)
237  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<cr>", 'tx')
238  call assert_equal('  3 the theother', getline('.'))
239  1
240  " go to previous match (on line 2)
241  call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<C-T>\<cr>", 'tx')
242  call assert_equal('  2 these', getline('.'))
243
244  " Test 2: keep the view,
245  " after deleting a character from the search cmd
246  call setline(1, ['  1', '  2 these', '  3 the', '  4 their', '  5 there', '  6 their', '  7 the', '  8 them', '  9 these', ' 10 foobar'])
247  resize 5
248  1
249  call feedkeys("/foo\<bs>\<cr>", 'tx')
250  redraw
251  call assert_equal({'lnum': 10, 'leftcol': 0, 'col': 4, 'topfill': 0, 'topline': 6, 'coladd': 0, 'skipcol': 0, 'curswant': 4}, winsaveview())
252
253  " remove all history entries
254  for i in range(10)
255      call histdel('/')
256  endfor
257
258  " Test 3: reset the view,
259  " after deleting all characters from the search cmd
260  norm! 1gg0
261  " unfortunately, neither "/foo\<c-w>\<cr>", nor "/foo\<bs>\<bs>\<bs>\<cr>",
262  " nor "/foo\<c-u>\<cr>" works to delete the commandline.
263  " In that case Vim should return "E35 no previous regular expression",
264  " but it looks like Vim still sees /foo and therefore the test fails.
265  " Therefore, disableing this test
266  "call assert_fails(feedkeys("/foo\<c-w>\<cr>", 'tx'), 'E35')
267  "call assert_equal({'lnum': 1, 'leftcol': 0, 'col': 0, 'topfill': 0, 'topline': 1, 'coladd': 0, 'skipcol': 0, 'curswant': 0}, winsaveview())
268
269  " clean up
270  set noincsearch
271  call test_override("char_avail", 0)
272  bw!
273endfunc
274
275func Test_use_sub_pat()
276  split
277  let @/ = ''
278  func X()
279    s/^/a/
280    /
281  endfunc
282  call X()
283  bwipe!
284endfunc
285
286func Test_searchpair()
287  new
288  call setline(1, ['other code here', '', '[', '" cursor here', ']'])
289  4
290  let a = searchpair('\[','',']','bW')
291  call assert_equal(3, a)
292  set nomagic
293  4
294  let a = searchpair('\[','',']','bW')
295  call assert_equal(3, a)
296  set magic
297  q!
298endfunc
299
300func Test_searchpair_errors()
301  call assert_fails("call searchpair([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
302  call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
303  call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
304  call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
305  call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0')
306  call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
307  call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
308endfunc
309
310func Test_searchpair_skip()
311    func Zero()
312	return 0
313    endfunc
314    func Partial(x)
315	return a:x
316    endfunc
317    new
318    call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
319    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', ''))
320    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0'))
321    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0}))
322    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero')))
323    3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0])))
324    bw!
325endfunc
326
327func Test_searchpair_leak()
328  new
329  call setline(1, 'if one else another endif')
330
331  " The error in the skip expression caused memory to leak.
332  call assert_fails("call searchpair('\\<if\\>', '\\<else\\>', '\\<endif\\>', '', '\"foo\" 2')", 'E15:')
333
334  bwipe!
335endfunc
336
337func Test_searchc()
338  " These commands used to cause memory overflow in searchc().
339  new
340  norm ixx
341  exe "norm 0t\u93cf"
342  bw!
343endfunc
344
345func Cmdline3_prep()
346  " need to disable char_avail,
347  " so that expansion of commandline works
348  call test_override("char_avail", 1)
349  new
350  call setline(1, ['  1', '  2 the~e', '  3 the theother'])
351  set incsearch
352endfunc
353
354func Incsearch_cleanup()
355  set noincsearch
356  call test_override("char_avail", 0)
357  bw!
358endfunc
359
360func Test_search_cmdline3()
361  if !exists('+incsearch')
362    return
363  endif
364  call Cmdline3_prep()
365  1
366  " first match
367  call feedkeys("/the\<c-l>\<cr>", 'tx')
368  call assert_equal('  2 the~e', getline('.'))
369
370  call Incsearch_cleanup()
371endfunc
372
373func Test_search_cmdline3s()
374  if !exists('+incsearch')
375    return
376  endif
377  call Cmdline3_prep()
378  1
379  call feedkeys(":%s/the\<c-l>/xxx\<cr>", 'tx')
380  call assert_equal('  2 xxxe', getline('.'))
381  undo
382  call feedkeys(":%subs/the\<c-l>/xxx\<cr>", 'tx')
383  call assert_equal('  2 xxxe', getline('.'))
384  undo
385  call feedkeys(":%substitute/the\<c-l>/xxx\<cr>", 'tx')
386  call assert_equal('  2 xxxe', getline('.'))
387  undo
388  call feedkeys(":%smagic/the.e/xxx\<cr>", 'tx')
389  call assert_equal('  2 xxx', getline('.'))
390  undo
391  call assert_fails(":%snomagic/the.e/xxx\<cr>", 'E486')
392  "
393  call feedkeys(":%snomagic/the\\.e/xxx\<cr>", 'tx')
394  call assert_equal('  2 xxx', getline('.'))
395
396  call Incsearch_cleanup()
397endfunc
398
399func Test_search_cmdline3g()
400  if !exists('+incsearch')
401    return
402  endif
403  call Cmdline3_prep()
404  1
405  call feedkeys(":g/the\<c-l>/d\<cr>", 'tx')
406  call assert_equal('  3 the theother', getline(2))
407  undo
408  call feedkeys(":global/the\<c-l>/d\<cr>", 'tx')
409  call assert_equal('  3 the theother', getline(2))
410  undo
411  call feedkeys(":g!/the\<c-l>/d\<cr>", 'tx')
412  call assert_equal(1, line('$'))
413  call assert_equal('  2 the~e', getline(1))
414  undo
415  call feedkeys(":global!/the\<c-l>/d\<cr>", 'tx')
416  call assert_equal(1, line('$'))
417  call assert_equal('  2 the~e', getline(1))
418
419  call Incsearch_cleanup()
420endfunc
421
422func Test_search_cmdline3v()
423  if !exists('+incsearch')
424    return
425  endif
426  call Cmdline3_prep()
427  1
428  call feedkeys(":v/the\<c-l>/d\<cr>", 'tx')
429  call assert_equal(1, line('$'))
430  call assert_equal('  2 the~e', getline(1))
431  undo
432  call feedkeys(":vglobal/the\<c-l>/d\<cr>", 'tx')
433  call assert_equal(1, line('$'))
434  call assert_equal('  2 the~e', getline(1))
435
436  call Incsearch_cleanup()
437endfunc
438
439func Test_search_cmdline4()
440  if !exists('+incsearch')
441    return
442  endif
443  " need to disable char_avail,
444  " so that expansion of commandline works
445  call test_override("char_avail", 1)
446  new
447  call setline(1, ['  1 the first', '  2 the second', '  3 the third'])
448  set incsearch
449  $
450  call feedkeys("?the\<c-g>\<cr>", 'tx')
451  call assert_equal('  3 the third', getline('.'))
452  $
453  call feedkeys("?the\<c-g>\<c-g>\<cr>", 'tx')
454  call assert_equal('  1 the first', getline('.'))
455  $
456  call feedkeys("?the\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
457  call assert_equal('  2 the second', getline('.'))
458  $
459  call feedkeys("?the\<c-t>\<cr>", 'tx')
460  call assert_equal('  1 the first', getline('.'))
461  $
462  call feedkeys("?the\<c-t>\<c-t>\<cr>", 'tx')
463  call assert_equal('  3 the third', getline('.'))
464  $
465  call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
466  call assert_equal('  2 the second', getline('.'))
467  " clean up
468  set noincsearch
469  call test_override("char_avail", 0)
470  bw!
471endfunc
472
473func Test_search_cmdline5()
474  if !exists('+incsearch')
475    return
476  endif
477  " Do not call test_override("char_avail", 1) so that <C-g> and <C-t> work
478  " regardless char_avail.
479  new
480  call setline(1, ['  1 the first', '  2 the second', '  3 the third'])
481  set incsearch
482  1
483  call feedkeys("/the\<c-g>\<c-g>\<cr>", 'tx')
484  call assert_equal('  3 the third', getline('.'))
485  $
486  call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
487  call assert_equal('  2 the second', getline('.'))
488  " clean up
489  set noincsearch
490  bw!
491endfunc
492
493func Test_search_cmdline6()
494  " Test that consecutive matches
495  " are caught by <c-g>/<c-t>
496  if !exists('+incsearch')
497    return
498  endif
499  " need to disable char_avail,
500  " so that expansion of commandline works
501  call test_override("char_avail", 1)
502  new
503  call setline(1, [' bbvimb', ''])
504  set incsearch
505  " first match
506  norm! gg0
507  call feedkeys("/b\<cr>", 'tx')
508  call assert_equal([0,1,2,0], getpos('.'))
509  " second match
510  norm! gg0
511  call feedkeys("/b\<c-g>\<cr>", 'tx')
512  call assert_equal([0,1,3,0], getpos('.'))
513  " third match
514  norm! gg0
515  call feedkeys("/b\<c-g>\<c-g>\<cr>", 'tx')
516  call assert_equal([0,1,7,0], getpos('.'))
517  " first match again
518  norm! gg0
519  call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
520  call assert_equal([0,1,2,0], getpos('.'))
521  set nowrapscan
522  " last match
523  norm! gg0
524  call feedkeys("/b\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
525  call assert_equal([0,1,7,0], getpos('.'))
526  " clean up
527  set wrapscan&vim
528  set noincsearch
529  call test_override("char_avail", 0)
530  bw!
531endfunc
532
533func Test_search_cmdline7()
534  " Test that an pressing <c-g> in an empty command line
535  " does not move the cursor
536  if !exists('+incsearch')
537    return
538  endif
539  " need to disable char_avail,
540  " so that expansion of commandline works
541  call test_override("char_avail", 1)
542  new
543  let @/ = 'b'
544  call setline(1, [' bbvimb', ''])
545  set incsearch
546  " first match
547  norm! gg0
548  " moves to next match of previous search pattern, just like /<cr>
549  call feedkeys("/\<c-g>\<cr>", 'tx')
550  call assert_equal([0,1,2,0], getpos('.'))
551  " moves to next match of previous search pattern, just like /<cr>
552  call feedkeys("/\<cr>", 'tx')
553  call assert_equal([0,1,3,0], getpos('.'))
554  " moves to next match of previous search pattern, just like /<cr>
555  call feedkeys("/\<c-t>\<cr>", 'tx')
556  call assert_equal([0,1,7,0], getpos('.'))
557
558  " using an offset uses the last search pattern
559  call cursor(1, 1)
560  call setline(1, ['1 bbvimb', ' 2 bbvimb'])
561  let @/ = 'b'
562  call feedkeys("//e\<c-g>\<cr>", 'tx')
563  call assert_equal('1 bbvimb', getline('.'))
564  call assert_equal(4, col('.'))
565
566  set noincsearch
567  call test_override("char_avail", 0)
568  bw!
569endfunc
570
571func Test_search_cmdline8()
572  " Highlighting is cleared in all windows
573  " since hls applies to all windows
574  if !exists('+incsearch') || !has('terminal') || has('gui_running') || winwidth(0) < 30
575    return
576  endif
577  if has("win32")
578    throw "Skipped: Bug with sending <ESC> to terminal window not fixed yet"
579  endif
580  let h = winheight(0)
581  if h < 3
582    return
583  endif
584  " Prepare buffer text
585  let lines = ['abb vim vim vi', 'vimvivim']
586  call writefile(lines, 'Xsearch.txt')
587  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
588
589  call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
590
591  call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
592  call term_sendkeys(buf, ":14vsp\<cr>")
593  call term_sendkeys(buf, "/vim\<cr>")
594  call term_sendkeys(buf, "/b\<esc>")
595  call term_sendkeys(buf, "gg0")
596  call term_wait(buf, 500)
597  let screen_line = term_scrape(buf, 1)
598  let [a0,a1,a2,a3] = [screen_line[3].attr, screen_line[4].attr,
599        \ screen_line[18].attr, screen_line[19].attr]
600  call assert_notequal(a0, a1)
601  call assert_notequal(a0, a3)
602  call assert_notequal(a1, a2)
603  call assert_equal(a0, a2)
604  call assert_equal(a1, a3)
605  " clean up
606  call delete('Xsearch.txt')
607
608  bwipe!
609endfunc
610
611" Tests for regexp with various magic settings
612func Test_search_regexp()
613  enew!
614
615  put ='1 a aa abb abbccc'
616  exe 'normal! /a*b\{2}c\+/e' . "\<CR>"
617  call assert_equal([0, 2, 17, 0], getpos('.'))
618
619  put ='2 d dd dee deefff'
620  exe 'normal! /\Md\*e\{2}f\+/e' . "\<CR>"
621  call assert_equal([0, 3, 17, 0], getpos('.'))
622
623  set nomagic
624  put ='3 g gg ghh ghhiii'
625  exe 'normal! /g\*h\{2}i\+/e' . "\<CR>"
626  call assert_equal([0, 4, 17, 0], getpos('.'))
627
628  put ='4 j jj jkk jkklll'
629  exe 'normal! /\mj*k\{2}l\+/e' . "\<CR>"
630  call assert_equal([0, 5, 17, 0], getpos('.'))
631
632  put ='5 m mm mnn mnnooo'
633  exe 'normal! /\vm*n{2}o+/e' . "\<CR>"
634  call assert_equal([0, 6, 17, 0], getpos('.'))
635
636  put ='6 x ^aa$ x'
637  exe 'normal! /\V^aa$' . "\<CR>"
638  call assert_equal([0, 7, 5, 0], getpos('.'))
639
640  set magic
641  put ='7 (a)(b) abbaa'
642  exe 'normal! /\v(a)(b)\2\1\1/e' . "\<CR>"
643  call assert_equal([0, 8, 14, 0], getpos('.'))
644
645  put ='8 axx [ab]xx'
646  exe 'normal! /\V[ab]\(\[xy]\)\1' . "\<CR>"
647  call assert_equal([0, 9, 7, 0], getpos('.'))
648
649  set undolevels=100
650  put ='9 foobar'
651  put =''
652  exe "normal! a\<C-G>u\<Esc>"
653  normal G
654  exe 'normal! dv?bar?' . "\<CR>"
655  call assert_equal('9 foo', getline('.'))
656  call assert_equal([0, 10, 5, 0], getpos('.'))
657  call assert_equal(10, line('$'))
658  normal u
659  call assert_equal('9 foobar', getline('.'))
660  call assert_equal([0, 10, 6, 0], getpos('.'))
661  call assert_equal(11, line('$'))
662
663  set undolevels&
664  enew!
665endfunc
666
667func Test_search_cmdline_incsearch_highlight()
668  if !exists('+incsearch')
669    return
670  endif
671  set incsearch hlsearch
672  " need to disable char_avail,
673  " so that expansion of commandline works
674  call test_override("char_avail", 1)
675  new
676  call setline(1, ['aaa  1 the first', '  2 the second', '  3 the third'])
677
678  1
679  call feedkeys("/second\<cr>", 'tx')
680  call assert_equal('second', @/)
681  call assert_equal('  2 the second', getline('.'))
682
683  " Canceling search won't change @/
684  1
685  let @/ = 'last pattern'
686  call feedkeys("/third\<C-c>", 'tx')
687  call assert_equal('last pattern', @/)
688  call feedkeys("/third\<Esc>", 'tx')
689  call assert_equal('last pattern', @/)
690  call feedkeys("/3\<bs>\<bs>", 'tx')
691  call assert_equal('last pattern', @/)
692  call feedkeys("/third\<c-g>\<c-t>\<Esc>", 'tx')
693  call assert_equal('last pattern', @/)
694
695  " clean up
696  set noincsearch nohlsearch
697  bw!
698endfunc
699
700func Test_search_cmdline_incsearch_highlight_attr()
701  if !exists('+incsearch') || !has('terminal') || has('gui_running')
702    return
703  endif
704  let h = winheight(0)
705  if h < 3
706    return
707  endif
708
709  " Prepare buffer text
710  let lines = ['abb vim vim vi', 'vimvivim']
711  call writefile(lines, 'Xsearch.txt')
712  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
713
714  call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
715  " wait for vim to complete initialization
716  call term_wait(buf)
717
718  " Get attr of normal(a0), incsearch(a1), hlsearch(a2) highlight
719  call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
720  call term_sendkeys(buf, '/b')
721  call term_wait(buf, 200)
722  let screen_line1 = term_scrape(buf, 1)
723  call assert_true(len(screen_line1) > 2)
724  " a0: attr_normal
725  let a0 = screen_line1[0].attr
726  " a1: attr_incsearch
727  let a1 = screen_line1[1].attr
728  " a2: attr_hlsearch
729  let a2 = screen_line1[2].attr
730  call assert_notequal(a0, a1)
731  call assert_notequal(a0, a2)
732  call assert_notequal(a1, a2)
733  call term_sendkeys(buf, "\<cr>gg0")
734
735  " Test incremental highlight search
736  call term_sendkeys(buf, "/vim")
737  call term_wait(buf, 200)
738  " Buffer:
739  " abb vim vim vi
740  " vimvivim
741  " Search: /vim
742  let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a2,a2,a2,a0,a0,a0]
743  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
744  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
745  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
746
747  " Test <C-g>
748  call term_sendkeys(buf, "\<C-g>\<C-g>")
749  call term_wait(buf, 200)
750  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
751  let attr_line2 = [a1,a1,a1,a0,a0,a2,a2,a2]
752  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
753  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
754
755  " Test <C-t>
756  call term_sendkeys(buf, "\<C-t>")
757  call term_wait(buf, 200)
758  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a1,a1,a1,a0,a0,a0]
759  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
760  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
761  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
762
763  " Type Enter and a1(incsearch highlight) should become a2(hlsearch highlight)
764  call term_sendkeys(buf, "\<cr>")
765  call term_wait(buf, 200)
766  let attr_line1 = [a0,a0,a0,a0,a2,a2,a2,a0,a2,a2,a2,a0,a0,a0]
767  let attr_line2 = [a2,a2,a2,a0,a0,a2,a2,a2]
768  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
769  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
770
771  " Test nohlsearch. a2(hlsearch highlight) should become a0(normal highlight)
772  call term_sendkeys(buf, ":1\<cr>")
773  call term_sendkeys(buf, ":set nohlsearch\<cr>")
774  call term_sendkeys(buf, "/vim")
775  call term_wait(buf, 200)
776  let attr_line1 = [a0,a0,a0,a0,a1,a1,a1,a0,a0,a0,a0,a0,a0,a0]
777  let attr_line2 = [a0,a0,a0,a0,a0,a0,a0,a0]
778  call assert_equal(attr_line1, map(term_scrape(buf, 1)[:len(attr_line1)-1], 'v:val.attr'))
779  call assert_equal(attr_line2, map(term_scrape(buf, 2)[:len(attr_line2)-1], 'v:val.attr'))
780  call delete('Xsearch.txt')
781
782  call delete('Xsearch.txt')
783  bwipe!
784endfunc
785
786func Test_incsearch_scrolling()
787  if !CanRunVimInTerminal()
788    return
789  endif
790  call assert_equal(0, &scrolloff)
791  call writefile([
792	\ 'let dots = repeat(".", 120)',
793	\ 'set incsearch cmdheight=2 scrolloff=0',
794	\ 'call setline(1, [dots, dots, dots, "", "target", dots, dots])',
795	\ 'normal gg',
796	\ 'redraw',
797	\ ], 'Xscript')
798  let buf = RunVimInTerminal('-S Xscript', {'rows': 9, 'cols': 70})
799  " Need to send one key at a time to force a redraw
800  call term_sendkeys(buf, '/')
801  sleep 100m
802  call term_sendkeys(buf, 't')
803  sleep 100m
804  call term_sendkeys(buf, 'a')
805  sleep 100m
806  call term_sendkeys(buf, 'r')
807  sleep 100m
808  call term_sendkeys(buf, 'g')
809  call VerifyScreenDump(buf, 'Test_incsearch_scrolling_01', {})
810
811  call term_sendkeys(buf, "\<Esc>")
812  call StopVimInTerminal(buf)
813  call delete('Xscript')
814endfunc
815
816func Test_incsearch_search_dump()
817  if !exists('+incsearch')
818    return
819  endif
820  if !CanRunVimInTerminal()
821    return
822  endif
823  call writefile([
824	\ 'set incsearch hlsearch scrolloff=0',
825	\ 'for n in range(1, 8)',
826	\ '  call setline(n, "foo " . n)',
827	\ 'endfor',
828	\ '3',
829	\ ], 'Xis_search_script')
830  let buf = RunVimInTerminal('-S Xis_search_script', {'rows': 9, 'cols': 70})
831  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
832  " the 'ambiwidth' check.
833  sleep 100m
834
835  " Need to send one key at a time to force a redraw.
836  call term_sendkeys(buf, '/fo')
837  sleep 100m
838  call VerifyScreenDump(buf, 'Test_incsearch_search_01', {})
839  call term_sendkeys(buf, "\<Esc>")
840  sleep 100m
841
842  call term_sendkeys(buf, '/\v')
843  sleep 100m
844  call VerifyScreenDump(buf, 'Test_incsearch_search_02', {})
845  call term_sendkeys(buf, "\<Esc>")
846
847  call StopVimInTerminal(buf)
848  call delete('Xis_search_script')
849endfunc
850
851func Test_incsearch_substitute()
852  if !exists('+incsearch')
853    return
854  endif
855  call test_override("char_avail", 1)
856  new
857  set incsearch
858  for n in range(1, 10)
859    call setline(n, 'foo ' . n)
860  endfor
861  4
862  call feedkeys(":.,.+2s/foo\<BS>o\<BS>o/xxx\<cr>", 'tx')
863  call assert_equal('foo 3', getline(3))
864  call assert_equal('xxx 4', getline(4))
865  call assert_equal('xxx 5', getline(5))
866  call assert_equal('xxx 6', getline(6))
867  call assert_equal('foo 7', getline(7))
868
869  call Incsearch_cleanup()
870endfunc
871
872" Similar to Test_incsearch_substitute() but with a screendump halfway.
873func Test_incsearch_substitute_dump()
874  if !exists('+incsearch')
875    return
876  endif
877  if !CanRunVimInTerminal()
878    return
879  endif
880  call writefile([
881	\ 'set incsearch hlsearch scrolloff=0',
882	\ 'for n in range(1, 10)',
883	\ '  call setline(n, "foo " . n)',
884	\ 'endfor',
885	\ 'call setline(11, "bar 11")',
886	\ '3',
887	\ ], 'Xis_subst_script')
888  let buf = RunVimInTerminal('-S Xis_subst_script', {'rows': 9, 'cols': 70})
889  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
890  " the 'ambiwidth' check.
891  sleep 100m
892
893  " Need to send one key at a time to force a redraw.
894  " Select three lines at the cursor with typed pattern.
895  call term_sendkeys(buf, ':.,.+2s/')
896  sleep 100m
897  call term_sendkeys(buf, 'f')
898  sleep 100m
899  call term_sendkeys(buf, 'o')
900  sleep 100m
901  call term_sendkeys(buf, 'o')
902  sleep 100m
903  call VerifyScreenDump(buf, 'Test_incsearch_substitute_01', {})
904  call term_sendkeys(buf, "\<Esc>")
905
906  " Select three lines at the cursor using previous pattern.
907  call term_sendkeys(buf, "/foo\<CR>")
908  sleep 100m
909  call term_sendkeys(buf, ':.,.+2s//')
910  sleep 100m
911  call VerifyScreenDump(buf, 'Test_incsearch_substitute_02', {})
912
913  " Deleting last slash should remove the match.
914  call term_sendkeys(buf, "\<BS>")
915  sleep 100m
916  call VerifyScreenDump(buf, 'Test_incsearch_substitute_03', {})
917  call term_sendkeys(buf, "\<Esc>")
918
919  " Reverse range is accepted
920  call term_sendkeys(buf, ':5,2s/foo')
921  sleep 100m
922  call VerifyScreenDump(buf, 'Test_incsearch_substitute_04', {})
923  call term_sendkeys(buf, "\<Esc>")
924
925  " White space after the command is skipped
926  call term_sendkeys(buf, ':2,3sub  /fo')
927  sleep 100m
928  call VerifyScreenDump(buf, 'Test_incsearch_substitute_05', {})
929  call term_sendkeys(buf, "\<Esc>")
930
931  " Command modifiers are skipped
932  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.')
933  sleep 100m
934  call VerifyScreenDump(buf, 'Test_incsearch_substitute_06', {})
935  call term_sendkeys(buf, "\<Esc>")
936
937  " Cursorline highlighting at match
938  call term_sendkeys(buf, ":set cursorline\<CR>")
939  call term_sendkeys(buf, 'G9G')
940  call term_sendkeys(buf, ':9,11s/bar')
941  sleep 100m
942  call VerifyScreenDump(buf, 'Test_incsearch_substitute_07', {})
943  call term_sendkeys(buf, "\<Esc>")
944
945  " Cursorline highlighting at cursor when no match
946  call term_sendkeys(buf, ':9,10s/bar')
947  sleep 100m
948  call VerifyScreenDump(buf, 'Test_incsearch_substitute_08', {})
949  call term_sendkeys(buf, "\<Esc>")
950
951  " Only \v handled as empty pattern, does not move cursor
952  call term_sendkeys(buf, '3G4G')
953  call term_sendkeys(buf, ":nohlsearch\<CR>")
954  call term_sendkeys(buf, ':6,7s/\v')
955  sleep 100m
956  call VerifyScreenDump(buf, 'Test_incsearch_substitute_09', {})
957  call term_sendkeys(buf, "\<Esc>")
958
959  call StopVimInTerminal(buf)
960  call delete('Xis_subst_script')
961endfunc
962
963" Similar to Test_incsearch_substitute_dump() for :sort
964func Test_incsearch_sort_dump()
965  if !exists('+incsearch')
966    return
967  endif
968  if !CanRunVimInTerminal()
969    return
970  endif
971  call writefile([
972	\ 'set incsearch hlsearch scrolloff=0',
973	\ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
974	\ ], 'Xis_sort_script')
975  let buf = RunVimInTerminal('-S Xis_sort_script', {'rows': 9, 'cols': 70})
976  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
977  " the 'ambiwidth' check.
978  sleep 100m
979
980  " Need to send one key at a time to force a redraw.
981  call term_sendkeys(buf, ':sort ni u /on')
982  sleep 100m
983  call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {})
984  call term_sendkeys(buf, "\<Esc>")
985
986  call StopVimInTerminal(buf)
987  call delete('Xis_sort_script')
988endfunc
989
990" Similar to Test_incsearch_substitute_dump() for :vimgrep famiry
991func Test_incsearch_vimgrep_dump()
992  if !exists('+incsearch')
993    return
994  endif
995  if !CanRunVimInTerminal()
996    return
997  endif
998  call writefile([
999	\ 'set incsearch hlsearch scrolloff=0',
1000	\ 'call setline(1, ["another one 2", "that one 3", "the one 1"])',
1001	\ ], 'Xis_vimgrep_script')
1002  let buf = RunVimInTerminal('-S Xis_vimgrep_script', {'rows': 9, 'cols': 70})
1003  " Give Vim a chance to redraw to get rid of the spaces in line 2 caused by
1004  " the 'ambiwidth' check.
1005  sleep 100m
1006
1007  " Need to send one key at a time to force a redraw.
1008  call term_sendkeys(buf, ':vimgrep on')
1009  sleep 100m
1010  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_01', {})
1011  call term_sendkeys(buf, "\<Esc>")
1012
1013  call term_sendkeys(buf, ':vimg /on/ *.txt')
1014  sleep 100m
1015  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_02', {})
1016  call term_sendkeys(buf, "\<Esc>")
1017
1018  call term_sendkeys(buf, ':vimgrepadd "\<on')
1019  sleep 100m
1020  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_03', {})
1021  call term_sendkeys(buf, "\<Esc>")
1022
1023  call term_sendkeys(buf, ':lv "tha')
1024  sleep 100m
1025  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_04', {})
1026  call term_sendkeys(buf, "\<Esc>")
1027
1028  call term_sendkeys(buf, ':lvimgrepa "the" **/*.txt')
1029  sleep 100m
1030  call VerifyScreenDump(buf, 'Test_incsearch_vimgrep_05', {})
1031  call term_sendkeys(buf, "\<Esc>")
1032
1033  call StopVimInTerminal(buf)
1034  call delete('Xis_vimgrep_script')
1035endfunc
1036
1037func Test_search_undefined_behaviour()
1038  if !has("terminal")
1039    return
1040  endif
1041  let h = winheight(0)
1042  if h < 3
1043    return
1044  endif
1045  " did cause an undefined left shift
1046  let g:buf = term_start([GetVimProg(), '--clean', '-e', '-s', '-c', 'call search(getline("."))', 'samples/test000'], {'term_rows': 3})
1047  call assert_equal([''], getline(1, '$'))
1048  call term_sendkeys(g:buf, ":qa!\<cr>")
1049  bwipe!
1050endfunc
1051
1052func Test_search_undefined_behaviour2()
1053  call search("\%UC0000000")
1054endfunc
1055
1056" Test for search('multi-byte char', 'bce')
1057func Test_search_multibyte()
1058  if !has('multi_byte')
1059    return
1060  endif
1061  let save_enc = &encoding
1062  set encoding=utf8
1063  enew!
1064  call append('$', 'A')
1065  call cursor(2, 1)
1066  call assert_equal(2, search('A', 'bce', line('.')))
1067  enew!
1068  let &encoding = save_enc
1069endfunc
1070
1071" This was causing E874.  Also causes an invalid read?
1072func Test_look_behind()
1073  new
1074  call setline(1, '0\|\&\n\@<=')
1075  call search(getline("."))
1076  bwipe!
1077endfunc
1078
1079func Test_search_sentence()
1080  new
1081  " this used to cause a crash
1082  call assert_fails("/\\%')", 'E486')
1083  call assert_fails("/", 'E486')
1084  /\%'(
1085  /
1086endfunc
1087