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)