input_spec.lua 17 KB

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