cmdline_spec.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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 expect = n.expect
  8. local eval = n.eval
  9. local next_msg = n.next_msg
  10. local feed = n.feed
  11. local api = n.api
  12. describe('cmdline autocommands', function()
  13. local channel
  14. before_each(function()
  15. clear()
  16. channel = api.nvim_get_chan_info(0).id
  17. api.nvim_set_var('channel', channel)
  18. command("autocmd CmdlineEnter * call rpcnotify(g:channel, 'CmdlineEnter', v:event)")
  19. command("autocmd CmdlineLeave * call rpcnotify(g:channel, 'CmdlineLeave', v:event)")
  20. command("autocmd CmdWinEnter * call rpcnotify(g:channel, 'CmdWinEnter', v:event)")
  21. command("autocmd CmdWinLeave * call rpcnotify(g:channel, 'CmdWinLeave', v:event)")
  22. end)
  23. it('works', function()
  24. feed(':')
  25. eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
  26. feed('redraw<cr>')
  27. eq(
  28. { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } },
  29. next_msg()
  30. )
  31. feed(':')
  32. eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
  33. -- note: feed('bork<c-c>') might not consume 'bork'
  34. -- due to out-of-band interrupt handling
  35. feed('bork<esc>')
  36. eq(
  37. { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = true } } },
  38. next_msg()
  39. )
  40. end)
  41. it('can abort cmdline', function()
  42. command('autocmd CmdlineLeave * let v:event.abort= len(getcmdline())>15')
  43. feed(":put! ='ok'<cr>")
  44. expect([[
  45. ok
  46. ]])
  47. feed(":put! ='blah blah'<cr>")
  48. expect([[
  49. ok
  50. ]])
  51. end)
  52. it('handles errors correctly', function()
  53. clear()
  54. local screen = Screen.new(72, 8)
  55. command("autocmd CmdlineEnter * echoerr 'FAIL'")
  56. command("autocmd CmdlineLeave * echoerr 'very error'")
  57. feed(':')
  58. screen:expect([[
  59. |
  60. {1:~ }|*3
  61. {3: }|
  62. : |
  63. {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
  64. :^ |
  65. ]])
  66. feed("put ='lorem ipsum'<cr>")
  67. screen:expect([[
  68. |
  69. {3: }|
  70. : |
  71. {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
  72. :put ='lorem ipsum' |
  73. {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
  74. |
  75. {6:Press ENTER or type command to continue}^ |
  76. ]])
  77. -- cmdline was still executed
  78. feed('<cr>')
  79. screen:expect([[
  80. |
  81. ^lorem ipsum |
  82. {1:~ }|*5
  83. |
  84. ]])
  85. command("autocmd CmdlineChanged * echoerr 'change erreor'")
  86. -- history recall still works
  87. feed(':<c-p>')
  88. screen:expect([[
  89. |
  90. lorem ipsum |
  91. {3: }|
  92. : |
  93. {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
  94. :put ='lorem ipsum' |
  95. {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
  96. :put ='lorem ipsum'^ |
  97. ]])
  98. feed('<left>')
  99. screen:expect([[
  100. |
  101. lorem ipsum |
  102. {3: }|
  103. : |
  104. {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
  105. :put ='lorem ipsum' |
  106. {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
  107. :put ='lorem ipsum^' |
  108. ]])
  109. -- edit still works
  110. feed('.')
  111. screen:expect([[
  112. {3: }|
  113. : |
  114. {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
  115. :put ='lorem ipsum' |
  116. {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
  117. :put ='lorem ipsum.' |
  118. {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
  119. :put ='lorem ipsum.^' |
  120. ]])
  121. feed('<cr>')
  122. screen:expect([[
  123. :put ='lorem ipsum' |
  124. {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
  125. :put ='lorem ipsum.' |
  126. {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
  127. :put ='lorem ipsum.' |
  128. {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
  129. |
  130. {6:Press ENTER or type command to continue}^ |
  131. ]])
  132. -- cmdline was still executed
  133. feed('<cr>')
  134. screen:expect([[
  135. |
  136. lorem ipsum |
  137. ^lorem ipsum. |
  138. {1:~ }|*4
  139. |
  140. ]])
  141. end)
  142. it('works with nested cmdline', function()
  143. feed(':')
  144. eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
  145. feed('<c-r>=')
  146. eq({ 'notification', 'CmdlineEnter', { { cmdtype = '=', cmdlevel = 2 } } }, next_msg())
  147. feed('<c-f>')
  148. eq({ 'notification', 'CmdWinEnter', { {} } }, next_msg())
  149. feed(':')
  150. eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 3 } } }, next_msg())
  151. feed('<c-c>')
  152. eq(
  153. { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 3, abort = true } } },
  154. next_msg()
  155. )
  156. feed('<c-c>')
  157. eq({ 'notification', 'CmdWinLeave', { {} } }, next_msg())
  158. feed('1+2<cr>')
  159. eq(
  160. { 'notification', 'CmdlineLeave', { { cmdtype = '=', cmdlevel = 2, abort = false } } },
  161. next_msg()
  162. )
  163. end)
  164. it('no crash with recursive use of v:event #19484', function()
  165. command('autocmd CmdlineEnter * normal :')
  166. feed(':')
  167. eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
  168. feed('<CR>')
  169. eq(
  170. { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } },
  171. next_msg()
  172. )
  173. end)
  174. it('supports CmdlineChanged', function()
  175. command(
  176. "autocmd CmdlineChanged * call rpcnotify(g:channel, 'CmdlineChanged', v:event, getcmdline())"
  177. )
  178. feed(':')
  179. eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
  180. feed('l')
  181. eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'l' } }, next_msg())
  182. feed('e')
  183. eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'le' } }, next_msg())
  184. feed('t')
  185. eq({ 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let' } }, next_msg())
  186. feed('<space>')
  187. eq(
  188. { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let ' } },
  189. next_msg()
  190. )
  191. feed('x')
  192. eq(
  193. { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x' } },
  194. next_msg()
  195. )
  196. feed('<space>')
  197. eq(
  198. { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x ' } },
  199. next_msg()
  200. )
  201. feed('=')
  202. eq(
  203. { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x =' } },
  204. next_msg()
  205. )
  206. feed('<space>')
  207. eq(
  208. { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x = ' } },
  209. next_msg()
  210. )
  211. feed('<c-r>=')
  212. eq({ 'notification', 'CmdlineEnter', { { cmdtype = '=', cmdlevel = 2 } } }, next_msg())
  213. feed('1')
  214. eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1' } }, next_msg())
  215. feed('+')
  216. eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1+' } }, next_msg())
  217. feed('1')
  218. eq({ 'notification', 'CmdlineChanged', { { cmdtype = '=', cmdlevel = 2 }, '1+1' } }, next_msg())
  219. feed('<cr>')
  220. eq(
  221. { 'notification', 'CmdlineLeave', { { cmdtype = '=', cmdlevel = 2, abort = false } } },
  222. next_msg()
  223. )
  224. eq(
  225. { 'notification', 'CmdlineChanged', { { cmdtype = ':', cmdlevel = 1 }, 'let x = 2' } },
  226. next_msg()
  227. )
  228. feed('<cr>')
  229. eq(
  230. { 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } },
  231. next_msg()
  232. )
  233. eq(2, eval('x'))
  234. end)
  235. end)