cmdline_highlight_spec.lua 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. local helpers = require('test.functional.helpers')(after_each)
  2. local Screen = require('test.functional.ui.screen')
  3. local eq = helpers.eq
  4. local feed = helpers.feed
  5. local clear = helpers.clear
  6. local meths = helpers.meths
  7. local funcs = helpers.funcs
  8. local source = helpers.source
  9. local dedent = helpers.dedent
  10. local command = helpers.command
  11. local curbufmeths = helpers.curbufmeths
  12. local screen
  13. -- Bug in input() handling: :redraw! will erase the whole prompt up until
  14. -- user types something. It exists in Vim as well, so using `h<BS>` as
  15. -- a workaround.
  16. local function redraw_input()
  17. feed('{REDRAW}h<BS>')
  18. end
  19. before_each(function()
  20. clear()
  21. screen = Screen.new(40, 8)
  22. screen:attach()
  23. command("set display-=msgsep")
  24. source([[
  25. highlight RBP1 guibg=Red
  26. highlight RBP2 guibg=Yellow
  27. highlight RBP3 guibg=Green
  28. highlight RBP4 guibg=Blue
  29. let g:NUM_LVLS = 4
  30. function Redraw()
  31. mode
  32. return ''
  33. endfunction
  34. let g:id = ''
  35. cnoremap <expr> {REDRAW} Redraw()
  36. function DoPrompt(do_return) abort
  37. let id = g:id
  38. let Cb = g:Nvim_color_input{g:id}
  39. let out = input({'prompt': ':', 'highlight': Cb})
  40. let g:out{id} = out
  41. return (a:do_return ? out : '')
  42. endfunction
  43. nnoremap <expr> {PROMPT} DoPrompt(0)
  44. cnoremap <expr> {PROMPT} DoPrompt(1)
  45. function RainBowParens(cmdline)
  46. let ret = []
  47. let i = 0
  48. let lvl = 0
  49. while i < len(a:cmdline)
  50. if a:cmdline[i] is# '('
  51. call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
  52. let lvl += 1
  53. elseif a:cmdline[i] is# ')'
  54. let lvl -= 1
  55. call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
  56. endif
  57. let i += 1
  58. endwhile
  59. return ret
  60. endfunction
  61. function SplittedMultibyteStart(cmdline)
  62. let ret = []
  63. let i = 0
  64. while i < len(a:cmdline)
  65. let char = nr2char(char2nr(a:cmdline[i:]))
  66. if a:cmdline[i:i + len(char) - 1] is# char
  67. if len(char) > 1
  68. call add(ret, [i + 1, i + len(char), 'RBP2'])
  69. endif
  70. let i += len(char)
  71. else
  72. let i += 1
  73. endif
  74. endwhile
  75. return ret
  76. endfunction
  77. function SplittedMultibyteEnd(cmdline)
  78. let ret = []
  79. let i = 0
  80. while i < len(a:cmdline)
  81. let char = nr2char(char2nr(a:cmdline[i:]))
  82. if a:cmdline[i:i + len(char) - 1] is# char
  83. if len(char) > 1
  84. call add(ret, [i, i + 1, 'RBP1'])
  85. endif
  86. let i += len(char)
  87. else
  88. let i += 1
  89. endif
  90. endwhile
  91. return ret
  92. endfunction
  93. function Echoing(cmdline)
  94. echo 'HERE'
  95. return v:_null_list
  96. endfunction
  97. function Echoning(cmdline)
  98. echon 'HERE'
  99. return v:_null_list
  100. endfunction
  101. function Echomsging(cmdline)
  102. echomsg 'HERE'
  103. return v:_null_list
  104. endfunction
  105. function Echoerring(cmdline)
  106. echoerr 'HERE'
  107. return v:_null_list
  108. endfunction
  109. function Redrawing(cmdline)
  110. redraw!
  111. return v:_null_list
  112. endfunction
  113. function Throwing(cmdline)
  114. throw "ABC"
  115. return v:_null_list
  116. endfunction
  117. function Halting(cmdline)
  118. while 1
  119. endwhile
  120. endfunction
  121. function ReturningGlobal(cmdline)
  122. return g:callback_return
  123. endfunction
  124. function ReturningGlobal2(cmdline)
  125. return g:callback_return[:len(a:cmdline)-1]
  126. endfunction
  127. function ReturningGlobalN(n, cmdline)
  128. return g:callback_return{a:n}
  129. endfunction
  130. let g:recording_calls = []
  131. function Recording(cmdline)
  132. call add(g:recording_calls, a:cmdline)
  133. return []
  134. endfunction
  135. ]])
  136. screen:set_default_attr_ids({
  137. RBP1={background = Screen.colors.Red},
  138. RBP2={background = Screen.colors.Yellow},
  139. RBP3={background = Screen.colors.Green},
  140. RBP4={background = Screen.colors.Blue},
  141. EOB={bold = true, foreground = Screen.colors.Blue1},
  142. ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
  143. SK={foreground = Screen.colors.Blue},
  144. PE={bold = true, foreground = Screen.colors.SeaGreen4},
  145. NUM={foreground = Screen.colors.Blue2},
  146. NPAR={foreground = Screen.colors.Yellow},
  147. SQ={foreground = Screen.colors.Blue3},
  148. SB={foreground = Screen.colors.Blue4},
  149. E={foreground = Screen.colors.Red, background = Screen.colors.Blue},
  150. M={bold = true},
  151. })
  152. end)
  153. local function set_color_cb(funcname, callback_return, id)
  154. meths.set_var('id', id or '')
  155. if id and id ~= '' and funcs.exists('*' .. funcname .. 'N') then
  156. command(('let g:Nvim_color_input%s = {cmdline -> %sN(%s, cmdline)}'):format(
  157. id, funcname, id))
  158. if callback_return then
  159. meths.set_var('callback_return' .. id, callback_return)
  160. end
  161. else
  162. meths.set_var('Nvim_color_input', funcname)
  163. if callback_return then
  164. meths.set_var('callback_return', callback_return)
  165. end
  166. end
  167. end
  168. local function start_prompt(text)
  169. feed('{PROMPT}' .. (text or ''))
  170. end
  171. describe('Command-line coloring', function()
  172. it('works', function()
  173. set_color_cb('RainBowParens')
  174. meths.set_option('more', false)
  175. start_prompt()
  176. screen:expect([[
  177. |
  178. {EOB:~ }|
  179. {EOB:~ }|
  180. {EOB:~ }|
  181. {EOB:~ }|
  182. {EOB:~ }|
  183. {EOB:~ }|
  184. :^ |
  185. ]])
  186. feed('e')
  187. screen:expect([[
  188. |
  189. {EOB:~ }|
  190. {EOB:~ }|
  191. {EOB:~ }|
  192. {EOB:~ }|
  193. {EOB:~ }|
  194. {EOB:~ }|
  195. :e^ |
  196. ]])
  197. feed('cho ')
  198. screen:expect([[
  199. |
  200. {EOB:~ }|
  201. {EOB:~ }|
  202. {EOB:~ }|
  203. {EOB:~ }|
  204. {EOB:~ }|
  205. {EOB:~ }|
  206. :echo ^ |
  207. ]])
  208. feed('(')
  209. screen:expect([[
  210. |
  211. {EOB:~ }|
  212. {EOB:~ }|
  213. {EOB:~ }|
  214. {EOB:~ }|
  215. {EOB:~ }|
  216. {EOB:~ }|
  217. :echo {RBP1:(}^ |
  218. ]])
  219. feed('(')
  220. screen:expect([[
  221. |
  222. {EOB:~ }|
  223. {EOB:~ }|
  224. {EOB:~ }|
  225. {EOB:~ }|
  226. {EOB:~ }|
  227. {EOB:~ }|
  228. :echo {RBP1:(}{RBP2:(}^ |
  229. ]])
  230. feed('42')
  231. screen:expect([[
  232. |
  233. {EOB:~ }|
  234. {EOB:~ }|
  235. {EOB:~ }|
  236. {EOB:~ }|
  237. {EOB:~ }|
  238. {EOB:~ }|
  239. :echo {RBP1:(}{RBP2:(}42^ |
  240. ]])
  241. feed('))')
  242. screen:expect([[
  243. |
  244. {EOB:~ }|
  245. {EOB:~ }|
  246. {EOB:~ }|
  247. {EOB:~ }|
  248. {EOB:~ }|
  249. {EOB:~ }|
  250. :echo {RBP1:(}{RBP2:(}42{RBP2:)}{RBP1:)}^ |
  251. ]])
  252. feed('<BS>')
  253. screen:expect([[
  254. |
  255. {EOB:~ }|
  256. {EOB:~ }|
  257. {EOB:~ }|
  258. {EOB:~ }|
  259. {EOB:~ }|
  260. {EOB:~ }|
  261. :echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
  262. ]])
  263. redraw_input()
  264. screen:expect{grid=[[
  265. |
  266. {EOB:~ }|
  267. {EOB:~ }|
  268. {EOB:~ }|
  269. {EOB:~ }|
  270. {EOB:~ }|
  271. {EOB:~ }|
  272. :echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
  273. ]], reset=true}
  274. end)
  275. for _, func_part in ipairs({'', 'n', 'msg'}) do
  276. it('disables :echo' .. func_part .. ' messages', function()
  277. set_color_cb('Echo' .. func_part .. 'ing')
  278. start_prompt('echo')
  279. screen:expect([[
  280. |
  281. {EOB:~ }|
  282. {EOB:~ }|
  283. {EOB:~ }|
  284. {EOB:~ }|
  285. {EOB:~ }|
  286. {EOB:~ }|
  287. :echo^ |
  288. ]])
  289. end)
  290. end
  291. it('does the right thing when hl start appears to split multibyte char',
  292. function()
  293. set_color_cb('SplittedMultibyteStart')
  294. start_prompt('echo "«')
  295. screen:expect([[
  296. {EOB:~ }|
  297. {EOB:~ }|
  298. {EOB:~ }|
  299. {EOB:~ }|
  300. :echo " |
  301. {ERR:E5405: Chunk 0 start 7 splits multibyte }|
  302. {ERR:character} |
  303. :echo "«^ |
  304. ]])
  305. feed('»')
  306. screen:expect([[
  307. {EOB:~ }|
  308. {EOB:~ }|
  309. {EOB:~ }|
  310. {EOB:~ }|
  311. :echo " |
  312. {ERR:E5405: Chunk 0 start 7 splits multibyte }|
  313. {ERR:character} |
  314. :echo "«»^ |
  315. ]])
  316. end)
  317. it('does the right thing when hl end appears to split multibyte char',
  318. function()
  319. set_color_cb('SplittedMultibyteEnd')
  320. start_prompt('echo "«')
  321. screen:expect([[
  322. {EOB:~ }|
  323. {EOB:~ }|
  324. {EOB:~ }|
  325. {EOB:~ }|
  326. :echo " |
  327. {ERR:E5406: Chunk 0 end 7 splits multibyte ch}|
  328. {ERR:aracter} |
  329. :echo "«^ |
  330. ]])
  331. end)
  332. it('does the right thing when errorring', function()
  333. set_color_cb('Echoerring')
  334. start_prompt('e')
  335. screen:expect([[
  336. {EOB:~ }|
  337. {EOB:~ }|
  338. {EOB:~ }|
  339. {EOB:~ }|
  340. : |
  341. {ERR:E5407: Callback has thrown an exception:}|
  342. {ERR: Vim(echoerr):HERE} |
  343. :e^ |
  344. ]])
  345. end)
  346. it('silences :echo', function()
  347. set_color_cb('Echoing')
  348. start_prompt('e')
  349. screen:expect([[
  350. |
  351. {EOB:~ }|
  352. {EOB:~ }|
  353. {EOB:~ }|
  354. {EOB:~ }|
  355. {EOB:~ }|
  356. {EOB:~ }|
  357. :e^ |
  358. ]])
  359. eq('', meths.command_output('messages'))
  360. end)
  361. it('silences :echon', function()
  362. set_color_cb('Echoning')
  363. start_prompt('e')
  364. screen:expect([[
  365. |
  366. {EOB:~ }|
  367. {EOB:~ }|
  368. {EOB:~ }|
  369. {EOB:~ }|
  370. {EOB:~ }|
  371. {EOB:~ }|
  372. :e^ |
  373. ]])
  374. eq('', meths.command_output('messages'))
  375. end)
  376. it('silences :echomsg', function()
  377. set_color_cb('Echomsging')
  378. start_prompt('e')
  379. screen:expect([[
  380. |
  381. {EOB:~ }|
  382. {EOB:~ }|
  383. {EOB:~ }|
  384. {EOB:~ }|
  385. {EOB:~ }|
  386. {EOB:~ }|
  387. :e^ |
  388. ]])
  389. eq('', meths.command_output('messages'))
  390. end)
  391. it('does the right thing when throwing', function()
  392. set_color_cb('Throwing')
  393. start_prompt('e')
  394. screen:expect([[
  395. {EOB:~ }|
  396. {EOB:~ }|
  397. {EOB:~ }|
  398. {EOB:~ }|
  399. : |
  400. {ERR:E5407: Callback has thrown an exception:}|
  401. {ERR: ABC} |
  402. :e^ |
  403. ]])
  404. end)
  405. it('stops executing callback after a number of errors', function()
  406. set_color_cb('SplittedMultibyteStart')
  407. start_prompt('let x = "«»«»«»«»«»"\n')
  408. screen:expect([[
  409. {EOB:~ }|
  410. {EOB:~ }|
  411. {EOB:~ }|
  412. {EOB:~ }|
  413. :let x = " |
  414. {ERR:E5405: Chunk 0 start 10 splits multibyte}|
  415. {ERR: character} |
  416. ^:let x = "«»«»«»«»«»" |
  417. ]])
  418. feed('\n')
  419. screen:expect([[
  420. ^ |
  421. {EOB:~ }|
  422. {EOB:~ }|
  423. {EOB:~ }|
  424. {EOB:~ }|
  425. {EOB:~ }|
  426. {EOB:~ }|
  427. |
  428. ]])
  429. eq('let x = "«»«»«»«»«»"', meths.get_var('out'))
  430. local msg = '\nE5405: Chunk 0 start 10 splits multibyte character'
  431. eq(msg:rep(1), funcs.execute('messages'))
  432. end)
  433. it('allows interrupting callback with <C-c>', function()
  434. set_color_cb('Halting')
  435. start_prompt('echo 42')
  436. screen:expect([[
  437. ^ |
  438. {EOB:~ }|
  439. {EOB:~ }|
  440. {EOB:~ }|
  441. {EOB:~ }|
  442. {EOB:~ }|
  443. {EOB:~ }|
  444. |
  445. ]])
  446. screen:sleep(500)
  447. feed('<C-c>')
  448. screen:expect([[
  449. {EOB:~ }|
  450. {EOB:~ }|
  451. {EOB:~ }|
  452. {EOB:~ }|
  453. : |
  454. {ERR:E5407: Callback has thrown an exception:}|
  455. {ERR: Keyboard interrupt} |
  456. :echo 42^ |
  457. ]])
  458. redraw_input()
  459. screen:expect([[
  460. |
  461. {EOB:~ }|
  462. {EOB:~ }|
  463. {EOB:~ }|
  464. {EOB:~ }|
  465. {EOB:~ }|
  466. {EOB:~ }|
  467. :echo 42^ |
  468. ]])
  469. feed('\n')
  470. screen:expect([[
  471. |
  472. {EOB:~ }|
  473. {EOB:~ }|
  474. {EOB:~ }|
  475. {EOB:~ }|
  476. {EOB:~ }|
  477. {EOB:~ }|
  478. ^:echo 42 |
  479. ]])
  480. feed('\n')
  481. eq('echo 42', meths.get_var('out'))
  482. feed('<C-c>')
  483. screen:expect([[
  484. ^ |
  485. {EOB:~ }|
  486. {EOB:~ }|
  487. {EOB:~ }|
  488. {EOB:~ }|
  489. {EOB:~ }|
  490. {EOB:~ }|
  491. Type :qa! and pr...nges and exit Nvim |
  492. ]])
  493. end)
  494. it('works fine with NUL, NL, CR', function()
  495. set_color_cb('RainBowParens')
  496. start_prompt('echo ("<C-v><CR><C-v><Nul><C-v><NL>")')
  497. screen:expect([[
  498. |
  499. {EOB:~ }|
  500. {EOB:~ }|
  501. {EOB:~ }|
  502. {EOB:~ }|
  503. {EOB:~ }|
  504. {EOB:~ }|
  505. :echo {RBP1:(}"{SK:^M^@^@}"{RBP1:)}^ |
  506. ]])
  507. end)
  508. it('errors out when callback returns something wrong', function()
  509. command('cnoremap + ++')
  510. set_color_cb('ReturningGlobal', '')
  511. start_prompt('#')
  512. screen:expect([[
  513. {EOB:~ }|
  514. {EOB:~ }|
  515. {EOB:~ }|
  516. {EOB:~ }|
  517. {EOB:~ }|
  518. : |
  519. {ERR:E5400: Callback should return list} |
  520. :#^ |
  521. ]])
  522. feed('<CR><CR><CR>')
  523. set_color_cb('ReturningGlobal', {{0, 1, 'Normal'}, 42})
  524. start_prompt('#')
  525. screen:expect([[
  526. {EOB:~ }|
  527. {EOB:~ }|
  528. {EOB:~ }|
  529. {EOB:~ }|
  530. {EOB:~ }|
  531. : |
  532. {ERR:E5401: List item 1 is not a List} |
  533. :#^ |
  534. ]])
  535. feed('<CR><CR><CR>')
  536. set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {1}})
  537. start_prompt('+')
  538. screen:expect([[
  539. {EOB:~ }|
  540. {EOB:~ }|
  541. {EOB:~ }|
  542. {EOB:~ }|
  543. :+ |
  544. {ERR:E5402: List item 1 has incorrect length:}|
  545. {ERR: 1 /= 3} |
  546. :++^ |
  547. ]])
  548. feed('<CR><CR><CR>')
  549. set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {2, 3, 'Normal'}})
  550. start_prompt('+')
  551. screen:expect([[
  552. {EOB:~ }|
  553. {EOB:~ }|
  554. {EOB:~ }|
  555. {EOB:~ }|
  556. :+ |
  557. {ERR:E5403: Chunk 1 start 2 not in range [1, }|
  558. {ERR:2)} |
  559. :++^ |
  560. ]])
  561. feed('<CR><CR><CR>')
  562. set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {1, 3, 'Normal'}})
  563. start_prompt('+')
  564. screen:expect([[
  565. {EOB:~ }|
  566. {EOB:~ }|
  567. {EOB:~ }|
  568. {EOB:~ }|
  569. :+ |
  570. {ERR:E5404: Chunk 1 end 3 not in range (1, 2]}|
  571. |
  572. :++^ |
  573. ]])
  574. end)
  575. it('does not error out when called from a errorred out cycle', function()
  576. set_color_cb('ReturningGlobal', {{0, 1, 'Normal'}})
  577. feed(dedent([[
  578. :set regexpengine=2
  579. :for pat in [' \ze*', ' \zs*']
  580. : try
  581. : let l = matchlist('x x', pat)
  582. : $put =input({'prompt':'>','highlight':'ReturningGlobal'})
  583. :
  584. : $put ='E888 NOT detected for ' . pat
  585. : catch
  586. : $put =input({'prompt':'>','highlight':'ReturningGlobal'})
  587. :
  588. : $put ='E888 detected for ' . pat
  589. : endtry
  590. :endfor
  591. :
  592. :
  593. :
  594. :
  595. :
  596. :
  597. ]]))
  598. eq({'', ':', 'E888 detected for \\ze*', ':', 'E888 detected for \\zs*'},
  599. curbufmeths.get_lines(0, -1, false))
  600. eq('', funcs.execute('messages'))
  601. end)
  602. it('allows nesting input()s', function()
  603. set_color_cb('ReturningGlobal', {{0, 1, 'RBP1'}}, '')
  604. start_prompt('1')
  605. screen:expect([[
  606. |
  607. {EOB:~ }|
  608. {EOB:~ }|
  609. {EOB:~ }|
  610. {EOB:~ }|
  611. {EOB:~ }|
  612. {EOB:~ }|
  613. :{RBP1:1}^ |
  614. ]])
  615. set_color_cb('ReturningGlobal', {{0, 1, 'RBP2'}}, '1')
  616. start_prompt('2')
  617. screen:expect([[
  618. |
  619. {EOB:~ }|
  620. {EOB:~ }|
  621. {EOB:~ }|
  622. {EOB:~ }|
  623. {EOB:~ }|
  624. {EOB:~ }|
  625. :{RBP2:2}^ |
  626. ]])
  627. set_color_cb('ReturningGlobal', {{0, 1, 'RBP3'}}, '2')
  628. start_prompt('3')
  629. screen:expect([[
  630. |
  631. {EOB:~ }|
  632. {EOB:~ }|
  633. {EOB:~ }|
  634. {EOB:~ }|
  635. {EOB:~ }|
  636. {EOB:~ }|
  637. :{RBP3:3}^ |
  638. ]])
  639. set_color_cb('ReturningGlobal', {{0, 1, 'RBP4'}}, '3')
  640. start_prompt('4')
  641. screen:expect([[
  642. |
  643. {EOB:~ }|
  644. {EOB:~ }|
  645. {EOB:~ }|
  646. {EOB:~ }|
  647. {EOB:~ }|
  648. {EOB:~ }|
  649. :{RBP4:4}^ |
  650. ]])
  651. feed('<CR>')
  652. screen:expect([[
  653. |
  654. {EOB:~ }|
  655. {EOB:~ }|
  656. {EOB:~ }|
  657. {EOB:~ }|
  658. {EOB:~ }|
  659. {EOB:~ }|
  660. :{RBP3:3}4^ |
  661. ]])
  662. feed('<CR>')
  663. screen:expect([[
  664. |
  665. {EOB:~ }|
  666. {EOB:~ }|
  667. {EOB:~ }|
  668. {EOB:~ }|
  669. {EOB:~ }|
  670. {EOB:~ }|
  671. :{RBP2:2}34^ |
  672. ]])
  673. feed('<CR>')
  674. screen:expect([[
  675. |
  676. {EOB:~ }|
  677. {EOB:~ }|
  678. {EOB:~ }|
  679. {EOB:~ }|
  680. {EOB:~ }|
  681. {EOB:~ }|
  682. :{RBP1:1}234^ |
  683. ]])
  684. feed('<CR><CR><C-l>')
  685. screen:expect([[
  686. ^ |
  687. {EOB:~ }|
  688. {EOB:~ }|
  689. {EOB:~ }|
  690. {EOB:~ }|
  691. {EOB:~ }|
  692. {EOB:~ }|
  693. |
  694. ]])
  695. eq('1234', meths.get_var('out'))
  696. eq('234', meths.get_var('out1'))
  697. eq('34', meths.get_var('out2'))
  698. eq('4', meths.get_var('out3'))
  699. eq(0, funcs.exists('g:out4'))
  700. end)
  701. it('runs callback with the same data only once', function()
  702. local function new_recording_calls(...)
  703. eq({...}, meths.get_var('recording_calls'))
  704. meths.set_var('recording_calls', {})
  705. end
  706. set_color_cb('Recording')
  707. start_prompt('')
  708. -- Regression test. Disambiguation:
  709. --
  710. -- new_recording_calls(expected_result) -- (actual_before_fix)
  711. --
  712. feed('a')
  713. new_recording_calls('a') -- ('a', 'a')
  714. feed('b')
  715. new_recording_calls('ab') -- ('a', 'ab', 'ab')
  716. feed('c')
  717. new_recording_calls('abc') -- ('ab', 'abc', 'abc')
  718. feed('<BS>')
  719. new_recording_calls('ab') -- ('abc', 'ab', 'ab')
  720. feed('<BS>')
  721. new_recording_calls('a') -- ('ab', 'a', 'a')
  722. feed('<BS>')
  723. new_recording_calls() -- ('a')
  724. feed('<CR><CR>')
  725. eq('', meths.get_var('out'))
  726. end)
  727. it('does not crash when callback has caught not-a-editor-command exception',
  728. function()
  729. source([[
  730. function CaughtExc(cmdline) abort
  731. try
  732. gibberish
  733. catch
  734. " Do nothing
  735. endtry
  736. return []
  737. endfunction
  738. ]])
  739. set_color_cb('CaughtExc')
  740. start_prompt('1')
  741. eq(1, meths.eval('1'))
  742. end)
  743. end)
  744. describe('Ex commands coloring', function()
  745. it('works', function()
  746. meths.set_var('Nvim_color_cmdline', 'RainBowParens')
  747. feed(':echo (((1)))')
  748. screen:expect([[
  749. |
  750. {EOB:~ }|
  751. {EOB:~ }|
  752. {EOB:~ }|
  753. {EOB:~ }|
  754. {EOB:~ }|
  755. {EOB:~ }|
  756. :echo {RBP1:(}{RBP2:(}{RBP3:(}1{RBP3:)}{RBP2:)}{RBP1:)}^ |
  757. ]])
  758. end)
  759. it('still executes command-line even if errored out', function()
  760. meths.set_var('Nvim_color_cmdline', 'SplittedMultibyteStart')
  761. feed(':let x = "«"\n')
  762. eq('«', meths.get_var('x'))
  763. local msg = 'E5405: Chunk 0 start 10 splits multibyte character'
  764. eq('\n'..msg, funcs.execute('messages'))
  765. end)
  766. it('does not error out when called from a errorred out cycle', function()
  767. -- Apparently when there is a cycle in which one of the commands errors out
  768. -- this error may be caught by color_cmdline before it is presented to the
  769. -- user.
  770. feed(dedent([[
  771. :set regexpengine=2
  772. :for pat in [' \ze*', ' \zs*']
  773. : try
  774. : let l = matchlist('x x', pat)
  775. : $put ='E888 NOT detected for ' . pat
  776. : catch
  777. : $put ='E888 detected for ' . pat
  778. : endtry
  779. :endfor
  780. ]]))
  781. eq({'', 'E888 detected for \\ze*', 'E888 detected for \\zs*'},
  782. curbufmeths.get_lines(0, -1, false))
  783. eq('', funcs.execute('messages'))
  784. end)
  785. it('does not crash when using `n` in debug mode', function()
  786. feed(':debug execute "echo 1"\n')
  787. screen:expect([[
  788. {EOB:~ }|
  789. {EOB:~ }|
  790. {EOB:~ }|
  791. {EOB:~ }|
  792. Entering Debug mode. Type "cont" to con|
  793. tinue. |
  794. cmd: execute "echo 1" |
  795. >^ |
  796. ]])
  797. feed('n\n')
  798. screen:expect([[
  799. {EOB:~ }|
  800. {EOB:~ }|
  801. Entering Debug mode. Type "cont" to con|
  802. tinue. |
  803. cmd: execute "echo 1" |
  804. >n |
  805. 1 |
  806. {PE:Press ENTER or type command to continue}^ |
  807. ]])
  808. feed('\n')
  809. screen:expect([[
  810. ^ |
  811. {EOB:~ }|
  812. {EOB:~ }|
  813. {EOB:~ }|
  814. {EOB:~ }|
  815. {EOB:~ }|
  816. {EOB:~ }|
  817. |
  818. ]])
  819. end)
  820. it('mapping error does not cancel prompt', function()
  821. command("cnoremap <expr> x execute('throw 42')[-1]")
  822. feed(':#x')
  823. screen:expect([[
  824. {EOB:~ }|
  825. {EOB:~ }|
  826. {EOB:~ }|
  827. {EOB:~ }|
  828. :# |
  829. {ERR:Error detected while processing :} |
  830. {ERR:E605: Exception not caught: 42} |
  831. :#^ |
  832. ]])
  833. feed('<CR>')
  834. screen:expect([[
  835. {EOB:~ }|
  836. {EOB:~ }|
  837. {EOB:~ }|
  838. :# |
  839. {ERR:Error detected while processing :} |
  840. {ERR:E605: Exception not caught: 42} |
  841. {ERR:E749: empty buffer} |
  842. {PE:Press ENTER or type command to continue}^ |
  843. ]])
  844. feed('<CR>')
  845. eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer',
  846. meths.command_output('messages'))
  847. end)
  848. it('errors out when failing to get callback', function()
  849. meths.set_var('Nvim_color_cmdline', 42)
  850. feed(':#')
  851. screen:expect([[
  852. {EOB:~ }|
  853. {EOB:~ }|
  854. {EOB:~ }|
  855. : |
  856. {ERR:E5408: Unable to get g:Nvim_color_cmdlin}|
  857. {ERR:e callback: Vim:E6000: Argument is not a}|
  858. {ERR: function or function name} |
  859. :#^ |
  860. ]])
  861. end)
  862. end)
  863. describe('Expressions coloring support', function()
  864. it('works', function()
  865. meths.command('hi clear NvimNumber')
  866. meths.command('hi clear NvimNestingParenthesis')
  867. meths.command('hi NvimNumber guifg=Blue2')
  868. meths.command('hi NvimNestingParenthesis guifg=Yellow')
  869. feed(':echo <C-r>=(((1)))')
  870. screen:expect([[
  871. |
  872. {EOB:~ }|
  873. {EOB:~ }|
  874. {EOB:~ }|
  875. {EOB:~ }|
  876. {EOB:~ }|
  877. {EOB:~ }|
  878. ={NPAR:(((}{NUM:1}{NPAR:)))}^ |
  879. ]])
  880. end)
  881. it('does not use Nvim_color_expr', function()
  882. meths.set_var('Nvim_color_expr', 42)
  883. -- Used to error out due to failing to get callback.
  884. meths.command('hi clear NvimNumber')
  885. meths.command('hi NvimNumber guifg=Blue2')
  886. feed(':<C-r>=1')
  887. screen:expect([[
  888. |
  889. {EOB:~ }|
  890. {EOB:~ }|
  891. {EOB:~ }|
  892. {EOB:~ }|
  893. {EOB:~ }|
  894. {EOB:~ }|
  895. ={NUM:1}^ |
  896. ]])
  897. end)
  898. it('works correctly with non-ASCII and control characters', function()
  899. meths.command('hi clear NvimStringBody')
  900. meths.command('hi clear NvimStringQuote')
  901. meths.command('hi clear NvimInvalid')
  902. meths.command('hi NvimStringQuote guifg=Blue3')
  903. meths.command('hi NvimStringBody guifg=Blue4')
  904. meths.command('hi NvimInvalid guifg=Red guibg=Blue')
  905. feed('i<C-r>="«»"«»')
  906. screen:expect([[
  907. |
  908. {EOB:~ }|
  909. {EOB:~ }|
  910. {EOB:~ }|
  911. {EOB:~ }|
  912. {EOB:~ }|
  913. {EOB:~ }|
  914. ={SQ:"}{SB:«»}{SQ:"}{E:«»}^ |
  915. ]])
  916. feed('<C-c>')
  917. screen:expect([[
  918. ^ |
  919. {EOB:~ }|
  920. {EOB:~ }|
  921. {EOB:~ }|
  922. {EOB:~ }|
  923. {EOB:~ }|
  924. {EOB:~ }|
  925. {M:-- INSERT --} |
  926. ]])
  927. feed('<Esc>')
  928. screen:expect([[
  929. ^ |
  930. {EOB:~ }|
  931. {EOB:~ }|
  932. {EOB:~ }|
  933. {EOB:~ }|
  934. {EOB:~ }|
  935. {EOB:~ }|
  936. |
  937. ]])
  938. feed(':<C-\\>e"<C-v><C-x>"<C-v><C-x>')
  939. -- TODO(ZyX-I): Parser highlighting should not override special character
  940. -- highlighting.
  941. screen:expect([[
  942. |
  943. {EOB:~ }|
  944. {EOB:~ }|
  945. {EOB:~ }|
  946. {EOB:~ }|
  947. {EOB:~ }|
  948. {EOB:~ }|
  949. ={SQ:"}{SB:^X}{SQ:"}{ERR:^X}^ |
  950. ]])
  951. feed('<C-c>')
  952. screen:expect([[
  953. |
  954. {EOB:~ }|
  955. {EOB:~ }|
  956. {EOB:~ }|
  957. {EOB:~ }|
  958. {EOB:~ }|
  959. {EOB:~ }|
  960. :^ |
  961. ]])
  962. funcs.setreg('a', {'\192'})
  963. feed('<C-r>="<C-r><C-r>a"<C-r><C-r>a"foo"')
  964. -- TODO(ZyX-I): Parser highlighting should not override special character
  965. -- highlighting.
  966. screen:expect([[
  967. |
  968. {EOB:~ }|
  969. {EOB:~ }|
  970. {EOB:~ }|
  971. {EOB:~ }|
  972. {EOB:~ }|
  973. {EOB:~ }|
  974. ={SQ:"}{SB:<c0>}{SQ:"}{E:<c0>"}{SB:foo}{E:"}^ |
  975. ]])
  976. end)
  977. end)