mode_insert_spec.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. -- Insert-mode tests.
  2. local t = require('test.testutil')
  3. local n = require('test.functional.testnvim')()
  4. local Screen = require('test.functional.ui.screen')
  5. local clear, feed, insert = n.clear, n.feed, n.insert
  6. local expect = n.expect
  7. local command = n.command
  8. local eq = t.eq
  9. local eval = n.eval
  10. local curbuf_contents = n.curbuf_contents
  11. local api = n.api
  12. describe('insert-mode', function()
  13. before_each(function()
  14. clear()
  15. end)
  16. it('indents only once after "!" keys #12894', function()
  17. command('let counter = []')
  18. command('set indentexpr=len(add(counter,0))')
  19. feed('i<C-F>x')
  20. eq(' x', curbuf_contents())
  21. end)
  22. it('CTRL-@', function()
  23. -- Inserts last-inserted text, leaves insert-mode.
  24. insert('hello')
  25. feed('i<C-@>x')
  26. expect('hellhello')
  27. -- C-Space is the same as C-@.
  28. -- CTRL-SPC inserts last-inserted text, leaves insert-mode.
  29. feed('i<C-Space>x')
  30. expect('hellhellhello')
  31. -- CTRL-A inserts last inserted text
  32. feed('i<C-A>x')
  33. expect('hellhellhellhelloxo')
  34. end)
  35. describe('Ctrl-R', function()
  36. it('works', function()
  37. command("let @@ = 'test'")
  38. feed('i<C-r>"')
  39. expect('test')
  40. end)
  41. it('works with multi-byte text', function()
  42. command("let @@ = 'påskägg'")
  43. feed('i<C-r>"')
  44. expect('påskägg')
  45. end)
  46. it('double quote is removed after hit-enter prompt #22609', function()
  47. local screen = Screen.new(50, 6)
  48. feed('i<C-R>')
  49. screen:expect([[
  50. {18:^"} |
  51. {1:~ }|*4
  52. {5:-- INSERT --} |
  53. ]])
  54. feed("=function('add')")
  55. screen:expect([[
  56. {18:"} |
  57. {1:~ }|*4
  58. ={25:function}{16:(}{26:'add'}{16:)}^ |
  59. ]])
  60. feed('<CR>')
  61. screen:expect([[
  62. {18:"} |
  63. {1:~ }|
  64. {3: }|
  65. ={25:function}{16:(}{26:'add'}{16:)} |
  66. {9:E729: Using a Funcref as a String} |
  67. {6:Press ENTER or type command to continue}^ |
  68. ]])
  69. feed('<CR>')
  70. screen:expect([[
  71. ^ |
  72. {1:~ }|*4
  73. {5:-- INSERT --} |
  74. ]])
  75. end)
  76. end)
  77. describe('Ctrl-O', function()
  78. it('enters command mode for one command', function()
  79. feed('ihello world<C-o>')
  80. feed(':let ctrlo = "test"<CR>')
  81. feed('iii')
  82. expect('hello worldiii')
  83. eq(1, eval('ctrlo ==# "test"'))
  84. end)
  85. it('re-enters insert mode at the end of the line when running startinsert', function()
  86. -- #6962
  87. feed('ihello world<C-o>')
  88. feed(':startinsert<CR>')
  89. feed('iii')
  90. expect('hello worldiii')
  91. end)
  92. it('re-enters insert mode at the beginning of the line when running startinsert', function()
  93. insert('hello world')
  94. feed('0<C-o>')
  95. feed(':startinsert<CR>')
  96. feed('aaa')
  97. expect('aaahello world')
  98. end)
  99. it('re-enters insert mode in the middle of the line when running startinsert', function()
  100. insert('hello world')
  101. feed('bi<C-o>')
  102. feed(':startinsert<CR>')
  103. feed('ooo')
  104. expect('hello oooworld')
  105. end)
  106. end)
  107. describe('Ctrl-V', function()
  108. it('supports entering the decimal value of a character', function()
  109. feed('i<C-V>076<C-V>167')
  110. expect('L§')
  111. end)
  112. it('supports entering the octal value of a character with "o"', function()
  113. feed('i<C-V>o114<C-V>o247<Esc>')
  114. expect('L§')
  115. end)
  116. it('supports entering the octal value of a character with "O"', function()
  117. feed('i<C-V>O114<C-V>O247<Esc>')
  118. expect('L§')
  119. end)
  120. it('supports entering the hexadecimal value of a character with "x"', function()
  121. feed('i<C-V>x4c<C-V>xA7<Esc>')
  122. expect('L§')
  123. end)
  124. it('supports entering the hexadecimal value of a character with "X"', function()
  125. feed('i<C-V>X4c<C-V>XA7<Esc>')
  126. expect('L§')
  127. end)
  128. it('supports entering the hexadecimal value of a character with "u"', function()
  129. feed('i<C-V>u25ba<C-V>u25C7<Esc>')
  130. expect('►◇')
  131. end)
  132. it('supports entering the hexadecimal value of a character with "U"', function()
  133. feed('i<C-V>U0001f600<C-V>U0001F601<Esc>')
  134. expect('😀😁')
  135. end)
  136. it('entering character by value is interrupted by invalid character', function()
  137. 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>')
  138. expect('LcL<C-F2>πjπ<M-F3>😀j😀<D-F4>')
  139. end)
  140. it('shows o, O, u, U, x, X, and digits with modifiers', function()
  141. feed('i<C-V><M-o><C-V><D-o><C-V><M-O><C-V><D-O><Esc>')
  142. expect('<M-o><D-o><M-O><D-O>')
  143. feed('cc<C-V><M-u><C-V><D-u><C-V><M-U><C-V><D-U><Esc>')
  144. expect('<M-u><D-u><M-U><D-U>')
  145. feed('cc<C-V><M-x><C-V><D-x><C-V><M-X><C-V><D-X><Esc>')
  146. expect('<M-x><D-x><M-X><D-X>')
  147. feed('cc<C-V><M-1><C-V><D-2><C-V><M-7><C-V><D-8><Esc>')
  148. expect('<M-1><D-2><M-7><D-8>')
  149. end)
  150. end)
  151. it('Ctrl-Shift-V supports entering unsimplified key notations', function()
  152. 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>')
  153. expect('<C-J><C-@><C-[><C-S-M><M-C-I><C-D-J>')
  154. end)
  155. it('multi-char mapping updates screen properly #25626', function()
  156. local screen = Screen.new(60, 6)
  157. command('vnew')
  158. insert('foo\nfoo\nfoo')
  159. command('wincmd w')
  160. command('set timeoutlen=10000')
  161. command('inoremap jk <Esc>')
  162. feed('i<CR>βββ<Left><Left>j')
  163. screen:expect {
  164. grid = [[
  165. foo │ |
  166. foo │β^jβ |
  167. foo │{1:~ }|
  168. {1:~ }│{1:~ }|
  169. {2:[No Name] [+] }{3:[No Name] [+] }|
  170. {5:-- INSERT --} |
  171. ]],
  172. }
  173. feed('k')
  174. screen:expect {
  175. grid = [[
  176. foo │ |
  177. foo │^βββ |
  178. foo │{1:~ }|
  179. {1:~ }│{1:~ }|
  180. {2:[No Name] [+] }{3:[No Name] [+] }|
  181. |
  182. ]],
  183. }
  184. end)
  185. describe('backspace', function()
  186. local function set_lines(line_b, line_e, ...)
  187. api.nvim_buf_set_lines(0, line_b, line_e, true, { ... })
  188. end
  189. local function s(count)
  190. return (' '):rep(count)
  191. end
  192. local function test_cols(expected_cols)
  193. local cols = { { n.fn.col('.'), n.fn.virtcol('.') } }
  194. for _ = 2, #expected_cols do
  195. feed('<BS>')
  196. table.insert(cols, { n.fn.col('.'), n.fn.virtcol('.') })
  197. end
  198. eq(expected_cols, cols)
  199. end
  200. it('works with tabs and spaces', function()
  201. local _ = Screen.new(30, 2)
  202. command('setl ts=4 sw=4')
  203. set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
  204. feed('$i')
  205. test_cols({
  206. { 18, 26 },
  207. { 17, 25 },
  208. { 15, 21 },
  209. { 11, 17 },
  210. { 7, 13 },
  211. { 6, 9 },
  212. { 2, 5 },
  213. { 1, 1 },
  214. })
  215. end)
  216. it('works with varsofttabstop', function()
  217. local _ = Screen.new(30, 2)
  218. command('setl vsts=6,2,5,3')
  219. set_lines(0, 1, 'a\t' .. s(4) .. '\t a')
  220. feed('$i')
  221. test_cols({
  222. { 9, 18 },
  223. { 8, 17 },
  224. { 8, 14 },
  225. { 3, 9 },
  226. { 7, 7 },
  227. { 2, 2 },
  228. { 1, 1 },
  229. })
  230. end)
  231. it('works with tab as ^I', function()
  232. local _ = Screen.new(30, 2)
  233. command('set list listchars=space:.')
  234. command('setl ts=4 sw=4')
  235. set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
  236. feed('$i')
  237. test_cols({
  238. { 18, 21 },
  239. { 15, 17 },
  240. { 11, 13 },
  241. { 7, 9 },
  242. { 4, 5 },
  243. { 1, 1 },
  244. })
  245. end)
  246. it('works in replace mode', function()
  247. local _ = Screen.new(50, 2)
  248. command('setl ts=8 sw=8 sts=8')
  249. set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
  250. feed('$R')
  251. test_cols({
  252. { 18, 34 },
  253. { 17, 33 },
  254. { 15, 25 },
  255. { 7, 17 },
  256. { 2, 9 },
  257. { 1, 8 }, -- last screen cell of first tab is at vcol 8
  258. })
  259. end)
  260. it('works with breakindent', function()
  261. local _ = Screen.new(17, 4)
  262. command('setl ts=4 sw=4 bri briopt=min:5')
  263. set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
  264. feed('$i')
  265. test_cols({
  266. { 18, 50 },
  267. { 17, 49 },
  268. { 15, 33 },
  269. { 11, 17 },
  270. { 7, 13 },
  271. { 6, 9 },
  272. { 2, 5 },
  273. { 1, 1 },
  274. })
  275. end)
  276. it('works with inline virtual text', function()
  277. local _ = Screen.new(50, 2)
  278. command('setl ts=4 sw=4')
  279. set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a')
  280. local ns = api.nvim_create_namespace('')
  281. local vt_opts = { virt_text = { { 'text' } }, virt_text_pos = 'inline' }
  282. api.nvim_buf_set_extmark(0, ns, 0, 2, vt_opts)
  283. feed('$i')
  284. test_cols({
  285. { 18, 30 },
  286. { 17, 29 },
  287. { 15, 25 },
  288. { 11, 21 },
  289. { 7, 17 },
  290. { 6, 13 },
  291. { 2, 9 },
  292. { 1, 5 },
  293. })
  294. end)
  295. it("works with 'revins'", function()
  296. local _ = Screen.new(30, 3)
  297. command('setl ts=4 sw=4 revins')
  298. set_lines(0, 1, ('a'):rep(16), s(3) .. '\t' .. s(4) .. '\t a')
  299. feed('j$i')
  300. test_cols({
  301. { 11, 14 },
  302. { 10, 13 },
  303. { 9, 9 },
  304. { 5, 5 },
  305. { 1, 1 },
  306. { 1, 1 }, -- backspace on empty line does nothing
  307. })
  308. eq(2, api.nvim_win_get_cursor(0)[1])
  309. end)
  310. end)
  311. it('backspace after replacing multibyte chars', function()
  312. local screen = Screen.new(30, 3)
  313. api.nvim_buf_set_lines(0, 0, -1, true, { 'test ȧ̟̜̝̅̚m̆̉̐̐̇̈ å' })
  314. feed('^Rabcdefghi')
  315. screen:expect([[
  316. abcdefghi^ |
  317. {1:~ }|
  318. {5:-- REPLACE --} |
  319. ]])
  320. feed('<bs>')
  321. screen:expect([[
  322. abcdefgh^å |
  323. {1:~ }|
  324. {5:-- REPLACE --} |
  325. ]])
  326. feed('<bs>')
  327. screen:expect([[
  328. abcdefg^ å |
  329. {1:~ }|
  330. {5:-- REPLACE --} |
  331. ]])
  332. feed('<bs>')
  333. screen:expect([[
  334. abcdef^m̆̉̐̐̇̈ å |
  335. {1:~ }|
  336. {5:-- REPLACE --} |
  337. ]])
  338. feed('<bs>')
  339. screen:expect([[
  340. abcde^ȧ̟̜̝̅̚m̆̉̐̐̇̈ å |
  341. {1:~ }|
  342. {5:-- REPLACE --} |
  343. ]])
  344. feed('<bs>')
  345. screen:expect([[
  346. abcd^ ȧ̟̜̝̅̚m̆̉̐̐̇̈ å |
  347. {1:~ }|
  348. {5:-- REPLACE --} |
  349. ]])
  350. feed('<esc>')
  351. api.nvim_buf_set_lines(0, 0, -1, true, { 'wow 🧑‍🌾🏳️‍⚧️x' })
  352. feed('^Rabcd')
  353. screen:expect([[
  354. abcd^🧑‍🌾🏳️‍⚧️x |
  355. {1:~ }|
  356. {5:-- REPLACE --} |
  357. ]])
  358. feed('e')
  359. screen:expect([[
  360. abcde^🏳️‍⚧️x |
  361. {1:~ }|
  362. {5:-- REPLACE --} |
  363. ]])
  364. feed('f')
  365. screen:expect([[
  366. abcdef^x |
  367. {1:~ }|
  368. {5:-- REPLACE --} |
  369. ]])
  370. feed('<bs>')
  371. screen:expect([[
  372. abcde^🏳️‍⚧️x |
  373. {1:~ }|
  374. {5:-- REPLACE --} |
  375. ]])
  376. feed('<bs>')
  377. screen:expect([[
  378. abcd^🧑‍🌾🏳️‍⚧️x |
  379. {1:~ }|
  380. {5:-- REPLACE --} |
  381. ]])
  382. feed('<bs>')
  383. screen:expect([[
  384. abc^ 🧑‍🌾🏳️‍⚧️x |
  385. {1:~ }|
  386. {5:-- REPLACE --} |
  387. ]])
  388. end)
  389. end)