local helpers = require('test.functional.helpers')(after_each) local clear, feed_command = helpers.clear, helpers.feed_command local feed, next_msg, eq = helpers.feed, helpers.next_msg, helpers.eq local command = helpers.command local expect = helpers.expect local curbuf_contents = helpers.curbuf_contents local api = helpers.api local exec_lua = helpers.exec_lua local write_file = helpers.write_file local fn = helpers.fn local eval = helpers.eval local Screen = require('test.functional.ui.screen') before_each(clear) describe('mappings', function() local add_mapping = function(mapping, send) local cmd = 'nnoremap ' .. mapping .. " :call rpcnotify(1, 'mapped', '" .. send:gsub('<', '') .. "')" feed_command(cmd) end local check_mapping = function(mapping, expected) feed(mapping) eq({ 'notification', 'mapped', { expected } }, next_msg()) end before_each(function() add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') add_mapping('', '') end) it('ok', function() check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') check_mapping('', '') end) it('support meta + multibyte char mapping', function() add_mapping('', '') check_mapping('', '') end) end) describe('input utf sequences that contain K_SPECIAL (0x80)', function() it('ok', function() feed('i…') expect('…') end) it('can be mapped', function() command('inoremap … E280A6') feed('i…') expect('E280A6') end) end) describe('input utf sequences that contain CSI (0x9B)', function() it('ok', function() feed('iě') expect('ě') end) it('can be mapped', function() command('inoremap ě C49B') feed('iě') expect('C49B') end) end) describe('input split utf sequences', function() it('ok', function() local str = '►' feed('i' .. str:sub(1, 1)) vim.uv.sleep(10) feed(str:sub(2, 3)) expect('►') end) it('can be mapped', function() command('inoremap ► E296BA') local str = '►' feed('i' .. str:sub(1, 1)) vim.uv.sleep(10) feed(str:sub(2, 3)) expect('E296BA') end) end) describe('input pairs', function() describe(' / ', function() it('ok', function() feed('i') eq('\t\t', curbuf_contents()) end) describe('can be mapped separately', function() it('if is mapped after ', function() command('inoremap CTRL-I!') command('inoremap TAB!') feed('i') eq('TAB!CTRL-I!', curbuf_contents()) end) it('if is mapped before ', function() command('inoremap TAB!') command('inoremap CTRL-I!') feed('i') eq('TAB!CTRL-I!', curbuf_contents()) end) end) end) describe(' / ', function() it('ok', function() feed('iunosdostres') eq('unos\ndos\ntres', curbuf_contents()) end) describe('can be mapped separately', function() it('if is mapped after ', function() command('inoremap SNIPPET!') command('inoremap , and then') feed('iunosdostres') eq('unosSNIPPET!dos, and then\ntres', curbuf_contents()) end) it('if is mapped before ', function() command('inoremap , and then') command('inoremap SNIPPET!') feed('iunosdostres') eq('unosSNIPPET!dos, and then\ntres', curbuf_contents()) end) end) end) describe(' / ', function() it('ok', function() feed('2adoubleasingle') eq('doubledoublesingle', curbuf_contents()) end) describe('can be mapped separately', function() it('if is mapped after ', function() command('inoremap HALLOJ!') command('inoremap ,') feed('2adubbelupp') eq('dubbelHALLOJ!upp,dubbelHALLOJ!upp,', curbuf_contents()) end) it('if is mapped before ', function() command('inoremap ,') command('inoremap HALLOJ!') feed('2adubbelupp') eq('dubbelHALLOJ!upp,dubbelHALLOJ!upp,', curbuf_contents()) end) end) end) end) it('Ctrl-6 is Ctrl-^ vim-patch:8.1.2333', function() command('split aaa') command('edit bbb') feed('') eq('aaa', fn.bufname()) end) it('c_CTRL-R_CTRL-R, i_CTRL-R_CTRL-R, i_CTRL-G_CTRL-K work properly vim-patch:8.1.2346', function() command('set timeoutlen=10') command([[let @a = 'aaa']]) feed([[:let x = 'a']]) eq([[let x = 'aaa']], eval('@:')) feed('aa') expect('aaa') command('bwipe!') feed('axxyya') expect([[ axx yy]]) end) it('typing a simplifiable key at hit-enter prompt triggers mapping vim-patch:8.2.0839', function() local screen = Screen.new(60, 8) screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText [2] = { bold = true, reverse = true }, -- MsgSeparator [3] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg }) screen:attach() command([[nnoremap echo 'hit ctrl-6']]) feed_command('ls') screen:expect([[ | {1:~ }|*3 {2: }| :ls | 1 %a "[No Name]" line 1 | {3:Press ENTER or type command to continue}^ | ]]) feed('') screen:expect([[ ^ | {1:~ }|*6 hit ctrl-6 | ]]) end) it('mixing simplified and unsimplified keys can trigger mapping vim-patch:8.2.0916', function() command('set timeoutlen=10') command([[imap ' ]]) command('imap c-a') feed([[a']]) expect('c-a') end) it('unsimplified mapping works when there was a partial match vim-patch:8.2.4504', function() command('set timeoutlen=10') command('nnoremap a') command('nnoremap x') command('nnoremap x ') fn.setline(1, 'x') -- CTRL-J b should have trigger the mapping and then insert "b" feed('b') expect('xb') end) describe('input non-printable chars', function() after_each(function() os.remove('Xtest-overwrite') end) it("doesn't crash when echoing them back", function() write_file('Xtest-overwrite', [[foobar]]) local screen = Screen.new(60, 8) screen:set_default_attr_ids { [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, [4] = { bold = true, reverse = true }, } screen:attach() command('set shortmess-=F') feed_command('e Xtest-overwrite') screen:expect([[ ^foobar | {1:~ }|*6 "Xtest-overwrite" [noeol] 1L, 6B | ]]) -- The timestamp is in second resolution, wait two seconds to be sure. screen:sleep(2000) write_file('Xtest-overwrite', [[smurf]]) feed_command('w') screen:expect([[ foobar | {1:~ }|*3 {4: }| "Xtest-overwrite" | {2:WARNING: The file has been changed since reading it!!!} | {3:Do you really want to write to it (y/n)?}^ | ]]) feed('u') screen:expect([[ foobar | {1:~ }|*2 {4: }| "Xtest-overwrite" | {2:WARNING: The file has been changed since reading it!!!} | {3:Do you really want to write to it (y/n)?}u | {3:Do you really want to write to it (y/n)?}^ | ]]) feed('\005') screen:expect([[ foobar | {1:~ }| {4: }| "Xtest-overwrite" | {2:WARNING: The file has been changed since reading it!!!} | {3:Do you really want to write to it (y/n)?}u | {3:Do you really want to write to it (y/n)?} | {3:Do you really want to write to it (y/n)?}^ | ]]) feed('n') screen:expect([[ foobar | {4: }| "Xtest-overwrite" | {2:WARNING: The file has been changed since reading it!!!} | {3:Do you really want to write to it (y/n)?}u | {3:Do you really want to write to it (y/n)?} | {3:Do you really want to write to it (y/n)?}n | {3:Press ENTER or type command to continue}^ | ]]) feed('') screen:expect([[ ^foobar | {1:~ }|*6 | ]]) end) end) describe('event processing and input', function() it('not blocked by event bursts', function() api.nvim_set_keymap( '', '', "lua vim.rpcnotify(1, 'stop') winning = true ", { noremap = true } ) exec_lua [[ winning = false burst = vim.schedule_wrap(function(tell) if tell then vim.rpcnotify(1, 'start') end -- Are we winning, son? if not winning then burst(false) end end) burst(true) ]] eq({ 'notification', 'start', {} }, next_msg()) feed '' eq({ 'notification', 'stop', {} }, next_msg()) end) end) describe('display is updated', function() local screen before_each(function() screen = Screen.new(60, 8) screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, -- NonText [2] = { bold = true }, -- ModeMsg }) screen:attach() end) it('in Insert mode after mapping #17911', function() command('imap test ') command('imap abctest') feed('i') screen:expect([[ abc | ^ | {1:~ }|*5 {2:-- INSERT --} | ]]) end) it('in Insert mode after empty string mapping #17911', function() command('imap test ""') command('imap abctest') feed('i') screen:expect([[ abc | ^ | {1:~ }|*5 {2:-- INSERT --} | ]]) end) end)