blob: d7e4caa9112a148123096865299117a904197205 [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 Moolenaar26d98212019-01-27 22:32:55 +01007
Bram Moolenaar2d1a2482016-08-14 15:32:11 +02008func Test_abbreviation()
9 " abbreviation with 0x80 should work
10 inoreab чкпр vim
11 call feedkeys("Goчкпр \<Esc>", "xt")
12 call assert_equal('vim ', getline('$'))
13 iunab чкпр
14 set nomodified
15endfunc
16
Bram Moolenaar8485be42019-04-23 16:36:05 +020017func Test_abclear()
18 abbrev foo foobar
19 iabbrev fooi foobari
20 cabbrev fooc foobarc
21 call assert_equal("\n\n"
22 \ .. "c fooc foobarc\n"
23 \ .. "i fooi foobari\n"
24 \ .. "! foo foobar", execute('abbrev'))
25
26 iabclear
27 call assert_equal("\n\n"
28 \ .. "c fooc foobarc\n"
29 \ .. "c foo foobar", execute('abbrev'))
30 abbrev foo foobar
31 iabbrev fooi foobari
32
33 cabclear
34 call assert_equal("\n\n"
35 \ .. "i fooi foobari\n"
36 \ .. "i foo foobar", execute('abbrev'))
37 abbrev foo foobar
38 cabbrev fooc foobarc
39
40 abclear
41 call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
Bram Moolenaarf0cee192020-02-16 13:33:56 +010042 call assert_fails('%abclear', 'E481:')
Bram Moolenaar8485be42019-04-23 16:36:05 +020043endfunc
44
45func Test_abclear_buffer()
46 abbrev foo foobar
47 new X1
48 abbrev <buffer> foo1 foobar1
49 new X2
50 abbrev <buffer> foo2 foobar2
51
52 call assert_equal("\n\n"
53 \ .. "! foo2 @foobar2\n"
54 \ .. "! foo foobar", execute('abbrev'))
55
56 abclear <buffer>
57 call assert_equal("\n\n"
58 \ .. "! foo foobar", execute('abbrev'))
59
60 b X1
61 call assert_equal("\n\n"
62 \ .. "! foo1 @foobar1\n"
63 \ .. "! foo foobar", execute('abbrev'))
64 abclear <buffer>
65 call assert_equal("\n\n"
66 \ .. "! foo foobar", execute('abbrev'))
67
68 abclear
69 call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
70
71 %bwipe
72endfunc
73
Bram Moolenaar2d1a2482016-08-14 15:32:11 +020074func Test_map_ctrl_c_insert()
75 " mapping of ctrl-c in Insert mode
76 set cpo-=< cpo-=k
77 inoremap <c-c> <ctrl-c>
78 cnoremap <c-c> dummy
79 cunmap <c-c>
Bram Moolenaarfccd93f2020-05-31 22:06:51 +020080 call feedkeys("GoTEST2: CTRL-C |\<*C-C>A|\<Esc>", "xt")
Bram Moolenaar2d1a2482016-08-14 15:32:11 +020081 call assert_equal('TEST2: CTRL-C |<ctrl-c>A|', getline('$'))
82 unmap! <c-c>
83 set nomodified
84endfunc
85
86func Test_map_ctrl_c_visual()
87 " mapping of ctrl-c in Visual mode
88 vnoremap <c-c> :<C-u>$put ='vmap works'
Bram Moolenaarfccd93f2020-05-31 22:06:51 +020089 call feedkeys("GV\<*C-C>\<CR>", "xt")
Bram Moolenaar2d1a2482016-08-14 15:32:11 +020090 call assert_equal('vmap works', getline('$'))
91 vunmap <c-c>
92 set nomodified
93endfunc
94
95func Test_map_langmap()
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +020096 CheckFeature langmap
Bram Moolenaar920694c2016-08-21 17:45:02 +020097
98 " check langmap applies in normal mode
99 set langmap=+- nolangremap
100 new
101 call setline(1, ['a', 'b', 'c'])
102 2
103 call assert_equal('b', getline('.'))
104 call feedkeys("+", "xt")
105 call assert_equal('a', getline('.'))
106
107 " check no remapping
108 map x +
109 2
110 call feedkeys("x", "xt")
111 call assert_equal('c', getline('.'))
112
113 " check with remapping
114 set langremap
115 2
116 call feedkeys("x", "xt")
117 call assert_equal('a', getline('.'))
118
119 unmap x
120 bwipe!
121
122 " 'langnoremap' follows 'langremap' and vise versa
123 set langremap
124 set langnoremap
125 call assert_equal(0, &langremap)
126 set langremap
127 call assert_equal(0, &langnoremap)
128 set nolangremap
129 call assert_equal(1, &langnoremap)
130
Bram Moolenaarda9ce2c2016-09-02 19:34:10 +0200131 " check default values
132 set langnoremap&
133 call assert_equal(0, &langnoremap)
134 call assert_equal(1, &langremap)
135 set langremap&
136 call assert_equal(0, &langnoremap)
137 call assert_equal(1, &langremap)
138
Bram Moolenaar920694c2016-08-21 17:45:02 +0200139 " langmap should not apply in insert mode, 'langremap' doesn't matter
140 set langmap=+{ nolangremap
141 call feedkeys("Go+\<Esc>", "xt")
142 call assert_equal('+', getline('$'))
143 set langmap=+{ langremap
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200144 call feedkeys("Go+\<Esc>", "xt")
145 call assert_equal('+', getline('$'))
146
Bram Moolenaar920694c2016-08-21 17:45:02 +0200147 " langmap used for register name in insert mode.
148 call setreg('a', 'aaaa')
149 call setreg('b', 'bbbb')
150 call setreg('c', 'cccc')
151 set langmap=ab langremap
152 call feedkeys("Go\<C-R>a\<Esc>", "xt")
153 call assert_equal('bbbb', getline('$'))
154 call feedkeys("Go\<C-R>\<C-R>a\<Esc>", "xt")
155 call assert_equal('bbbb', getline('$'))
156 " mapping does not apply
157 imap c a
158 call feedkeys("Go\<C-R>c\<Esc>", "xt")
159 call assert_equal('cccc', getline('$'))
160 imap a c
161 call feedkeys("Go\<C-R>a\<Esc>", "xt")
162 call assert_equal('bbbb', getline('$'))
163
164 " langmap should not apply in Command-line mode
165 set langmap=+{ nolangremap
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200166 call feedkeys(":call append(line('$'), '+')\<CR>", "xt")
167 call assert_equal('+', getline('$'))
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200168
Bram Moolenaare90858d2017-02-01 17:24:34 +0100169 iunmap a
170 iunmap c
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200171 set nomodified
172endfunc
173
174func Test_map_feedkeys()
175 " issue #212 (feedkeys insert mapping at current position)
176 nnoremap . :call feedkeys(".", "in")<cr>
177 call setline('$', ['a b c d', 'a b c d'])
178 $-1
179 call feedkeys("0qqdw.ifoo\<Esc>qj0@q\<Esc>", "xt")
180 call assert_equal(['fooc d', 'fooc d'], getline(line('$') - 1, line('$')))
Bram Moolenaare90858d2017-02-01 17:24:34 +0100181 nunmap .
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200182 set nomodified
183endfunc
184
185func Test_map_cursor()
186 " <c-g>U<cursor> works only within a single line
187 imapclear
188 imap ( ()<c-g>U<left>
189 call feedkeys("G2o\<Esc>ki\<CR>Test1: text with a (here some more text\<Esc>k.", "xt")
190 call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 2))
191 call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 1))
192
193 " test undo
194 call feedkeys("G2o\<Esc>ki\<CR>Test2: text wit a (here some more text [und undo]\<C-G>u\<Esc>k.u", "xt")
195 call assert_equal('', getline(line('$') - 2))
196 call assert_equal('Test2: text wit a (here some more text [und undo])', getline(line('$') - 1))
197 set nomodified
198 imapclear
199endfunc
200
Bram Moolenaar75bf3d22019-03-26 22:46:05 +0100201func Test_map_cursor_ctrl_gU()
202 " <c-g>U<cursor> works only within a single line
203 nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left>
204 call setline(1, ['foo', 'foobar', '', 'foo'])
205 call cursor(1,2)
206 call feedkeys("c<*PREFIX\<esc>.", 'xt')
207 call assert_equal(['PREFIXfoo', 'foobar', '', 'PREFIXfoo'], getline(1,'$'))
208 " break undo manually
209 set ul=1000
210 exe ":norm! uu"
211 call assert_equal(['foo', 'foobar', '', 'foo'], getline(1,'$'))
212
213 " Test that it does not work if the cursor moves to the previous line
214 " 2 times <S-Left> move to the previous line
215 nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left><C-G>U<S-Left>
216 call setline(1, ['', ' foo', 'foobar', '', 'foo'])
217 call cursor(2,3)
218 call feedkeys("c<*PREFIX\<esc>.", 'xt')
219 call assert_equal(['PREFIXPREFIX', ' foo', 'foobar', '', 'foo'], getline(1,'$'))
220 nmapclear
221endfunc
222
223
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200224" This isn't actually testing a mapping, but similar use of CTRL-G U as above.
225func Test_break_undo()
Bram Moolenaar75bf3d22019-03-26 22:46:05 +0100226 set whichwrap=<,>,[,]
Bram Moolenaar2d1a2482016-08-14 15:32:11 +0200227 call feedkeys("G4o2k", "xt")
228 exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>."
229 call assert_equal('new line here', getline(line('$') - 3))
230 call assert_equal('Test3: text with a (parenthesis here', getline(line('$') - 2))
231 call assert_equal('new line here', getline(line('$') - 1))
232 set nomodified
233endfunc
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +0200234
235func Test_map_meta_quotes()
236 imap <M-"> foo
Bram Moolenaarfccd93f2020-05-31 22:06:51 +0200237 call feedkeys("Go-\<*M-\">-\<Esc>", "xt")
Bram Moolenaar35a4cfa2016-08-14 16:07:48 +0200238 call assert_equal("-foo-", getline('$'))
239 set nomodified
240 iunmap <M-">
241endfunc
Bram Moolenaar878c2632017-04-01 15:15:52 +0200242
Bram Moolenaarc8fd33d2019-08-16 20:33:05 +0200243func Test_map_meta_multibyte()
244 imap <M-á> foo
Bram Moolenaar2f710af2019-08-16 20:56:03 +0200245 call assert_match('i <M-á>\s*foo', execute('imap'))
Bram Moolenaarc8fd33d2019-08-16 20:33:05 +0200246 iunmap <M-á>
247endfunc
248
Bram Moolenaar878c2632017-04-01 15:15:52 +0200249func Test_abbr_after_line_join()
250 new
251 abbr foo bar
252 set backspace=indent,eol,start
253 exe "normal o\<BS>foo "
254 call assert_equal("bar ", getline(1))
255 bwipe!
256 unabbr foo
257 set backspace&
258endfunc
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200259
260func Test_map_timeout()
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200261 CheckFeature timers
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200262 nnoremap aaaa :let got_aaaa = 1<CR>
263 nnoremap bb :let got_bb = 1<CR>
264 nmap b aaa
265 new
266 func ExitInsert(timer)
267 let g:line = getline(1)
268 call feedkeys("\<Esc>", "t")
269 endfunc
270 set timeout timeoutlen=200
Bram Moolenaar26d98212019-01-27 22:32:55 +0100271 let timer = timer_start(300, 'ExitInsert')
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200272 " After the 'b' Vim waits for another character to see if it matches 'bb'.
273 " When it times out it is expanded to "aaa", but there is no wait for
274 " "aaaa". Can't check that reliably though.
275 call feedkeys("b", "xt!")
276 call assert_equal("aa", g:line)
277 call assert_false(exists('got_aaa'))
278 call assert_false(exists('got_bb'))
279
280 bwipe!
281 nunmap aaaa
282 nunmap bb
283 nunmap b
284 set timeoutlen&
285 delfunc ExitInsert
Bram Moolenaar26d98212019-01-27 22:32:55 +0100286 call timer_stop(timer)
287endfunc
288
289func Test_map_timeout_with_timer_interrupt()
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200290 CheckFeature job
291 CheckFeature timers
Bram Moolenaar26d98212019-01-27 22:32:55 +0100292
293 " Confirm the timer invoked in exit_cb of the job doesn't disturb mapped key
294 " sequence.
295 new
296 let g:val = 0
297 nnoremap \12 :let g:val = 1<CR>
298 nnoremap \123 :let g:val = 2<CR>
Bram Moolenaarea94c852019-08-16 21:47:27 +0200299 set timeout timeoutlen=200
Bram Moolenaar26d98212019-01-27 22:32:55 +0100300
301 func ExitCb(job, status)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +0100302 let g:timer = timer_start(1, {-> feedkeys("3\<Esc>", 't')})
Bram Moolenaar26d98212019-01-27 22:32:55 +0100303 endfunc
304
305 call job_start([&shell, &shellcmdflag, 'echo'], {'exit_cb': 'ExitCb'})
306 call feedkeys('\12', 'xt!')
307 call assert_equal(2, g:val)
308
309 bwipe!
310 nunmap \12
311 nunmap \123
312 set timeoutlen&
313 call WaitFor({-> exists('g:timer')})
314 call timer_stop(g:timer)
315 unlet g:timer
316 unlet g:val
317 delfunc ExitCb
Bram Moolenaarb7637c42017-04-23 18:49:36 +0200318endfunc
Bram Moolenaarc3c3e692018-04-26 22:30:33 +0200319
320func Test_abbreviation_CR()
321 new
322 func Eatchar(pat)
323 let c = nr2char(getchar(0))
324 return (c =~ a:pat) ? '' : c
325 endfunc
326 iabbrev <buffer><silent> ~~7 <c-r>=repeat('~', 7)<CR><c-r>=Eatchar('\s')<cr>
327 call feedkeys("GA~~7 \<esc>", 'xt')
328 call assert_equal('~~~~~~~', getline('$'))
329 %d
330 call feedkeys("GA~~7\<cr>\<esc>", 'xt')
331 call assert_equal(['~~~~~~~', ''], getline(1,'$'))
332 delfunc Eatchar
333 bw!
334endfunc
Bram Moolenaar5e3423d2018-05-13 18:36:27 +0200335
336func Test_cabbr_visual_mode()
337 cabbr s su
338 call feedkeys(":s \<c-B>\"\<CR>", 'itx')
339 call assert_equal('"su ', getreg(':'))
340 call feedkeys(":'<,'>s \<c-B>\"\<CR>", 'itx')
341 let expected = '"'. "'<,'>su "
342 call assert_equal(expected, getreg(':'))
343 call feedkeys(": '<,'>s \<c-B>\"\<CR>", 'itx')
344 let expected = '" '. "'<,'>su "
345 call assert_equal(expected, getreg(':'))
346 call feedkeys(":'a,'bs \<c-B>\"\<CR>", 'itx')
347 let expected = '"'. "'a,'bsu "
348 call assert_equal(expected, getreg(':'))
349 cunabbr s
350endfunc
Bram Moolenaar5976f8f2018-12-27 23:44:44 +0100351
352func Test_motionforce_omap()
353 func GetCommand()
354 let g:m=mode(1)
355 let [g:lnum1, g:col1] = searchpos('-', 'Wb')
356 if g:lnum1 == 0
357 return "\<Esc>"
358 endif
359 let [g:lnum2, g:col2] = searchpos('-', 'W')
360 if g:lnum2 == 0
361 return "\<Esc>"
362 endif
363 return ":call Select()\<CR>"
364 endfunc
365 func Select()
366 call cursor([g:lnum1, g:col1])
367 exe "normal! 1 ". (strlen(g:m) == 2 ? 'v' : g:m[2])
368 call cursor([g:lnum2, g:col2])
369 execute "normal! \<BS>"
370 endfunc
371 new
372 onoremap <buffer><expr> i- GetCommand()
373 " 1) default omap mapping
374 %d_
375 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
376 call cursor(2, 1)
377 norm di-
378 call assert_equal('no', g:m)
379 call assert_equal(['aaa -- eee'], getline(1, '$'))
380 " 2) forced characterwise operation
381 %d_
382 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
383 call cursor(2, 1)
384 norm dvi-
385 call assert_equal('nov', g:m)
386 call assert_equal(['aaa -- eee'], getline(1, '$'))
387 " 3) forced linewise operation
388 %d_
389 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
390 call cursor(2, 1)
391 norm dVi-
392 call assert_equal('noV', g:m)
393 call assert_equal([''], getline(1, '$'))
394 " 4) forced blockwise operation
395 %d_
396 call setline(1, ['aaa - bbb', 'x', 'ddd - eee'])
397 call cursor(2, 1)
398 exe "norm d\<C-V>i-"
399 call assert_equal("no\<C-V>", g:m)
400 call assert_equal(['aaabbb', 'x', 'dddeee'], getline(1, '$'))
401 bwipe!
402 delfunc Select
403 delfunc GetCommand
404endfunc
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200405
406func Test_error_in_map_expr()
Bram Moolenaar8c5a2782019-08-07 23:07:07 +0200407 " Unlike CheckRunVimInTerminal this does work in a win32 console
408 CheckFeature terminal
409 if has('win32') && has('gui_running')
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200410 throw 'Skipped: cannot run Vim in a terminal window'
411 endif
412
413 let lines =<< trim [CODE]
414 func Func()
415 " fail to create list
416 let x = [
417 endfunc
418 nmap <expr> ! Func()
419 set updatetime=50
420 [CODE]
421 call writefile(lines, 'Xtest.vim')
422
Bram Moolenaar0d702022019-07-04 14:20:41 +0200423 let buf = term_start(GetVimCommandCleanTerm() .. ' -S Xtest.vim', {'term_rows': 8})
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200424 let job = term_getjob(buf)
425 call WaitForAssert({-> assert_notequal('', term_getline(buf, 8))})
426
427 " GC must not run during map-expr processing, which can make Vim crash.
428 call term_sendkeys(buf, '!')
Bram Moolenaar6a2c5a72020-04-08 21:50:25 +0200429 call TermWait(buf, 50)
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200430 call term_sendkeys(buf, "\<CR>")
Bram Moolenaar6a2c5a72020-04-08 21:50:25 +0200431 call TermWait(buf, 50)
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200432 call assert_equal('run', job_status(job))
433
434 call term_sendkeys(buf, ":qall!\<CR>")
435 call WaitFor({-> job_status(job) ==# 'dead'})
436 if has('unix')
437 call assert_equal('', job_info(job).termsig)
438 endif
439
440 call delete('Xtest.vim')
441 exe buf .. 'bwipe!'
442endfunc
Bram Moolenaarfafb4b12019-10-16 18:34:57 +0200443
444func Test_list_mappings()
Bram Moolenaar2559a472019-10-16 23:33:12 +0200445 " Remove default mappings
446 imapclear
Bram Moolenaar4f2f61a2019-10-16 22:27:49 +0200447
Bram Moolenaarfafb4b12019-10-16 18:34:57 +0200448 inoremap <C-M> CtrlM
449 inoremap <A-S> AltS
450 inoremap <S-/> ShiftSlash
451 call assert_equal([
452 \ 'i <S-/> * ShiftSlash',
453 \ 'i <M-S> * AltS',
454 \ 'i <C-M> * CtrlM',
455 \], execute('imap')->trim()->split("\n"))
456 iunmap <C-M>
457 iunmap <A-S>
458 call assert_equal(['i <S-/> * ShiftSlash'], execute('imap')->trim()->split("\n"))
459 iunmap <S-/>
460 call assert_equal(['No mapping found'], execute('imap')->trim()->split("\n"))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100461
462 " List global, buffer local and script local mappings
463 nmap ,f /^\k\+ (<CR>
464 nmap <buffer> ,f /^\k\+ (<CR>
465 nmap <script> ,fs /^\k\+ (<CR>
466 call assert_equal(['n ,f @/^\k\+ (<CR>',
467 \ 'n ,fs & /^\k\+ (<CR>',
468 \ 'n ,f /^\k\+ (<CR>'],
469 \ execute('nmap ,f')->trim()->split("\n"))
470
471 " List <Nop> mapping
472 nmap ,n <Nop>
473 call assert_equal(['n ,n <Nop>'],
474 \ execute('nmap ,n')->trim()->split("\n"))
475
Bram Moolenaar7f51bbe2020-01-24 20:21:19 +0100476 " verbose map
477 call assert_match("\tLast set from .*/test_mapping.vim line \\d\\+$",
478 \ execute('verbose map ,n')->trim()->split("\n")[1])
479
480 " map to CTRL-V
481 exe "nmap ,k \<C-V>"
482 call assert_equal(['n ,k <Nop>'],
483 \ execute('nmap ,k')->trim()->split("\n"))
484
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100485 nmapclear
Bram Moolenaarfafb4b12019-10-16 18:34:57 +0200486endfunc
Bram Moolenaar4ebe0e62019-11-22 20:55:40 +0100487
Bram Moolenaar18b7d862021-03-17 13:28:05 +0100488func Test_expr_map_gets_cursor()
489 new
490 call setline(1, ['one', 'some w!rd'])
491 func StoreColumn()
492 let g:exprLine = line('.')
493 let g:exprCol = col('.')
494 return 'x'
495 endfunc
496 nnoremap <expr> x StoreColumn()
497 2
498 nmap ! f!<Ignore>x
499 call feedkeys("!", 'xt')
500 call assert_equal('some wrd', getline(2))
501 call assert_equal(2, g:exprLine)
502 call assert_equal(7, g:exprCol)
503
504 bwipe!
505 unlet g:exprLine
506 unlet g:exprCol
Bram Moolenaar6ccfd992021-03-17 13:39:33 +0100507 delfunc StoreColumn
Bram Moolenaar18b7d862021-03-17 13:28:05 +0100508 nunmap x
509 nunmap !
510endfunc
511
Bram Moolenaar4ebe0e62019-11-22 20:55:40 +0100512func Test_expr_map_restore_cursor()
513 CheckScreendump
514
515 let lines =<< trim END
516 call setline(1, ['one', 'two', 'three'])
517 2
518 set ls=2
519 hi! link StatusLine ErrorMsg
520 noremap <expr> <C-B> Func()
521 func Func()
522 let g:on = !get(g:, 'on', 0)
523 redraws
524 return ''
525 endfunc
526 func Status()
527 return get(g:, 'on', 0) ? '[on]' : ''
528 endfunc
529 set stl=%{Status()}
530 END
531 call writefile(lines, 'XtestExprMap')
532 let buf = RunVimInTerminal('-S XtestExprMap', #{rows: 10})
Bram Moolenaar6a2c5a72020-04-08 21:50:25 +0200533 call TermWait(buf)
Bram Moolenaar4ebe0e62019-11-22 20:55:40 +0100534 call term_sendkeys(buf, "\<C-B>")
535 call VerifyScreenDump(buf, 'Test_map_expr_1', {})
536
537 " clean up
538 call StopVimInTerminal(buf)
539 call delete('XtestExprMap')
540endfunc
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100541
542" Test for mapping errors
543func Test_map_error()
544 call assert_fails('unmap', 'E474:')
545 call assert_fails("exe 'map ' .. repeat('a', 51) .. ' :ls'", 'E474:')
546 call assert_fails('unmap abc', 'E31:')
547 call assert_fails('unabbr abc', 'E24:')
548 call assert_equal('', maparg(''))
549 call assert_fails('echo maparg("abc", [])', 'E730:')
550
551 " unique map
552 map ,w /[#&!]<CR>
553 call assert_fails("map <unique> ,w /[#&!]<CR>", 'E227:')
554 " unique buffer-local map
555 call assert_fails("map <buffer> <unique> ,w /[.,;]<CR>", 'E225:')
556 unmap ,w
557
558 " unique abbreviation
559 abbr SP special
560 call assert_fails("abbr <unique> SP special", 'E226:')
561 " unique buffer-local map
562 call assert_fails("abbr <buffer> <unique> SP special", 'E224:')
563 unabbr SP
564
565 call assert_fails('mapclear abc', 'E474:')
566 call assert_fails('abclear abc', 'E474:')
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100567 call assert_fails('abbr $xyz abc', 'E474:')
568
569 " space character in an abbreviation
570 call assert_fails('abbr ab<space> ABC', 'E474:')
571
572 " invalid <expr> map
573 map <expr> ,f abc
574 call assert_fails('normal ,f', 'E121:')
575 unmap <expr> ,f
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100576
577 " Recursive use of :normal in a map
578 set maxmapdepth=100
579 map gq :normal gq<CR>
580 call assert_fails('normal gq', 'E192:')
581 unmap gq
582 set maxmapdepth&
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100583endfunc
584
585" Test for <special> key mapping
586func Test_map_special()
587 new
588 let old_cpo = &cpo
589 set cpo+=<
590 imap <F12> Blue
591 call feedkeys("i\<F12>", "x")
592 call assert_equal("<F12>", getline(1))
593 call feedkeys("ddi<F12>", "x")
594 call assert_equal("Blue", getline(1))
595 iunmap <F12>
596 imap <special> <F12> Green
597 call feedkeys("ddi\<F12>", "x")
598 call assert_equal("Green", getline(1))
599 call feedkeys("ddi<F12>", "x")
600 call assert_equal("<F12>", getline(1))
601 iunmap <special> <F12>
602 let &cpo = old_cpo
603 %bwipe!
604endfunc
605
606" Test for hasmapto()
607func Test_hasmapto()
608 call assert_equal(0, hasmapto('/^\k\+ ('))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100609 map ,f /^\k\+ (<CR>
610 call assert_equal(1, hasmapto('/^\k\+ ('))
611 unmap ,f
612
613 " Insert mode mapping
614 call assert_equal(0, hasmapto('/^\k\+ (', 'i'))
615 imap ,f /^\k\+ (<CR>
616 call assert_equal(1, hasmapto('/^\k\+ (', 'i'))
617 iunmap ,f
618
619 " Normal mode mapping
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100620 call assert_equal(0, hasmapto('/^\k\+ (', 'n'))
621 nmap ,f /^\k\+ (<CR>
622 call assert_equal(1, hasmapto('/^\k\+ ('))
623 call assert_equal(1, hasmapto('/^\k\+ (', 'n'))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100624 nunmap ,f
625
626 " Visual and Select mode mapping
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100627 call assert_equal(0, hasmapto('/^\k\+ (', 'v'))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100628 call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
629 call assert_equal(0, hasmapto('/^\k\+ (', 's'))
630 vmap ,f /^\k\+ (<CR>
631 call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
632 call assert_equal(1, hasmapto('/^\k\+ (', 'x'))
633 call assert_equal(1, hasmapto('/^\k\+ (', 's'))
634 vunmap ,f
635
636 " Visual mode mapping
637 call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
638 xmap ,f /^\k\+ (<CR>
639 call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
640 call assert_equal(1, hasmapto('/^\k\+ (', 'x'))
641 call assert_equal(0, hasmapto('/^\k\+ (', 's'))
642 xunmap ,f
643
644 " Select mode mapping
645 call assert_equal(0, hasmapto('/^\k\+ (', 's'))
646 smap ,f /^\k\+ (<CR>
647 call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
648 call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
649 call assert_equal(1, hasmapto('/^\k\+ (', 's'))
650 sunmap ,f
651
652 " Operator-pending mode mapping
653 call assert_equal(0, hasmapto('/^\k\+ (', 'o'))
654 omap ,f /^\k\+ (<CR>
655 call assert_equal(1, hasmapto('/^\k\+ (', 'o'))
656 ounmap ,f
657
658 " Language mapping
659 call assert_equal(0, hasmapto('/^\k\+ (', 'l'))
660 lmap ,f /^\k\+ (<CR>
661 call assert_equal(1, hasmapto('/^\k\+ (', 'l'))
662 lunmap ,f
663
664 " Cmdline mode mapping
665 call assert_equal(0, hasmapto('/^\k\+ (', 'c'))
666 cmap ,f /^\k\+ (<CR>
667 call assert_equal(1, hasmapto('/^\k\+ (', 'c'))
668 cunmap ,f
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100669
670 call assert_equal(0, hasmapto('/^\k\+ (', 'n', 1))
671endfunc
672
673" Test for command-line completion of maps
674func Test_mapcomplete()
675 call assert_equal(['<buffer>', '<expr>', '<nowait>', '<script>',
676 \ '<silent>', '<special>', '<unique>'],
677 \ getcompletion('', 'mapping'))
678 call assert_equal([], getcompletion(',d', 'mapping'))
679
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100680 call feedkeys(":unmap <buf\<C-A>\<C-B>\"\<CR>", 'tx')
681 call assert_equal('"unmap <buffer>', @:)
682
683 call feedkeys(":unabbr <buf\<C-A>\<C-B>\"\<CR>", 'tx')
684 call assert_equal('"unabbr <buffer>', @:)
685
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100686 call feedkeys(":abbr! \<C-A>\<C-B>\"\<CR>", 'tx')
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100687 call assert_equal("\"abbr! \x01", @:)
688
689 " Multiple matches for a map
690 nmap ,f /H<CR>
691 omap ,f /H<CR>
692 call feedkeys(":map ,\<C-A>\<C-B>\"\<CR>", 'tx')
693 call assert_equal('"map ,f', @:)
694 mapclear
695endfunc
696
697" Test for <expr> in abbreviation
698func Test_expr_abbr()
699 new
700 iabbr <expr> teh "the"
701 call feedkeys("iteh ", "tx")
702 call assert_equal('the ', getline(1))
703 iabclear
704 call setline(1, '')
705
706 " invalid <expr> abbreviation
707 abbr <expr> hte GetAbbr()
708 call assert_fails('normal ihte ', 'E117:')
Bram Moolenaar28ee8922020-10-28 20:20:00 +0100709 call assert_equal('', getline(1))
Bram Moolenaarc2a60ae2020-01-23 16:19:54 +0100710 unabbr <expr> hte
711
712 close!
713endfunc
714
715" Test for storing mappings in different modes in a vimrc file
716func Test_mkvimrc_mapmodes()
717 map a1 /a1
718 nmap a2 /a2
719 vmap a3 /a3
720 smap a4 /a4
721 xmap a5 /a5
722 omap a6 /a6
723 map! a7 /a7
724 imap a8 /a8
725 lmap a9 /a9
726 cmap a10 /a10
727 tmap a11 /a11
728 " Normal + Visual map
729 map a12 /a12
730 sunmap a12
731 ounmap a12
732 " Normal + Selectmode map
733 map a13 /a13
734 xunmap a13
735 ounmap a13
736 " Normal + OpPending map
737 map a14 /a14
738 vunmap a14
739 " Visual + Selectmode map
740 map a15 /a15
741 nunmap a15
742 ounmap a15
743 " Visual + OpPending map
744 map a16 /a16
745 nunmap a16
746 sunmap a16
747 " Selectmode + OpPending map
748 map a17 /a17
749 nunmap a17
750 xunmap a17
751 " Normal + Visual + Selectmode map
752 map a18 /a18
753 ounmap a18
754 " Normal + Visual + OpPending map
755 map a19 /a19
756 sunmap a19
757 " Normal + Selectmode + OpPending map
758 map a20 /a20
759 xunmap a20
760 " Visual + Selectmode + OpPending map
761 map a21 /a21
762 nunmap a21
763 " Mapping to Nop
764 map a22 <Nop>
765 " Script local mapping
766 map <script> a23 /a23
767
768 " Newline in {lhs} and {rhs} of a map
769 exe "map a24\<C-V>\<C-J> ia24\<C-V>\<C-J><Esc>"
770
771 " Abbreviation
772 abbr a25 A25
773 cabbr a26 A26
774 iabbr a27 A27
775
776 mkvimrc! Xvimrc
777 let l = readfile('Xvimrc')
778 call assert_equal(['map a1 /a1'], filter(copy(l), 'v:val =~ " a1 "'))
779 call assert_equal(['nmap a2 /a2'], filter(copy(l), 'v:val =~ " a2 "'))
780 call assert_equal(['vmap a3 /a3'], filter(copy(l), 'v:val =~ " a3 "'))
781 call assert_equal(['smap a4 /a4'], filter(copy(l), 'v:val =~ " a4 "'))
782 call assert_equal(['xmap a5 /a5'], filter(copy(l), 'v:val =~ " a5 "'))
783 call assert_equal(['omap a6 /a6'], filter(copy(l), 'v:val =~ " a6 "'))
784 call assert_equal(['map! a7 /a7'], filter(copy(l), 'v:val =~ " a7 "'))
785 call assert_equal(['imap a8 /a8'], filter(copy(l), 'v:val =~ " a8 "'))
786 call assert_equal(['lmap a9 /a9'], filter(copy(l), 'v:val =~ " a9 "'))
787 call assert_equal(['cmap a10 /a10'], filter(copy(l), 'v:val =~ " a10 "'))
788 call assert_equal(['tmap a11 /a11'], filter(copy(l), 'v:val =~ " a11 "'))
789 call assert_equal(['nmap a12 /a12', 'xmap a12 /a12'],
790 \ filter(copy(l), 'v:val =~ " a12 "'))
791 call assert_equal(['nmap a13 /a13', 'smap a13 /a13'],
792 \ filter(copy(l), 'v:val =~ " a13 "'))
793 call assert_equal(['nmap a14 /a14', 'omap a14 /a14'],
794 \ filter(copy(l), 'v:val =~ " a14 "'))
795 call assert_equal(['vmap a15 /a15'], filter(copy(l), 'v:val =~ " a15 "'))
796 call assert_equal(['xmap a16 /a16', 'omap a16 /a16'],
797 \ filter(copy(l), 'v:val =~ " a16 "'))
798 call assert_equal(['smap a17 /a17', 'omap a17 /a17'],
799 \ filter(copy(l), 'v:val =~ " a17 "'))
800 call assert_equal(['nmap a18 /a18', 'vmap a18 /a18'],
801 \ filter(copy(l), 'v:val =~ " a18 "'))
802 call assert_equal(['nmap a19 /a19', 'xmap a19 /a19', 'omap a19 /a19'],
803 \ filter(copy(l), 'v:val =~ " a19 "'))
804 call assert_equal(['nmap a20 /a20', 'smap a20 /a20', 'omap a20 /a20'],
805 \ filter(copy(l), 'v:val =~ " a20 "'))
806 call assert_equal(['vmap a21 /a21', 'omap a21 /a21'],
807 \ filter(copy(l), 'v:val =~ " a21 "'))
808 call assert_equal(['map a22 <Nop>'], filter(copy(l), 'v:val =~ " a22 "'))
809 call assert_equal([], filter(copy(l), 'v:val =~ " a23 "'))
810 call assert_equal(["map a24<NL> ia24<NL>\x16\e"],
811 \ filter(copy(l), 'v:val =~ " a24"'))
812
813 call assert_equal(['abbr a25 A25'], filter(copy(l), 'v:val =~ " a25 "'))
814 call assert_equal(['cabbr a26 A26'], filter(copy(l), 'v:val =~ " a26 "'))
815 call assert_equal(['iabbr a27 A27'], filter(copy(l), 'v:val =~ " a27 "'))
816 call delete('Xvimrc')
817
818 mapclear
819 nmapclear
820 vmapclear
821 xmapclear
822 smapclear
823 omapclear
824 imapclear
825 lmapclear
826 cmapclear
827 tmapclear
828endfunc
829
830" Test for recursive mapping ('maxmapdepth')
831func Test_map_recursive()
832 map x y
833 map y x
834 call assert_fails('normal x', 'E223:')
835 unmap x
836 unmap y
837endfunc
838
839" Test for removing an abbreviation using {rhs} and with space after {lhs}
840func Test_abbr_remove()
841 abbr foo bar
842 let d = maparg('foo', 'i', 1, 1)
843 call assert_equal(['foo', 'bar', '!'], [d.lhs, d.rhs, d.mode])
844 unabbr bar
845 call assert_equal({}, maparg('foo', 'i', 1, 1))
846
847 abbr foo bar
848 unabbr foo<space><tab>
849 call assert_equal({}, maparg('foo', 'i', 1, 1))
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +0100850endfunc
851
Bram Moolenaar7f51bbe2020-01-24 20:21:19 +0100852" Trigger an abbreviation using a special key
853func Test_abbr_trigger_special()
854 new
855 iabbr teh the
856 call feedkeys("iteh\<F2>\<Esc>", 'xt')
857 call assert_equal('the<F2>', getline(1))
858 iunab teh
859 close!
860endfunc
861
862" Test for '<' in 'cpoptions'
863func Test_map_cpo_special_keycode()
864 set cpo-=<
865 imap x<Bslash>k Test
866 let d = maparg('x<Bslash>k', 'i', 0, 1)
867 call assert_equal(['x\k', 'Test', 'i'], [d.lhs, d.rhs, d.mode])
868 call feedkeys(":imap x\<C-A>\<C-B>\"\<CR>", 'tx')
869 call assert_equal('"imap x\k', @:)
870 iunmap x<Bslash>k
871 set cpo+=<
872 imap x<Bslash>k Test
873 let d = maparg('x<Bslash>k', 'i', 0, 1)
874 call assert_equal(['x<Bslash>k', 'Test', 'i'], [d.lhs, d.rhs, d.mode])
875 call feedkeys(":imap x\<C-A>\<C-B>\"\<CR>", 'tx')
876 call assert_equal('"imap x<Bslash>k', @:)
877 iunmap x<Bslash>k
878 set cpo-=<
879 " Modifying 'cpo' above adds some default mappings, remove them
880 mapclear
881 mapclear!
882endfunc
883
Bram Moolenaar957cf672020-11-12 14:21:06 +0100884" Test for <Cmd> key in maps to execute commands
885func Test_map_cmdkey()
886 new
887
888 " Error cases
889 let x = 0
890 noremap <F3> <Cmd><Cmd>let x = 1<CR>
891 call assert_fails('call feedkeys("\<F3>", "xt")', 'E1136:')
892 call assert_equal(0, x)
893
894 noremap <F3> <Cmd><F3>let x = 2<CR>
895 call assert_fails('call feedkeys("\<F3>", "xt")', 'E1137:')
896 call assert_equal(0, x)
897
898 noremap <F3> <Cmd>let x = 3
899 call assert_fails('call feedkeys("\<F3>", "xt!")', 'E1135:')
900 call assert_equal(0, x)
901
902 " works in various modes and sees the correct mode()
903 noremap <F3> <Cmd>let m = mode(1)<CR>
904 noremap! <F3> <Cmd>let m = mode(1)<CR>
905
906 " normal mode
907 call feedkeys("\<F3>", 'xt')
908 call assert_equal('n', m)
909
910 " visual mode
911 call feedkeys("v\<F3>", 'xt!')
912 call assert_equal('v', m)
913 " shouldn't leave the visual mode
914 call assert_equal('v', mode(1))
915 call feedkeys("\<Esc>", 'xt')
916 call assert_equal('n', mode(1))
917
918 " visual mapping in select mode
919 call feedkeys("gh\<F3>", 'xt!')
920 call assert_equal('v', m)
921 " shouldn't leave select mode
922 call assert_equal('s', mode(1))
923 call feedkeys("\<Esc>", 'xt')
924 call assert_equal('n', mode(1))
925
926 " select mode mapping
927 snoremap <F3> <Cmd>let m = mode(1)<cr>
928 call feedkeys("gh\<F3>", 'xt!')
929 call assert_equal('s', m)
930 " shouldn't leave select mode
931 call assert_equal('s', mode(1))
932 call feedkeys("\<Esc>", 'xt')
933 call assert_equal('n', mode(1))
934
935 " operator-pending mode
936 call feedkeys("d\<F3>", 'xt!')
937 call assert_equal('no', m)
938 " leaves the operator-pending mode
939 call assert_equal('n', mode(1))
940
941 " insert mode
942 call feedkeys("i\<F3>abc", 'xt')
943 call assert_equal('i', m)
944 call assert_equal('abc', getline('.'))
945
946 " replace mode
947 call feedkeys("0R\<F3>two", 'xt')
948 call assert_equal('R', m)
949 call assert_equal('two', getline('.'))
950
951 " virtual replace mode
952 call setline('.', "one\ttwo")
953 call feedkeys("4|gR\<F3>xxx", 'xt')
954 call assert_equal('Rv', m)
955 call assert_equal("onexxx\ttwo", getline('.'))
956
957 " cmdline mode
958 call feedkeys(":\<F3>\"xxx\<CR>", 'xt!')
959 call assert_equal('c', m)
960 call assert_equal('"xxx', @:)
961
962 " terminal mode
963 if CanRunVimInTerminal()
964 tnoremap <F3> <Cmd>let m = mode(1)<CR>
965 let buf = Run_shell_in_terminal({})
966 call feedkeys("\<F3>", 'xt')
967 call assert_equal('t', m)
968 call assert_equal('t', mode(1))
969 call StopShellInTerminal(buf)
970 call TermWait(buf)
971 close!
972 tunmap <F3>
973 endif
974
975 " invoke cmdline mode recursively
976 noremap! <F2> <Cmd>norm! :foo<CR>
977 %d
978 call setline(1, ['some short lines', 'of test text'])
979 call feedkeys(":bar\<F2>x\<C-B>\"\r", 'xt')
980 call assert_equal('"barx', @:)
981 unmap! <F2>
982
983 " test for calling a <SID> function
984 let lines =<< trim END
985 map <F2> <Cmd>call <SID>do_it()<CR>
986 func s:do_it()
987 let g:x = 32
988 endfunc
989 END
990 call writefile(lines, 'Xscript')
991 source Xscript
992 call feedkeys("\<F2>", 'xt')
993 call assert_equal(32, g:x)
994 call delete('Xscript')
995
996 unmap <F3>
997 unmap! <F3>
998 %bw!
Bram Moolenaar4a441202020-11-28 14:43:26 +0100999
1000 " command line ending in "0" is handled without errors
1001 onoremap ix <cmd>eval 0<cr>
1002 call feedkeys('dix.', 'xt')
1003 ounmap ix
Bram Moolenaar957cf672020-11-12 14:21:06 +01001004endfunc
1005
1006" text object enters visual mode
1007func TextObj()
1008 if mode() !=# "v"
1009 normal! v
1010 end
1011 call cursor(1, 3)
1012 normal! o
1013 call cursor(2, 4)
1014endfunc
1015
1016func s:cmdmap(lhs, rhs)
1017 exe 'noremap ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
1018 exe 'noremap! ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
1019endfunc
1020
1021func s:cmdunmap(lhs)
1022 exe 'unmap ' .. a:lhs
1023 exe 'unmap! ' .. a:lhs
1024endfunc
1025
1026" Map various <Fx> keys used by the <Cmd> key tests
1027func s:setupMaps()
1028 call s:cmdmap('<F3>', 'let m = mode(1)')
1029 call s:cmdmap('<F4>', 'normal! ww')
1030 call s:cmdmap('<F5>', 'normal! "ay')
1031 call s:cmdmap('<F6>', 'throw "very error"')
1032 call s:cmdmap('<F7>', 'call TextObj()')
1033 call s:cmdmap('<F8>', 'startinsert')
1034 call s:cmdmap('<F9>', 'stopinsert')
1035endfunc
1036
1037" Remove the mappings setup by setupMaps()
1038func s:cleanupMaps()
1039 call s:cmdunmap('<F3>')
1040 call s:cmdunmap('<F4>')
1041 call s:cmdunmap('<F5>')
1042 call s:cmdunmap('<F6>')
1043 call s:cmdunmap('<F7>')
1044 call s:cmdunmap('<F8>')
1045 call s:cmdunmap('<F9>')
1046endfunc
1047
1048" Test for <Cmd> mapping in normal mode
1049func Test_map_cmdkey_normal_mode()
1050 new
1051 call s:setupMaps()
1052
1053 " check v:count and v:register works
1054 call s:cmdmap('<F2>', 'let s = [mode(1), v:count, v:register]')
1055 call feedkeys("\<F2>", 'xt')
1056 call assert_equal(['n', 0, '"'], s)
1057 call feedkeys("7\<F2>", 'xt')
1058 call assert_equal(['n', 7, '"'], s)
1059 call feedkeys("\"e\<F2>", 'xt')
1060 call assert_equal(['n', 0, 'e'], s)
1061 call feedkeys("5\"k\<F2>", 'xt')
1062 call assert_equal(['n', 5, 'k'], s)
1063 call s:cmdunmap('<F2>')
1064
1065 call setline(1, ['some short lines', 'of test text'])
1066 call feedkeys("\<F7>y", 'xt')
1067 call assert_equal("me short lines\nof t", @")
1068 call assert_equal('v', getregtype('"'))
1069 call assert_equal([0, 1, 3, 0], getpos("'<"))
1070 call assert_equal([0, 2, 4, 0], getpos("'>"))
1071
1072 " startinsert
1073 %d
1074 call feedkeys("\<F8>abc", 'xt')
1075 call assert_equal('abc', getline(1))
1076
1077 " feedkeys are not executed immediately
1078 noremap ,a <Cmd>call feedkeys("aalpha") \| let g:a = getline(2)<CR>
1079 %d
1080 call setline(1, ['some short lines', 'of test text'])
1081 call cursor(2, 3)
1082 call feedkeys(",a\<F3>", 'xt')
1083 call assert_equal('of test text', g:a)
1084 call assert_equal('n', m)
1085 call assert_equal(['some short lines', 'of alphatest text'], getline(1, '$'))
1086 nunmap ,a
1087
1088 " feedkeys(..., 'x') is executed immediately, but insert mode is aborted
1089 noremap ,b <Cmd>call feedkeys("abeta", 'x') \| let g:b = getline(2)<CR>
1090 call feedkeys(",b\<F3>", 'xt')
1091 call assert_equal('n', m)
1092 call assert_equal('of alphabetatest text', g:b)
1093 nunmap ,b
1094
1095 call s:cleanupMaps()
1096 %bw!
1097endfunc
1098
1099" Test for <Cmd> mapping with the :normal command
1100func Test_map_cmdkey_normal_cmd()
1101 new
1102 noremap ,x <Cmd>call append(1, "xx") \| call append(1, "aa")<CR>
1103 noremap ,f <Cmd>nosuchcommand<CR>
1104 noremap ,e <Cmd>throw "very error" \| call append(1, "yy")<CR>
1105 noremap ,m <Cmd>echoerr "The message." \| call append(1, "zz")<CR>
1106 noremap ,w <Cmd>for i in range(5) \| if i==1 \| echoerr "Err" \| endif \| call append(1, i) \| endfor<CR>
1107
1108 call setline(1, ['some short lines', 'of test text'])
1109 exe "norm ,x\r"
1110 call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], getline(1, '$'))
1111
1112 call assert_fails('norm ,f', 'E492:')
1113 call assert_fails('norm ,e', 'very error')
1114 call assert_fails('norm ,m', 'The message.')
1115 call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], getline(1, '$'))
1116
1117 %d
1118 let caught_err = 0
1119 try
1120 exe "normal ,w"
1121 catch /Vim(echoerr):Err/
1122 let caught_err = 1
1123 endtry
1124 call assert_equal(1, caught_err)
1125 call assert_equal(['', '0'], getline(1, '$'))
1126
1127 %d
1128 call assert_fails('normal ,w', 'Err')
1129 call assert_equal(['', '4', '3', '2' ,'1', '0'], getline(1, '$'))
1130 call assert_equal(1, line('.'))
1131
1132 nunmap ,x
1133 nunmap ,f
1134 nunmap ,e
1135 nunmap ,m
1136 nunmap ,w
1137 %bw!
1138endfunc
1139
1140" Test for <Cmd> mapping in visual mode
1141func Test_map_cmdkey_visual_mode()
1142 new
1143 set showmode
1144 call s:setupMaps()
1145
1146 call setline(1, ['some short lines', 'of test text'])
1147 call feedkeys("v\<F4>", 'xt!')
1148 call assert_equal(['v', 1, 12], [mode(1), col('v'), col('.')])
1149
1150 " can invoke an opeartor, ending the visual mode
1151 let @a = ''
1152 call feedkeys("\<F5>", 'xt!')
1153 call assert_equal('n', mode(1))
1154 call assert_equal('some short l', @a)
1155
1156 " error doesn't interrupt visual mode
1157 call assert_fails('call feedkeys("ggvw\<F6>", "xt!")', 'E605:')
1158 call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
1159 call feedkeys("\<F7>", 'xt!')
1160 call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1161
1162 " startinsert gives "-- (insert) VISUAL --" mode
1163 call feedkeys("\<F8>", 'xt!')
1164 call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1165 redraw!
1166 call assert_match('^-- (insert) VISUAL --', Screenline(&lines))
1167 call feedkeys("\<Esc>new ", 'x')
1168 call assert_equal(['some short lines', 'of new test text'], getline(1, '$'))
1169
1170 call s:cleanupMaps()
1171 set showmode&
1172 %bw!
1173endfunc
1174
1175" Test for <Cmd> mapping in select mode
1176func Test_map_cmdkey_select_mode()
1177 new
1178 set showmode
1179 call s:setupMaps()
1180
1181 snoremap <F1> <cmd>throw "very error"<CR>
1182 snoremap <F2> <cmd>normal! <c-g>"by<CR>
1183 call setline(1, ['some short lines', 'of test text'])
1184
1185 call feedkeys("gh\<F4>", "xt!")
1186 call assert_equal(['s', 1, 12], [mode(1), col('v'), col('.')])
1187 redraw!
1188 call assert_match('^-- SELECT --', Screenline(&lines))
1189
1190 " visual mapping in select mode restarts select mode after operator
1191 let @a = ''
1192 call feedkeys("\<F5>", 'xt!')
1193 call assert_equal('s', mode(1))
1194 call assert_equal('some short l', @a)
1195
1196 " select mode mapping works, and does not restart select mode
1197 let @b = ''
1198 call feedkeys("\<F2>", 'xt!')
1199 call assert_equal('n', mode(1))
1200 call assert_equal('some short l', @b)
1201
1202 " error doesn't interrupt temporary visual mode
1203 call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F6>", "xt!")', 'E605:')
1204 redraw!
1205 call assert_match('^-- VISUAL --', Screenline(&lines))
1206 " quirk: restoration of select mode is not performed
1207 call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
1208
1209 " error doesn't interrupt select mode
1210 call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F1>", "xt!")', 'E605:')
1211 redraw!
1212 call assert_match('^-- SELECT --', Screenline(&lines))
1213 call assert_equal(['s', 1, 6], [mode(1), col('v'), col('.')])
1214
1215 call feedkeys("\<F7>", 'xt!')
1216 redraw!
1217 call assert_match('^-- SELECT --', Screenline(&lines))
1218 call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1219
1220 " startinsert gives "-- SELECT (insert) --" mode
1221 call feedkeys("\<F8>", 'xt!')
1222 redraw!
1223 call assert_match('^-- (insert) SELECT --', Screenline(&lines))
1224 call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
1225 call feedkeys("\<Esc>new ", 'x')
1226 call assert_equal(['some short lines', 'of new test text'], getline(1, '$'))
1227
1228 sunmap <F1>
1229 sunmap <F2>
1230 call s:cleanupMaps()
1231 set showmode&
1232 %bw!
1233endfunc
1234
1235" Test for <Cmd> mapping in operator-pending mode
1236func Test_map_cmdkey_op_pending_mode()
1237 new
1238 call s:setupMaps()
1239
1240 call setline(1, ['some short lines', 'of test text'])
1241 call feedkeys("d\<F4>", 'xt')
1242 call assert_equal(['lines', 'of test text'], getline(1, '$'))
1243 call assert_equal(['some short '], getreg('"', 1, 1))
1244 " create a new undo point
1245 let &undolevels = &undolevels
1246
1247 call feedkeys(".", 'xt')
1248 call assert_equal(['test text'], getline(1, '$'))
1249 call assert_equal(['lines', 'of '], getreg('"', 1, 1))
1250 " create a new undo point
1251 let &undolevels = &undolevels
1252
1253 call feedkeys("uu", 'xt')
1254 call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
1255
1256 " error aborts operator-pending, operator not performed
1257 call assert_fails('call feedkeys("d\<F6>", "xt")', 'E605:')
1258 call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
1259
1260 call feedkeys("\"bd\<F7>", 'xt')
1261 call assert_equal(['soest text'], getline(1, '$'))
1262 call assert_equal(['me short lines', 'of t'], getreg('b', 1, 1))
1263
1264 " startinsert aborts operator
1265 call feedkeys("d\<F8>cc", 'xt')
1266 call assert_equal(['soccest text'], getline(1, '$'))
1267
1268 call s:cleanupMaps()
1269 %bw!
1270endfunc
1271
1272" Test for <Cmd> mapping in insert mode
1273func Test_map_cmdkey_insert_mode()
1274 new
1275 call s:setupMaps()
1276
1277 call setline(1, ['some short lines', 'of test text'])
1278 " works the same as <C-O>w<C-O>w
1279 call feedkeys("iindeed \<F4>little ", 'xt')
1280 call assert_equal(['indeed some short little lines', 'of test text'], getline(1, '$'))
1281 call assert_fails('call feedkeys("i\<F6> 2", "xt")', 'E605:')
1282 call assert_equal(['indeed some short little 2 lines', 'of test text'], getline(1, '$'))
1283
1284 " Note when entering visual mode from InsertEnter autocmd, an async event,
1285 " or a <Cmd> mapping, vim ends up in undocumented "INSERT VISUAL" mode.
1286 call feedkeys("i\<F7>stuff ", 'xt')
1287 call assert_equal(['indeed some short little 2 lines', 'of stuff test text'], getline(1, '$'))
1288 call assert_equal(['v', 1, 3, 2, 9], [mode(1), line('v'), col('v'), line('.'), col('.')])
1289
1290 call feedkeys("\<F5>", 'xt')
1291 call assert_equal(['deed some short little 2 lines', 'of stuff '], getreg('a', 1, 1))
1292
1293 " also works as part of abbreviation
1294 abbr foo <Cmd>let g:y = 17<CR>bar
1295 exe "normal i\<space>foo "
1296 call assert_equal(17, g:y)
1297 call assert_equal('in bar deed some short little 2 lines', getline(1))
1298 unabbr foo
1299
1300 " :startinsert does nothing
1301 call setline(1, 'foo bar')
1302 call feedkeys("ggi\<F8>vim", 'xt')
1303 call assert_equal('vimfoo bar', getline(1))
1304
1305 " :stopinsert works
1306 call feedkeys("ggi\<F9>Abc", 'xt')
1307 call assert_equal('vimfoo barbc', getline(1))
1308
1309 call s:cleanupMaps()
1310 %bw!
1311endfunc
1312
1313" Test for <Cmd> mapping in insert-completion mode
1314func Test_map_cmdkey_insert_complete_mode()
1315 new
1316 call s:setupMaps()
1317
1318 call setline(1, 'some short lines')
1319 call feedkeys("os\<C-X>\<C-N>\<F3>\<C-N> ", 'xt')
1320 call assert_equal('ic', m)
1321 call assert_equal(['some short lines', 'short '], getline(1, '$'))
1322
1323 call s:cleanupMaps()
1324 %bw!
1325endfunc
1326
1327" Test for <Cmd> mapping in cmdline mode
1328func Test_map_cmdkey_cmdline_mode()
1329 new
1330 call s:setupMaps()
1331
1332 call setline(1, ['some short lines', 'of test text'])
1333 let x = 0
1334 call feedkeys(":let x\<F3>= 10\r", 'xt')
1335 call assert_equal('c', m)
1336 call assert_equal(10, x)
1337
1338 " exception doesn't leave cmdline mode
1339 call assert_fails('call feedkeys(":let x\<F6>= 20\r", "xt")', 'E605:')
1340 call assert_equal(20, x)
1341
1342 " move cursor in the buffer from cmdline mode
1343 call feedkeys(":let x\<F4>= 30\r", 'xt')
1344 call assert_equal(30, x)
1345 call assert_equal(12, col('.'))
1346
1347 " :startinsert takes effect after leaving cmdline mode
1348 call feedkeys(":let x\<F8>= 40\rnew ", 'xt')
1349 call assert_equal(40, x)
1350 call assert_equal('some short new lines', getline(1))
1351
1352 call s:cleanupMaps()
1353 %bw!
1354endfunc
1355
Bram Moolenaarc77534c2020-11-18 11:34:37 +01001356func Test_map_cmdkey_redo()
1357 func SelectDash()
1358 call search('^---\n\zs', 'bcW')
1359 norm! V
1360 call search('\n\ze---$', 'W')
1361 endfunc
1362
1363 let text =<< trim END
1364 ---
1365 aaa
1366 ---
1367 bbb
1368 bbb
1369 ---
1370 ccc
1371 ccc
1372 ccc
1373 ---
1374 END
1375 new Xcmdtext
1376 call setline(1, text)
1377
1378 onoremap <silent> i- <Cmd>call SelectDash()<CR>
1379 call feedkeys('2Gdi-', 'xt')
1380 call assert_equal(['---', '---'], getline(1, 2))
1381 call feedkeys('j.', 'xt')
1382 call assert_equal(['---', '---', '---'], getline(1, 3))
1383 call feedkeys('j.', 'xt')
1384 call assert_equal(['---', '---', '---', '---'], getline(1, 4))
1385
1386 bwipe!
1387 call delete('Xcmdtext')
1388 delfunc SelectDash
1389 ounmap i-
1390endfunc
1391
Bram Moolenaar1f448d92021-03-22 19:37:06 +01001392" Test for using <script> with a map to remap characters in rhs
1393func Test_script_local_remap()
1394 new
1395 inoremap <buffer> <SID>xyz mno
1396 inoremap <buffer> <script> abc st<SID>xyzre
1397 normal iabc
1398 call assert_equal('stmnore', getline(1))
1399 bwipe!
1400endfunc
1401
Bram Moolenaar8ba6bb72020-01-20 20:41:42 +01001402" vim: shiftwidth=2 sts=2 expandtab