blob: b413f4fc345b8efa590e59dc22a14ecb352f811f [file] [log] [blame]
Bram Moolenaar2d1a2482016-08-14 15:32:11 +02001" Tests for mappings and abbreviations
2
Bram Moolenaar26d98212019-01-27 22:32:55 +01003source shared.vim
Bram Moolenaar8c5a2782019-08-07 23:07:07 +02004source check.vim
Bram Moolenaar4ebe0e62019-11-22 20:55:40 +01005source screendump.vim
Bram Moolenaar957cf672020-11-12 14:21:06 +01006source term_util.vim
Bram Moolenaar62aec932022-01-29 21:45:34 +00007import './vim9.vim' as v9
Bram Moolenaar26d98212019-01-27 22:32:55 +01008
Bram Moolenaar2d1a2482016-08-14 15:32:11 +02009func Test_abbreviation()
10 " abbreviation with 0x80 should work
11 inoreab чкпр vim
12 call feedkeys("Goчкпр \<Esc>", "xt")
13 call assert_equal('vim ', getline('$'))
14 iunab чкпр
15 set nomodified
16endfunc
17
Bram Moolenaar8485be42019-04-23 16:36:05 +020018func Test_abclear()
19 abbrev foo foobar
20 iabbrev fooi foobari
21 cabbrev fooc foobarc
22 call assert_equal("\n\n"
23 \ .. "c fooc foobarc\n"
24 \ .. "i fooi foobari\n"
25 \ .. "! foo foobar", execute('abbrev'))
26
27 iabclear
28 call assert_equal("\n\n"
29 \ .. "c fooc foobarc\n"
30 \ .. "c foo foobar", execute('abbrev'))
31 abbrev foo foobar
32 iabbrev fooi foobari
33
34 cabclear
35 call assert_equal("\n\n"
36 \ .. "i fooi foobari\n"
37 \ .. "i foo foobar", execute('abbrev'))
38 abbrev foo foobar
39 cabbrev fooc foobarc
40
41 abclear
42 call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
Bram Moolenaarf0cee192020-02-16 13:33:56 +010043 call assert_fails('%abclear', 'E481:')
Bram Moolenaar8485be42019-04-23 16:36:05 +020044endfunc
45
46func Test_abclear_buffer()
47 abbrev foo foobar
48 new X1
49 abbrev <buffer> foo1 foobar1
50 new X2
51 abbrev <buffer> foo2 foobar2
52
53 call assert_equal("\n\n"
54 \ .. "! foo2 @foobar2\n"
55 \ .. "! foo foobar", execute('abbrev'))
56
57 abclear <buffer>
58 call assert_equal("\n\n"
59 \ .. "! foo foobar", execute('abbrev'))
60
61 b X1
62 call assert_equal("\n\n"
63 \ .. "! foo1 @foobar1\n"
64 \ .. "! foo foobar", execute('abbrev'))
65 abclear <buffer>
66 call assert_equal("\n\n"
67 \ .. "! foo foobar", execute('abbrev'))
68
69 abclear
70 call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
71
72 %bwipe
73endfunc
74
Bram Moolenaar2d1a2482016-08-14 15:32:11 +020075func Test_map_ctrl_c_insert()
76 " mapping of ctrl-c in Insert mode
77 set cpo-=< cpo-=k
78 inoremap <c-c> <ctrl-c>
79 cnoremap <c-c> dummy
80 cunmap <c-c>
Bram Moolenaarfccd93f2020-05-31 22:06:51 +020081 call feedkeys("GoTEST2: CTRL-C |\<*C-C>A|\<Esc>", "xt")
Bram Moolenaar2d1a2482016-08-14 15:32:11 +020082 call assert_equal('TEST2: CTRL-C |<ctrl-c>A|', getline('$'))
83 unmap! <c-c>
84 set nomodified
85endfunc
86
87func Test_map_ctrl_c_visual()
88 " mapping of ctrl-c in Visual mode
89 vnoremap <c-c> :<C-u>$put ='vmap works'
Bram Moolenaarfccd93f2020-05-31 22:06:51 +020090 call feedkeys("GV\<*C-C>\<CR>", "xt")
Bram Moolenaar2d1a2482016-08-14 15:32:11 +020091 call assert_equal('vmap works', getline('$'))
92 vunmap <c-c>
93 set nomodified
94endfunc
95
96func Test_map_langmap()
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +020097 CheckFeature langmap
Bram Moolenaar920694c2016-08-21 17:45:02 +020098
99 " check langmap applies in normal mode
100 set langmap=+- nolangremap
101 new
102 call setline(1, ['a', 'b', 'c'])
103 2
104 call assert_equal('b', getline('.'))
105 call feedkeys("+", "xt")
106 call assert_equal('a', getline('.'))
107
108 " check no remapping
109 map x +
110 2
111 call feedkeys("x", "xt")
112 call assert_equal('c', getline('.'))
113
114 " check with remapping
115 set langremap
116 2
117 call feedkeys("x", "xt")
118 call assert_equal('a', getline('.'))
119
120 unmap x
121 bwipe!
122
123 " 'langnoremap' follows 'langremap' and vise versa
124 set langremap
125 set langnoremap
126 call assert_equal(0, &langremap)
127 set langremap
128 call assert_equal(0, &langnoremap)
129 set nolangremap
130 call assert_equal(1, &langnoremap)
131
Bram Moolenaarda9ce2c2016-09-02 19:34:10 +0200132 " check default values
133 set langnoremap&
134 call assert_equal(0, &langnoremap)
135 call assert_equal(1, &langremap)
136 set langremap&
137 call assert_equal(0, &langnoremap)
138 call assert_equal(1, &langremap)
139
Bram Moolenaar920694c2016-08-21 17:45:02 +0200140 " langmap should not apply in insert mode, 'langremap' doesn't matter
141 set langmap=+{ nolangremap
142 call feedkeys("Go+\<Esc>", "xt")
143 call assert_equal('+', getline('$'))
144 set langmap=+{ langremap
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200145 call feedkeys("Go+\<Esc>", "xt")
146 call assert_equal('+', getline('$'))
147
Bram Moolenaar920694c2016-08-21 17:45:02 +0200148 " langmap used for register name in insert mode.
149 call setreg('a', 'aaaa')
150 call setreg('b', 'bbbb')
151 call setreg('c', 'cccc')
152 set langmap=ab langremap
153 call feedkeys("Go\<C-R>a\<Esc>", "xt")
154 call assert_equal('bbbb', getline('$'))
155 call feedkeys("Go\<C-R>\<C-R>a\<Esc>", "xt")
156 call assert_equal('bbbb', getline('$'))
157 " mapping does not apply
158 imap c a
159 call feedkeys("Go\<C-R>c\<Esc>", "xt")
160 call assert_equal('cccc', getline('$'))
161 imap a c
162 call feedkeys("Go\<C-R>a\<Esc>", "xt")
163 call assert_equal('bbbb', getline('$'))
164
165 " langmap should not apply in Command-line mode
166 set langmap=+{ nolangremap
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200167 call feedkeys(":call append(line('$'), '+')\<CR>", "xt")
168 call assert_equal('+', getline('$'))
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200169
Bram Moolenaare90858d2017-02-01 17:24:34 +0100170 iunmap a
171 iunmap c
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200172 set nomodified
173endfunc
174
175func Test_map_feedkeys()
176 " issue #212 (feedkeys insert mapping at current position)
177 nnoremap . :call feedkeys(".", "in")<cr>
178 call setline('$', ['a b c d', 'a b c d'])
179 $-1
180 call feedkeys("0qqdw.ifoo\<Esc>qj0@q\<Esc>", "xt")
181 call assert_equal(['fooc d', 'fooc d'], getline(line('$') - 1, line('$')))
Bram Moolenaare90858d2017-02-01 17:24:34 +0100182 nunmap .
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200183 set nomodified
184endfunc
185
186func Test_map_cursor()
187 " <c-g>U<cursor> works only within a single line
188 imapclear
189 imap ( ()<c-g>U<left>
190 call feedkeys("G2o\<Esc>ki\<CR>Test1: text with a (here some more text\<Esc>k.", "xt")
191 call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 2))
192 call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 1))
193
194 " test undo
195 call feedkeys("G2o\<Esc>ki\<CR>Test2: text wit a (here some more text [und undo]\<C-G>u\<Esc>k.u", "xt")
196 call assert_equal('', getline(line('$') - 2))
197 call assert_equal('Test2: text wit a (here some more text [und undo])', getline(line('$') - 1))
198 set nomodified
199 imapclear
200endfunc
201
Bram Moolenaar75bf3d22019-03-26 22:46:05 +0100202func Test_map_cursor_ctrl_gU()
203 " <c-g>U<cursor> works only within a single line
204 nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left>
205 call setline(1, ['foo', 'foobar', '', 'foo'])
206 call cursor(1,2)
207 call feedkeys("c<*PREFIX\<esc>.", 'xt')
208 call assert_equal(['PREFIXfoo', 'foobar', '', 'PREFIXfoo'], getline(1,'$'))
209 " break undo manually
210 set ul=1000
211 exe ":norm! uu"
212 call assert_equal(['foo', 'foobar', '', 'foo'], getline(1,'$'))
213
214 " Test that it does not work if the cursor moves to the previous line
215 " 2 times <S-Left> move to the previous line
216 nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left><C-G>U<S-Left>
217 call setline(1, ['', ' foo', 'foobar', '', 'foo'])
218 call cursor(2,3)
219 call feedkeys("c<*PREFIX\<esc>.", 'xt')
220 call assert_equal(['PREFIXPREFIX', ' foo', 'foobar', '', 'foo'], getline(1,'$'))
221 nmapclear
222endfunc
223
224
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200225" This isn't actually testing a mapping, but similar use of CTRL-G U as above.
226func Test_break_undo()
Bram Moolenaar75bf3d22019-03-26 22:46:05 +0100227 set whichwrap=<,>,[,]
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200228 call feedkeys("G4o2k", "xt")
229 exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>."
230 call assert_equal('new line here', getline(line('$') - 3))
231 call assert_equal('Test3: text with a (parenthesis here', getline(line('$') - 2))
232 call assert_equal('new line here', getline(line('$') - 1))
233 set nomodified
234endfunc
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +0200235
236func Test_map_meta_quotes()
237 imap <M-"> foo
Bram Moolenaarfccd93f2020-05-31 22:06:51 +0200238 call feedkeys("Go-\<*M-\">-\<Esc>", "xt")
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +0200239 call assert_equal("-foo-", getline('$'))
240 set nomodified
241 iunmap <M-">
242endfunc
Bram Moolenaar878c2632017-04-01 15:15:52 +0200243
Bram Moolenaarc8fd33d2019-08-16 20:33:05 +0200244func Test_map_meta_multibyte()
245 imap <M-á> foo
Bram Moolenaar2f710af2019-08-16 20:56:03 +0200246 call assert_match('i <M-á>\s*foo', execute('imap'))
Bram Moolenaarc8fd33d2019-08-16 20:33:05 +0200247 iunmap <M-á>
248endfunc
249
Bram Moolenaar878c2632017-04-01 15:15:52 +0200250func Test_abbr_after_line_join()
251 new
252 abbr foo bar
253 set backspace=indent,eol,start
254 exe "normal o\<BS>foo "
255 call assert_equal("bar ", getline(1))
256 bwipe!
257 unabbr foo
258 set backspace&
259endfunc
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200260
261func Test_map_timeout()
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200262 CheckFeature timers
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200263 nnoremap aaaa :let got_aaaa = 1<CR>
264 nnoremap bb :let got_bb = 1<CR>
265 nmap b aaa
266 new
267 func ExitInsert(timer)
268 let g:line = getline(1)
269 call feedkeys("\<Esc>", "t")
270 endfunc
271 set timeout timeoutlen=200
Bram Moolenaar26d98212019-01-27 22:32:55 +0100272 let timer = timer_start(300, 'ExitInsert')
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200273 " After the 'b' Vim waits for another character to see if it matches 'bb'.
274 " When it times out it is expanded to "aaa", but there is no wait for
275 " "aaaa". Can't check that reliably though.
276 call feedkeys("b", "xt!")
277 call assert_equal("aa", g:line)
278 call assert_false(exists('got_aaa'))
279 call assert_false(exists('got_bb'))
280
281 bwipe!
282 nunmap aaaa
283 nunmap bb
284 nunmap b
285 set timeoutlen&
286 delfunc ExitInsert
Bram Moolenaar26d98212019-01-27 22:32:55 +0100287 call timer_stop(timer)
288endfunc
289
290func Test_map_timeout_with_timer_interrupt()
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200291 CheckFeature job
292 CheckFeature timers
Bram Moolenaarf08b0eb2021-10-16 13:00:14 +0100293 let g:test_is_flaky = 1
Bram Moolenaar26d98212019-01-27 22:32:55 +0100294
295 " Confirm the timer invoked in exit_cb of the job doesn't disturb mapped key
296 " sequence.
297 new
298 let g:val = 0
299 nnoremap \12 :let g:val = 1<CR>
300 nnoremap \123 :let g:val = 2<CR>
Bram Moolenaarea94c852019-08-16 21:47:27 +0200301 set timeout timeoutlen=200
Bram Moolenaar26d98212019-01-27 22:32:55 +0100302
303 func ExitCb(job, status)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +0100304 let g:timer = timer_start(1, {-> feedkeys("3\<Esc>", 't')})
Bram Moolenaar26d98212019-01-27 22:32:55 +0100305 endfunc
306
307 call job_start([&shell, &shellcmdflag, 'echo'], {'exit_cb': 'ExitCb'})
308 call feedkeys('\12', 'xt!')
309 call assert_equal(2, g:val)
310
311 bwipe!
312 nunmap \12
313 nunmap \123
314 set timeoutlen&
315 call WaitFor({-> exists('g:timer')})
316 call timer_stop(g:timer)
317 unlet g:timer
318 unlet g:val
319 delfunc ExitCb
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200320endfunc
Bram Moolenaarc3c3e692018-04-26 22:30:33 +0200321
322func Test_abbreviation_CR()
323 new
324 func Eatchar(pat)
325 let c = nr2char(getchar(0))
326 return (c =~ a:pat) ? '' : c
327 endfunc
328 iabbrev <buffer><silent> ~~7 <c-r>=repeat('~', 7)<CR><c-r>=Eatchar('\s')<cr>
329 call feedkeys("GA~~7 \<esc>", 'xt')
330 call assert_equal('~~~~~~~', getline('$'))
331 %d
332 call feedkeys("GA~~7\<cr>\<esc>", 'xt')
333 call assert_equal(['~~~~~~~', ''], getline(1,'$'))
334 delfunc Eatchar
335 bw!
336endfunc
Bram Moolenaar5e3423d2018-05-13 18:36:27 +0200337
338func Test_cabbr_visual_mode()
339 cabbr s su
340 call feedkeys(":s \<c-B>\"\<CR>", 'itx')
341 call assert_equal('"su ', getreg(':'))
342 call feedkeys(":'<,'>s \<c-B>\"\<CR>", 'itx')
343 let expected = '"'. "'<,'>su "
344 call assert_equal(expected, getreg(':'))
345 call feedkeys(": '<,'>s \<c-B>\"\<CR>", 'itx')
346 let expected = '" '. "'<,'>su "
347 call assert_equal(expected, getreg(':'))
348 call feedkeys(":'a,'bs \<c-B>\"\<CR>", 'itx')
349 let expected = '"'. "'a,'bsu "
350 call assert_equal(expected, getreg(':'))
351 cunabbr s
352endfunc
Bram Moolenaar5976f8f2018-12-27 23:44:44 +0100353
354func Test_motionforce_omap()
355 func GetCommand()
356 let g:m=mode(1)
357 let [g:lnum1, g:col1] = searchpos('-', 'Wb')
358 if g:lnum1 == 0
359 return "\<Esc>"
360 endif
361 let [g:lnum2, g:col2] = searchpos('-', 'W')
362 if g:lnum2 == 0
363 return "\<Esc>"
364 endif
365 return ":call Select()\<CR>"
366 endfunc
367 func Select()
368 call cursor([g:lnum1, g:col1])
369 exe "normal! 1 ". (strlen(g:m) == 2 ? 'v' : g:m[2])
370 call cursor([g:lnum2, g:col2])
371 execute "normal! \<BS>"
372 endfunc
373 new
374 onoremap <buffer><expr> i- GetCommand()
375 " 1) default omap mapping
376 %d_
377 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
378 call cursor(2, 1)
379 norm di-
380 call assert_equal('no', g:m)
381 call assert_equal(['aaa -- eee'], getline(1, '$'))
382 " 2) forced characterwise operation
383 %d_
384 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
385 call cursor(2, 1)
386 norm dvi-
387 call assert_equal('nov', g:m)
388 call assert_equal(['aaa -- eee'], getline(1, '$'))
389 " 3) forced linewise operation
390 %d_
391 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
392 call cursor(2, 1)
393 norm dVi-
394 call assert_equal('noV', g:m)
395 call assert_equal([''], getline(1, '$'))
396 " 4) forced blockwise operation
397 %d_
398 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
399 call cursor(2, 1)
400 exe "norm d\<C-V>i-"
401 call assert_equal("no\<C-V>", g:m)
402 call assert_equal(['aaabbb', 'x', 'dddeee'], getline(1, '$'))
403 bwipe!
404 delfunc Select
405 delfunc GetCommand
406endfunc
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200407
408func Test_error_in_map_expr()
Bram Moolenaar8c5a2782019-08-07 23:07:07 +0200409 " Unlike CheckRunVimInTerminal this does work in a win32 console
410 CheckFeature terminal
411 if has('win32') && has('gui_running')
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200412 throw 'Skipped: cannot run Vim in a terminal window'
413 endif
414
415 let lines =<< trim [CODE]
416 func Func()
417 " fail to create list
418 let x = [
419 endfunc
420 nmap <expr> ! Func()
421 set updatetime=50
422 [CODE]
423 call writefile(lines, 'Xtest.vim')
424
Bram Moolenaar0d702022019-07-04 14:20:41 +0200425 let buf = term_start(GetVimCommandCleanTerm() .. ' -S Xtest.vim', {'term_rows': 8})
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200426 let job = term_getjob(buf)
427 call WaitForAssert({-> assert_notequal('', term_getline(buf, 8))})
428
429 " GC must not run during map-expr processing, which can make Vim crash.
430 call term_sendkeys(buf, '!')
Bram Moolenaar6a2c5a72020-04-08 21:50:25 +0200431 call TermWait(buf, 50)
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200432 call term_sendkeys(buf, "\<CR>")
Bram Moolenaar6a2c5a72020-04-08 21:50:25 +0200433 call TermWait(buf, 50)
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200434 call assert_equal('run', job_status(job))
435
436 call term_sendkeys(buf, ":qall!\<CR>")
437 call WaitFor({-> job_status(job) ==# 'dead'})
438 if has('unix')
439 call assert_equal('', job_info(job).termsig)
440 endif
441
442 call delete('Xtest.vim')
443 exe buf .. 'bwipe!'
444endfunc
Bram Moolenaarfafb4b12019-10-16 18:34:57 +0200445
446func Test_list_mappings()
Bram Moolenaar2559a472019-10-16 23:33:12 +0200447 " Remove default mappings
448 imapclear
Bram Moolenaar4f2f61a2019-10-16 22:27:49 +0200449
Bram Moolenaare3d1f4c2021-04-06 20:21:59 +0200450 " reset 'isident' to check it isn't used
451 set isident=
452 inoremap <C-m> CtrlM
Bram Moolenaarfafb4b12019-10-16 18:34:57 +0200453 inoremap <A-S> AltS
454 inoremap <S-/> ShiftSlash
Bram Moolenaare3d1f4c2021-04-06 20:21:59 +0200455 set isident&
Bram Moolenaarfafb4b12019-10-16 18:34:57 +0200456 call assert_equal([
457 \ 'i <S-/> * ShiftSlash',
458 \ 'i <M-S> * AltS',
459 \ 'i <C-M> * CtrlM',
460 \], execute('imap')->trim()->split("\n"))
461 iunmap <C-M>
462 iunmap <A-S>
463 call assert_equal(['i <S-/> * ShiftSlash'], execute('imap')->trim()->split("\n"))
464 iunmap <S-/>
465 call assert_equal(['No mapping found'], execute('imap')->trim()->split("\n"))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100466
467 " List global, buffer local and script local mappings
468 nmap ,f /^\k\+ (<CR>
469 nmap <buffer> ,f /^\k\+ (<CR>
470 nmap <script> ,fs /^\k\+ (<CR>
471 call assert_equal(['n ,f @/^\k\+ (<CR>',
472 \ 'n ,fs & /^\k\+ (<CR>',
473 \ 'n ,f /^\k\+ (<CR>'],
474 \ execute('nmap ,f')->trim()->split("\n"))
475
476 " List <Nop> mapping
477 nmap ,n <Nop>
478 call assert_equal(['n ,n <Nop>'],
479 \ execute('nmap ,n')->trim()->split("\n"))
480
Bram Moolenaar7f51bbe2020-01-24 20:21:19 +0100481 " verbose map
482 call assert_match("\tLast set from .*/test_mapping.vim line \\d\\+$",
483 \ execute('verbose map ,n')->trim()->split("\n")[1])
484
485 " map to CTRL-V
486 exe "nmap ,k \<C-V>"
487 call assert_equal(['n ,k <Nop>'],
488 \ execute('nmap ,k')->trim()->split("\n"))
489
Yegappan Lakshmanan2d6d7182021-06-13 21:52:48 +0200490 " map with space at the beginning
491 exe "nmap \<C-V> w <Nop>"
492 call assert_equal(['n <Space>w <Nop>'],
493 \ execute("nmap \<C-V> w")->trim()->split("\n"))
494
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100495 nmapclear
Bram Moolenaarfafb4b12019-10-16 18:34:57 +0200496endfunc
Bram Moolenaar4ebe0e62019-11-22 20:55:40 +0100497
Bram Moolenaar18b7d862021-03-17 13:28:05 +0100498func Test_expr_map_gets_cursor()
499 new
500 call setline(1, ['one', 'some w!rd'])
501 func StoreColumn()
502 let g:exprLine = line('.')
503 let g:exprCol = col('.')
504 return 'x'
505 endfunc
506 nnoremap <expr> x StoreColumn()
507 2
508 nmap ! f!<Ignore>x
509 call feedkeys("!", 'xt')
510 call assert_equal('some wrd', getline(2))
511 call assert_equal(2, g:exprLine)
512 call assert_equal(7, g:exprCol)
513
514 bwipe!
515 unlet g:exprLine
516 unlet g:exprCol
Bram Moolenaar6ccfd992021-03-17 13:39:33 +0100517 delfunc StoreColumn
Bram Moolenaar18b7d862021-03-17 13:28:05 +0100518 nunmap x
519 nunmap !
520endfunc
521
Bram Moolenaar4ebe0e62019-11-22 20:55:40 +0100522func Test_expr_map_restore_cursor()
523 CheckScreendump
524
525 let lines =<< trim END
526 call setline(1, ['one', 'two', 'three'])
527 2
528 set ls=2
529 hi! link StatusLine ErrorMsg
530 noremap <expr> <C-B> Func()
531 func Func()
532 let g:on = !get(g:, 'on', 0)
533 redraws
534 return ''
535 endfunc
536 func Status()
537 return get(g:, 'on', 0) ? '[on]' : ''
538 endfunc
539 set stl=%{Status()}
540 END
541 call writefile(lines, 'XtestExprMap')
542 let buf = RunVimInTerminal('-S XtestExprMap', #{rows: 10})
Bram Moolenaar4ebe0e62019-11-22 20:55:40 +0100543 call term_sendkeys(buf, "\<C-B>")
544 call VerifyScreenDump(buf, 'Test_map_expr_1', {})
545
546 " clean up
547 call StopVimInTerminal(buf)
548 call delete('XtestExprMap')
549endfunc
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100550
Bram Moolenaard288eaa2022-02-16 18:27:55 +0000551func Test_map_listing()
552 CheckScreendump
553
554 let lines =<< trim END
555 nmap a b
556 END
557 call writefile(lines, 'XtestMapList')
558 let buf = RunVimInTerminal('-S XtestMapList', #{rows: 6})
559 call term_sendkeys(buf, ": nmap a\<CR>")
560 call VerifyScreenDump(buf, 'Test_map_list_1', {})
561
562 " clean up
563 call StopVimInTerminal(buf)
564 call delete('XtestMapList')
565endfunc
566
Bram Moolenaar74a0a5b2022-02-10 14:07:41 +0000567func Test_expr_map_error()
568 CheckScreendump
569
570 let lines =<< trim END
571 func Func()
572 throw 'test'
573 return ''
574 endfunc
575
576 nnoremap <expr> <F2> Func()
577 cnoremap <expr> <F2> Func()
578
579 call test_override('ui_delay', 10)
580 END
581 call writefile(lines, 'XtestExprMap')
582 let buf = RunVimInTerminal('-S XtestExprMap', #{rows: 10})
Bram Moolenaar74a0a5b2022-02-10 14:07:41 +0000583 call term_sendkeys(buf, "\<F2>")
584 call TermWait(buf)
585 call term_sendkeys(buf, "\<CR>")
586 call VerifyScreenDump(buf, 'Test_map_expr_2', {})
587
588 call term_sendkeys(buf, ":abc\<F2>")
589 call VerifyScreenDump(buf, 'Test_map_expr_3', {})
590 call term_sendkeys(buf, "\<Esc>0")
591 call VerifyScreenDump(buf, 'Test_map_expr_4', {})
592
593 " clean up
594 call StopVimInTerminal(buf)
595 call delete('XtestExprMap')
596endfunc
597
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100598" Test for mapping errors
599func Test_map_error()
600 call assert_fails('unmap', 'E474:')
601 call assert_fails("exe 'map ' .. repeat('a', 51) .. ' :ls'", 'E474:')
602 call assert_fails('unmap abc', 'E31:')
603 call assert_fails('unabbr abc', 'E24:')
604 call assert_equal('', maparg(''))
605 call assert_fails('echo maparg("abc", [])', 'E730:')
606
607 " unique map
608 map ,w /[#&!]<CR>
609 call assert_fails("map <unique> ,w /[#&!]<CR>", 'E227:')
610 " unique buffer-local map
611 call assert_fails("map <buffer> <unique> ,w /[.,;]<CR>", 'E225:')
612 unmap ,w
613
614 " unique abbreviation
615 abbr SP special
616 call assert_fails("abbr <unique> SP special", 'E226:')
617 " unique buffer-local map
618 call assert_fails("abbr <buffer> <unique> SP special", 'E224:')
619 unabbr SP
620
621 call assert_fails('mapclear abc', 'E474:')
622 call assert_fails('abclear abc', 'E474:')
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100623 call assert_fails('abbr $xyz abc', 'E474:')
624
625 " space character in an abbreviation
626 call assert_fails('abbr ab<space> ABC', 'E474:')
627
628 " invalid <expr> map
629 map <expr> ,f abc
630 call assert_fails('normal ,f', 'E121:')
631 unmap <expr> ,f
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100632
633 " Recursive use of :normal in a map
634 set maxmapdepth=100
635 map gq :normal gq<CR>
636 call assert_fails('normal gq', 'E192:')
637 unmap gq
638 set maxmapdepth&
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100639endfunc
640
641" Test for <special> key mapping
642func Test_map_special()
643 new
644 let old_cpo = &cpo
645 set cpo+=<
646 imap <F12> Blue
647 call feedkeys("i\<F12>", "x")
648 call assert_equal("<F12>", getline(1))
649 call feedkeys("ddi<F12>", "x")
650 call assert_equal("Blue", getline(1))
651 iunmap <F12>
652 imap <special> <F12> Green
653 call feedkeys("ddi\<F12>", "x")
654 call assert_equal("Green", getline(1))
655 call feedkeys("ddi<F12>", "x")
656 call assert_equal("<F12>", getline(1))
657 iunmap <special> <F12>
658 let &cpo = old_cpo
659 %bwipe!
660endfunc
661
662" Test for hasmapto()
663func Test_hasmapto()
664 call assert_equal(0, hasmapto('/^\k\+ ('))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100665 map ,f /^\k\+ (<CR>
666 call assert_equal(1, hasmapto('/^\k\+ ('))
667 unmap ,f
668
669 " Insert mode mapping
670 call assert_equal(0, hasmapto('/^\k\+ (', 'i'))
671 imap ,f /^\k\+ (<CR>
672 call assert_equal(1, hasmapto('/^\k\+ (', 'i'))
673 iunmap ,f
674
675 " Normal mode mapping
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100676 call assert_equal(0, hasmapto('/^\k\+ (', 'n'))
677 nmap ,f /^\k\+ (<CR>
678 call assert_equal(1, hasmapto('/^\k\+ ('))
679 call assert_equal(1, hasmapto('/^\k\+ (', 'n'))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100680 nunmap ,f
681
682 " Visual and Select mode mapping
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100683 call assert_equal(0, hasmapto('/^\k\+ (', 'v'))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100684 call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
685 call assert_equal(0, hasmapto('/^\k\+ (', 's'))
686 vmap ,f /^\k\+ (<CR>
687 call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
688 call assert_equal(1, hasmapto('/^\k\+ (', 'x'))
689 call assert_equal(1, hasmapto('/^\k\+ (', 's'))
690 vunmap ,f
691
692 " Visual mode mapping
693 call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
694 xmap ,f /^\k\+ (<CR>
695 call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
696 call assert_equal(1, hasmapto('/^\k\+ (', 'x'))
697 call assert_equal(0, hasmapto('/^\k\+ (', 's'))
698 xunmap ,f
699
700 " Select mode mapping
701 call assert_equal(0, hasmapto('/^\k\+ (', 's'))
702 smap ,f /^\k\+ (<CR>
703 call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
704 call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
705 call assert_equal(1, hasmapto('/^\k\+ (', 's'))
706 sunmap ,f
707
708 " Operator-pending mode mapping
709 call assert_equal(0, hasmapto('/^\k\+ (', 'o'))
710 omap ,f /^\k\+ (<CR>
711 call assert_equal(1, hasmapto('/^\k\+ (', 'o'))
712 ounmap ,f
713
714 " Language mapping
715 call assert_equal(0, hasmapto('/^\k\+ (', 'l'))
716 lmap ,f /^\k\+ (<CR>
717 call assert_equal(1, hasmapto('/^\k\+ (', 'l'))
718 lunmap ,f
719
720 " Cmdline mode mapping
721 call assert_equal(0, hasmapto('/^\k\+ (', 'c'))
722 cmap ,f /^\k\+ (<CR>
723 call assert_equal(1, hasmapto('/^\k\+ (', 'c'))
724 cunmap ,f
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100725
726 call assert_equal(0, hasmapto('/^\k\+ (', 'n', 1))
727endfunc
728
729" Test for command-line completion of maps
730func Test_mapcomplete()
731 call assert_equal(['<buffer>', '<expr>', '<nowait>', '<script>',
732 \ '<silent>', '<special>', '<unique>'],
733 \ getcompletion('', 'mapping'))
734 call assert_equal([], getcompletion(',d', 'mapping'))
735
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100736 call feedkeys(":unmap <buf\<C-A>\<C-B>\"\<CR>", 'tx')
737 call assert_equal('"unmap <buffer>', @:)
738
739 call feedkeys(":unabbr <buf\<C-A>\<C-B>\"\<CR>", 'tx')
740 call assert_equal('"unabbr <buffer>', @:)
741
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100742 call feedkeys(":abbr! \<C-A>\<C-B>\"\<CR>", 'tx')
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100743 call assert_equal("\"abbr! \x01", @:)
744
745 " Multiple matches for a map
746 nmap ,f /H<CR>
747 omap ,f /H<CR>
748 call feedkeys(":map ,\<C-A>\<C-B>\"\<CR>", 'tx')
749 call assert_equal('"map ,f', @:)
750 mapclear
751endfunc
752
Bram Moolenaar94075b22022-01-18 20:30:39 +0000753func GetAbbrText()
754 unabbr hola
755 return 'hello'
756endfunc
757
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100758" Test for <expr> in abbreviation
759func Test_expr_abbr()
760 new
761 iabbr <expr> teh "the"
762 call feedkeys("iteh ", "tx")
763 call assert_equal('the ', getline(1))
764 iabclear
765 call setline(1, '')
766
767 " invalid <expr> abbreviation
768 abbr <expr> hte GetAbbr()
769 call assert_fails('normal ihte ', 'E117:')
Bram Moolenaar28ee8922020-10-28 20:20:00 +0100770 call assert_equal('', getline(1))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100771 unabbr <expr> hte
772
Bram Moolenaar94075b22022-01-18 20:30:39 +0000773 " evaluating the expression deletes the abbreviation
774 abbr <expr> hola GetAbbrText()
775 call assert_equal('GetAbbrText()', maparg('hola', 'i', '1'))
776 call feedkeys("ahola \<Esc>", 'xt')
777 call assert_equal('hello ', getline('.'))
778 call assert_equal('', maparg('hola', 'i', '1'))
779
780 bwipe!
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100781endfunc
782
783" Test for storing mappings in different modes in a vimrc file
784func Test_mkvimrc_mapmodes()
785 map a1 /a1
786 nmap a2 /a2
787 vmap a3 /a3
788 smap a4 /a4
789 xmap a5 /a5
790 omap a6 /a6
791 map! a7 /a7
792 imap a8 /a8
793 lmap a9 /a9
794 cmap a10 /a10
795 tmap a11 /a11
796 " Normal + Visual map
797 map a12 /a12
798 sunmap a12
799 ounmap a12
800 " Normal + Selectmode map
801 map a13 /a13
802 xunmap a13
803 ounmap a13
804 " Normal + OpPending map
805 map a14 /a14
806 vunmap a14
807 " Visual + Selectmode map
808 map a15 /a15
809 nunmap a15
810 ounmap a15
811 " Visual + OpPending map
812 map a16 /a16
813 nunmap a16
814 sunmap a16
815 " Selectmode + OpPending map
816 map a17 /a17
817 nunmap a17
818 xunmap a17
819 " Normal + Visual + Selectmode map
820 map a18 /a18
821 ounmap a18
822 " Normal + Visual + OpPending map
823 map a19 /a19
824 sunmap a19
825 " Normal + Selectmode + OpPending map
826 map a20 /a20
827 xunmap a20
828 " Visual + Selectmode + OpPending map
829 map a21 /a21
830 nunmap a21
831 " Mapping to Nop
832 map a22 <Nop>
833 " Script local mapping
834 map <script> a23 /a23
835
836 " Newline in {lhs} and {rhs} of a map
837 exe "map a24\<C-V>\<C-J> ia24\<C-V>\<C-J><Esc>"
838
839 " Abbreviation
840 abbr a25 A25
841 cabbr a26 A26
842 iabbr a27 A27
843
844 mkvimrc! Xvimrc
845 let l = readfile('Xvimrc')
846 call assert_equal(['map a1 /a1'], filter(copy(l), 'v:val =~ " a1 "'))
847 call assert_equal(['nmap a2 /a2'], filter(copy(l), 'v:val =~ " a2 "'))
848 call assert_equal(['vmap a3 /a3'], filter(copy(l), 'v:val =~ " a3 "'))
849 call assert_equal(['smap a4 /a4'], filter(copy(l), 'v:val =~ " a4 "'))
850 call assert_equal(['xmap a5 /a5'], filter(copy(l), 'v:val =~ " a5 "'))
851 call assert_equal(['omap a6 /a6'], filter(copy(l), 'v:val =~ " a6 "'))
852 call assert_equal(['map! a7 /a7'], filter(copy(l), 'v:val =~ " a7 "'))
853 call assert_equal(['imap a8 /a8'], filter(copy(l), 'v:val =~ " a8 "'))
854 call assert_equal(['lmap a9 /a9'], filter(copy(l), 'v:val =~ " a9 "'))
855 call assert_equal(['cmap a10 /a10'], filter(copy(l), 'v:val =~ " a10 "'))
856 call assert_equal(['tmap a11 /a11'], filter(copy(l), 'v:val =~ " a11 "'))
857 call assert_equal(['nmap a12 /a12', 'xmap a12 /a12'],
858 \ filter(copy(l), 'v:val =~ " a12 "'))
859 call assert_equal(['nmap a13 /a13', 'smap a13 /a13'],
860 \ filter(copy(l), 'v:val =~ " a13 "'))
861 call assert_equal(['nmap a14 /a14', 'omap a14 /a14'],
862 \ filter(copy(l), 'v:val =~ " a14 "'))
863 call assert_equal(['vmap a15 /a15'], filter(copy(l), 'v:val =~ " a15 "'))
864 call assert_equal(['xmap a16 /a16', 'omap a16 /a16'],
865 \ filter(copy(l), 'v:val =~ " a16 "'))
866 call assert_equal(['smap a17 /a17', 'omap a17 /a17'],
867 \ filter(copy(l), 'v:val =~ " a17 "'))
868 call assert_equal(['nmap a18 /a18', 'vmap a18 /a18'],
869 \ filter(copy(l), 'v:val =~ " a18 "'))
870 call assert_equal(['nmap a19 /a19', 'xmap a19 /a19', 'omap a19 /a19'],
871 \ filter(copy(l), 'v:val =~ " a19 "'))
872 call assert_equal(['nmap a20 /a20', 'smap a20 /a20', 'omap a20 /a20'],
873 \ filter(copy(l), 'v:val =~ " a20 "'))
874 call assert_equal(['vmap a21 /a21', 'omap a21 /a21'],
875 \ filter(copy(l), 'v:val =~ " a21 "'))
876 call assert_equal(['map a22 <Nop>'], filter(copy(l), 'v:val =~ " a22 "'))
877 call assert_equal([], filter(copy(l), 'v:val =~ " a23 "'))
878 call assert_equal(["map a24<NL> ia24<NL>\x16\e"],
879 \ filter(copy(l), 'v:val =~ " a24"'))
880
881 call assert_equal(['abbr a25 A25'], filter(copy(l), 'v:val =~ " a25 "'))
882 call assert_equal(['cabbr a26 A26'], filter(copy(l), 'v:val =~ " a26 "'))
883 call assert_equal(['iabbr a27 A27'], filter(copy(l), 'v:val =~ " a27 "'))
884 call delete('Xvimrc')
885
886 mapclear
887 nmapclear
888 vmapclear
889 xmapclear
890 smapclear
891 omapclear
892 imapclear
893 lmapclear
894 cmapclear
895 tmapclear
896endfunc
897
898" Test for recursive mapping ('maxmapdepth')
899func Test_map_recursive()
900 map x y
901 map y x
902 call assert_fails('normal x', 'E223:')
903 unmap x
904 unmap y
905endfunc
906
907" Test for removing an abbreviation using {rhs} and with space after {lhs}
908func Test_abbr_remove()
909 abbr foo bar
910 let d = maparg('foo', 'i', 1, 1)
911 call assert_equal(['foo', 'bar', '!'], [d.lhs, d.rhs, d.mode])
912 unabbr bar
913 call assert_equal({}, maparg('foo', 'i', 1, 1))
914
915 abbr foo bar
916 unabbr foo<space><tab>
917 call assert_equal({}, maparg('foo', 'i', 1, 1))
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100918endfunc
919
Bram Moolenaar7f51bbe2020-01-24 20:21:19 +0100920" Trigger an abbreviation using a special key
921func Test_abbr_trigger_special()
922 new
923 iabbr teh the
924 call feedkeys("iteh\<F2>\<Esc>", 'xt')
925 call assert_equal('the<F2>', getline(1))
926 iunab teh
927 close!
928endfunc
929
930" Test for '<' in 'cpoptions'
931func Test_map_cpo_special_keycode()
932 set cpo-=<
933 imap x<Bslash>k Test
934 let d = maparg('x<Bslash>k', 'i', 0, 1)
935 call assert_equal(['x\k', 'Test', 'i'], [d.lhs, d.rhs, d.mode])
936 call feedkeys(":imap x\<C-A>\<C-B>\"\<CR>", 'tx')
937 call assert_equal('"imap x\k', @:)
938 iunmap x<Bslash>k
939 set cpo+=<
940 imap x<Bslash>k Test
941 let d = maparg('x<Bslash>k', 'i', 0, 1)
942 call assert_equal(['x<Bslash>k', 'Test', 'i'], [d.lhs, d.rhs, d.mode])
943 call feedkeys(":imap x\<C-A>\<C-B>\"\<CR>", 'tx')
944 call assert_equal('"imap x<Bslash>k', @:)
945 iunmap x<Bslash>k
946 set cpo-=<
947 " Modifying 'cpo' above adds some default mappings, remove them
948 mapclear
949 mapclear!
950endfunc
951
Bram Moolenaar957cf672020-11-12 14:21:06 +0100952" Test for <Cmd> key in maps to execute commands
953func Test_map_cmdkey()
954 new
955
956 " Error cases
957 let x = 0
958 noremap <F3> <Cmd><Cmd>let x = 1<CR>
959 call assert_fails('call feedkeys("\<F3>", "xt")', 'E1136:')
960 call assert_equal(0, x)
961
962 noremap <F3> <Cmd><F3>let x = 2<CR>
963 call assert_fails('call feedkeys("\<F3>", "xt")', 'E1137:')
964 call assert_equal(0, x)
965
966 noremap <F3> <Cmd>let x = 3
Bram Moolenaar806da512021-12-24 19:54:52 +0000967 call assert_fails('call feedkeys("\<F3>", "xt!")', 'E1255:')
Bram Moolenaar957cf672020-11-12 14:21:06 +0100968 call assert_equal(0, x)
969
970 " works in various modes and sees the correct mode()
971 noremap <F3> <Cmd>let m = mode(1)<CR>
972 noremap! <F3> <Cmd>let m = mode(1)<CR>
973
974 " normal mode
975 call feedkeys("\<F3>", 'xt')
976 call assert_equal('n', m)
977
978 " visual mode
979 call feedkeys("v\<F3>", 'xt!')
980 call assert_equal('v', m)
981 " shouldn't leave the visual mode
982 call assert_equal('v', mode(1))
983 call feedkeys("\<Esc>", 'xt')
984 call assert_equal('n', mode(1))
985
986 " visual mapping in select mode
987 call feedkeys("gh\<F3>", 'xt!')
988 call assert_equal('v', m)
989 " shouldn't leave select mode
990 call assert_equal('s', mode(1))
991 call feedkeys("\<Esc>", 'xt')
992 call assert_equal('n', mode(1))
993
994 " select mode mapping
995 snoremap <F3> <Cmd>let m = mode(1)<cr>
996 call feedkeys("gh\<F3>", 'xt!')
997 call assert_equal('s', m)
998 " shouldn't leave select mode
999 call assert_equal('s', mode(1))
1000 call feedkeys("\<Esc>", 'xt')
1001 call assert_equal('n', mode(1))
1002
1003 " operator-pending mode
1004 call feedkeys("d\<F3>", 'xt!')
1005 call assert_equal('no', m)
1006 " leaves the operator-pending mode
1007 call assert_equal('n', mode(1))
1008
1009 " insert mode
1010 call feedkeys("i\<F3>abc", 'xt')
1011 call assert_equal('i', m)
1012 call assert_equal('abc', getline('.'))
1013
1014 " replace mode
1015 call feedkeys("0R\<F3>two", 'xt')
1016 call assert_equal('R', m)
1017 call assert_equal('two', getline('.'))
1018
1019 " virtual replace mode
1020 call setline('.', "one\ttwo")
1021 call feedkeys("4|gR\<F3>xxx", 'xt')
1022 call assert_equal('Rv', m)
1023 call assert_equal("onexxx\ttwo", getline('.'))
1024
1025 " cmdline mode
1026 call feedkeys(":\<F3>\"xxx\<CR>", 'xt!')
1027 call assert_equal('c', m)
1028 call assert_equal('"xxx', @:)
1029
1030 " terminal mode
1031 if CanRunVimInTerminal()
1032 tnoremap <F3> <Cmd>let m = mode(1)<CR>
1033 let buf = Run_shell_in_terminal({})
1034 call feedkeys("\<F3>", 'xt')
1035 call assert_equal('t', m)
1036 call assert_equal('t', mode(1))
1037 call StopShellInTerminal(buf)
Bram Moolenaar957cf672020-11-12 14:21:06 +01001038 close!
1039 tunmap <F3>
1040 endif
1041
1042 " invoke cmdline mode recursively
1043 noremap! <F2> <Cmd>norm! :foo<CR>
1044 %d
1045 call setline(1, ['some short lines', 'of test text'])
1046 call feedkeys(":bar\<F2>x\<C-B>\"\r", 'xt')
1047 call assert_equal('"barx', @:)
1048 unmap! <F2>
1049
1050 " test for calling a <SID> function
1051 let lines =<< trim END
1052 map <F2> <Cmd>call <SID>do_it()<CR>
1053 func s:do_it()
1054 let g:x = 32
1055 endfunc
1056 END
1057 call writefile(lines, 'Xscript')
1058 source Xscript
1059 call feedkeys("\<F2>", 'xt')
1060 call assert_equal(32, g:x)
1061 call delete('Xscript')
1062
1063 unmap <F3>
1064 unmap! <F3>
1065 %bw!
Bram Moolenaar4a441202020-11-28 14:43:26 +01001066
1067 " command line ending in "0" is handled without errors
1068 onoremap ix <cmd>eval 0<cr>
1069 call feedkeys('dix.', 'xt')
1070 ounmap ix
Bram Moolenaar957cf672020-11-12 14:21:06 +01001071endfunc
1072
1073" text object enters visual mode
1074func TextObj()
1075 if mode() !=# "v"
1076 normal! v
1077 end
1078 call cursor(1, 3)
1079 normal! o
1080 call cursor(2, 4)
1081endfunc
1082
1083func s:cmdmap(lhs, rhs)
1084 exe 'noremap ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
1085 exe 'noremap! ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
1086endfunc
1087
1088func s:cmdunmap(lhs)
1089 exe 'unmap ' .. a:lhs
1090 exe 'unmap! ' .. a:lhs
1091endfunc
1092
1093" Map various <Fx> keys used by the <Cmd> key tests
1094func s:setupMaps()
1095 call s:cmdmap('<F3>', 'let m = mode(1)')
1096 call s:cmdmap('<F4>', 'normal! ww')
1097 call s:cmdmap('<F5>', 'normal! "ay')
1098 call s:cmdmap('<F6>', 'throw "very error"')
1099 call s:cmdmap('<F7>', 'call TextObj()')
1100 call s:cmdmap('<F8>', 'startinsert')
1101 call s:cmdmap('<F9>', 'stopinsert')
1102endfunc
1103
1104" Remove the mappings setup by setupMaps()
1105func s:cleanupMaps()
1106 call s:cmdunmap('<F3>')
1107 call s:cmdunmap('<F4>')
1108 call s:cmdunmap('<F5>')
1109 call s:cmdunmap('<F6>')
1110 call s:cmdunmap('<F7>')
1111 call s:cmdunmap('<F8>')
1112 call s:cmdunmap('<F9>')
1113endfunc
1114
1115" Test for <Cmd> mapping in normal mode
1116func Test_map_cmdkey_normal_mode()
1117 new
1118 call s:setupMaps()
1119
1120 " check v:count and v:register works
1121 call s:cmdmap('<F2>', 'let s = [mode(1), v:count, v:register]')
1122 call feedkeys("\<F2>", 'xt')
1123 call assert_equal(['n', 0, '"'], s)
1124 call feedkeys("7\<F2>", 'xt')
1125 call assert_equal(['n', 7, '"'], s)
1126 call feedkeys("\"e\<F2>", 'xt')
1127 call assert_equal(['n', 0, 'e'], s)
1128 call feedkeys("5\"k\<F2>", 'xt')
1129 call assert_equal(['n', 5, 'k'], s)
1130 call s:cmdunmap('<F2>')
1131
1132 call setline(1, ['some short lines', 'of test text'])
1133 call feedkeys("\<F7>y", 'xt')
1134 call assert_equal("me short lines\nof t", @")
1135 call assert_equal('v', getregtype('"'))
1136 call assert_equal([0, 1, 3, 0], getpos("'<"))
1137 call assert_equal([0, 2, 4, 0], getpos("'>"))
1138
1139 " startinsert
1140 %d
1141 call feedkeys("\<F8>abc", 'xt')
1142 call assert_equal('abc', getline(1))
1143
1144 " feedkeys are not executed immediately
1145 noremap ,a <Cmd>call feedkeys("aalpha") \| let g:a = getline(2)<CR>
1146 %d
1147 call setline(1, ['some short lines', 'of test text'])
1148 call cursor(2, 3)
1149 call feedkeys(",a\<F3>", 'xt')
1150 call assert_equal('of test text', g:a)
1151 call assert_equal('n', m)
1152 call assert_equal(['some short lines', 'of alphatest text'], getline(1, '$'))
1153 nunmap ,a
1154
1155 " feedkeys(..., 'x') is executed immediately, but insert mode is aborted
1156 noremap ,b <Cmd>call feedkeys("abeta", 'x') \| let g:b = getline(2)<CR>
1157 call feedkeys(",b\<F3>", 'xt')
1158 call assert_equal('n', m)
1159 call assert_equal('of alphabetatest text', g:b)
1160 nunmap ,b
1161
1162 call s:cleanupMaps()
1163 %bw!
1164endfunc
1165
1166" Test for <Cmd> mapping with the :normal command
1167func Test_map_cmdkey_normal_cmd()
1168 new
1169 noremap ,x <Cmd>call append(1, "xx") \| call append(1, "aa")<CR>
1170 noremap ,f <Cmd>nosuchcommand<CR>
1171 noremap ,e <Cmd>throw "very error" \| call append(1, "yy")<CR>
1172 noremap ,m <Cmd>echoerr "The message." \| call append(1, "zz")<CR>
1173 noremap ,w <Cmd>for i in range(5) \| if i==1 \| echoerr "Err" \| endif \| call append(1, i) \| endfor<CR>
1174
1175 call setline(1, ['some short lines', 'of test text'])
1176 exe "norm ,x\r"
1177 call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], getline(1, '$'))
1178
1179 call assert_fails('norm ,f', 'E492:')
1180 call assert_fails('norm ,e', 'very error')
1181 call assert_fails('norm ,m', 'The message.')
1182 call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], getline(1, '$'))
1183
1184 %d
1185 let caught_err = 0
1186 try
1187 exe "normal ,w"
1188 catch /Vim(echoerr):Err/
1189 let caught_err = 1
1190 endtry
1191 call assert_equal(1, caught_err)
1192 call assert_equal(['', '0'], getline(1, '$'))
1193
1194 %d
1195 call assert_fails('normal ,w', 'Err')
1196 call assert_equal(['', '4', '3', '2' ,'1', '0'], getline(1, '$'))
1197 call assert_equal(1, line('.'))
1198
1199 nunmap ,x
1200 nunmap ,f
1201 nunmap ,e
1202 nunmap ,m
1203 nunmap ,w
1204 %bw!
1205endfunc
1206
1207" Test for <Cmd> mapping in visual mode
1208func Test_map_cmdkey_visual_mode()
1209 new
1210 set showmode
1211 call s:setupMaps()
1212
1213 call setline(1, ['some short lines', 'of test text'])
1214 call feedkeys("v\<F4>", 'xt!')
1215 call assert_equal(['v', 1, 12], [mode(1), col('v'), col('.')])
1216
Bram Moolenaarf08b0eb2021-10-16 13:00:14 +01001217 " can invoke an operator, ending the visual mode
Bram Moolenaar957cf672020-11-12 14:21:06 +01001218 let @a = ''
1219 call feedkeys("\<F5>", 'xt!')
1220 call assert_equal('n', mode(1))
1221 call assert_equal('some short l', @a)
1222
1223 " error doesn't interrupt visual mode
1224 call assert_fails('call feedkeys("ggvw\<F6>", "xt!")', 'E605:')
1225 call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
1226 call feedkeys("\<F7>", 'xt!')
1227 call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1228
1229 " startinsert gives "-- (insert) VISUAL --" mode
1230 call feedkeys("\<F8>", 'xt!')
1231 call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1232 redraw!
1233 call assert_match('^-- (insert) VISUAL --', Screenline(&lines))
1234 call feedkeys("\<Esc>new ", 'x')
1235 call assert_equal(['some short lines', 'of new test text'], getline(1, '$'))
1236
1237 call s:cleanupMaps()
1238 set showmode&
1239 %bw!
1240endfunc
1241
1242" Test for <Cmd> mapping in select mode
1243func Test_map_cmdkey_select_mode()
1244 new
1245 set showmode
1246 call s:setupMaps()
1247
1248 snoremap <F1> <cmd>throw "very error"<CR>
1249 snoremap <F2> <cmd>normal! <c-g>"by<CR>
1250 call setline(1, ['some short lines', 'of test text'])
1251
1252 call feedkeys("gh\<F4>", "xt!")
1253 call assert_equal(['s', 1, 12], [mode(1), col('v'), col('.')])
1254 redraw!
1255 call assert_match('^-- SELECT --', Screenline(&lines))
1256
1257 " visual mapping in select mode restarts select mode after operator
1258 let @a = ''
1259 call feedkeys("\<F5>", 'xt!')
1260 call assert_equal('s', mode(1))
1261 call assert_equal('some short l', @a)
1262
1263 " select mode mapping works, and does not restart select mode
1264 let @b = ''
1265 call feedkeys("\<F2>", 'xt!')
1266 call assert_equal('n', mode(1))
1267 call assert_equal('some short l', @b)
1268
1269 " error doesn't interrupt temporary visual mode
1270 call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F6>", "xt!")', 'E605:')
1271 redraw!
1272 call assert_match('^-- VISUAL --', Screenline(&lines))
1273 " quirk: restoration of select mode is not performed
1274 call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
1275
1276 " error doesn't interrupt select mode
1277 call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F1>", "xt!")', 'E605:')
1278 redraw!
1279 call assert_match('^-- SELECT --', Screenline(&lines))
1280 call assert_equal(['s', 1, 6], [mode(1), col('v'), col('.')])
1281
1282 call feedkeys("\<F7>", 'xt!')
1283 redraw!
1284 call assert_match('^-- SELECT --', Screenline(&lines))
1285 call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1286
1287 " startinsert gives "-- SELECT (insert) --" mode
1288 call feedkeys("\<F8>", 'xt!')
1289 redraw!
1290 call assert_match('^-- (insert) SELECT --', Screenline(&lines))
1291 call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1292 call feedkeys("\<Esc>new ", 'x')
1293 call assert_equal(['some short lines', 'of new test text'], getline(1, '$'))
1294
1295 sunmap <F1>
1296 sunmap <F2>
1297 call s:cleanupMaps()
1298 set showmode&
1299 %bw!
1300endfunc
1301
1302" Test for <Cmd> mapping in operator-pending mode
1303func Test_map_cmdkey_op_pending_mode()
1304 new
1305 call s:setupMaps()
1306
1307 call setline(1, ['some short lines', 'of test text'])
1308 call feedkeys("d\<F4>", 'xt')
1309 call assert_equal(['lines', 'of test text'], getline(1, '$'))
1310 call assert_equal(['some short '], getreg('"', 1, 1))
1311 " create a new undo point
1312 let &undolevels = &undolevels
1313
1314 call feedkeys(".", 'xt')
1315 call assert_equal(['test text'], getline(1, '$'))
1316 call assert_equal(['lines', 'of '], getreg('"', 1, 1))
1317 " create a new undo point
1318 let &undolevels = &undolevels
1319
1320 call feedkeys("uu", 'xt')
1321 call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
1322
1323 " error aborts operator-pending, operator not performed
1324 call assert_fails('call feedkeys("d\<F6>", "xt")', 'E605:')
1325 call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
1326
1327 call feedkeys("\"bd\<F7>", 'xt')
1328 call assert_equal(['soest text'], getline(1, '$'))
1329 call assert_equal(['me short lines', 'of t'], getreg('b', 1, 1))
1330
1331 " startinsert aborts operator
1332 call feedkeys("d\<F8>cc", 'xt')
1333 call assert_equal(['soccest text'], getline(1, '$'))
1334
1335 call s:cleanupMaps()
1336 %bw!
1337endfunc
1338
1339" Test for <Cmd> mapping in insert mode
1340func Test_map_cmdkey_insert_mode()
1341 new
1342 call s:setupMaps()
1343
1344 call setline(1, ['some short lines', 'of test text'])
1345 " works the same as <C-O>w<C-O>w
1346 call feedkeys("iindeed \<F4>little ", 'xt')
1347 call assert_equal(['indeed some short little lines', 'of test text'], getline(1, '$'))
1348 call assert_fails('call feedkeys("i\<F6> 2", "xt")', 'E605:')
1349 call assert_equal(['indeed some short little 2 lines', 'of test text'], getline(1, '$'))
1350
1351 " Note when entering visual mode from InsertEnter autocmd, an async event,
1352 " or a <Cmd> mapping, vim ends up in undocumented "INSERT VISUAL" mode.
1353 call feedkeys("i\<F7>stuff ", 'xt')
1354 call assert_equal(['indeed some short little 2 lines', 'of stuff test text'], getline(1, '$'))
1355 call assert_equal(['v', 1, 3, 2, 9], [mode(1), line('v'), col('v'), line('.'), col('.')])
1356
1357 call feedkeys("\<F5>", 'xt')
1358 call assert_equal(['deed some short little 2 lines', 'of stuff '], getreg('a', 1, 1))
1359
1360 " also works as part of abbreviation
1361 abbr foo <Cmd>let g:y = 17<CR>bar
1362 exe "normal i\<space>foo "
1363 call assert_equal(17, g:y)
1364 call assert_equal('in bar deed some short little 2 lines', getline(1))
1365 unabbr foo
1366
1367 " :startinsert does nothing
1368 call setline(1, 'foo bar')
1369 call feedkeys("ggi\<F8>vim", 'xt')
1370 call assert_equal('vimfoo bar', getline(1))
1371
1372 " :stopinsert works
1373 call feedkeys("ggi\<F9>Abc", 'xt')
1374 call assert_equal('vimfoo barbc', getline(1))
1375
1376 call s:cleanupMaps()
1377 %bw!
1378endfunc
1379
1380" Test for <Cmd> mapping in insert-completion mode
1381func Test_map_cmdkey_insert_complete_mode()
1382 new
1383 call s:setupMaps()
1384
1385 call setline(1, 'some short lines')
1386 call feedkeys("os\<C-X>\<C-N>\<F3>\<C-N> ", 'xt')
1387 call assert_equal('ic', m)
1388 call assert_equal(['some short lines', 'short '], getline(1, '$'))
1389
1390 call s:cleanupMaps()
1391 %bw!
1392endfunc
1393
1394" Test for <Cmd> mapping in cmdline mode
1395func Test_map_cmdkey_cmdline_mode()
1396 new
1397 call s:setupMaps()
1398
1399 call setline(1, ['some short lines', 'of test text'])
1400 let x = 0
1401 call feedkeys(":let x\<F3>= 10\r", 'xt')
1402 call assert_equal('c', m)
1403 call assert_equal(10, x)
1404
1405 " exception doesn't leave cmdline mode
1406 call assert_fails('call feedkeys(":let x\<F6>= 20\r", "xt")', 'E605:')
1407 call assert_equal(20, x)
1408
1409 " move cursor in the buffer from cmdline mode
1410 call feedkeys(":let x\<F4>= 30\r", 'xt')
1411 call assert_equal(30, x)
1412 call assert_equal(12, col('.'))
1413
1414 " :startinsert takes effect after leaving cmdline mode
1415 call feedkeys(":let x\<F8>= 40\rnew ", 'xt')
1416 call assert_equal(40, x)
1417 call assert_equal('some short new lines', getline(1))
1418
1419 call s:cleanupMaps()
1420 %bw!
1421endfunc
1422
Bram Moolenaarc77534c2020-11-18 11:34:37 +01001423func Test_map_cmdkey_redo()
1424 func SelectDash()
1425 call search('^---\n\zs', 'bcW')
1426 norm! V
1427 call search('\n\ze---$', 'W')
1428 endfunc
1429
1430 let text =<< trim END
1431 ---
1432 aaa
1433 ---
1434 bbb
1435 bbb
1436 ---
1437 ccc
1438 ccc
1439 ccc
1440 ---
1441 END
1442 new Xcmdtext
1443 call setline(1, text)
1444
1445 onoremap <silent> i- <Cmd>call SelectDash()<CR>
1446 call feedkeys('2Gdi-', 'xt')
1447 call assert_equal(['---', '---'], getline(1, 2))
1448 call feedkeys('j.', 'xt')
1449 call assert_equal(['---', '---', '---'], getline(1, 3))
1450 call feedkeys('j.', 'xt')
1451 call assert_equal(['---', '---', '---', '---'], getline(1, 4))
1452
1453 bwipe!
1454 call delete('Xcmdtext')
1455 delfunc SelectDash
1456 ounmap i-
1457endfunc
1458
Bram Moolenaara9725222022-01-16 13:30:33 +00001459func Test_map_script_cmd_restore()
1460 let lines =<< trim END
1461 vim9script
1462 nnoremap <F3> <ScriptCmd>eval 1 + 2<CR>
1463 END
Bram Moolenaar62aec932022-01-29 21:45:34 +00001464 call v9.CheckScriptSuccess(lines)
Bram Moolenaara9725222022-01-16 13:30:33 +00001465 call feedkeys("\<F3>:let g:result = 3+4\<CR>", 'xtc')
1466 call assert_equal(7, g:result)
1467
1468 nunmap <F3>
1469 unlet g:result
1470endfunc
1471
Bram Moolenaardc987762022-01-16 15:52:35 +00001472func Test_map_script_cmd_finds_func()
1473 let lines =<< trim END
1474 vim9script
1475 onoremap <F3> <ScriptCmd>Func()<CR>
1476 def Func()
1477 g:func_called = 'yes'
1478 enddef
1479 END
Bram Moolenaar62aec932022-01-29 21:45:34 +00001480 call v9.CheckScriptSuccess(lines)
Bram Moolenaardc987762022-01-16 15:52:35 +00001481 call feedkeys("y\<F3>\<Esc>", 'xtc')
1482 call assert_equal('yes', g:func_called)
1483
1484 ounmap <F3>
1485 unlet g:func_called
1486endfunc
1487
Bram Moolenaarf61c89d2022-01-19 22:51:48 +00001488func Test_map_script_cmd_survives_unmap()
1489 let lines =<< trim END
1490 vim9script
1491 var n = 123
1492 nnoremap <F4> <ScriptCmd><CR>
1493 autocmd CmdlineEnter * silent! nunmap <F4>
1494 nnoremap <F3> :<ScriptCmd>eval setbufvar(bufnr(), "result", n)<CR>
1495 feedkeys("\<F3>\<CR>", 'xct')
1496 assert_equal(123, b:result)
1497 END
Bram Moolenaar62aec932022-01-29 21:45:34 +00001498 call v9.CheckScriptSuccess(lines)
Bram Moolenaarf61c89d2022-01-19 22:51:48 +00001499
1500 nunmap <F3>
1501 unlet b:result
Bram Moolenaarca34db32022-01-20 11:17:18 +00001502 autocmd! CmdlineEnter
Bram Moolenaarf61c89d2022-01-19 22:51:48 +00001503endfunc
1504
Bram Moolenaar1f448d92021-03-22 19:37:06 +01001505" Test for using <script> with a map to remap characters in rhs
1506func Test_script_local_remap()
1507 new
1508 inoremap <buffer> <SID>xyz mno
1509 inoremap <buffer> <script> abc st<SID>xyzre
1510 normal iabc
1511 call assert_equal('stmnore', getline(1))
1512 bwipe!
1513endfunc
1514
Bram Moolenaar4934ed32021-04-30 19:43:11 +02001515func Test_abbreviate_multi_byte()
1516 new
1517 iabbrev foo bar
1518 call feedkeys("ifoo…\<Esc>", 'xt')
1519 call assert_equal("bar…", getline(1))
1520 iunabbrev foo
1521 bwipe!
1522endfunc
1523
Yegappan Lakshmanan2d6d7182021-06-13 21:52:48 +02001524" Test for abbreviations with 'latin1' encoding
1525func Test_abbreviate_latin1_encoding()
1526 set encoding=latin1
1527 call assert_fails('abbr ab#$c ABC', 'E474:')
1528 new
1529 iabbr <buffer> #i #include
1530 iabbr <buffer> ## #enddef
1531 exe "normal i#i\<C-]>"
1532 call assert_equal('#include', getline(1))
1533 exe "normal 0Di##\<C-]>"
1534 call assert_equal('#enddef', getline(1))
1535 %bw!
1536 set encoding=utf-8
1537endfunc
1538
Bram Moolenaar1fc34222022-03-03 13:56:24 +00001539" Test for <Plug> always being mapped, even when used with "noremap".
1540func Test_plug_remap()
1541 let g:foo = 0
1542 nnoremap <Plug>(Increase_x) <Cmd>let g:foo += 1<CR>
1543 nmap <F2> <Plug>(Increase_x)
1544 nnoremap <F3> <Plug>(Increase_x)
1545 call feedkeys("\<F2>", 'xt')
1546 call assert_equal(1, g:foo)
1547 call feedkeys("\<F3>", 'xt')
1548 call assert_equal(2, g:foo)
1549 nnoremap x <Nop>
1550 nmap <F4> x<Plug>(Increase_x)x
1551 nnoremap <F5> x<Plug>(Increase_x)x
1552 call setline(1, 'Some text')
1553 normal! gg$
1554 call feedkeys("\<F4>", 'xt')
1555 call assert_equal(3, g:foo)
1556 call assert_equal('Some text', getline(1))
1557 call feedkeys("\<F5>", 'xt')
1558 call assert_equal(4, g:foo)
1559 call assert_equal('Some te', getline(1))
1560 nunmap <Plug>(Increase_x)
1561 nunmap <F2>
1562 nunmap <F3>
1563 nunmap <F4>
1564 nunmap <F5>
1565 unlet g:foo
1566 %bw!
1567endfunc
1568
zeertzjqac92ab72022-04-24 15:58:30 +01001569func Test_mouse_drag_mapped_start_select()
1570 set mouse=a
1571 set selectmode=key,mouse
1572 func ClickExpr()
1573 call test_setmouse(1, 1)
1574 return "\<LeftMouse>"
1575 endfunc
1576 func DragExpr()
1577 call test_setmouse(1, 2)
1578 return "\<LeftDrag>"
1579 endfunc
1580 nnoremap <expr> <F2> ClickExpr()
1581 nmap <expr> <F3> DragExpr()
1582
1583 nnoremap <LeftDrag> <LeftDrag><Cmd><CR>
1584 exe "normal \<F2>\<F3>"
1585 call assert_equal('s', mode())
1586 exe "normal! \<C-\>\<C-N>"
1587
1588 nunmap <LeftDrag>
1589 nunmap <F2>
1590 nunmap <F3>
1591 delfunc ClickExpr
1592 delfunc DragExpr
1593 set selectmode&
1594 set mouse&
1595endfunc
1596
zeertzjq0f68e6c2022-04-05 13:17:01 +01001597" Test for mapping <LeftDrag> in Insert mode
1598func Test_mouse_drag_insert_map()
1599 set mouse=a
1600 func ClickExpr()
1601 call test_setmouse(1, 1)
1602 return "\<LeftMouse>"
1603 endfunc
1604 func DragExpr()
1605 call test_setmouse(1, 2)
1606 return "\<LeftDrag>"
1607 endfunc
1608 inoremap <expr> <F2> ClickExpr()
1609 imap <expr> <F3> DragExpr()
1610
1611 inoremap <LeftDrag> <LeftDrag><Cmd>let g:dragged = 1<CR>
1612 exe "normal i\<F2>\<F3>"
1613 call assert_equal(1, g:dragged)
1614 call assert_equal('v', mode())
1615 exe "normal! \<C-\>\<C-N>"
1616 unlet g:dragged
1617
1618 inoremap <LeftDrag> <LeftDrag><C-\><C-N>
1619 exe "normal i\<F2>\<F3>"
1620 call assert_equal('n', mode())
1621
1622 iunmap <LeftDrag>
1623 iunmap <F2>
1624 iunmap <F3>
1625 delfunc ClickExpr
1626 delfunc DragExpr
1627 set mouse&
1628endfunc
1629
zeertzjqabeb09b2022-04-26 12:29:43 +01001630func Test_unmap_simplifiable()
zeertzjqa4e33322022-04-24 17:07:53 +01001631 map <C-I> foo
1632 map <Tab> bar
1633 call assert_equal('foo', maparg('<C-I>'))
1634 call assert_equal('bar', maparg('<Tab>'))
1635 unmap <C-I>
1636 call assert_equal('', maparg('<C-I>'))
1637 call assert_equal('bar', maparg('<Tab>'))
1638 unmap <Tab>
zeertzjqabeb09b2022-04-26 12:29:43 +01001639
1640 map <C-I> foo
1641 unmap <Tab>
1642 " This should not error
1643 unmap <C-I>
zeertzjqa4e33322022-04-24 17:07:53 +01001644endfunc
1645
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +01001646" vim: shiftwidth=2 sts=2 expandtab