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