neovim

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

command_line_completion_spec.lua (9799B)


      1 local t = require('test.testutil')
      2 local n = require('test.functional.testnvim')()
      3 
      4 local clear = n.clear
      5 local eq = t.eq
      6 local exec_lua = n.exec_lua
      7 
      8 --- @return { [1]: string[], [2]: integer }
      9 local get_completions = function(input, env)
     10  return exec_lua('return { vim._expand_pat(...) }', input, env)
     11 end
     12 
     13 --- @return { [1]: string[], [2]: integer }
     14 local get_compl_parts = function(parts)
     15  return exec_lua('return { vim._expand_pat_get_parts(...) }', parts)
     16 end
     17 
     18 before_each(clear)
     19 
     20 describe('nlua_expand_pat', function()
     21  it('completes exact matches', function()
     22    eq({ { 'exact' }, 0 }, get_completions('exact', { exact = true }))
     23  end)
     24 
     25  it('returns empty table when nothing matches', function()
     26    eq({ {}, 0 }, get_completions('foo', { bar = true }))
     27 
     28    -- can access non-exist field
     29    for _, m in ipairs {
     30      'vim.',
     31      'vim.lsp.',
     32      'vim.treesitter.',
     33      'vim.deepcopy.',
     34      'vim.fn.',
     35      'vim.api.',
     36      'vim.o.',
     37      'vim.b.',
     38    } do
     39      eq({ {}, m:len() }, get_completions(m .. 'foo'))
     40      eq({ {}, 0 }, get_completions(m .. 'foo.'))
     41      eq({ {}, 0 }, get_completions(m .. 'foo.bar'))
     42      eq({ {}, 0 }, get_completions(m .. 'foo.bar.'))
     43    end
     44  end)
     45 
     46  it('returns nice completions with function call prefix', function()
     47    eq({ { 'FOO' }, 6 }, get_completions('print(F', { FOO = true, bawr = true }))
     48  end)
     49 
     50  it('returns keys for nested dicts', function()
     51    eq(
     52      { {
     53        'nvim_buf_set_lines',
     54      }, 8 },
     55      get_completions('vim.api.nvim_buf_', {
     56        vim = {
     57          api = {
     58            nvim_buf_set_lines = true,
     59            nvim_win_doesnt_match = true,
     60          },
     61          other_key = true,
     62        },
     63      })
     64    )
     65  end)
     66 
     67  it('with colons', function()
     68    eq(
     69      { {
     70        'bawr',
     71        'baz',
     72      }, 8 },
     73      get_completions('MyClass:b', {
     74        MyClass = {
     75          baz = true,
     76          bawr = true,
     77          foo = false,
     78        },
     79      })
     80    )
     81  end)
     82 
     83  it('returns keys after string key', function()
     84    eq(
     85      { {
     86        'nvim_buf_set_lines',
     87      }, 11 },
     88      get_completions('vim["api"].nvim_buf_', {
     89        vim = {
     90          api = {
     91            nvim_buf_set_lines = true,
     92            nvim_win_doesnt_match = true,
     93          },
     94          other_key = true,
     95        },
     96      })
     97    )
     98 
     99    eq(
    100      { {
    101        'nvim_buf_set_lines',
    102      }, 21 },
    103      get_completions('vim["nested"]["api"].nvim_buf_', {
    104        vim = {
    105          nested = {
    106            api = {
    107              nvim_buf_set_lines = true,
    108              nvim_win_doesnt_match = true,
    109            },
    110          },
    111          other_key = true,
    112        },
    113      })
    114    )
    115  end)
    116 
    117  it('with lazy submodules of "vim" global', function()
    118    eq({ { 'inspect', 'inspect_pos' }, 4 }, get_completions('vim.inspec'))
    119    eq({ { 'treesitter' }, 4 }, get_completions('vim.treesi'))
    120    eq({ { 'dev' }, 15 }, get_completions('vim.treesitter.de'))
    121    eq({ { 'edit_query' }, 19 }, get_completions('vim.treesitter.dev.edit_'))
    122    eq({ { 'set' }, 11 }, get_completions('vim.keymap.se'))
    123  end)
    124 
    125  it('include keys in mt.__index and ._submodules', function()
    126    eq(
    127      { { 'bar1', 'bar2', 'bar3' }, 4 },
    128      exec_lua(function() -- metatable cannot be serialized
    129        return {
    130          vim._expand_pat('foo.', {
    131            foo = setmetatable(
    132              { bar1 = true, _submodules = { bar2 = true } },
    133              { __index = { bar3 = true } }
    134            ),
    135          }),
    136        }
    137      end)
    138    )
    139  end)
    140 
    141  it('excludes private fields after "."', function()
    142    eq(
    143      { { 'bar' }, 4 },
    144      get_completions('foo.', {
    145        foo = {
    146          _bar = true,
    147          bar = true,
    148        },
    149      })
    150    )
    151  end)
    152 
    153  it('includes private fields after "._"', function()
    154    eq(
    155      { { '_bar' }, 4 },
    156      get_completions('foo._', {
    157        foo = {
    158          _bar = true,
    159          bar = true,
    160        },
    161      })
    162    )
    163  end)
    164 
    165  it('can interpolate globals', function()
    166    eq(
    167      { {
    168        'nvim_buf_set_lines',
    169      }, 12 },
    170      get_completions('vim[MY_VAR].nvim_buf_', {
    171        MY_VAR = 'api',
    172        vim = {
    173          api = {
    174            nvim_buf_set_lines = true,
    175            nvim_win_doesnt_match = true,
    176          },
    177          other_key = true,
    178        },
    179      })
    180    )
    181  end)
    182 
    183  describe('vim.fn', function()
    184    it('simple completion', function()
    185      local actual = get_completions('vim.fn.did')
    186      local expected = {
    187        { 'did_filetype' },
    188        #'vim.fn.',
    189      }
    190      eq(expected, actual)
    191    end)
    192    it('does not suggest "#" items', function()
    193      exec_lua [[
    194        -- ensure remote#host#... functions exist
    195        vim.cmd [=[
    196          runtime! autoload/remote/host.vim
    197        ]=]
    198        -- make a dummy call to ensure vim.fn contains an entry: remote#host#...
    199        vim.fn['remote#host#IsRunning']('python3')
    200      ]]
    201      local actual = get_completions('vim.fn.remo')
    202      local expected = {
    203        { 'remove' }, -- there should be no completion "remote#host#..."
    204        #'vim.fn.',
    205      }
    206      eq(expected, actual)
    207    end)
    208  end)
    209 
    210  describe('completes', function()
    211    it('vim.v', function()
    212      local actual = get_completions('vim.v.t_')
    213      local expected = {
    214        { 't_blob', 't_bool', 't_dict', 't_float', 't_func', 't_list', 't_number', 't_string' },
    215        #'vim.v.',
    216      }
    217      eq(expected, actual)
    218    end)
    219 
    220    it('vim.g', function()
    221      exec_lua [[
    222        vim.cmd [=[
    223          let g:nlua_foo = 'completion'
    224          let g:nlua_foo_bar = 'completion'
    225          let g:nlua_foo#bar = 'nocompletion'  " should be excluded from lua completion
    226        ]=]
    227      ]]
    228      local actual = get_completions('vim.g.nlua')
    229      local expected = {
    230        { 'nlua_foo', 'nlua_foo_bar' },
    231        #'vim.g.',
    232      }
    233      eq(expected, actual)
    234    end)
    235 
    236    it('vim.b', function()
    237      exec_lua [[
    238        vim.b.nlua_foo_buf = 'bar'
    239        vim.b.some_other_vars = 'bar'
    240      ]]
    241      local actual = get_completions('vim.b.nlua')
    242      local expected = {
    243        { 'nlua_foo_buf' },
    244        #'vim.b.',
    245      }
    246      eq(expected, actual)
    247    end)
    248 
    249    it('vim.w', function()
    250      exec_lua [[
    251        vim.w.nlua_win_var = 42
    252      ]]
    253      local actual = get_completions('vim.w.nlua')
    254      local expected = {
    255        { 'nlua_win_var' },
    256        #'vim.w.',
    257      }
    258      eq(expected, actual)
    259    end)
    260 
    261    it('vim.t', function()
    262      exec_lua [[
    263        vim.t.nlua_tab_var = 42
    264      ]]
    265      local actual = get_completions('vim.t.')
    266      local expected = {
    267        { 'nlua_tab_var' },
    268        #'vim.t.',
    269      }
    270      eq(expected, actual)
    271    end)
    272 
    273    it('vim.env', function()
    274      exec_lua [[
    275        vim.env.NLUA_ENV_VAR = 'foo'
    276      ]]
    277      local actual = get_completions('vim.env.NLUA')
    278      local expected = {
    279        { 'NLUA_ENV_VAR' },
    280        #'vim.env.',
    281      }
    282      eq(expected, actual)
    283    end)
    284  end)
    285 
    286  describe('completes', function()
    287    -- for { vim.o, vim.go, vim.opt, vim.opt_local, vim.opt_global }
    288    local test_opt = function(accessor)
    289      it(accessor, function()
    290        do
    291          local actual = get_completions(accessor .. '.file')
    292          local expected = {
    293            'fileencoding',
    294            'fileencodings',
    295            'fileformat',
    296            'fileformats',
    297            'fileignorecase',
    298            'filetype',
    299          }
    300          eq({ expected, #accessor + 1 }, actual, accessor .. '.file')
    301        end
    302        do
    303          local actual = get_completions(accessor .. '.winh')
    304          local expected = {
    305            'winheight',
    306            'winhighlight',
    307          }
    308          eq({ expected, #accessor + 1 }, actual, accessor .. '.winh')
    309        end
    310      end)
    311    end
    312 
    313    test_opt('vim.o')
    314    test_opt('vim.go')
    315    test_opt('vim.opt')
    316    test_opt('vim.opt_local')
    317    test_opt('vim.opt_global')
    318 
    319    it('vim.o, suggesting all known options', function()
    320      local completions = get_completions('vim.o.')[1] ---@type string[]
    321      eq(
    322        exec_lua [[
    323        return vim.tbl_count(vim.api.nvim_get_all_options_info())
    324      ]],
    325        #completions
    326      )
    327    end)
    328 
    329    it('vim.bo', function()
    330      do
    331        local actual = get_completions('vim.bo.file')
    332        local compls = {
    333          -- should contain buffer options only
    334          'fileencoding',
    335          'fileformat',
    336          'filetype',
    337        }
    338        eq({ compls, #'vim.bo.' }, actual)
    339      end
    340      do
    341        local actual = get_completions('vim.bo.winh')
    342        local compls = {}
    343        eq({ compls, #'vim.bo.' }, actual)
    344      end
    345    end)
    346 
    347    it('vim.wo', function()
    348      do
    349        local actual = get_completions('vim.wo.file')
    350        local compls = {}
    351        eq({ compls, #'vim.wo.' }, actual)
    352      end
    353      do
    354        local actual = get_completions('vim.wo.winh')
    355        -- should contain window options only
    356        local compls = { 'winhighlight' }
    357        eq({ compls, #'vim.wo.' }, actual)
    358      end
    359    end)
    360  end)
    361 
    362  it('returns everything if input is empty', function()
    363    eq({ { 'other', 'vim' }, 0 }, get_completions('', { vim = true, other = true }))
    364  end)
    365 
    366  it('get_parts', function()
    367    eq({ {}, 1 }, get_compl_parts('vim'))
    368    eq({ { 'vim' }, 5 }, get_compl_parts('vim.ap'))
    369    eq({ { 'vim', 'api' }, 9 }, get_compl_parts('vim.api.nvim_buf'))
    370    eq({ { 'vim', 'api' }, 9 }, get_compl_parts('vim:api.nvim_buf'))
    371    eq({ { 'vim', 'api' }, 12 }, get_compl_parts("vim['api'].nvim_buf"))
    372    eq({ { 'vim', 'api' }, 12 }, get_compl_parts('vim["api"].nvim_buf'))
    373    eq({ { 'vim', 'nested', 'api' }, 22 }, get_compl_parts('vim["nested"]["api"].nvim_buf'))
    374    eq({ { 'vim', 'nested', 'api' }, 25 }, get_compl_parts('vim[ "nested"  ]["api"].nvim_buf'))
    375    eq({ { 'vim', { 'NESTED' }, 'api' }, 20 }, get_compl_parts('vim[NESTED]["api"].nvim_buf'))
    376  end)
    377 end)