neovim

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

test_ex_mode.vim (12753B)


      1 " Test editing line in Ex mode (see :help Q and :help gQ).
      2 
      3 source check.vim
      4 source shared.vim
      5 
      6 " Helper function to test editing line in Q Ex mode
      7 func Ex_Q(cmd)
      8  " Is there a simpler way to test editing Ex line?
      9  call feedkeys("Q"
     10        \    .. "let s:test_ex =<< END\<CR>"
     11        \    .. a:cmd .. "\<CR>"
     12        \    .. "END\<CR>"
     13        \    .. "visual\<CR>", 'tx')
     14  return s:test_ex[0]
     15 endfunc
     16 
     17 " Helper function to test editing line in gQ Ex mode
     18 func Ex_gQ(cmd)
     19  call feedkeys("gQ" .. a:cmd .. "\<C-b>\"\<CR>", 'tx')
     20  let ret = @:[1:] " Remove leading quote.
     21  call feedkeys("visual\<CR>", 'tx')
     22  return ret
     23 endfunc
     24 
     25 " Helper function to test editing line with both Q and gQ Ex mode.
     26 func Ex(cmd)
     27 return [Ex_Q(a:cmd), Ex_gQ(a:cmd)]
     28 endfunc
     29 
     30 " Test editing line in Ex mode (both Q and gQ)
     31 func Test_ex_mode()
     32  throw 'Skipped: Nvim only supports Vim Ex mode'
     33  let encoding_save = &encoding
     34  set sw=2
     35 
     36  for e in ['utf8', 'latin1']
     37    exe 'set encoding=' . e
     38 
     39    call assert_equal(['bar', 'bar'],             Ex("foo bar\<C-u>bar"), e)
     40    call assert_equal(["1\<C-u>2", "1\<C-u>2"],   Ex("1\<C-v>\<C-u>2"), e)
     41    call assert_equal(["1\<C-b>2\<C-e>3", '213'], Ex("1\<C-b>2\<C-e>3"), e)
     42    call assert_equal(['0123', '2013'],           Ex("01\<Home>2\<End>3"), e)
     43    call assert_equal(['0123', '0213'],           Ex("01\<Left>2\<Right>3"), e)
     44    call assert_equal(['01234', '0342'],          Ex("012\<Left>\<Left>\<Insert>3\<Insert>4"), e)
     45    call assert_equal(["foo bar\<C-w>", 'foo '],  Ex("foo bar\<C-w>"), e)
     46    call assert_equal(['foo', 'foo'],             Ex("fooba\<Del>\<Del>"), e)
     47    call assert_equal(["foo\tbar", 'foobar'],     Ex("foo\<Tab>bar"), e)
     48    call assert_equal(["abbrev\t", 'abbreviate'], Ex("abbrev\<Tab>"), e)
     49    call assert_equal(['    1', "1\<C-t>\<C-t>"], Ex("1\<C-t>\<C-t>"), e)
     50    call assert_equal(['  1', "1\<C-t>\<C-t>"],   Ex("1\<C-t>\<C-t>\<C-d>"), e)
     51    call assert_equal(['  foo', '    foo'],       Ex("    foo\<C-d>"), e)
     52    call assert_equal(['foo', '    foo0'],        Ex("    foo0\<C-d>"), e)
     53    call assert_equal(['foo', '    foo^'],        Ex("    foo^\<C-d>"), e)
     54    call assert_equal(['foo', 'foo'],
     55          \ Ex("\<BS>\<C-H>\<Del>\<kDel>foo"), e)
     56    " default wildchar <Tab> interferes with this test
     57    set wildchar=<c-e>
     58    call assert_equal(["a\tb", "a\tb"],           Ex("a\t\t\<C-H>b"), e)
     59    call assert_equal(["\t  mn", "\tm\<C-T>n"],        Ex("\tm\<C-T>n"), e)
     60    set wildchar&
     61  endfor
     62 
     63  set sw&
     64  let &encoding = encoding_save
     65 endfunc
     66 
     67 " Test substitute confirmation prompt :%s/pat/str/c in Ex mode
     68 func Test_Ex_substitute()
     69  CheckRunVimInTerminal
     70  let buf = RunVimInTerminal('', {'rows': 6})
     71 
     72  call term_sendkeys(buf, ":call setline(1, repeat(['foo foo'], 4))\<CR>")
     73  call term_sendkeys(buf, ":set number\<CR>")
     74  call term_sendkeys(buf, "gQ")
     75  call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
     76 
     77  call term_sendkeys(buf, "%s/foo/bar/gc\<CR>")
     78  call WaitForAssert({-> assert_match('  1 foo foo', term_getline(buf, 5))},
     79        \ 1000)
     80  call WaitForAssert({-> assert_match('    ^^^', term_getline(buf, 6))}, 1000)
     81  call term_sendkeys(buf, "N\<CR>")
     82  call term_wait(buf)
     83  call WaitForAssert({-> assert_match('    ^^^', term_getline(buf, 6))}, 1000)
     84  call term_sendkeys(buf, "n\<CR>")
     85  call WaitForAssert({-> assert_match('        ^^^', term_getline(buf, 6))},
     86        \ 1000)
     87  call term_sendkeys(buf, "y\<CR>")
     88 
     89  call term_sendkeys(buf, "q\<CR>")
     90  call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
     91 
     92  " Pressing enter in ex mode should print the current line
     93  call term_sendkeys(buf, "\<CR>")
     94  call WaitForAssert({-> assert_match('  3 foo foo', term_getline(buf, 5))}, 1000)
     95  call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
     96 
     97  " The printed line should overwrite the colon
     98  call term_sendkeys(buf, "\<CR>")
     99  call WaitForAssert({-> assert_match('  3 foo foo', term_getline(buf, 4))}, 1000)
    100  call WaitForAssert({-> assert_match('  4 foo foo', term_getline(buf, 5))}, 1000)
    101  call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
    102 
    103  call term_sendkeys(buf, ":vi\<CR>")
    104  call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000)
    105 
    106  call StopVimInTerminal(buf)
    107 endfunc
    108 
    109 " Test for displaying lines from an empty buffer in Ex mode
    110 func Test_Ex_emptybuf()
    111  new
    112  call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E749:')
    113  call setline(1, "abc")
    114  call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E501:')
    115  call assert_fails('call feedkeys("Q%d\<CR>", "xt")', 'E749:')
    116  bw!
    117 endfunc
    118 
    119 " Test for the :open command
    120 func Test_open_command()
    121  throw 'Skipped: Nvim does not have :open'
    122  new
    123  call setline(1, ['foo foo', 'foo bar', 'foo baz'])
    124  call feedkeys("Qopen\<CR>j", 'xt')
    125  call assert_equal('foo bar', getline('.'))
    126  call feedkeys("Qopen /bar/\<CR>", 'xt')
    127  call assert_equal(5, col('.'))
    128  call assert_fails('call feedkeys("Qopen /baz/\<CR>", "xt")', 'E479:')
    129  bw!
    130 endfunc
    131 
    132 func Test_open_command_flush_line()
    133  throw 'Skipped: Nvim does not have :open'
    134  " this was accessing freed memory: the regexp match uses a pointer to the
    135  " current line which becomes invalid when searching for the ') mark.
    136  new
    137  call setline(1, ['one', 'two. three'])
    138  s/one/ONE
    139  try
    140    open /\%')/
    141  catch /E479/
    142  endtry
    143  bwipe!
    144 endfunc
    145 
    146 " FIXME: this doesn't fail without the fix but hangs
    147 func Skip_Test_open_command_state()
    148  " Tricky script that failed because State was not set properly
    149  let lines =<< trim END
    150      !ls ƒ
    151      0scìi
    152      so! Xsourced
    153      set t_û0=0
    154      v/-/o
    155  END
    156  call writefile(lines, 'XopenScript', '')
    157 
    158  let sourced = ["!f\u0083\x02\<Esc>z=0"]
    159  call writefile(sourced, 'Xsourced', 'b')
    160 
    161  CheckRunVimInTerminal
    162  let buf = RunVimInTerminal('-u NONE -i NONE -n -m -X -Z -e -s -S XopenScript -c qa!', #{rows: 6, wait_for_ruler: 0, no_clean: 1})
    163  sleep 3
    164 
    165  call StopVimInTerminal(buf)
    166 endfunc
    167 
    168 " Test for :g/pat/visual to run vi commands in Ex mode
    169 " This used to hang Vim before 8.2.0274.
    170 func Test_Ex_global()
    171  new
    172  call setline(1, ['', 'foo', 'bar', 'foo', 'bar', 'foo'])
    173  call feedkeys("Q\<bs>g/bar/visual\<CR>$rxQ$ryQvisual\<CR>j", "xt")
    174  call assert_equal('bax', getline(3))
    175  call assert_equal('bay', getline(5))
    176  bwipe!
    177 
    178  throw 'Skipped: Nvim only supports Vim Ex mode'
    179  new
    180  call setline(1, ['foo', 'bar'])
    181  call feedkeys("Qg/./i\\\na\\\n.\\\na\\\nb\\\n.", "xt")
    182  call assert_equal(['a', 'b', 'foo', 'a', 'b', 'bar'], getline(1, '$'))
    183  bwipe!
    184 endfunc
    185 
    186 func Test_Ex_shell()
    187  throw 'Skipped: Nvim only supports Vim Ex mode'
    188  CheckUnix
    189 
    190  new
    191  call feedkeys("Qr !echo foo\\\necho bar\n", 'xt')
    192  call assert_equal(['', 'foo', 'bar'], getline(1, '$'))
    193  bwipe!
    194 
    195  new
    196  call feedkeys("Qr !echo foo\\\\\nbar\n", 'xt')
    197  call assert_equal(['', 'foobar'], getline(1, '$'))
    198  bwipe!
    199 
    200  new
    201  call feedkeys("Qr !echo foo\\ \\\necho bar\n", 'xt')
    202  call assert_equal(['', 'foo ', 'bar'], getline(1, '$'))
    203  bwipe!
    204 
    205  new
    206  call setline(1, ['bar', 'baz'])
    207  call feedkeys("Qg/./!echo \\\ns/b/c/", "xt")
    208  call assert_equal(['car', 'caz'], getline(1, '$'))
    209  bwipe!
    210 endfunc
    211 
    212 " Test for pressing Ctrl-C in :append inside a loop in Ex mode
    213 " This used to hang Vim
    214 func Test_Ex_append_in_loop()
    215  CheckRunVimInTerminal
    216  let buf = RunVimInTerminal('', {'rows': 6})
    217 
    218  call term_sendkeys(buf, "gQ")
    219  call term_sendkeys(buf, "for i in range(1)\<CR>")
    220  call term_sendkeys(buf, "append\<CR>")
    221  call WaitForAssert({-> assert_match(':  append', term_getline(buf, 5))}, 1000)
    222  call term_sendkeys(buf, "\<C-C>")
    223  " Wait for input to be flushed
    224  call term_wait(buf)
    225  call term_sendkeys(buf, "foo\<CR>")
    226  call WaitForAssert({-> assert_match('foo', term_getline(buf, 5))}, 1000)
    227  call term_sendkeys(buf, ".\<CR>")
    228  call WaitForAssert({-> assert_match('.', term_getline(buf, 5))}, 1000)
    229  call term_sendkeys(buf, "endfor\<CR>")
    230  call term_sendkeys(buf, "vi\<CR>")
    231  call WaitForAssert({-> assert_match('foo', term_getline(buf, 1))}, 1000)
    232 
    233  call StopVimInTerminal(buf)
    234 endfunc
    235 
    236 " In Ex-mode, a backslash escapes a newline
    237 func Test_Ex_escape_enter()
    238  call feedkeys("gQlet l = \"a\\\<kEnter>b\"\<cr>vi\<cr>", 'xt')
    239  call assert_equal("a\rb", l)
    240 endfunc
    241 
    242 " Test for :append! command in Ex mode
    243 func Test_Ex_append()
    244  throw 'Skipped: Nvim only supports Vim Ex mode'
    245  new
    246  call setline(1, "\t   abc")
    247  call feedkeys("Qappend!\npqr\nxyz\n.\nvisual\n", 'xt')
    248  call assert_equal(["\t   abc", "\t   pqr", "\t   xyz"], getline(1, '$'))
    249  bw!
    250 
    251  new
    252  call feedkeys("Qappend\na\\\n.", 'xt')
    253  call assert_equal(['a\'], getline(1, '$'))
    254  bw!
    255 endfunc
    256 
    257 func Test_ex_mode_errors()
    258  " Not allowed to enter ex mode when text is locked
    259  au InsertCharPre <buffer> normal! gQ<CR>
    260  let caught_e565 = 0
    261  try
    262    call feedkeys("ix\<esc>", 'xt')
    263  catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
    264    let caught_e565 = 1
    265  endtry
    266  call assert_equal(1, caught_e565)
    267  au! InsertCharPre
    268 
    269  new
    270  au CmdLineEnter * call ExEnterFunc()
    271  func ExEnterFunc()
    272 
    273  endfunc
    274  call feedkeys("gQvi\r", 'xt')
    275 
    276  au! CmdLineEnter
    277  delfunc ExEnterFunc
    278 
    279  au CmdlineEnter * :
    280  call feedkeys("gQecho 1\r", 'xt')
    281 
    282  au! CmdlineEnter
    283 
    284  quit
    285 endfunc
    286 
    287 func Test_ex_mode_with_global()
    288  CheckNotGui
    289  CheckFeature timers
    290 
    291  " This will get stuck in Normal mode after the failed "J", use a timer to
    292  " get going again.
    293  let lines =<< trim END
    294    " call ch_logfile('logfile', 'w')
    295    pedit
    296    func FeedQ(id)
    297      call feedkeys('gQ', 't')
    298    endfunc
    299    call timer_start(10, 'FeedQ')
    300    g/^/vi|HJ
    301    call writefile(['done'], 'Xdidexmode')
    302    qall!
    303  END
    304  call writefile(lines, 'Xexmodescript')
    305  call assert_equal(1, RunVim([], [], '-e -s -S Xexmodescript'))
    306  call assert_equal(['done'], readfile('Xdidexmode'))
    307 
    308  call delete('Xdidexmode')
    309  call delete('Xexmodescript')
    310 endfunc
    311 
    312 func Test_ex_mode_count_overflow()
    313  " The multiplication causes an integer overflow
    314  CheckNotAsan
    315 
    316  " this used to cause a crash
    317  let lines =<< trim END
    318    call feedkeys("\<Esc>gQ\<CR>")
    319    v9|9silent! vi|333333233333y32333333%O
    320    call writefile(['done'], 'Xdidexmode')
    321    qall!
    322  END
    323  call writefile(lines, 'Xexmodescript')
    324  call assert_equal(1, RunVim([], [], '-e -s -S Xexmodescript -c qa'))
    325  call assert_equal(['done'], readfile('Xdidexmode'))
    326 
    327  call delete('Xdidexmode')
    328  call delete('Xexmodescript')
    329 endfunc
    330 
    331 func Test_ex_mode_large_indent()
    332  new
    333  set ts=500 ai
    334  call setline(1, "\t")
    335  exe "normal gQi\<CR>."
    336  set ts=8 noai
    337  bwipe!
    338 endfunc
    339 
    340 " This was accessing illegal memory when using "+" for eap->cmd.
    341 func Test_empty_command_visual_mode()
    342  let lines =<< trim END
    343      r<sfile>
    344      0norm0V:
    345      :qall!
    346  END
    347  call writefile(lines, 'Xexmodescript')
    348  call assert_equal(1, RunVim([], [], '-u NONE -e -s -S Xexmodescript'))
    349 
    350  call delete('Xexmodescript')
    351 endfunc
    352 
    353 " Test using backslash in ex-mode
    354 func Test_backslash_multiline()
    355  throw 'Skipped: Nvim only supports Vim Ex mode'
    356  new
    357  call setline(1, 'enum')
    358  call feedkeys('Qg/enum/i\\.', "xt")
    359  call assert_equal(["", "enum"], getline(1, 2))
    360 endfunc
    361 
    362 " Test using backslash in ex-mode after patch 9.1.0535
    363 func Test_backslash_multiline2()
    364  throw 'Skipped: Nvim only supports Vim Ex mode'
    365  new
    366  call feedkeys('QaX \\Y.', "xt")
    367  call assert_equal(['X \\', "Y"], getline(1, 2))
    368 endfunc
    369 
    370 " Testing implicit print command
    371 func Test_implicit_print()
    372  new
    373  call setline(1, ['one', 'two', 'three'])
    374  call feedkeys('Q:let a=execute(":1,2")', 'xt')
    375  call feedkeys('Q:let b=execute(":3")', 'xt')
    376  call assert_equal('one two', a->split('\n')->join(' '))
    377  call assert_equal('three', b->split('\n')->join(' '))
    378  bw!
    379 endfunc
    380 
    381 " Test inserting text after the trailing bar
    382 func Test_insert_after_trailing_bar()
    383  new
    384  call feedkeys("Qi|\nfoo\n.\na|bar\nbar\n.\nc|baz\n.", "xt")
    385  call assert_equal(['', 'foo', 'bar', 'baz'], getline(1, '$'))
    386  bwipe!
    387 endfunc
    388 
    389 " Test global insert of a newline without terminating period
    390 func Test_global_insert_newline()
    391  new
    392  call setline(1, ['foo'])
    393  call feedkeys("Qg/foo/i\\\n", "xt")
    394  call assert_equal(['', 'foo'], getline(1, '$'))
    395  bwipe!
    396 endfunc
    397 
    398 " An empty command followed by a newline shouldn't cause E749 in Ex mode.
    399 func Test_ex_empty_command_newline()
    400  let g:var = 0
    401  call feedkeys("gQexecute \"\\nlet g:var = 1\"\r", 'xt')
    402  call assert_equal(1, g:var)
    403  call feedkeys("gQexecute \"  \\nlet g:var = 2\"\r", 'xt')
    404  call assert_equal(2, g:var)
    405  call feedkeys("gQexecute \"\\t \\nlet g:var = 3\"\r", 'xt')
    406  call assert_equal(3, g:var)
    407  call feedkeys("gQexecute \"\\\"?!\\nlet g:var = 4\"\r", 'xt')
    408  call assert_equal(4, g:var)
    409  call feedkeys("gQexecute \"  \\\"?!\\nlet g:var = 5\"\r", 'xt')
    410  call assert_equal(5, g:var)
    411  unlet g:var
    412 endfunc
    413 
    414 " vim: shiftwidth=2 sts=2 expandtab