input_spec.lua (15202B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local clear = n.clear 6 local feed, next_msg, eq = n.feed, n.next_msg, t.eq 7 local command = n.command 8 local expect = n.expect 9 local curbuf_contents = n.curbuf_contents 10 local api = n.api 11 local exec_lua = n.exec_lua 12 local write_file = t.write_file 13 local fn = n.fn 14 local eval = n.eval 15 16 before_each(clear) 17 18 describe('mappings', function() 19 local add_mapping = function(mapping, send) 20 local cmd = 'nnoremap ' 21 .. mapping 22 .. " :call rpcnotify(1, 'mapped', '" 23 .. send:gsub('<', '<lt>') 24 .. "')<cr>" 25 command(cmd) 26 end 27 28 local check_mapping = function(mapping, expected) 29 feed(mapping) 30 eq({ 'notification', 'mapped', { expected } }, next_msg()) 31 end 32 33 before_each(function() 34 add_mapping('<A-l>', '<A-l>') 35 add_mapping('<A-L>', '<A-L>') 36 add_mapping('<D-l>', '<D-l>') 37 add_mapping('<D-L>', '<D-L>') 38 add_mapping('<C-L>', '<C-L>') 39 add_mapping('<C-S-L>', '<C-S-L>') 40 add_mapping('<s-up>', '<s-up>') 41 add_mapping('<s-up>', '<s-up>') 42 add_mapping('<c-s-up>', '<c-s-up>') 43 add_mapping('<c-s-a-up>', '<c-s-a-up>') 44 add_mapping('<c-s-a-d-up>', '<c-s-a-d-up>') 45 add_mapping('<c-d-a>', '<c-d-a>') 46 add_mapping('<d-1>', '<d-1>') 47 add_mapping('<khome>', '<khome>') 48 add_mapping('<kup>', '<kup>') 49 add_mapping('<kpageup>', '<kpageup>') 50 add_mapping('<kleft>', '<kleft>') 51 add_mapping('<korigin>', '<korigin>') 52 add_mapping('<kright>', '<kright>') 53 add_mapping('<kend>', '<kend>') 54 add_mapping('<kdown>', '<kdown>') 55 add_mapping('<kpagedown>', '<kpagedown>') 56 add_mapping('<kinsert>', '<kinsert>') 57 add_mapping('<kdel>', '<kdel>') 58 add_mapping('<kdivide>', '<kdivide>') 59 add_mapping('<kmultiply>', '<kmultiply>') 60 add_mapping('<kminus>', '<kminus>') 61 add_mapping('<kplus>', '<kplus>') 62 add_mapping('<kenter>', '<kenter>') 63 add_mapping('<kcomma>', '<kcomma>') 64 add_mapping('<kequal>', '<kequal>') 65 add_mapping('<find>', '<find>') 66 add_mapping('<select>', '<select>') 67 add_mapping('<f38>', '<f38>') 68 add_mapping('<f63>', '<f63>') 69 end) 70 71 it('ok', function() 72 check_mapping('<A-l>', '<A-l>') 73 check_mapping('<A-L>', '<A-L>') 74 check_mapping('<A-S-l>', '<A-L>') 75 check_mapping('<A-S-L>', '<A-L>') 76 check_mapping('<D-l>', '<D-l>') 77 check_mapping('<D-L>', '<D-L>') 78 check_mapping('<D-S-l>', '<D-L>') 79 check_mapping('<D-S-L>', '<D-L>') 80 check_mapping('<C-l>', '<C-L>') 81 check_mapping('<C-L>', '<C-L>') 82 check_mapping('<C-S-l>', '<C-S-L>') 83 check_mapping('<C-S-L>', '<C-S-L>') 84 check_mapping('<s-up>', '<s-up>') 85 check_mapping('<c-s-up>', '<c-s-up>') 86 check_mapping('<s-c-up>', '<c-s-up>') 87 check_mapping('<c-s-a-up>', '<c-s-a-up>') 88 check_mapping('<s-c-a-up>', '<c-s-a-up>') 89 check_mapping('<c-a-s-up>', '<c-s-a-up>') 90 check_mapping('<s-a-c-up>', '<c-s-a-up>') 91 check_mapping('<a-c-s-up>', '<c-s-a-up>') 92 check_mapping('<a-s-c-up>', '<c-s-a-up>') 93 check_mapping('<c-s-a-d-up>', '<c-s-a-d-up>') 94 check_mapping('<s-a-d-c-up>', '<c-s-a-d-up>') 95 check_mapping('<d-s-a-c-up>', '<c-s-a-d-up>') 96 check_mapping('<c-d-a>', '<c-d-a>') 97 check_mapping('<d-c-a>', '<c-d-a>') 98 check_mapping('<d-1>', '<d-1>') 99 check_mapping('<khome>', '<khome>') 100 check_mapping('<KP7>', '<khome>') 101 check_mapping('<kup>', '<kup>') 102 check_mapping('<KP8>', '<kup>') 103 check_mapping('<kpageup>', '<kpageup>') 104 check_mapping('<KP9>', '<kpageup>') 105 check_mapping('<kleft>', '<kleft>') 106 check_mapping('<KP4>', '<kleft>') 107 check_mapping('<korigin>', '<korigin>') 108 check_mapping('<KP5>', '<korigin>') 109 check_mapping('<kright>', '<kright>') 110 check_mapping('<KP6>', '<kright>') 111 check_mapping('<kend>', '<kend>') 112 check_mapping('<KP1>', '<kend>') 113 check_mapping('<kdown>', '<kdown>') 114 check_mapping('<KP2>', '<kdown>') 115 check_mapping('<kpagedown>', '<kpagedown>') 116 check_mapping('<KP3>', '<kpagedown>') 117 check_mapping('<kinsert>', '<kinsert>') 118 check_mapping('<KP0>', '<kinsert>') 119 check_mapping('<kdel>', '<kdel>') 120 check_mapping('<KPPeriod>', '<kdel>') 121 check_mapping('<kdivide>', '<kdivide>') 122 check_mapping('<KPDiv>', '<kdivide>') 123 check_mapping('<kmultiply>', '<kmultiply>') 124 check_mapping('<KPMult>', '<kmultiply>') 125 check_mapping('<kminus>', '<kminus>') 126 check_mapping('<KPMinus>', '<kminus>') 127 check_mapping('<kplus>', '<kplus>') 128 check_mapping('<KPPlus>', '<kplus>') 129 check_mapping('<kenter>', '<kenter>') 130 check_mapping('<KPEnter>', '<kenter>') 131 check_mapping('<kcomma>', '<kcomma>') 132 check_mapping('<KPComma>', '<kcomma>') 133 check_mapping('<kequal>', '<kequal>') 134 check_mapping('<KPEquals>', '<kequal>') 135 check_mapping('<Find>', '<find>') 136 check_mapping('<Select>', '<select>') 137 check_mapping('<f38>', '<f38>') 138 check_mapping('<f63>', '<f63>') 139 end) 140 141 it('support meta + multibyte char mapping', function() 142 add_mapping('<m-ä>', '<m-ä>') 143 check_mapping('<m-ä>', '<m-ä>') 144 end) 145 end) 146 147 describe('input utf sequences that contain K_SPECIAL (0x80)', function() 148 it('ok', function() 149 feed('i…<esc>') 150 expect('…') 151 end) 152 153 it('can be mapped', function() 154 command('inoremap … E280A6') 155 feed('i…<esc>') 156 expect('E280A6') 157 end) 158 end) 159 160 describe('input utf sequences that contain CSI (0x9B)', function() 161 it('ok', function() 162 feed('iě<esc>') 163 expect('ě') 164 end) 165 166 it('can be mapped', function() 167 command('inoremap ě C49B') 168 feed('iě<esc>') 169 expect('C49B') 170 end) 171 end) 172 173 describe('input split utf sequences', function() 174 it('ok', function() 175 local str = '►' 176 feed('i' .. str:sub(1, 1)) 177 vim.uv.sleep(10) 178 feed(str:sub(2, 3)) 179 expect('►') 180 end) 181 182 it('can be mapped', function() 183 command('inoremap ► E296BA') 184 local str = '►' 185 feed('i' .. str:sub(1, 1)) 186 vim.uv.sleep(10) 187 feed(str:sub(2, 3)) 188 expect('E296BA') 189 end) 190 end) 191 192 describe('input pairs', function() 193 describe('<tab> / <c-i>', function() 194 it('ok', function() 195 feed('i<tab><c-i><esc>') 196 eq('\t\t', curbuf_contents()) 197 end) 198 199 describe('can be mapped separately', function() 200 it('if <tab> is mapped after <c-i>', function() 201 command('inoremap <c-i> CTRL-I!') 202 command('inoremap <tab> TAB!') 203 feed('i<tab><c-i><esc>') 204 eq('TAB!CTRL-I!', curbuf_contents()) 205 end) 206 207 it('if <tab> is mapped before <c-i>', function() 208 command('inoremap <tab> TAB!') 209 command('inoremap <c-i> CTRL-I!') 210 feed('i<tab><c-i><esc>') 211 eq('TAB!CTRL-I!', curbuf_contents()) 212 end) 213 end) 214 end) 215 216 describe('<cr> / <c-m>', function() 217 it('ok', function() 218 feed('iunos<c-m>dos<cr>tres<esc>') 219 eq('unos\ndos\ntres', curbuf_contents()) 220 end) 221 222 describe('can be mapped separately', function() 223 it('if <cr> is mapped after <c-m>', function() 224 command('inoremap <c-m> SNIPPET!') 225 command('inoremap <cr> , and then<cr>') 226 feed('iunos<c-m>dos<cr>tres<esc>') 227 eq('unosSNIPPET!dos, and then\ntres', curbuf_contents()) 228 end) 229 230 it('if <cr> is mapped before <c-m>', function() 231 command('inoremap <cr> , and then<cr>') 232 command('inoremap <c-m> SNIPPET!') 233 feed('iunos<c-m>dos<cr>tres<esc>') 234 eq('unosSNIPPET!dos, and then\ntres', curbuf_contents()) 235 end) 236 end) 237 end) 238 239 describe('<esc> / <c-[>', function() 240 it('ok', function() 241 feed('2adouble<c-[>asingle<esc>') 242 eq('doubledoublesingle', curbuf_contents()) 243 end) 244 245 describe('can be mapped separately', function() 246 it('if <esc> is mapped after <c-[>', function() 247 command('inoremap <c-[> HALLOJ!') 248 command('inoremap <esc> ,<esc>') 249 feed('2adubbel<c-[>upp<esc>') 250 eq('dubbelHALLOJ!upp,dubbelHALLOJ!upp,', curbuf_contents()) 251 end) 252 253 it('if <esc> is mapped before <c-[>', function() 254 command('inoremap <esc> ,<esc>') 255 command('inoremap <c-[> HALLOJ!') 256 feed('2adubbel<c-[>upp<esc>') 257 eq('dubbelHALLOJ!upp,dubbelHALLOJ!upp,', curbuf_contents()) 258 end) 259 end) 260 end) 261 end) 262 263 it('Ctrl-6 is Ctrl-^ vim-patch:8.1.2333', function() 264 command('split aaa') 265 command('edit bbb') 266 feed('<C-6>') 267 eq('aaa', fn.bufname()) 268 end) 269 270 it('c_CTRL-R_CTRL-R, i_CTRL-R_CTRL-R, i_CTRL-G_CTRL-K work properly vim-patch:8.1.2346', function() 271 command('set timeoutlen=10') 272 273 command([[let @a = 'aaa']]) 274 feed([[:let x = '<C-R><C-R>a'<CR>]]) 275 eq([[let x = 'aaa']], eval('@:')) 276 277 feed('a<C-R><C-R>a<Esc>') 278 expect('aaa') 279 command('bwipe!') 280 281 feed('axx<CR>yy<C-G><C-K>a<Esc>') 282 expect([[ 283 axx 284 yy]]) 285 end) 286 287 it('typing a simplifiable key at hit-enter prompt triggers mapping vim-patch:8.2.0839', function() 288 local screen = Screen.new(60, 8) 289 command([[nnoremap <C-6> <Cmd>echo 'hit ctrl-6'<CR>]]) 290 feed(':ls<CR>') 291 screen:expect([[ 292 | 293 {1:~ }|*3 294 {3: }| 295 :ls | 296 1 %a "[No Name]" line 1 | 297 {6:Press ENTER or type command to continue}^ | 298 ]]) 299 feed('<C-6>') 300 screen:expect([[ 301 ^ | 302 {1:~ }|*6 303 hit ctrl-6 | 304 ]]) 305 end) 306 307 it('mixing simplified and unsimplified keys can trigger mapping vim-patch:8.2.0916', function() 308 command('set timeoutlen=10') 309 command([[imap ' <C-W>]]) 310 command('imap <C-W><C-A> c-a') 311 feed([[a'<C-A>]]) 312 expect('c-a') 313 end) 314 315 it('unsimplified mapping works when there was a partial match vim-patch:8.2.4504', function() 316 command('set timeoutlen=10') 317 command('nnoremap <C-J> a') 318 command('nnoremap <NL> x') 319 command('nnoremap <C-J>x <Nop>') 320 fn.setline(1, 'x') 321 -- CTRL-J b should have trigger the <C-J> mapping and then insert "b" 322 feed('<C-J>b<Esc>') 323 expect('xb') 324 end) 325 326 describe('input non-printable chars', function() 327 after_each(function() 328 os.remove('Xtest-overwrite') 329 end) 330 331 it("doesn't crash when echoing them back", function() 332 write_file('Xtest-overwrite', [[foobar]]) 333 local screen = Screen.new(60, 8) 334 command('set shortmess-=F') 335 336 command('e Xtest-overwrite') 337 screen:expect([[ 338 ^foobar | 339 {1:~ }|*6 340 "Xtest-overwrite" [noeol] 1L, 6B | 341 ]]) 342 343 -- Wait for some time so that the timestamp changes. 344 vim.uv.sleep(10) 345 write_file('Xtest-overwrite', [[smurf]]) 346 feed(':w<CR>') 347 screen:expect([[ 348 foobar | 349 {1:~ }|*3 350 {3: }| 351 "Xtest-overwrite" | 352 {9:WARNING: The file has been changed since reading it!!!} | 353 {6:Do you really want to write to it (y/n)?}^ | 354 ]]) 355 356 feed('u') 357 screen:expect([[ 358 foobar | 359 {1:~ }|*2 360 {3: }| 361 "Xtest-overwrite" | 362 {9:WARNING: The file has been changed since reading it!!!} | 363 {6:Do you really want to write to it (y/n)?}u | 364 {6:Do you really want to write to it (y/n)?}^ | 365 ]]) 366 367 feed('\005') 368 screen:expect([[ 369 foobar | 370 {1:~ }| 371 {3: }| 372 "Xtest-overwrite" | 373 {9:WARNING: The file has been changed since reading it!!!} | 374 {6:Do you really want to write to it (y/n)?}u | 375 {6:Do you really want to write to it (y/n)?}{18:^E} | 376 {6:Do you really want to write to it (y/n)?}^ | 377 ]]) 378 379 feed('n') 380 screen:expect([[ 381 foobar | 382 {3: }| 383 "Xtest-overwrite" | 384 {9:WARNING: The file has been changed since reading it!!!} | 385 {6:Do you really want to write to it (y/n)?}u | 386 {6:Do you really want to write to it (y/n)?}{18:^E} | 387 {6:Do you really want to write to it (y/n)?}n | 388 {6:Press ENTER or type command to continue}^ | 389 ]]) 390 391 feed('<cr>') 392 screen:expect([[ 393 ^foobar | 394 {1:~ }|*6 395 | 396 ]]) 397 end) 398 end) 399 400 describe('event processing and input', function() 401 it('not blocked by event bursts', function() 402 api.nvim_set_keymap( 403 '', 404 '<f2>', 405 "<cmd>lua vim.rpcnotify(1, 'stop') winning = true <cr>", 406 { noremap = true } 407 ) 408 409 exec_lua [[ 410 winning = false 411 burst = vim.schedule_wrap(function(tell) 412 if tell then 413 vim.rpcnotify(1, 'start') 414 end 415 -- Are we winning, son? 416 if not winning then 417 burst(false) 418 end 419 end) 420 burst(true) 421 ]] 422 423 eq({ 'notification', 'start', {} }, next_msg()) 424 feed '<f2>' 425 eq({ 'notification', 'stop', {} }, next_msg()) 426 end) 427 end) 428 429 describe('display is updated', function() 430 local screen 431 before_each(function() 432 screen = Screen.new(60, 8) 433 end) 434 435 it('in Insert mode after <Nop> mapping #17911', function() 436 command('imap <Plug>test <Nop>') 437 command('imap <F2> abc<CR><Plug>test') 438 feed('i<F2>') 439 screen:expect([[ 440 abc | 441 ^ | 442 {1:~ }|*5 443 {5:-- INSERT --} | 444 ]]) 445 end) 446 447 it('in Insert mode after empty string <expr> mapping #17911', function() 448 command('imap <expr> <Plug>test ""') 449 command('imap <F2> abc<CR><Plug>test') 450 feed('i<F2>') 451 screen:expect([[ 452 abc | 453 ^ | 454 {1:~ }|*5 455 {5:-- INSERT --} | 456 ]]) 457 end) 458 end)