execute_spec.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local eq = t.eq
  5. local eval = n.eval
  6. local clear = n.clear
  7. local source = n.source
  8. local exc_exec = n.exc_exec
  9. local pcall_err = t.pcall_err
  10. local fn = n.fn
  11. local command = n.command
  12. local feed = n.feed
  13. local is_os = t.is_os
  14. describe('execute()', function()
  15. before_each(clear)
  16. it('captures the same result as :redir', function()
  17. command([[
  18. echomsg 'foo 1'
  19. echomsg 'foo 2'
  20. redir => g:__redir_output
  21. silent! messages
  22. redir END
  23. ]])
  24. eq(eval('g:__redir_output'), fn.execute('messages'))
  25. end)
  26. it('captures the concatenated outputs of a List of commands', function()
  27. eq('foobar', fn.execute({ 'echon "foo"', 'echon "bar"' }))
  28. eq('\nfoo\nbar', fn.execute({ 'echo "foo"', 'echo "bar"' }))
  29. end)
  30. it('supports nested execute("execute(...)")', function()
  31. eq('42', fn.execute([[echon execute("echon execute('echon 42')")]]))
  32. end)
  33. it('supports nested :redir to a variable', function()
  34. source([[
  35. function! g:Foo()
  36. let a = ''
  37. redir => a
  38. silent echon "foo"
  39. redir END
  40. return a
  41. endfunction
  42. function! g:Bar()
  43. let a = ''
  44. redir => a
  45. silent echon "bar1"
  46. call g:Foo()
  47. silent echon "bar2"
  48. redir END
  49. silent echon "bar3"
  50. return a
  51. endfunction
  52. ]])
  53. eq('top1bar1foobar2bar3', fn.execute('echon "top1"|call g:Bar()'))
  54. end)
  55. it('supports nested :redir to a register', function()
  56. source([[
  57. let @a = ''
  58. function! g:Foo()
  59. redir @a>>
  60. silent echon "foo"
  61. redir END
  62. return @a
  63. endfunction
  64. function! g:Bar()
  65. redir @a>>
  66. silent echon "bar1"
  67. call g:Foo()
  68. silent echon "bar2"
  69. redir END
  70. silent echon "bar3"
  71. return @a
  72. endfunction
  73. ]])
  74. eq('top1bar1foobar2bar3', fn.execute('echon "top1"|call g:Bar()'))
  75. -- :redir itself doesn't nest, so the redirection ends in g:Foo
  76. eq('bar1foo', eval('@a'))
  77. end)
  78. it('captures a transformed string', function()
  79. eq('^A', fn.execute('echon "\\<C-a>"'))
  80. end)
  81. it('returns empty string if the argument list is empty', function()
  82. eq('', fn.execute({}))
  83. eq(0, exc_exec('let g:ret = execute(v:_null_list)'))
  84. eq('', eval('g:ret'))
  85. end)
  86. it('captures errors', function()
  87. local ret
  88. ret = exc_exec('call execute(v:_null_dict)')
  89. eq('Vim(call):E731: Using a Dictionary as a String', ret)
  90. ret = exc_exec('call execute(function("tr"))')
  91. eq('Vim(call):E729: Using a Funcref as a String', ret)
  92. ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])')
  93. eq('Vim:E731: Using a Dictionary as a String', ret)
  94. ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])')
  95. eq('Vim:E729: Using a Funcref as a String', ret)
  96. end)
  97. it('captures output with highlights', function()
  98. eq(
  99. '\nErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red',
  100. eval('execute("hi ErrorMsg")')
  101. )
  102. end)
  103. it('does not corrupt the command display #5422', function()
  104. local screen = Screen.new(70, 7)
  105. feed(':echo execute("hi ErrorMsg")<CR>')
  106. screen:expect(
  107. [[
  108. |
  109. {1:~ }|*2
  110. {2: }|
  111. |
  112. ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red |
  113. {3:Press ENTER or type command to continue}^ |
  114. ]],
  115. {
  116. [1] = { bold = true, foreground = Screen.colors.Blue1 },
  117. [2] = { bold = true, reverse = true },
  118. [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
  119. }
  120. )
  121. feed('<CR>')
  122. end)
  123. it('places cursor correctly #6035', function()
  124. local screen = Screen.new(40, 6)
  125. source([=[
  126. " test 1: non-silenced output goes as usual
  127. function! Test1()
  128. echo 1234
  129. let x = execute('echon "abcdef"', '')
  130. echon 'ABCD'
  131. endfunction
  132. " test 2: silenced output does not affect ui
  133. function! Test2()
  134. echo 1234
  135. let x = execute('echon "abcdef"', 'silent')
  136. echon 'ABCD'
  137. endfunction
  138. " test 3: silenced! error does not affect ui
  139. function! Test3()
  140. echo 1234
  141. let x = execute('echoerr "abcdef"', 'silent!')
  142. echon 'ABCDXZYZ'
  143. endfunction
  144. " test 4: silenced echoerr goes as usual
  145. " bug here
  146. function! Test4()
  147. echo 1234
  148. let x = execute('echoerr "abcdef"', 'silent')
  149. echon 'ABCD'
  150. endfunction
  151. " test 5: silenced! echoerr does not affect ui
  152. function! Test5()
  153. echo 1234
  154. let x = execute('echoerr "abcdef"', 'silent!')
  155. echon 'ABCD'
  156. endfunction
  157. " test 6: silenced error goes as usual
  158. function! Test6()
  159. echo 1234
  160. let x = execute('echo undefined', 'silent')
  161. echon 'ABCD'
  162. endfunction
  163. " test 7: existing error does not mess the result
  164. function! Test7()
  165. " display from Test6() is still visible
  166. " why does the "abcdef" goes into a newline
  167. let x = execute('echon "abcdef"', '')
  168. echon 'ABCD'
  169. endfunction
  170. ]=])
  171. feed([[:call Test1()<cr>]])
  172. screen:expect([[
  173. ^ |
  174. {1:~ }|*4
  175. ABCD |
  176. ]])
  177. feed([[:call Test2()<cr>]])
  178. screen:expect([[
  179. ^ |
  180. {1:~ }|*4
  181. 1234ABCD |
  182. ]])
  183. feed([[:call Test3()<cr>]])
  184. screen:expect([[
  185. ^ |
  186. {1:~ }|*4
  187. 1234ABCDXZYZ |
  188. ]])
  189. feed([[:call Test4()<cr>]])
  190. -- unexpected: need to fix
  191. -- echoerr does not set did_emsg
  192. -- "ef" was overwritten since msg_col was recovered wrongly
  193. screen:expect([[
  194. 1234 |
  195. {9:Error detected while processing function}|
  196. {9: Test4:} |
  197. {8:line 2:} |
  198. {9:abcd}ABCD |
  199. {6:Press ENTER or type command to continue}^ |
  200. ]])
  201. feed([[<cr>]]) -- to clear screen
  202. feed([[:call Test5()<cr>]])
  203. screen:expect([[
  204. ^ |
  205. {1:~ }|*4
  206. 1234ABCD |
  207. ]])
  208. feed([[:call Test6()<cr>]])
  209. screen:expect([[
  210. |
  211. {9:Error detected while processing function}|
  212. {9: Test6:} |
  213. {8:line 2:} |
  214. {9:E121}ABCD |
  215. {6:Press ENTER or type command to continue}^ |
  216. ]])
  217. feed([[:call Test7()<cr>]])
  218. screen:expect([[
  219. {9:Error detected while processing function}|
  220. {9: Test6:} |
  221. {8:line 2:} |
  222. {9:E121}ABCD |
  223. ABCD |
  224. {6:Press ENTER or type command to continue}^ |
  225. ]])
  226. end)
  227. -- This deviates from vim behavior, but is consistent
  228. -- with how nvim currently displays the output.
  229. it('captures shell-command output', function()
  230. local win_lf = is_os('win') and '\13' or ''
  231. eq('\n:!echo foo\r\n\nfoo' .. win_lf .. '\n', fn.execute('!echo foo'))
  232. end)
  233. describe('{silent} argument', function()
  234. it('captures & displays output for ""', function()
  235. local screen = Screen.new(40, 5)
  236. command('let g:mes = execute("echon 42", "")')
  237. screen:expect([[
  238. ^ |
  239. {1:~ }|*3
  240. 42 |
  241. ]])
  242. eq('42', eval('g:mes'))
  243. end)
  244. it('gives E493 instead of prompting on backwards range for ""', function()
  245. command('split')
  246. eq(
  247. 'Vim(windo):E493: Backwards range given: 2,1windo echo',
  248. pcall_err(fn.execute, '2,1windo echo', '')
  249. )
  250. eq(
  251. 'Vim(windo):E493: Backwards range given: 2,1windo echo',
  252. pcall_err(fn.execute, { '2,1windo echo' }, '')
  253. )
  254. end)
  255. it('captures but does not display output for "silent"', function()
  256. local screen = Screen.new(40, 5)
  257. command('let g:mes = execute("echon 42")')
  258. screen:expect([[
  259. ^ |
  260. {1:~ }|*3
  261. |
  262. ]])
  263. eq('42', eval('g:mes'))
  264. command('let g:mes = execute("echon 13", "silent")')
  265. screen:expect {
  266. grid = [[
  267. ^ |
  268. {1:~ }|*3
  269. |
  270. ]],
  271. unchanged = true,
  272. }
  273. eq('13', eval('g:mes'))
  274. end)
  275. it('suppresses errors for "silent!"', function()
  276. eq(0, exc_exec('let g:mes = execute(0.0, "silent!")'))
  277. eq('', eval('g:mes'))
  278. eq(0, exc_exec('let g:mes = execute("echon add(1, 1)", "silent!")'))
  279. eq('1', eval('g:mes'))
  280. eq(0, exc_exec('let g:mes = execute(["echon 42", "echon add(1, 1)"], "silent!")'))
  281. eq('421', eval('g:mes'))
  282. end)
  283. it('propagates errors for "" and "silent"', function()
  284. local ret
  285. ret = exc_exec('call execute(v:_null_dict, "silent")')
  286. eq('Vim(call):E731: Using a Dictionary as a String', ret)
  287. ret = exc_exec('call execute("echo add(1, 1)", "")')
  288. eq('Vim(echo):E897: List or Blob required', ret)
  289. ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "")')
  290. eq('Vim(echo):E897: List or Blob required', ret)
  291. ret = exc_exec('call execute("echo add(1, 1)", "silent")')
  292. eq('Vim(echo):E897: List or Blob required', ret)
  293. ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "silent")')
  294. eq('Vim(echo):E897: List or Blob required', ret)
  295. end)
  296. end)
  297. end)