searchhl_spec.lua 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. local helpers = require('test.functional.helpers')(after_each)
  2. local Screen = require('test.functional.ui.screen')
  3. local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
  4. local command = helpers.command
  5. local feed_command = helpers.feed_command
  6. local eq = helpers.eq
  7. local eval = helpers.eval
  8. local nvim_dir = helpers.nvim_dir
  9. describe('search highlighting', function()
  10. local screen
  11. local colors = Screen.colors
  12. before_each(function()
  13. clear()
  14. screen = Screen.new(40, 7)
  15. screen:attach()
  16. screen:set_default_attr_ids( {
  17. [1] = {bold=true, foreground=Screen.colors.Blue},
  18. [2] = {background = colors.Yellow}, -- Search
  19. [3] = {reverse = true},
  20. [4] = {foreground = colors.Red}, -- Message
  21. [6] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded
  22. })
  23. end)
  24. it('is disabled by ":set nohlsearch"', function()
  25. feed_command('set nohlsearch')
  26. insert("some text\nmore text")
  27. feed("gg/text<cr>")
  28. screen:expect([[
  29. some ^text |
  30. more text |
  31. {1:~ }|
  32. {1:~ }|
  33. {1:~ }|
  34. {1:~ }|
  35. /text |
  36. ]])
  37. end)
  38. it('is disabled in folded text', function()
  39. insert("some text\nmore text")
  40. feed_command('1,2fold')
  41. feed("gg/text")
  42. screen:expect([[
  43. {6:+-- 2 lines: some text·················}|
  44. {1:~ }|
  45. {1:~ }|
  46. {1:~ }|
  47. {1:~ }|
  48. {1:~ }|
  49. /text^ |
  50. ]])
  51. end)
  52. it('works', function()
  53. insert([[
  54. some text
  55. more textstuff
  56. stupidtexttextstuff
  57. a text word
  58. ]])
  59. -- 'hlsearch' is enabled by default. #2859
  60. feed("gg/text<cr>")
  61. screen:expect([[
  62. some {2:^text} |
  63. more {2:text}stuff |
  64. stupid{2:texttext}stuff |
  65. a {2:text} word |
  66. |
  67. {1:~ }|
  68. /text |
  69. ]])
  70. -- overlapping matches not allowed
  71. feed("3nx")
  72. screen:expect([[
  73. some {2:text} |
  74. more {2:text}stuff |
  75. stupid{2:text}^extstuff |
  76. a {2:text} word |
  77. |
  78. {1:~ }|
  79. /text |
  80. ]])
  81. feed("ggn*") -- search for entire word
  82. screen:expect([[
  83. some {2:text} |
  84. more textstuff |
  85. stupidtextextstuff |
  86. a {2:^text} word |
  87. |
  88. {1:~ }|
  89. /\<text\> |
  90. ]])
  91. feed_command("nohlsearch")
  92. screen:expect([[
  93. some text |
  94. more textstuff |
  95. stupidtextextstuff |
  96. a ^text word |
  97. |
  98. {1:~ }|
  99. :nohlsearch |
  100. ]])
  101. end)
  102. it('highlights after EOL', function()
  103. insert("\n\n\n\n\n\n")
  104. feed("gg/^<cr>")
  105. screen:expect([[
  106. {2: } |
  107. {2:^ } |
  108. {2: } |
  109. {2: } |
  110. {2: } |
  111. {2: } |
  112. /^ |
  113. ]])
  114. -- Test that highlights are preserved after moving the cursor.
  115. feed("j")
  116. screen:expect([[
  117. {2: } |
  118. {2: } |
  119. {2:^ } |
  120. {2: } |
  121. {2: } |
  122. {2: } |
  123. /^ |
  124. ]])
  125. -- Repeat the test in rightleft mode.
  126. command("nohlsearch")
  127. command("set rightleft")
  128. feed("gg/^<cr>")
  129. screen:expect([[
  130. {2: }|
  131. {2:^ }|
  132. {2: }|
  133. {2: }|
  134. {2: }|
  135. {2: }|
  136. ^/ |
  137. ]])
  138. feed("j")
  139. screen:expect([[
  140. {2: }|
  141. {2: }|
  142. {2:^ }|
  143. {2: }|
  144. {2: }|
  145. {2: }|
  146. ^/ |
  147. ]])
  148. end)
  149. it('is preserved during :terminal activity', function()
  150. feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 5000 foo<cr>]])
  151. feed(':file term<CR>')
  152. feed('G') -- Follow :terminal output.
  153. feed(':vnew<CR>')
  154. insert([[
  155. foo bar baz
  156. bar baz foo
  157. bar foo baz
  158. ]])
  159. feed('/foo')
  160. helpers.poke_eventloop()
  161. screen:expect_unchanged()
  162. end)
  163. it('works with incsearch', function()
  164. feed_command('set hlsearch')
  165. feed_command('set incsearch')
  166. insert([[
  167. the first line
  168. in a little file
  169. ]])
  170. feed("gg/li")
  171. screen:expect([[
  172. the first {3:li}ne |
  173. in a {2:li}ttle file |
  174. |
  175. {1:~ }|
  176. {1:~ }|
  177. {1:~ }|
  178. /li^ |
  179. ]])
  180. -- check that consecutive matches are caught by C-g/C-t
  181. feed("<C-g>")
  182. screen:expect([[
  183. the first {2:li}ne |
  184. in a {3:li}ttle file |
  185. |
  186. {1:~ }|
  187. {1:~ }|
  188. {1:~ }|
  189. /li^ |
  190. ]])
  191. feed("<C-t>")
  192. screen:expect([[
  193. the first {3:li}ne |
  194. in a {2:li}ttle file |
  195. |
  196. {1:~ }|
  197. {1:~ }|
  198. {1:~ }|
  199. /li^ |
  200. ]])
  201. feed("t")
  202. screen:expect([[
  203. the first line |
  204. in a {3:lit}tle file |
  205. |
  206. {1:~ }|
  207. {1:~ }|
  208. {1:~ }|
  209. /lit^ |
  210. ]])
  211. feed("<cr>")
  212. screen:expect([[
  213. the first line |
  214. in a {2:^lit}tle file |
  215. |
  216. {1:~ }|
  217. {1:~ }|
  218. {1:~ }|
  219. /lit |
  220. ]])
  221. feed("/fir")
  222. screen:expect([[
  223. the {3:fir}st line |
  224. in a little file |
  225. |
  226. {1:~ }|
  227. {1:~ }|
  228. {1:~ }|
  229. /fir^ |
  230. ]])
  231. -- incsearch have priority over hlsearch
  232. feed("<esc>/ttle")
  233. screen:expect([[
  234. the first line |
  235. in a li{3:ttle} file |
  236. |
  237. {1:~ }|
  238. {1:~ }|
  239. {1:~ }|
  240. /ttle^ |
  241. ]])
  242. -- cancelling search resets to the old search term
  243. feed('<esc>')
  244. screen:expect([[
  245. the first line |
  246. in a {2:^lit}tle file |
  247. |
  248. {1:~ }|
  249. {1:~ }|
  250. {1:~ }|
  251. |
  252. ]])
  253. eq('lit', eval('@/'))
  254. -- cancelling inc search restores the hl state
  255. feed(':noh<cr>')
  256. screen:expect([[
  257. the first line |
  258. in a ^little file |
  259. |
  260. {1:~ }|
  261. {1:~ }|
  262. {1:~ }|
  263. :noh |
  264. ]])
  265. feed('/first')
  266. screen:expect([[
  267. the {3:first} line |
  268. in a little file |
  269. |
  270. {1:~ }|
  271. {1:~ }|
  272. {1:~ }|
  273. /first^ |
  274. ]])
  275. feed('<esc>')
  276. screen:expect([[
  277. the first line |
  278. in a ^little file |
  279. |
  280. {1:~ }|
  281. {1:~ }|
  282. {1:~ }|
  283. |
  284. ]])
  285. -- test that pressing C-g in an empty command line does not move the cursor
  286. feed('/<C-g>')
  287. screen:expect([[
  288. the first line |
  289. in a little file |
  290. |
  291. {1:~ }|
  292. {1:~ }|
  293. {1:~ }|
  294. /^ |
  295. ]])
  296. -- same, for C-t
  297. feed('<ESC>')
  298. screen:expect([[
  299. the first line |
  300. in a ^little file |
  301. |
  302. {1:~ }|
  303. {1:~ }|
  304. {1:~ }|
  305. |
  306. ]])
  307. feed('/<C-t>')
  308. screen:expect([[
  309. the first line |
  310. in a little file |
  311. |
  312. {1:~ }|
  313. {1:~ }|
  314. {1:~ }|
  315. /^ |
  316. ]])
  317. -- 8.0.1304, test that C-g and C-t works with incsearch and empty pattern
  318. feed('<esc>/fi<CR>')
  319. feed('//')
  320. screen:expect([[
  321. the {3:fi}rst line |
  322. in a little {2:fi}le |
  323. |
  324. {1:~ }|
  325. {1:~ }|
  326. {1:~ }|
  327. //^ |
  328. ]])
  329. feed('<C-g>')
  330. screen:expect([[
  331. the {2:fi}rst line |
  332. in a little {3:fi}le |
  333. |
  334. {1:~ }|
  335. {1:~ }|
  336. {1:~ }|
  337. //^ |
  338. ]])
  339. end)
  340. it('works with incsearch and offset', function()
  341. feed_command('set hlsearch')
  342. feed_command('set incsearch')
  343. insert([[
  344. not the match you're looking for
  345. the match is here]])
  346. feed("gg/mat/e")
  347. screen:expect([[
  348. not the {3:mat}ch you're looking for |
  349. the {2:mat}ch is here |
  350. {1:~ }|
  351. {1:~ }|
  352. {1:~ }|
  353. {1:~ }|
  354. /mat/e^ |
  355. ]])
  356. -- Search with count and /e offset fixed in Vim patch 7.4.532.
  357. feed("<esc>2/mat/e")
  358. screen:expect([[
  359. not the {2:mat}ch you're looking for |
  360. the {3:mat}ch is here |
  361. {1:~ }|
  362. {1:~ }|
  363. {1:~ }|
  364. {1:~ }|
  365. /mat/e^ |
  366. ]])
  367. feed("<cr>")
  368. screen:expect([[
  369. not the {2:mat}ch you're looking for |
  370. the {2:ma^t}ch is here |
  371. {1:~ }|
  372. {1:~ }|
  373. {1:~ }|
  374. {1:~ }|
  375. /mat/e |
  376. ]])
  377. end)
  378. it('works with multiline regexps', function()
  379. feed_command('set hlsearch')
  380. feed('4oa repeated line<esc>')
  381. feed('/line\\na<cr>')
  382. screen:expect([[
  383. |
  384. a repeated {2:^line} |
  385. {2:a} repeated {2:line} |
  386. {2:a} repeated {2:line} |
  387. {2:a} repeated line |
  388. {1:~ }|
  389. {4:search hit BOTTOM, continuing at TOP} |
  390. ]])
  391. -- it redraws rows above the changed one
  392. feed('4Grb')
  393. screen:expect([[
  394. |
  395. a repeated {2:line} |
  396. {2:a} repeated line |
  397. ^b repeated {2:line} |
  398. {2:a} repeated line |
  399. {1:~ }|
  400. {4:search hit BOTTOM, continuing at TOP} |
  401. ]])
  402. end)
  403. it('works with matchadd and syntax', function()
  404. screen:set_default_attr_ids( {
  405. [1] = {bold=true, foreground=Screen.colors.Blue},
  406. [2] = {background = colors.Yellow},
  407. [3] = {reverse = true},
  408. [4] = {foreground = colors.Red},
  409. [5] = {bold = true, background = colors.Green},
  410. [6] = {italic = true, background = colors.Magenta},
  411. [7] = {bold = true, background = colors.Yellow},
  412. } )
  413. feed_command('set hlsearch')
  414. insert([[
  415. very special text
  416. ]])
  417. feed_command("syntax on")
  418. feed_command("highlight MyGroup guibg=Green gui=bold")
  419. feed_command("highlight MyGroup2 guibg=Magenta gui=italic")
  420. feed_command("call matchadd('MyGroup', 'special')")
  421. feed_command("call matchadd('MyGroup2', 'text', 0)")
  422. -- searchhl and matchadd matches are exclusive, only the highest priority
  423. -- is used (and matches with lower priorities are not combined)
  424. feed_command("/ial te")
  425. screen:expect([[
  426. very {5:spec^ial}{2: te}{6:xt} |
  427. |
  428. {1:~ }|
  429. {1:~ }|
  430. {1:~ }|
  431. {1:~ }|
  432. {4:search hit BOTTOM, continuing at TOP} |
  433. ]])
  434. -- check hilights work also in folds
  435. feed("zf4j")
  436. command("%foldopen")
  437. screen:expect([[
  438. very {5:spec^ial}{2: te}{6:xt} |
  439. |
  440. {1:~ }|
  441. {1:~ }|
  442. {1:~ }|
  443. {1:~ }|
  444. {4:search hit BOTTOM, continuing at TOP} |
  445. ]])
  446. feed_command("call clearmatches()")
  447. screen:expect([[
  448. very spec{2:^ial te}xt |
  449. |
  450. {1:~ }|
  451. {1:~ }|
  452. {1:~ }|
  453. {1:~ }|
  454. :call clearmatches() |
  455. ]])
  456. -- searchhl has priority over syntax, but in this case
  457. -- nonconflicting attributes are combined
  458. feed_command("syntax keyword MyGroup special")
  459. screen:expect([[
  460. very {5:spec}{7:^ial}{2: te}xt |
  461. |
  462. {1:~ }|
  463. {1:~ }|
  464. {1:~ }|
  465. {1:~ }|
  466. :syntax keyword MyGroup special |
  467. ]])
  468. end)
  469. it('highlights entire pattern on :%g@a/b', function()
  470. command('set inccommand=nosplit')
  471. feed('ia/b/c<Esc>')
  472. feed(':%g@a/b')
  473. screen:expect([[
  474. {3:a/b}/c |
  475. {1:~ }|
  476. {1:~ }|
  477. {1:~ }|
  478. {1:~ }|
  479. {1:~ }|
  480. :%g@a/b^ |
  481. ]])
  482. end)
  483. end)