cmdline_highlight_spec.lua 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  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 "\<Ignore>"
  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 : "\<Ignore>")
  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.exec('messages', true))
  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.exec('messages', true))
  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.exec('messages', true))
  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 = "«»«»«»«»«»"')
  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. feed('\n')
  430. eq('let x = "«»«»«»«»«»"', meths.get_var('out'))
  431. local msg = '\nE5405: Chunk 0 start 10 splits multibyte character'
  432. eq(msg:rep(1), funcs.execute('messages'))
  433. end)
  434. it('allows interrupting callback with <C-c>', function()
  435. set_color_cb('Halting')
  436. start_prompt('echo 42')
  437. screen:expect([[
  438. ^ |
  439. {EOB:~ }|
  440. {EOB:~ }|
  441. {EOB:~ }|
  442. {EOB:~ }|
  443. {EOB:~ }|
  444. {EOB:~ }|
  445. |
  446. ]])
  447. screen:sleep(500)
  448. feed('<C-c>')
  449. screen:expect([[
  450. {EOB:~ }|
  451. {EOB:~ }|
  452. {EOB:~ }|
  453. {EOB:~ }|
  454. : |
  455. {ERR:E5407: Callback has thrown an exception:}|
  456. {ERR: Keyboard interrupt} |
  457. :echo 42^ |
  458. ]])
  459. redraw_input()
  460. screen:expect([[
  461. |
  462. {EOB:~ }|
  463. {EOB:~ }|
  464. {EOB:~ }|
  465. {EOB:~ }|
  466. {EOB:~ }|
  467. {EOB:~ }|
  468. :echo 42^ |
  469. ]])
  470. feed('\n')
  471. screen:expect([[
  472. ^ |
  473. {EOB:~ }|
  474. {EOB:~ }|
  475. {EOB:~ }|
  476. {EOB:~ }|
  477. {EOB:~ }|
  478. {EOB:~ }|
  479. :echo 42 |
  480. ]])
  481. feed('\n')
  482. eq('echo 42', meths.get_var('out'))
  483. feed('<C-c>')
  484. screen:expect([[
  485. ^ |
  486. {EOB:~ }|
  487. {EOB:~ }|
  488. {EOB:~ }|
  489. {EOB:~ }|
  490. {EOB:~ }|
  491. {EOB:~ }|
  492. Type :qa and pre...nter> to exit Nvim |
  493. ]])
  494. end)
  495. it('works fine with NUL, NL, CR', function()
  496. set_color_cb('RainBowParens')
  497. start_prompt('echo ("<C-v><CR><C-v><Nul><C-v><NL>")')
  498. screen:expect([[
  499. |
  500. {EOB:~ }|
  501. {EOB:~ }|
  502. {EOB:~ }|
  503. {EOB:~ }|
  504. {EOB:~ }|
  505. {EOB:~ }|
  506. :echo {RBP1:(}"{SK:^M^@^@}"{RBP1:)}^ |
  507. ]])
  508. end)
  509. it('errors out when callback returns something wrong', function()
  510. command('cnoremap + ++')
  511. set_color_cb('ReturningGlobal', '')
  512. start_prompt('#')
  513. screen:expect([[
  514. {EOB:~ }|
  515. {EOB:~ }|
  516. {EOB:~ }|
  517. {EOB:~ }|
  518. {EOB:~ }|
  519. : |
  520. {ERR:E5400: Callback should return list} |
  521. :#^ |
  522. ]])
  523. feed('<CR><CR><CR>')
  524. set_color_cb('ReturningGlobal', {{0, 1, 'Normal'}, 42})
  525. start_prompt('#')
  526. screen:expect([[
  527. {EOB:~ }|
  528. {EOB:~ }|
  529. {EOB:~ }|
  530. {EOB:~ }|
  531. {EOB:~ }|
  532. : |
  533. {ERR:E5401: List item 1 is not a List} |
  534. :#^ |
  535. ]])
  536. feed('<CR><CR><CR>')
  537. set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {1}})
  538. start_prompt('+')
  539. screen:expect([[
  540. {EOB:~ }|
  541. {EOB:~ }|
  542. {EOB:~ }|
  543. {EOB:~ }|
  544. :+ |
  545. {ERR:E5402: List item 1 has incorrect length:}|
  546. {ERR: 1 /= 3} |
  547. :++^ |
  548. ]])
  549. feed('<CR><CR><CR>')
  550. set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {2, 3, 'Normal'}})
  551. start_prompt('+')
  552. screen:expect([[
  553. {EOB:~ }|
  554. {EOB:~ }|
  555. {EOB:~ }|
  556. {EOB:~ }|
  557. :+ |
  558. {ERR:E5403: Chunk 1 start 2 not in range [1, }|
  559. {ERR:2)} |
  560. :++^ |
  561. ]])
  562. feed('<CR><CR><CR>')
  563. set_color_cb('ReturningGlobal2', {{0, 1, 'Normal'}, {1, 3, 'Normal'}})
  564. start_prompt('+')
  565. screen:expect([[
  566. {EOB:~ }|
  567. {EOB:~ }|
  568. {EOB:~ }|
  569. {EOB:~ }|
  570. :+ |
  571. {ERR:E5404: Chunk 1 end 3 not in range (1, 2]}|
  572. |
  573. :++^ |
  574. ]])
  575. end)
  576. it('does not error out when called from a errorred out cycle', function()
  577. set_color_cb('ReturningGlobal', {{0, 1, 'Normal'}})
  578. feed(dedent([[
  579. :set regexpengine=2
  580. :for pat in [' \ze*', ' \zs*']
  581. : try
  582. : let l = matchlist('x x', pat)
  583. : $put =input({'prompt':'>','highlight':'ReturningGlobal'})
  584. :
  585. : $put ='E888 NOT detected for ' . pat
  586. : catch
  587. : $put =input({'prompt':'>','highlight':'ReturningGlobal'})
  588. :
  589. : $put ='E888 detected for ' . pat
  590. : endtry
  591. :endfor
  592. :
  593. :
  594. :
  595. :
  596. :
  597. :
  598. ]]))
  599. eq({'', ':', 'E888 detected for \\ze*', ':', 'E888 detected for \\zs*'},
  600. curbufmeths.get_lines(0, -1, false))
  601. eq('', funcs.execute('messages'))
  602. end)
  603. it('allows nesting input()s', function()
  604. set_color_cb('ReturningGlobal', {{0, 1, 'RBP1'}}, '')
  605. start_prompt('1')
  606. screen:expect([[
  607. |
  608. {EOB:~ }|
  609. {EOB:~ }|
  610. {EOB:~ }|
  611. {EOB:~ }|
  612. {EOB:~ }|
  613. {EOB:~ }|
  614. :{RBP1:1}^ |
  615. ]])
  616. set_color_cb('ReturningGlobal', {{0, 1, 'RBP2'}}, '1')
  617. start_prompt('2')
  618. screen:expect([[
  619. |
  620. {EOB:~ }|
  621. {EOB:~ }|
  622. {EOB:~ }|
  623. {EOB:~ }|
  624. {EOB:~ }|
  625. {EOB:~ }|
  626. :{RBP2:2}^ |
  627. ]])
  628. set_color_cb('ReturningGlobal', {{0, 1, 'RBP3'}}, '2')
  629. start_prompt('3')
  630. screen:expect([[
  631. |
  632. {EOB:~ }|
  633. {EOB:~ }|
  634. {EOB:~ }|
  635. {EOB:~ }|
  636. {EOB:~ }|
  637. {EOB:~ }|
  638. :{RBP3:3}^ |
  639. ]])
  640. set_color_cb('ReturningGlobal', {{0, 1, 'RBP4'}}, '3')
  641. start_prompt('4')
  642. screen:expect([[
  643. |
  644. {EOB:~ }|
  645. {EOB:~ }|
  646. {EOB:~ }|
  647. {EOB:~ }|
  648. {EOB:~ }|
  649. {EOB:~ }|
  650. :{RBP4:4}^ |
  651. ]])
  652. feed('<CR>')
  653. screen:expect([[
  654. |
  655. {EOB:~ }|
  656. {EOB:~ }|
  657. {EOB:~ }|
  658. {EOB:~ }|
  659. {EOB:~ }|
  660. {EOB:~ }|
  661. :{RBP3:3}4^ |
  662. ]])
  663. feed('<CR>')
  664. screen:expect([[
  665. |
  666. {EOB:~ }|
  667. {EOB:~ }|
  668. {EOB:~ }|
  669. {EOB:~ }|
  670. {EOB:~ }|
  671. {EOB:~ }|
  672. :{RBP2:2}34^ |
  673. ]])
  674. feed('<CR>')
  675. screen:expect([[
  676. |
  677. {EOB:~ }|
  678. {EOB:~ }|
  679. {EOB:~ }|
  680. {EOB:~ }|
  681. {EOB:~ }|
  682. {EOB:~ }|
  683. :{RBP1:1}234^ |
  684. ]])
  685. feed('<CR><CR><C-l>')
  686. screen:expect([[
  687. ^ |
  688. {EOB:~ }|
  689. {EOB:~ }|
  690. {EOB:~ }|
  691. {EOB:~ }|
  692. {EOB:~ }|
  693. {EOB:~ }|
  694. |
  695. ]])
  696. eq('1234', meths.get_var('out'))
  697. eq('234', meths.get_var('out1'))
  698. eq('34', meths.get_var('out2'))
  699. eq('4', meths.get_var('out3'))
  700. eq(0, funcs.exists('g:out4'))
  701. end)
  702. it('runs callback with the same data only once', function()
  703. local function new_recording_calls(...)
  704. eq({...}, meths.get_var('recording_calls'))
  705. meths.set_var('recording_calls', {})
  706. end
  707. set_color_cb('Recording')
  708. start_prompt('')
  709. -- Regression test. Disambiguation:
  710. --
  711. -- new_recording_calls(expected_result) -- (actual_before_fix)
  712. --
  713. feed('a')
  714. new_recording_calls('a') -- ('a', 'a')
  715. feed('b')
  716. new_recording_calls('ab') -- ('a', 'ab', 'ab')
  717. feed('c')
  718. new_recording_calls('abc') -- ('ab', 'abc', 'abc')
  719. feed('<BS>')
  720. new_recording_calls('ab') -- ('abc', 'ab', 'ab')
  721. feed('<BS>')
  722. new_recording_calls('a') -- ('ab', 'a', 'a')
  723. feed('<BS>')
  724. new_recording_calls() -- ('a')
  725. feed('<CR><CR>')
  726. eq('', meths.get_var('out'))
  727. end)
  728. it('does not crash when callback has caught not-a-editor-command exception',
  729. function()
  730. source([[
  731. function CaughtExc(cmdline) abort
  732. try
  733. gibberish
  734. catch
  735. " Do nothing
  736. endtry
  737. return []
  738. endfunction
  739. ]])
  740. set_color_cb('CaughtExc')
  741. start_prompt('1')
  742. eq(1, meths.eval('1'))
  743. end)
  744. end)
  745. describe('Ex commands coloring', function()
  746. it('works', function()
  747. meths.set_var('Nvim_color_cmdline', 'RainBowParens')
  748. feed(':echo (((1)))')
  749. screen:expect([[
  750. |
  751. {EOB:~ }|
  752. {EOB:~ }|
  753. {EOB:~ }|
  754. {EOB:~ }|
  755. {EOB:~ }|
  756. {EOB:~ }|
  757. :echo {RBP1:(}{RBP2:(}{RBP3:(}1{RBP3:)}{RBP2:)}{RBP1:)}^ |
  758. ]])
  759. end)
  760. it('still executes command-line even if errored out', function()
  761. meths.set_var('Nvim_color_cmdline', 'SplittedMultibyteStart')
  762. feed(':let x = "«"\n')
  763. eq('«', meths.get_var('x'))
  764. local msg = 'E5405: Chunk 0 start 10 splits multibyte character'
  765. eq('\n'..msg, funcs.execute('messages'))
  766. end)
  767. it('does not error out when called from a errorred out cycle', function()
  768. -- Apparently when there is a cycle in which one of the commands errors out
  769. -- this error may be caught by color_cmdline before it is presented to the
  770. -- user.
  771. feed(dedent([[
  772. :set regexpengine=2
  773. :for pat in [' \ze*', ' \zs*']
  774. : try
  775. : let l = matchlist('x x', pat)
  776. : $put ='E888 NOT detected for ' . pat
  777. : catch
  778. : $put ='E888 detected for ' . pat
  779. : endtry
  780. :endfor
  781. ]]))
  782. eq({'', 'E888 detected for \\ze*', 'E888 detected for \\zs*'},
  783. curbufmeths.get_lines(0, -1, false))
  784. eq('', funcs.execute('messages'))
  785. end)
  786. it('does not crash when using `n` in debug mode', function()
  787. feed(':debug execute "echo 1"\n')
  788. screen:expect([[
  789. {EOB:~ }|
  790. {EOB:~ }|
  791. {EOB:~ }|
  792. {EOB:~ }|
  793. Entering Debug mode. Type "cont" to con|
  794. tinue. |
  795. cmd: execute "echo 1" |
  796. >^ |
  797. ]])
  798. feed('n\n')
  799. screen:expect([[
  800. {EOB:~ }|
  801. {EOB:~ }|
  802. Entering Debug mode. Type "cont" to con|
  803. tinue. |
  804. cmd: execute "echo 1" |
  805. >n |
  806. 1 |
  807. {PE:Press ENTER or type command to continue}^ |
  808. ]])
  809. feed('\n')
  810. screen:expect([[
  811. ^ |
  812. {EOB:~ }|
  813. {EOB:~ }|
  814. {EOB:~ }|
  815. {EOB:~ }|
  816. {EOB:~ }|
  817. {EOB:~ }|
  818. |
  819. ]])
  820. end)
  821. it('mapping error does not cancel prompt', function()
  822. command("cnoremap <expr> x execute('throw 42')[-1]")
  823. feed(':#x')
  824. screen:expect([[
  825. {EOB:~ }|
  826. {EOB:~ }|
  827. {EOB:~ }|
  828. {EOB:~ }|
  829. :# |
  830. {ERR:Error detected while processing :} |
  831. {ERR:E605: Exception not caught: 42} |
  832. :#^ |
  833. ]])
  834. feed('<CR>')
  835. screen:expect([[
  836. {EOB:~ }|
  837. {EOB:~ }|
  838. {EOB:~ }|
  839. :# |
  840. {ERR:Error detected while processing :} |
  841. {ERR:E605: Exception not caught: 42} |
  842. {ERR:E749: empty buffer} |
  843. {PE:Press ENTER or type command to continue}^ |
  844. ]])
  845. feed('<CR>')
  846. eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer',
  847. meths.exec('messages', true))
  848. end)
  849. it('errors out when failing to get callback', function()
  850. meths.set_var('Nvim_color_cmdline', 42)
  851. feed(':#')
  852. screen:expect([[
  853. {EOB:~ }|
  854. {EOB:~ }|
  855. {EOB:~ }|
  856. : |
  857. {ERR:E5408: Unable to get g:Nvim_color_cmdlin}|
  858. {ERR:e callback: Vim:E6000: Argument is not a}|
  859. {ERR: function or function name} |
  860. :#^ |
  861. ]])
  862. end)
  863. end)
  864. describe('Expressions coloring support', function()
  865. it('works', function()
  866. meths.command('hi clear NvimNumber')
  867. meths.command('hi clear NvimNestingParenthesis')
  868. meths.command('hi NvimNumber guifg=Blue2')
  869. meths.command('hi NvimNestingParenthesis guifg=Yellow')
  870. feed(':echo <C-r>=(((1)))')
  871. screen:expect([[
  872. |
  873. {EOB:~ }|
  874. {EOB:~ }|
  875. {EOB:~ }|
  876. {EOB:~ }|
  877. {EOB:~ }|
  878. {EOB:~ }|
  879. ={NPAR:(((}{NUM:1}{NPAR:)))}^ |
  880. ]])
  881. end)
  882. it('does not use Nvim_color_expr', function()
  883. meths.set_var('Nvim_color_expr', 42)
  884. -- Used to error out due to failing to get callback.
  885. meths.command('hi clear NvimNumber')
  886. meths.command('hi NvimNumber guifg=Blue2')
  887. feed(':<C-r>=1')
  888. screen:expect([[
  889. |
  890. {EOB:~ }|
  891. {EOB:~ }|
  892. {EOB:~ }|
  893. {EOB:~ }|
  894. {EOB:~ }|
  895. {EOB:~ }|
  896. ={NUM:1}^ |
  897. ]])
  898. end)
  899. it('works correctly with non-ASCII and control characters', function()
  900. meths.command('hi clear NvimStringBody')
  901. meths.command('hi clear NvimStringQuote')
  902. meths.command('hi clear NvimInvalid')
  903. meths.command('hi NvimStringQuote guifg=Blue3')
  904. meths.command('hi NvimStringBody guifg=Blue4')
  905. meths.command('hi NvimInvalid guifg=Red guibg=Blue')
  906. feed('i<C-r>="«»"«»')
  907. screen:expect([[
  908. |
  909. {EOB:~ }|
  910. {EOB:~ }|
  911. {EOB:~ }|
  912. {EOB:~ }|
  913. {EOB:~ }|
  914. {EOB:~ }|
  915. ={SQ:"}{SB:«»}{SQ:"}{E:«»}^ |
  916. ]])
  917. feed('<C-c>')
  918. screen:expect([[
  919. ^ |
  920. {EOB:~ }|
  921. {EOB:~ }|
  922. {EOB:~ }|
  923. {EOB:~ }|
  924. {EOB:~ }|
  925. {EOB:~ }|
  926. {M:-- INSERT --} |
  927. ]])
  928. feed('<Esc>')
  929. screen:expect([[
  930. ^ |
  931. {EOB:~ }|
  932. {EOB:~ }|
  933. {EOB:~ }|
  934. {EOB:~ }|
  935. {EOB:~ }|
  936. {EOB:~ }|
  937. |
  938. ]])
  939. feed(':<C-\\>e"<C-v><C-x>"<C-v><C-x>')
  940. -- TODO(ZyX-I): Parser highlighting should not override special character
  941. -- highlighting.
  942. screen:expect([[
  943. |
  944. {EOB:~ }|
  945. {EOB:~ }|
  946. {EOB:~ }|
  947. {EOB:~ }|
  948. {EOB:~ }|
  949. {EOB:~ }|
  950. ={SQ:"}{SB:^X}{SQ:"}{ERR:^X}^ |
  951. ]])
  952. feed('<C-c>')
  953. screen:expect([[
  954. |
  955. {EOB:~ }|
  956. {EOB:~ }|
  957. {EOB:~ }|
  958. {EOB:~ }|
  959. {EOB:~ }|
  960. {EOB:~ }|
  961. :^ |
  962. ]])
  963. funcs.setreg('a', {'\192'})
  964. feed('<C-r>="<C-r><C-r>a"<C-r><C-r>a"foo"')
  965. screen:expect([[
  966. |
  967. {EOB:~ }|
  968. {EOB:~ }|
  969. {EOB:~ }|
  970. {EOB:~ }|
  971. {EOB:~ }|
  972. {EOB:~ }|
  973. ={SQ:"}{SB:<c0>}{SQ:"}{E:<c0>"}{SB:foo}{E:"}^ |
  974. ]])
  975. end)
  976. end)