neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

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)