meta_key_spec.lua (5796B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 4 local clear, feed, insert = n.clear, n.feed, n.insert 5 local command = n.command 6 local exec_lua = n.exec_lua 7 local eval = n.eval 8 local expect = n.expect 9 local fn = n.fn 10 local eq = t.eq 11 12 describe('meta-keys #8226 #13042', function() 13 before_each(function() 14 clear() 15 end) 16 17 it('ALT/META, normal-mode', function() 18 -- Unmapped ALT-chord behaves as ESC+c. 19 insert('hello') 20 feed('0<A-x><M-x>') 21 expect('llo') 22 -- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869 23 command('nnoremap <ESC> A<lt>ESC><Esc>') 24 command('nnoremap ; A;<Esc>') 25 feed('<A-;><M-;>') 26 expect('llo<ESC>;<ESC>;') 27 -- Mapped ALT-chord behaves as mapped. 28 command('nnoremap <M-l> Ameta-l<Esc>') 29 command('nnoremap <A-j> Aalt-j<Esc>') 30 feed('<A-j><M-l>') 31 expect('llo<ESC>;<ESC>;alt-jmeta-l') 32 -- Unmapped ALT-chord with characters containing K_SPECIAL bytes 33 command('nnoremap … A…<Esc>') 34 feed('<A-…><M-…>') 35 expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…') 36 command("execute 'nnoremap' nr2char(0x40000000) 'AMAX<Esc>'") 37 command("call nvim_input('<A-'.nr2char(0x40000000).'>')") 38 command("call nvim_input('<M-'.nr2char(0x40000000).'>')") 39 expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX') 40 end) 41 42 it('ALT/META, visual-mode', function() 43 -- Unmapped ALT-chords behave as ESC+c 44 insert('peaches') 45 feed('viw<A-x>viw<M-x>') 46 expect('peach') 47 -- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869 48 command('vnoremap <ESC> A<lt>ESC>') 49 feed('viw<A-;><Esc>viw<M-;><Esc>') 50 expect('peach<ESC>;<ESC>;') 51 -- Mapped ALT-chord behaves as mapped. 52 command('vnoremap <M-l> Ameta-l<Esc>') 53 command('vnoremap <A-j> Aalt-j<Esc>') 54 feed('viw<A-j>viw<M-l>') 55 expect('peach<ESC>;<ESC>;alt-jmeta-l') 56 -- Unmapped ALT-chord with characters containing K_SPECIAL bytes 57 feed('viw<A-…><Esc>viw<M-…><Esc>') 58 expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…') 59 command("execute 'inoremap' nr2char(0x40000000) 'MAX'") 60 command("call nvim_input('viw<A-'.nr2char(0x40000000).'><Esc>')") 61 command("call nvim_input('viw<M-'.nr2char(0x40000000).'><Esc>')") 62 expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX') 63 end) 64 65 it('ALT/META insert-mode', function() 66 -- Mapped ALT-chord behaves as mapped. 67 command('inoremap <M-l> meta-l') 68 command('inoremap <A-j> alt-j') 69 feed('i<M-l> xxx <A-j><M-h>a<A-h>') 70 expect('meta-l xxx alt-j') 71 eq({ 0, 1, 14, 0 }, fn.getpos('.')) 72 -- Unmapped ALT-chord behaves as ESC+c. 73 command('iunmap <M-l>') 74 feed('0i<M-l>') 75 eq({ 0, 1, 2, 0 }, fn.getpos('.')) 76 -- Unmapped ALT-chord has same `undo` characteristics as ESC+<key> 77 command('0,$d') 78 feed('ahello<M-.>') 79 expect('hellohello') 80 feed('u') 81 expect('hello') 82 end) 83 84 it('ALT/META terminal-mode', function() 85 exec_lua([[ 86 _G.input_data = '' 87 vim.api.nvim_open_term(0, { on_input = function(_, _, _, data) 88 _G.input_data = _G.input_data .. vim.fn.strtrans(data) 89 end }) 90 ]]) 91 -- Mapped ALT-chord behaves as mapped. 92 command('tnoremap <M-l> meta-l') 93 command('tnoremap <A-j> alt-j') 94 feed('i<M-l> xxx <A-j>') 95 eq('meta-l xxx alt-j', exec_lua([[return _G.input_data]])) 96 -- Unmapped ALT-chord is sent to terminal as-is. #16202 #16220 97 exec_lua([[_G.input_data = '']]) 98 command('tunmap <M-l>') 99 feed('<M-l>') 100 local meta_l_seq = exec_lua([[return _G.input_data]]) 101 command('tnoremap <Esc> <C-\\><C-N>') 102 feed('yyy<M-l><A-j>') 103 eq(meta_l_seq .. 'yyy' .. meta_l_seq .. 'alt-j', exec_lua([[return _G.input_data]])) 104 eq('t', eval('mode(1)')) 105 feed('<Esc>j') 106 eq({ 0, 2, 1, 0 }, fn.getpos('.')) 107 eq('nt', eval('mode(1)')) 108 end) 109 110 it('ALT/META when recording a macro #13235', function() 111 command('inoremap <M-Esc> <lt>M-ESC>') 112 feed('ifoo<CR>bar<CR>baz<Esc>gg0') 113 -- <M-"> is reinterpreted as <Esc>" 114 feed('qrviw"ayC// This is some text: <M-">apq') 115 expect([[ 116 // This is some text: foo 117 bar 118 baz]]) 119 -- Should not insert an extra double quote or trigger <M-Esc> when replaying 120 feed('j0@rj0@@') 121 expect([[ 122 // This is some text: foo 123 // This is some text: bar 124 // This is some text: baz]]) 125 command('%delete') 126 end) 127 128 it('ALT/META with special key when recording a macro', function() 129 command('inoremap <M-Esc> <lt>M-ESC>') 130 command('noremap <S-Tab> "') 131 command('noremap! <S-Tab> "') 132 feed('ifoo<CR>bar<CR>baz<Esc>gg0') 133 -- <M-S-Tab> is reinterpreted as <Esc><S-Tab> 134 feed('qrviw<S-Tab>ayC// This is some text: <M-S-Tab>apq') 135 expect([[ 136 // This is some text: foo 137 bar 138 baz]]) 139 -- Should not insert an extra double quote or trigger <M-Esc> when replaying 140 feed('j0@rj0@@') 141 expect([[ 142 // This is some text: foo 143 // This is some text: bar 144 // This is some text: baz]]) 145 end) 146 147 it('ALT/META with vim.on_key()', function() 148 feed('ifoo<CR>bar<CR>baz<Esc>gg0viw"ay') 149 command('nnoremap … "') 150 151 exec_lua [[ 152 keys = {} 153 typed = {} 154 155 vim.on_key(function(buf, typed_buf) 156 table.insert(keys, vim.fn.keytrans(buf)) 157 table.insert(typed, vim.fn.keytrans(typed_buf)) 158 end) 159 ]] 160 161 -- <M-"> and <M-…> are reinterpreted as <Esc>" and <Esc>… 162 feed('c$FOO.<M-">apA.<M-…>ap') 163 expect([[ 164 FOO.foo.foo 165 bar 166 baz]]) 167 168 -- vim.on_key() callback should only receive <Esc>" and <Esc>… 169 eq('c$FOO.<Esc>"apA.<Esc>"ap', exec_lua [[return table.concat(keys, '')]]) 170 eq('c$FOO.<Esc>"apA.<Esc>…ap', exec_lua [[return table.concat(typed, '')]]) 171 end) 172 end)