search_spec.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local clear = n.clear
  5. local command = n.command
  6. local eq = t.eq
  7. local eval = n.eval
  8. local feed = n.feed
  9. local fn = n.fn
  10. local poke_eventloop = n.poke_eventloop
  11. local exec = n.exec
  12. describe('search cmdline', function()
  13. local screen
  14. before_each(function()
  15. clear()
  16. command('set nohlsearch inccommand=')
  17. screen = Screen.new(20, 3)
  18. end)
  19. local function tenlines()
  20. fn.setline(1, {
  21. ' 1',
  22. ' 2 these',
  23. ' 3 the',
  24. ' 4 their',
  25. ' 5 there',
  26. ' 6 their',
  27. ' 7 the',
  28. ' 8 them',
  29. ' 9 these',
  30. ' 10 foobar',
  31. })
  32. command('1')
  33. end
  34. it('history can be navigated with <C-N>/<C-P>', function()
  35. tenlines()
  36. command('set noincsearch')
  37. feed('/foobar<CR>')
  38. feed('/the<CR>')
  39. eq('the', eval('@/'))
  40. feed('/thes<C-P><C-P><CR>')
  41. eq('foobar', eval('@/'))
  42. end)
  43. describe('can traverse matches', function()
  44. before_each(tenlines)
  45. local function forwarditer(wrapscan)
  46. command('set incsearch ' .. wrapscan)
  47. feed('/the')
  48. screen:expect([[
  49. 1 |
  50. 2 {2:the}se |
  51. /the^ |
  52. ]])
  53. feed('<C-G>')
  54. screen:expect([[
  55. 2 these |
  56. 3 {2:the} |
  57. /the^ |
  58. ]])
  59. eq({ 0, 0, 0, 0 }, fn.getpos('"'))
  60. feed('<C-G>')
  61. screen:expect([[
  62. 3 the |
  63. 4 {2:the}ir |
  64. /the^ |
  65. ]])
  66. feed('<C-G>')
  67. screen:expect([[
  68. 4 their |
  69. 5 {2:the}re |
  70. /the^ |
  71. ]])
  72. feed('<C-G>')
  73. screen:expect([[
  74. 5 there |
  75. 6 {2:the}ir |
  76. /the^ |
  77. ]])
  78. feed('<C-G>')
  79. screen:expect([[
  80. 6 their |
  81. 7 {2:the} |
  82. /the^ |
  83. ]])
  84. feed('<C-G>')
  85. screen:expect([[
  86. 7 the |
  87. 8 {2:the}m |
  88. /the^ |
  89. ]])
  90. feed('<C-G>')
  91. screen:expect([[
  92. 8 them |
  93. 9 {2:the}se |
  94. /the^ |
  95. ]])
  96. screen.bell = false
  97. feed('<C-G>')
  98. if wrapscan == 'wrapscan' then
  99. screen:expect([[
  100. 2 {2:the}se |
  101. 3 the |
  102. /the^ |
  103. ]])
  104. else
  105. screen:expect {
  106. grid = [[
  107. 8 them |
  108. 9 {2:the}se |
  109. /the^ |
  110. ]],
  111. condition = function()
  112. eq(true, screen.bell)
  113. end,
  114. }
  115. feed('<CR>')
  116. eq({ 0, 0, 0, 0 }, fn.getpos('"'))
  117. end
  118. end
  119. local function backiter(wrapscan)
  120. command('set incsearch ' .. wrapscan)
  121. command('$')
  122. feed('?the')
  123. screen:expect([[
  124. 9 {2:the}se |
  125. 10 foobar |
  126. ?the^ |
  127. ]])
  128. screen.bell = false
  129. if wrapscan == 'wrapscan' then
  130. feed('<C-G>')
  131. screen:expect([[
  132. 2 {2:the}se |
  133. 3 the |
  134. ?the^ |
  135. ]])
  136. feed('<CR>')
  137. screen:expect([[
  138. 2 ^these |
  139. 3 the |
  140. ?the |
  141. ]])
  142. else
  143. feed('<C-G>')
  144. screen:expect {
  145. grid = [[
  146. 9 {2:the}se |
  147. 10 foobar |
  148. ?the^ |
  149. ]],
  150. condition = function()
  151. eq(true, screen.bell)
  152. end,
  153. }
  154. feed('<CR>')
  155. screen:expect([[
  156. 9 ^these |
  157. 10 foobar |
  158. ?the |
  159. ]])
  160. end
  161. command('$')
  162. feed('?the')
  163. screen:expect([[
  164. 9 {2:the}se |
  165. 10 foobar |
  166. ?the^ |
  167. ]])
  168. feed('<C-T>')
  169. screen:expect([[
  170. 8 {2:the}m |
  171. 9 these |
  172. ?the^ |
  173. ]])
  174. for i = 1, 6 do
  175. feed('<C-T>')
  176. -- Avoid sleep just before expect, otherwise expect will take the full
  177. -- timeout
  178. if i ~= 6 then
  179. screen:sleep(1)
  180. end
  181. end
  182. screen:expect([[
  183. 2 {2:the}se |
  184. 3 the |
  185. ?the^ |
  186. ]])
  187. screen.bell = false
  188. feed('<C-T>')
  189. if wrapscan == 'wrapscan' then
  190. screen:expect([[
  191. 9 {2:the}se |
  192. 10 foobar |
  193. ?the^ |
  194. ]])
  195. else
  196. screen:expect {
  197. grid = [[
  198. 2 {2:the}se |
  199. 3 the |
  200. ?the^ |
  201. ]],
  202. condition = function()
  203. eq(true, screen.bell)
  204. end,
  205. }
  206. end
  207. end
  208. it("using <C-G> and 'nowrapscan'", function()
  209. forwarditer('nowrapscan')
  210. end)
  211. it("using <C-G> and 'wrapscan'", function()
  212. forwarditer('wrapscan')
  213. end)
  214. it("using <C-T> and 'nowrapscan'", function()
  215. backiter('nowrapscan')
  216. end)
  217. it("using <C-T> and 'wrapscan'", function()
  218. backiter('wrapscan')
  219. end)
  220. end)
  221. it('expands pattern with <C-L>', function()
  222. tenlines()
  223. command('set incsearch wrapscan')
  224. feed('/the')
  225. screen:expect([[
  226. 1 |
  227. 2 {2:the}se |
  228. /the^ |
  229. ]])
  230. feed('<C-L>')
  231. screen:expect([[
  232. 1 |
  233. 2 {2:thes}e |
  234. /thes^ |
  235. ]])
  236. feed('<C-G>')
  237. screen:expect([[
  238. 9 {2:thes}e |
  239. 10 foobar |
  240. /thes^ |
  241. ]])
  242. feed('<C-G>')
  243. screen:expect([[
  244. 2 {2:thes}e |
  245. 3 the |
  246. /thes^ |
  247. ]])
  248. feed('<CR>')
  249. screen:expect([[
  250. 2 ^these |
  251. 3 the |
  252. /thes |
  253. ]])
  254. command('1')
  255. command('set nowrapscan')
  256. feed('/the')
  257. screen:expect([[
  258. 1 |
  259. 2 {2:the}se |
  260. /the^ |
  261. ]])
  262. feed('<C-L>')
  263. screen:expect([[
  264. 1 |
  265. 2 {2:thes}e |
  266. /thes^ |
  267. ]])
  268. feed('<C-G>')
  269. screen:expect([[
  270. 9 {2:thes}e |
  271. 10 foobar |
  272. /thes^ |
  273. ]])
  274. feed('<C-G><CR>')
  275. screen:expect([[
  276. 9 ^these |
  277. 10 foobar |
  278. /thes |
  279. ]])
  280. end)
  281. it('reduces pattern with <BS> and keeps cursor position', function()
  282. tenlines()
  283. command('set incsearch wrapscan')
  284. -- First match
  285. feed('/thei')
  286. screen:expect([[
  287. 3 the |
  288. 4 {2:thei}r |
  289. /thei^ |
  290. ]])
  291. -- Match from initial cursor position when modifying search
  292. feed('<BS>')
  293. screen:expect([[
  294. 1 |
  295. 2 {2:the}se |
  296. /the^ |
  297. ]])
  298. -- New text advances to next match
  299. feed('s')
  300. screen:expect([[
  301. 1 |
  302. 2 {2:thes}e |
  303. /thes^ |
  304. ]])
  305. -- Stay on this match when deleting a character
  306. feed('<BS>')
  307. screen:expect([[
  308. 1 |
  309. 2 {2:the}se |
  310. /the^ |
  311. ]])
  312. -- Advance to previous match
  313. feed('<C-T>')
  314. screen:expect([[
  315. 9 {2:the}se |
  316. 10 foobar |
  317. /the^ |
  318. ]])
  319. -- Extend search to include next character
  320. feed('<C-L>')
  321. screen:expect([[
  322. 9 {2:thes}e |
  323. 10 foobar |
  324. /thes^ |
  325. ]])
  326. -- Deleting all characters resets the cursor position
  327. feed('<BS><BS><BS><BS>')
  328. screen:expect([[
  329. 1 |
  330. 2 these |
  331. /^ |
  332. ]])
  333. feed('the')
  334. screen:expect([[
  335. 1 |
  336. 2 {2:the}se |
  337. /the^ |
  338. ]])
  339. feed('\\>')
  340. screen:expect([[
  341. 2 these |
  342. 3 {2:the} |
  343. /the\>^ |
  344. ]])
  345. end)
  346. it('can traverse matches in the same line with <C-G>/<C-T>', function()
  347. fn.setline(1, { ' 1', ' 2 these', ' 3 the theother' })
  348. command('1')
  349. command('set incsearch')
  350. -- First match
  351. feed('/the')
  352. screen:expect([[
  353. 1 |
  354. 2 {2:the}se |
  355. /the^ |
  356. ]])
  357. -- Next match, different line
  358. feed('<C-G>')
  359. screen:expect([[
  360. 2 these |
  361. 3 {2:the} theother |
  362. /the^ |
  363. ]])
  364. -- Next match, same line
  365. feed('<C-G>')
  366. screen:expect([[
  367. 2 these |
  368. 3 the {2:the}other |
  369. /the^ |
  370. ]])
  371. feed('<C-G>')
  372. screen:expect([[
  373. 2 these |
  374. 3 the theo{2:the}r |
  375. /the^ |
  376. ]])
  377. -- Previous match, same line
  378. feed('<C-T>')
  379. screen:expect([[
  380. 2 these |
  381. 3 the {2:the}other |
  382. /the^ |
  383. ]])
  384. feed('<C-T>')
  385. screen:expect([[
  386. 2 these |
  387. 3 {2:the} theother |
  388. /the^ |
  389. ]])
  390. -- Previous match, different line
  391. feed('<C-T>')
  392. screen:expect([[
  393. 2 {2:the}se |
  394. 3 the theother |
  395. /the^ |
  396. ]])
  397. end)
  398. it('keeps the view after deleting a char from the search', function()
  399. screen:try_resize(20, 6)
  400. tenlines()
  401. feed('/foo')
  402. screen:expect([[
  403. 6 their |
  404. 7 the |
  405. 8 them |
  406. 9 these |
  407. 10 {2:foo}bar |
  408. /foo^ |
  409. ]])
  410. feed('<BS>')
  411. screen:expect([[
  412. 6 their |
  413. 7 the |
  414. 8 them |
  415. 9 these |
  416. 10 {2:fo}obar |
  417. /fo^ |
  418. ]])
  419. feed('<CR>')
  420. screen:expect([[
  421. 6 their |
  422. 7 the |
  423. 8 them |
  424. 9 these |
  425. 10 ^foobar |
  426. /fo |
  427. ]])
  428. eq({
  429. lnum = 10,
  430. leftcol = 0,
  431. col = 4,
  432. topfill = 0,
  433. topline = 6,
  434. coladd = 0,
  435. skipcol = 0,
  436. curswant = 4,
  437. }, fn.winsaveview())
  438. end)
  439. it('restores original view after failed search', function()
  440. screen:try_resize(40, 3)
  441. tenlines()
  442. feed('0')
  443. feed('/foo')
  444. screen:expect([[
  445. 9 these |
  446. 10 {2:foo}bar |
  447. /foo^ |
  448. ]])
  449. feed('<C-W>')
  450. screen:expect([[
  451. 1 |
  452. 2 these |
  453. /^ |
  454. ]])
  455. feed('<CR>')
  456. screen:expect([[
  457. / |
  458. {9:E35: No previous regular expression} |
  459. {6:Press ENTER or type command to continue}^ |
  460. ]])
  461. feed('<CR>')
  462. eq({
  463. lnum = 1,
  464. leftcol = 0,
  465. col = 0,
  466. topfill = 0,
  467. topline = 1,
  468. coladd = 0,
  469. skipcol = 0,
  470. curswant = 0,
  471. }, fn.winsaveview())
  472. end)
  473. -- oldtest: Test_search_cmdline4().
  474. it("CTRL-G with 'incsearch' and ? goes in the right direction", function()
  475. screen:try_resize(40, 4)
  476. command('enew!')
  477. fn.setline(1, { ' 1 the first', ' 2 the second', ' 3 the third' })
  478. command('set laststatus=0 shortmess+=s')
  479. command('set incsearch')
  480. command('$')
  481. -- Send the input in chunks, so the cmdline logic regards it as
  482. -- "interactive". This mimics Vim's test_override("char_avail").
  483. -- (See legacy test: test_search.vim)
  484. feed('?the')
  485. poke_eventloop()
  486. feed('<c-g>')
  487. poke_eventloop()
  488. feed('<cr>')
  489. screen:expect([[
  490. 1 the first |
  491. 2 the second |
  492. 3 ^the third |
  493. ?the |
  494. ]])
  495. command('$')
  496. feed('?the')
  497. poke_eventloop()
  498. feed('<c-g>')
  499. poke_eventloop()
  500. feed('<c-g>')
  501. poke_eventloop()
  502. feed('<cr>')
  503. screen:expect([[
  504. 1 ^the first |
  505. 2 the second |
  506. 3 the third |
  507. ?the |
  508. ]])
  509. command('$')
  510. feed('?the')
  511. poke_eventloop()
  512. feed('<c-g>')
  513. poke_eventloop()
  514. feed('<c-g>')
  515. poke_eventloop()
  516. feed('<c-g>')
  517. poke_eventloop()
  518. feed('<cr>')
  519. screen:expect([[
  520. 1 the first |
  521. 2 ^the second |
  522. 3 the third |
  523. ?the |
  524. ]])
  525. command('$')
  526. feed('?the')
  527. poke_eventloop()
  528. feed('<c-t>')
  529. poke_eventloop()
  530. feed('<cr>')
  531. screen:expect([[
  532. 1 ^the first |
  533. 2 the second |
  534. 3 the third |
  535. ?the |
  536. ]])
  537. command('$')
  538. feed('?the')
  539. poke_eventloop()
  540. feed('<c-t>')
  541. poke_eventloop()
  542. feed('<c-t>')
  543. poke_eventloop()
  544. feed('<cr>')
  545. screen:expect([[
  546. 1 the first |
  547. 2 the second |
  548. 3 ^the third |
  549. ?the |
  550. ]])
  551. command('$')
  552. feed('?the')
  553. poke_eventloop()
  554. feed('<c-t>')
  555. poke_eventloop()
  556. feed('<c-t>')
  557. poke_eventloop()
  558. feed('<c-t>')
  559. poke_eventloop()
  560. feed('<cr>')
  561. screen:expect([[
  562. 1 the first |
  563. 2 ^the second |
  564. 3 the third |
  565. ?the |
  566. ]])
  567. end)
  568. -- oldtest: Test_incsearch_sort_dump().
  569. it('incsearch works with :sort', function()
  570. screen:try_resize(20, 4)
  571. command('set incsearch hlsearch scrolloff=0')
  572. fn.setline(1, { 'another one 2', 'that one 3', 'the one 1' })
  573. feed(':sort ni u /on')
  574. screen:expect([[
  575. another {2:on}e 2 |
  576. that {10:on}e 3 |
  577. the {10:on}e 1 |
  578. :sort ni u /on^ |
  579. ]])
  580. feed('<esc>')
  581. end)
  582. -- oldtest: Test_incsearch_vimgrep_dump().
  583. it('incsearch works with :vimgrep family', function()
  584. screen:try_resize(30, 4)
  585. command('set incsearch hlsearch scrolloff=0')
  586. fn.setline(1, { 'another one 2', 'that one 3', 'the one 1' })
  587. feed(':vimgrep on')
  588. screen:expect([[
  589. another {2:on}e 2 |
  590. that {10:on}e 3 |
  591. the {10:on}e 1 |
  592. :vimgrep on^ |
  593. ]])
  594. feed('<esc>')
  595. feed(':vimg /on/ *.txt')
  596. screen:expect([[
  597. another {2:on}e 2 |
  598. that {10:on}e 3 |
  599. the {10:on}e 1 |
  600. :vimg /on/ *.txt^ |
  601. ]])
  602. feed('<esc>')
  603. feed(':vimgrepadd "\\<LT>on')
  604. screen:expect([[
  605. another {2:on}e 2 |
  606. that {10:on}e 3 |
  607. the {10:on}e 1 |
  608. :vimgrepadd "\<on^ |
  609. ]])
  610. feed('<esc>')
  611. feed(':lv "tha')
  612. screen:expect([[
  613. another one 2 |
  614. {2:tha}t one 3 |
  615. the one 1 |
  616. :lv "tha^ |
  617. ]])
  618. feed('<esc>')
  619. feed(':lvimgrepa "the" **/*.txt')
  620. screen:expect([[
  621. ano{2:the}r one 2 |
  622. that one 3 |
  623. {10:the} one 1 |
  624. :lvimgrepa "the" **/*.txt^ |
  625. ]])
  626. feed('<esc>')
  627. end)
  628. -- oldtest: Test_incsearch_substitute_dump2()
  629. it('incsearch detects empty pattern properly vim-patch:8.2.2295', function()
  630. screen:try_resize(70, 6)
  631. exec([[
  632. set incsearch hlsearch scrolloff=0
  633. for n in range(1, 4)
  634. call setline(n, "foo " . n)
  635. endfor
  636. call setline(5, "abc|def")
  637. 3
  638. ]])
  639. feed([[:%s/\vabc|]])
  640. screen:expect([[
  641. foo 1 |
  642. foo 2 |
  643. foo 3 |
  644. foo 4 |
  645. abc|def |
  646. :%s/\vabc|^ |
  647. ]])
  648. feed('<Esc>')
  649. -- The following should not be highlighted
  650. feed([[:1,5s/\v|]])
  651. screen:expect([[
  652. foo 1 |
  653. foo 2 |
  654. foo 3 |
  655. foo 4 |
  656. abc|def |
  657. :1,5s/\v|^ |
  658. ]])
  659. end)
  660. -- oldtest: Test_incsearch_restore_view()
  661. it('incsearch restores viewport', function()
  662. screen:try_resize(20, 6)
  663. exec([[
  664. set incsearch nohlsearch
  665. setlocal scrolloff=0 smoothscroll
  666. call setline(1, [join(range(25), ' '), '', '', '', '', 'xxx'])
  667. call feedkeys("2\<C-E>", 't')
  668. ]])
  669. local s = [[
  670. {1:<<<} 18 19 20 21 22 2|
  671. ^3 24 |
  672. |*4
  673. ]]
  674. screen:expect(s)
  675. feed('/xx')
  676. screen:expect([[
  677. |*4
  678. {2:xx}x |
  679. /xx^ |
  680. ]])
  681. feed('x')
  682. screen:expect([[
  683. |*4
  684. {2:xxx} |
  685. /xxx^ |
  686. ]])
  687. feed('<Esc>')
  688. screen:expect(s)
  689. end)
  690. end)
  691. describe('Search highlight', function()
  692. before_each(clear)
  693. -- oldtest: Test_hlsearch_dump()
  694. it('beyond line end vim-patch:8.2.2542', function()
  695. local screen = Screen.new(50, 6)
  696. exec([[
  697. set hlsearch noincsearch cursorline
  698. call setline(1, ["xxx", "xxx", "xxx"])
  699. /.*
  700. 2
  701. ]])
  702. feed([[/\_.*<CR>]])
  703. screen:expect([[
  704. {10:xxx } |*2
  705. {10:^xxx }{21: }|
  706. {1:~ }|*2
  707. /\_.* |
  708. ]])
  709. end)
  710. -- oldtest: Test_hlsearch_and_visual()
  711. it('is combined with Visual highlight vim-patch:8.2.2797', function()
  712. local screen = Screen.new(40, 6)
  713. screen:add_extra_attr_ids {
  714. [100] = {
  715. foreground = Screen.colors.Black,
  716. bold = true,
  717. background = Screen.colors.LightGrey,
  718. },
  719. [101] = { bold = true, background = Screen.colors.Yellow },
  720. }
  721. exec([[
  722. set hlsearch noincsearch
  723. call setline(1, repeat(["xxx yyy zzz"], 3))
  724. hi Search gui=bold
  725. /yyy
  726. call cursor(1, 6)
  727. ]])
  728. feed('vjj')
  729. screen:expect([[
  730. xxx {101:y}{100:yy}{17: zzz} |
  731. {17:xxx }{100:yyy}{17: zzz} |
  732. {17:xxx }{100:y}{101:^yy} zzz |
  733. {1:~ }|*2
  734. {5:-- VISUAL --} |
  735. ]])
  736. end)
  737. end)