neovim

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

mode_insert_spec.lua (14317B)


      1 -- Insert-mode tests.
      2 
      3 local t = require('test.testutil')
      4 local n = require('test.functional.testnvim')()
      5 local Screen = require('test.functional.ui.screen')
      6 
      7 local clear, feed, insert = n.clear, n.feed, n.insert
      8 local expect = n.expect
      9 local command = n.command
     10 local eq = t.eq
     11 local eval = n.eval
     12 local curbuf_contents = n.curbuf_contents
     13 local api = n.api
     14 
     15 describe('insert-mode', function()
     16  before_each(function()
     17    clear()
     18  end)
     19 
     20  it('indents only once after "!" keys #12894', function()
     21    command('let counter = []')
     22    command('set indentexpr=len(add(counter,0))')
     23    feed('i<C-F>x')
     24    eq(' x', curbuf_contents())
     25  end)
     26 
     27  it('indent works properly with autocompletion enabled #35381', function()
     28    command('set autoindent cindent autocomplete')
     29    feed('ivoid func(void) {<CR>')
     30    expect('void func(void) {\n\t')
     31    feed('}')
     32    expect('void func(void) {\n}')
     33  end)
     34 
     35  it('CTRL-@', function()
     36    -- Inserts last-inserted text, leaves insert-mode.
     37    insert('hello')
     38    feed('i<C-@>x')
     39    expect('hellhello')
     40 
     41    -- C-Space is the same as C-@.
     42    -- CTRL-SPC inserts last-inserted text, leaves insert-mode.
     43    feed('i<C-Space>x')
     44    expect('hellhellhello')
     45 
     46    -- CTRL-A inserts last inserted text
     47    feed('i<C-A>x')
     48    expect('hellhellhellhelloxo')
     49  end)
     50 
     51  describe('Ctrl-R', function()
     52    it('works', function()
     53      command("let @@ = 'test'")
     54      feed('i<C-r>"')
     55      expect('test')
     56    end)
     57 
     58    it('works with multi-byte text', function()
     59      command("let @@ = 'påskägg'")
     60      feed('i<C-r>"')
     61      expect('påskägg')
     62    end)
     63 
     64    it('double quote is removed after hit-enter prompt #22609', function()
     65      local screen = Screen.new(50, 6)
     66      feed('i<C-R>')
     67      screen:expect([[
     68        {18:^"}                                                 |
     69        {1:~                                                 }|*4
     70        {5:-- INSERT --}                                      |
     71      ]])
     72      feed("=function('add')")
     73      screen:expect([[
     74        {18:"}                                                 |
     75        {1:~                                                 }|*4
     76        ={25:function}{16:(}{26:'add'}{16:)}^                                  |
     77      ]])
     78      feed('<CR>')
     79      screen:expect([[
     80        {18:"}                                                 |
     81        {1:~                                                 }|
     82        {3:                                                  }|
     83        ={25:function}{16:(}{26:'add'}{16:)}                                  |
     84        {9:E729: Using a Funcref as a String}                 |
     85        {6:Press ENTER or type command to continue}^           |
     86      ]])
     87      feed('<CR>')
     88      screen:expect([[
     89        ^                                                  |
     90        {1:~                                                 }|*4
     91        {5:-- INSERT --}                                      |
     92      ]])
     93    end)
     94 
     95    it('inserts named/clipboard registers literally', function()
     96      local screen = Screen.new(50, 6)
     97      -- regular text without special character command
     98      command('let @a = "test"')
     99      feed('i<C-R>a<ESC>')
    100      screen:expect([[
    101        tes^t                                              |
    102        {1:~                                                 }|*4
    103                                                          |
    104      ]])
    105 
    106      -- text with backspace character gets written literally by default
    107      command('let @a = "test\\<C-H>"')
    108      feed('cc<C-R>a<ESC>')
    109      screen:expect([[
    110        test{18:^^H}                                            |
    111        {1:~                                                 }|*4
    112                                                          |
    113      ]])
    114 
    115      -- =@reg<CR> can be used to get effect of keypress
    116      command('let @a = "test\\<C-H>"')
    117      feed('cc<C-R>=@a<CR><ESC>')
    118      screen:expect([[
    119        te^s                                               |
    120        {1:~                                                 }|*4
    121                                                          |
    122      ]])
    123    end)
    124  end)
    125 
    126  describe('Ctrl-O', function()
    127    it('enters command mode for one command', function()
    128      feed('ihello world<C-o>')
    129      feed(':let ctrlo = "test"<CR>')
    130      feed('iii')
    131      expect('hello worldiii')
    132      eq(1, eval('ctrlo ==# "test"'))
    133    end)
    134 
    135    it('re-enters insert mode at the end of the line when running startinsert', function()
    136      -- #6962
    137      feed('ihello world<C-o>')
    138      feed(':startinsert<CR>')
    139      feed('iii')
    140      expect('hello worldiii')
    141    end)
    142 
    143    it('re-enters insert mode at the beginning of the line when running startinsert', function()
    144      insert('hello world')
    145      feed('0<C-o>')
    146      feed(':startinsert<CR>')
    147      feed('aaa')
    148      expect('aaahello world')
    149    end)
    150 
    151    it('re-enters insert mode in the middle of the line when running startinsert', function()
    152      insert('hello world')
    153      feed('bi<C-o>')
    154      feed(':startinsert<CR>')
    155      feed('ooo')
    156      expect('hello oooworld')
    157    end)
    158  end)
    159 
    160  describe('Ctrl-V', function()
    161    it('supports entering the decimal value of a character', function()
    162      feed('i<C-V>076<C-V>167')
    163      expect('L§')
    164    end)
    165 
    166    it('supports entering the octal value of a character with "o"', function()
    167      feed('i<C-V>o114<C-V>o247<Esc>')
    168      expect('L§')
    169    end)
    170 
    171    it('supports entering the octal value of a character with "O"', function()
    172      feed('i<C-V>O114<C-V>O247<Esc>')
    173      expect('L§')
    174    end)
    175 
    176    it('supports entering the hexadecimal value of a character with "x"', function()
    177      feed('i<C-V>x4c<C-V>xA7<Esc>')
    178      expect('L§')
    179    end)
    180 
    181    it('supports entering the hexadecimal value of a character with "X"', function()
    182      feed('i<C-V>X4c<C-V>XA7<Esc>')
    183      expect('L§')
    184    end)
    185 
    186    it('supports entering the hexadecimal value of a character with "u"', function()
    187      feed('i<C-V>u25ba<C-V>u25C7<Esc>')
    188      expect('►◇')
    189    end)
    190 
    191    it('supports entering the hexadecimal value of a character with "U"', function()
    192      feed('i<C-V>U0001f600<C-V>U0001F601<Esc>')
    193      expect('😀😁')
    194    end)
    195 
    196    it('entering character by value is interrupted by invalid character', function()
    197      feed('i<C-V>76c<C-V>76<C-F2><C-V>u3c0j<C-V>u3c0<M-F3><C-V>U1f600j<C-V>U1f600<D-F4><Esc>')
    198      expect('LcL<C-F2>πjπ<M-F3>😀j😀<D-F4>')
    199    end)
    200 
    201    it('shows o, O, u, U, x, X, and digits with modifiers', function()
    202      feed('i<C-V><M-o><C-V><D-o><C-V><M-O><C-V><D-O><Esc>')
    203      expect('<M-o><D-o><M-O><D-O>')
    204      feed('cc<C-V><M-u><C-V><D-u><C-V><M-U><C-V><D-U><Esc>')
    205      expect('<M-u><D-u><M-U><D-U>')
    206      feed('cc<C-V><M-x><C-V><D-x><C-V><M-X><C-V><D-X><Esc>')
    207      expect('<M-x><D-x><M-X><D-X>')
    208      feed('cc<C-V><M-1><C-V><D-2><C-V><M-7><C-V><D-8><Esc>')
    209      expect('<M-1><D-2><M-7><D-8>')
    210    end)
    211  end)
    212 
    213  it('Ctrl-Shift-V supports entering unsimplified key notations', function()
    214    feed('i<C-S-V><C-J><C-S-V><C-@><C-S-V><C-[><C-S-V><C-S-M><C-S-V><M-C-I><C-S-V><C-D-J><Esc>')
    215    expect('<C-J><C-@><C-[><C-S-M><M-C-I><C-D-J>')
    216  end)
    217 
    218  it('multi-char mapping updates screen properly #25626', function()
    219    local screen = Screen.new(60, 6)
    220    command('vnew')
    221    insert('foo\nfoo\nfoo')
    222    command('wincmd w')
    223    command('set timeoutlen=10000')
    224    command('inoremap jk <Esc>')
    225    feed('i<CR>βββ<Left><Left>j')
    226    screen:expect {
    227      grid = [[
    228      foo                           │                             |
    229      foo                           │β^jβ                          |
    230      foo                           │{1:~                            }|
    231      {1:~                             }│{1:~                            }|
    232      {2:[No Name] [+]                  }{3:[No Name] [+]                }|
    233      {5:-- INSERT --}                                                |
    234    ]],
    235    }
    236    feed('k')
    237    screen:expect {
    238      grid = [[
    239      foo                           │                             |
    240      foo                           │^βββ                          |
    241      foo                           │{1:~                            }|
    242      {1:~                             }│{1:~                            }|
    243      {2:[No Name] [+]                  }{3:[No Name] [+]                }|
    244                                                                  |
    245    ]],
    246    }
    247  end)
    248 
    249  describe('backspace', function()
    250    local function set_lines(line_b, line_e, ...)
    251      api.nvim_buf_set_lines(0, line_b, line_e, true, { ... })
    252    end
    253    local function s(count)
    254      return (' '):rep(count)
    255    end
    256 
    257    local function test_cols(expected_cols)
    258      local cols = { { n.fn.col('.'), n.fn.virtcol('.') } }
    259      for _ = 2, #expected_cols do
    260        feed('<BS>')
    261        table.insert(cols, { n.fn.col('.'), n.fn.virtcol('.') })
    262      end
    263      eq(expected_cols, cols)
    264    end
    265 
    266    it('works with tabs and spaces', function()
    267      local _ = Screen.new(30, 2)
    268      command('setl ts=4 sw=4')
    269      set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
    270      feed('$i')
    271      test_cols({
    272        { 18, 26 },
    273        { 17, 25 },
    274        { 15, 21 },
    275        { 11, 17 },
    276        { 7, 13 },
    277        { 6, 9 },
    278        { 2, 5 },
    279        { 1, 1 },
    280      })
    281    end)
    282 
    283    it('works with varsofttabstop', function()
    284      local _ = Screen.new(30, 2)
    285      command('setl vsts=6,2,5,3')
    286      set_lines(0, 1, 'a\t' .. s(4) .. '\t a')
    287      feed('$i')
    288      test_cols({
    289        { 9, 18 },
    290        { 8, 17 },
    291        { 8, 14 },
    292        { 3, 9 },
    293        { 7, 7 },
    294        { 2, 2 },
    295        { 1, 1 },
    296      })
    297    end)
    298 
    299    it('works with tab as ^I', function()
    300      local _ = Screen.new(30, 2)
    301      command('set list listchars=space:.')
    302      command('setl ts=4 sw=4')
    303      set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
    304      feed('$i')
    305      test_cols({
    306        { 18, 21 },
    307        { 15, 17 },
    308        { 11, 13 },
    309        { 7, 9 },
    310        { 4, 5 },
    311        { 1, 1 },
    312      })
    313    end)
    314 
    315    it('works in replace mode', function()
    316      local _ = Screen.new(50, 2)
    317      command('setl ts=8 sw=8 sts=8')
    318      set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
    319      feed('$R')
    320      test_cols({
    321        { 18, 34 },
    322        { 17, 33 },
    323        { 15, 25 },
    324        { 7, 17 },
    325        { 2, 9 },
    326        { 1, 8 }, -- last screen cell of first tab is at vcol 8
    327      })
    328    end)
    329 
    330    it('works with breakindent', function()
    331      local _ = Screen.new(17, 4)
    332      command('setl ts=4 sw=4 bri briopt=min:5')
    333      set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
    334      feed('$i')
    335      test_cols({
    336        { 18, 50 },
    337        { 17, 49 },
    338        { 15, 33 },
    339        { 11, 17 },
    340        { 7, 13 },
    341        { 6, 9 },
    342        { 2, 5 },
    343        { 1, 1 },
    344      })
    345    end)
    346 
    347    it('works with inline virtual text', function()
    348      local _ = Screen.new(50, 2)
    349      command('setl ts=4 sw=4')
    350      set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
    351      local ns = api.nvim_create_namespace('')
    352      local vt_opts = { virt_text = { { 'text' } }, virt_text_pos = 'inline' }
    353      api.nvim_buf_set_extmark(0, ns, 0, 2, vt_opts)
    354      feed('$i')
    355      test_cols({
    356        { 18, 30 },
    357        { 17, 29 },
    358        { 15, 25 },
    359        { 11, 21 },
    360        { 7, 17 },
    361        { 6, 13 },
    362        { 2, 9 },
    363        { 1, 5 },
    364      })
    365    end)
    366 
    367    it("works with 'revins'", function()
    368      local _ = Screen.new(30, 3)
    369      command('setl ts=4 sw=4 revins')
    370      set_lines(0, 1, ('a'):rep(16), s(3) .. '\t' .. s(4) .. '\t a')
    371      feed('j$i')
    372      test_cols({
    373        { 11, 14 },
    374        { 10, 13 },
    375        { 9, 9 },
    376        { 5, 5 },
    377        { 1, 1 },
    378        { 1, 1 }, -- backspace on empty line does nothing
    379      })
    380      eq(2, api.nvim_win_get_cursor(0)[1])
    381    end)
    382  end)
    383 
    384  it('backspace after replacing multibyte chars', function()
    385    local screen = Screen.new(30, 3)
    386    api.nvim_buf_set_lines(0, 0, -1, true, { 'test ȧ̟̜̝̅̚m̆̉̐̐̇̈ å' })
    387    feed('^Rabcdefghi')
    388    screen:expect([[
    389      abcdefghi^                     |
    390      {1:~                             }|
    391      {5:-- REPLACE --}                 |
    392    ]])
    393 
    394    feed('<bs>')
    395    screen:expect([[
    396      abcdefgh^å                     |
    397      {1:~                             }|
    398      {5:-- REPLACE --}                 |
    399    ]])
    400 
    401    feed('<bs>')
    402    screen:expect([[
    403      abcdefg^ å                     |
    404      {1:~                             }|
    405      {5:-- REPLACE --}                 |
    406    ]])
    407 
    408    feed('<bs>')
    409    screen:expect([[
    410      abcdef^m̆̉̐̐̇̈ å                     |
    411      {1:~                             }|
    412      {5:-- REPLACE --}                 |
    413    ]])
    414 
    415    feed('<bs>')
    416    screen:expect([[
    417      abcde^ȧ̟̜̝̅̚m̆̉̐̐̇̈ å                     |
    418      {1:~                             }|
    419      {5:-- REPLACE --}                 |
    420    ]])
    421 
    422    feed('<bs>')
    423    screen:expect([[
    424      abcd^ ȧ̟̜̝̅̚m̆̉̐̐̇̈ å                     |
    425      {1:~                             }|
    426      {5:-- REPLACE --}                 |
    427    ]])
    428 
    429    feed('<esc>')
    430 
    431    api.nvim_buf_set_lines(0, 0, -1, true, { 'wow 🧑‍🌾🏳️‍⚧️x' })
    432    feed('^Rabcd')
    433 
    434    screen:expect([[
    435      abcd^🧑‍🌾🏳️‍⚧️x                     |
    436      {1:~                             }|
    437      {5:-- REPLACE --}                 |
    438    ]])
    439 
    440    feed('e')
    441    screen:expect([[
    442      abcde^🏳️‍⚧️x                      |
    443      {1:~                             }|
    444      {5:-- REPLACE --}                 |
    445    ]])
    446 
    447    feed('f')
    448    screen:expect([[
    449      abcdef^x                       |
    450      {1:~                             }|
    451      {5:-- REPLACE --}                 |
    452    ]])
    453 
    454    feed('<bs>')
    455    screen:expect([[
    456      abcde^🏳️‍⚧️x                      |
    457      {1:~                             }|
    458      {5:-- REPLACE --}                 |
    459    ]])
    460 
    461    feed('<bs>')
    462    screen:expect([[
    463      abcd^🧑‍🌾🏳️‍⚧️x                     |
    464      {1:~                             }|
    465      {5:-- REPLACE --}                 |
    466    ]])
    467 
    468    feed('<bs>')
    469    screen:expect([[
    470      abc^ 🧑‍🌾🏳️‍⚧️x                     |
    471      {1:~                             }|
    472      {5:-- REPLACE --}                 |
    473    ]])
    474  end)
    475 end)