output_spec.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local tt = require('test.functional.testterm')
  5. local assert_alive = n.assert_alive
  6. local mkdir, write_file, rmdir = t.mkdir, t.write_file, n.rmdir
  7. local eq = t.eq
  8. local feed = n.feed
  9. local feed_command = n.feed_command
  10. local clear = n.clear
  11. local command = n.command
  12. local testprg = n.testprg
  13. local nvim_dir = n.nvim_dir
  14. local has_powershell = n.has_powershell
  15. local set_shell_powershell = n.set_shell_powershell
  16. local skip = t.skip
  17. local is_os = t.is_os
  18. clear() -- for has_powershell()
  19. describe('shell command :!', function()
  20. local screen
  21. before_each(function()
  22. clear()
  23. screen = tt.setup_child_nvim({
  24. '-u',
  25. 'NONE',
  26. '-i',
  27. 'NONE',
  28. '--cmd',
  29. 'colorscheme vim',
  30. '--cmd',
  31. n.nvim_set .. ' notermguicolors',
  32. })
  33. screen:expect([[
  34. ^ |
  35. {4:~ }|*4
  36. |
  37. {3:-- TERMINAL --} |
  38. ]])
  39. end)
  40. after_each(function()
  41. tt.feed_data('\3') -- Ctrl-C
  42. end)
  43. it('displays output without LF/EOF. #4646 #4569 #3772', function()
  44. skip(is_os('win'))
  45. -- NOTE: We use a child nvim (within a :term buffer)
  46. -- to avoid triggering a UI flush.
  47. tt.feed_data(':!printf foo; sleep 200\n')
  48. screen:expect([[
  49. |
  50. {4:~ }|*2
  51. {5: }|
  52. :!printf foo; sleep 200 |
  53. foo |
  54. {3:-- TERMINAL --} |
  55. ]])
  56. end)
  57. it('throttles shell-command output greater than ~10KB', function()
  58. skip(is_os('openbsd'), 'FIXME #10804')
  59. skip(is_os('win'))
  60. tt.feed_data((':!%s REP 30001 foo\n'):format(testprg('shell-test')))
  61. -- If we observe any line starting with a dot, then throttling occurred.
  62. -- Avoid false failure on slow systems.
  63. screen:expect { any = '\n%.', timeout = 20000 }
  64. -- Final chunk of output should always be displayed, never skipped.
  65. -- (Throttling is non-deterministic, this test is merely a sanity check.)
  66. screen:expect(
  67. [[
  68. 29997: foo |
  69. 29998: foo |
  70. 29999: foo |
  71. 30000: foo |
  72. |
  73. {10:Press ENTER or type command to continue}^ |
  74. {3:-- TERMINAL --} |
  75. ]],
  76. {
  77. -- test/functional/testnvim.lua defaults to background=light.
  78. [1] = { reverse = true },
  79. [3] = { bold = true },
  80. [10] = { foreground = 2 },
  81. }
  82. )
  83. end)
  84. end)
  85. describe('shell command :!', function()
  86. before_each(function()
  87. clear()
  88. end)
  89. it('cat a binary file #4142', function()
  90. feed(":exe 'silent !cat '.shellescape(v:progpath)<CR>")
  91. assert_alive()
  92. end)
  93. it([[display \x08 char #4142]], function()
  94. feed(':silent !echo \08<CR>')
  95. assert_alive()
  96. end)
  97. it('handles control codes', function()
  98. skip(is_os('win'), 'missing printf')
  99. local screen = Screen.new(50, 4)
  100. -- Print TAB chars. #2958
  101. feed([[:!printf '1\t2\t3'<CR>]])
  102. screen:expect {
  103. grid = [[
  104. {3: }|
  105. :!printf '1\t2\t3' |
  106. 1 2 3 |
  107. {6:Press ENTER or type command to continue}^ |
  108. ]],
  109. }
  110. feed([[<CR>]])
  111. -- Print BELL control code. #4338
  112. screen.bell = false
  113. feed([[:!printf '\007\007\007\007text'<CR>]])
  114. screen:expect {
  115. grid = [[
  116. {3: }|
  117. :!printf '\007\007\007\007text' |
  118. text |
  119. {6:Press ENTER or type command to continue}^ |
  120. ]],
  121. condition = function()
  122. eq(true, screen.bell)
  123. end,
  124. }
  125. feed([[<CR>]])
  126. -- Print BS control code.
  127. feed([[:echo system('printf ''\010\n''')<CR>]])
  128. screen:expect([[
  129. {3: }|
  130. {18:^H} |
  131. |
  132. {6:Press ENTER or type command to continue}^ |
  133. ]])
  134. feed([[<CR>]])
  135. -- Print LF control code.
  136. feed([[:!printf '\n'<CR>]])
  137. screen:expect([[
  138. :!printf '\n' |
  139. |*2
  140. {6:Press ENTER or type command to continue}^ |
  141. ]])
  142. feed([[<CR>]])
  143. end)
  144. describe('', function()
  145. local screen
  146. before_each(function()
  147. rmdir('bang_filter_spec')
  148. mkdir('bang_filter_spec')
  149. write_file('bang_filter_spec/f1', 'f1')
  150. write_file('bang_filter_spec/f2', 'f2')
  151. write_file('bang_filter_spec/f3', 'f3')
  152. screen = Screen.new(53, 10)
  153. end)
  154. after_each(function()
  155. rmdir('bang_filter_spec')
  156. end)
  157. it("doesn't truncate Last line of shell output #3269", function()
  158. command(
  159. is_os('win') and [[nnoremap <silent>\l :!dir /b bang_filter_spec<cr>]]
  160. or [[nnoremap <silent>\l :!ls bang_filter_spec<cr>]]
  161. )
  162. local result = (
  163. is_os('win') and [[:!dir /b bang_filter_spec]] or [[:!ls bang_filter_spec ]]
  164. )
  165. feed([[\l]])
  166. screen:expect([[
  167. |
  168. {1:~ }|*2
  169. {3: }|
  170. ]] .. result .. [[ |
  171. f1 |
  172. f2 |
  173. f3 |
  174. |
  175. {6:Press ENTER or type command to continue}^ |
  176. ]])
  177. end)
  178. it('handles binary and multibyte data', function()
  179. feed_command('!cat test/functional/fixtures/shell_data.txt')
  180. screen.bell = false
  181. screen:expect {
  182. grid = [[
  183. |
  184. {1:~ }|
  185. {3: }|
  186. :!cat test/functional/fixtures/shell_data.txt |
  187. {18:^@^A^B^C^D^E^F^H} |
  188. {18:^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_} |
  189. ö 한글 {18:<a5><c3>} |
  190. t {18:<ff>} |
  191. |
  192. {6:Press ENTER or type command to continue}^ |
  193. ]],
  194. condition = function()
  195. eq(true, screen.bell)
  196. end,
  197. }
  198. end)
  199. it('handles multibyte sequences split over buffer boundaries', function()
  200. command('cd ' .. nvim_dir)
  201. local cmd = is_os('win') and '!shell-test UTF-8 ' or '!./shell-test UTF-8'
  202. feed_command(cmd)
  203. -- Note: only the first example of split composed char works
  204. screen:expect([[
  205. |
  206. {3: }|
  207. :]] .. cmd .. [[ |
  208. å |
  209. ref: å̲ |
  210. 1: å̲ |
  211. 2: å ̲ |
  212. 3: å ̲ |
  213. |
  214. {6:Press ENTER or type command to continue}^ |
  215. ]])
  216. end)
  217. end)
  218. if has_powershell() then
  219. it('powershell supports literal strings', function()
  220. set_shell_powershell()
  221. local screen = Screen.new(45, 4)
  222. feed_command([[!'Write-Output $a']])
  223. screen:expect([[
  224. :!'Write-Output $a' |
  225. Write-Output $a |
  226. |
  227. {6:Press ENTER or type command to continue}^ |
  228. ]])
  229. feed_command([[!$a = 1; Write-Output '$a']])
  230. screen:expect([[
  231. :!$a = 1; Write-Output '$a' |
  232. $a |
  233. |
  234. {6:Press ENTER or type command to continue}^ |
  235. ]])
  236. feed_command([[!"Write-Output $a"]])
  237. screen:expect([[
  238. :!"Write-Output $a" |
  239. Write-Output |
  240. |
  241. {6:Press ENTER or type command to continue}^ |
  242. ]])
  243. feed_command([[!$a = 1; Write-Output "$a"]])
  244. screen:expect([[
  245. :!$a = 1; Write-Output "$a" |
  246. 1 |
  247. |
  248. {6:Press ENTER or type command to continue}^ |
  249. ]])
  250. if is_os('win') then
  251. feed_command([[!& 'cmd.exe' /c 'echo $a']])
  252. screen:expect([[
  253. :!& 'cmd.exe' /c 'echo $a' |
  254. $a |
  255. |
  256. {6:Press ENTER or type command to continue}^ |
  257. ]])
  258. else
  259. feed_command([[!& '/bin/sh' -c 'echo ''$a''']])
  260. screen:expect([[
  261. :!& '/bin/sh' -c 'echo ''$a''' |
  262. $a |
  263. |
  264. {6:Press ENTER or type command to continue}^ |
  265. ]])
  266. end
  267. end)
  268. end
  269. end)