xref: /vim-8.2.3635/src/testdir/test_mapping.vim (revision 2e693a88)
1" Tests for mappings and abbreviations
2
3source shared.vim
4source check.vim
5
6func Test_abbreviation()
7  " abbreviation with 0x80 should work
8  inoreab чкпр   vim
9  call feedkeys("Goчкпр \<Esc>", "xt")
10  call assert_equal('vim ', getline('$'))
11  iunab чкпр
12  set nomodified
13endfunc
14
15func Test_abclear()
16   abbrev foo foobar
17   iabbrev fooi foobari
18   cabbrev fooc foobarc
19   call assert_equal("\n\n"
20         \        .. "c  fooc          foobarc\n"
21         \        .. "i  fooi          foobari\n"
22         \        .. "!  foo           foobar", execute('abbrev'))
23
24   iabclear
25   call assert_equal("\n\n"
26         \        .. "c  fooc          foobarc\n"
27         \        .. "c  foo           foobar", execute('abbrev'))
28   abbrev foo foobar
29   iabbrev fooi foobari
30
31   cabclear
32   call assert_equal("\n\n"
33         \        .. "i  fooi          foobari\n"
34         \        .. "i  foo           foobar", execute('abbrev'))
35   abbrev foo foobar
36   cabbrev fooc foobarc
37
38   abclear
39   call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
40endfunc
41
42func Test_abclear_buffer()
43  abbrev foo foobar
44  new X1
45  abbrev <buffer> foo1 foobar1
46  new X2
47  abbrev <buffer> foo2 foobar2
48
49  call assert_equal("\n\n"
50        \        .. "!  foo2         @foobar2\n"
51        \        .. "!  foo           foobar", execute('abbrev'))
52
53  abclear <buffer>
54  call assert_equal("\n\n"
55        \        .. "!  foo           foobar", execute('abbrev'))
56
57  b X1
58  call assert_equal("\n\n"
59        \        .. "!  foo1         @foobar1\n"
60        \        .. "!  foo           foobar", execute('abbrev'))
61  abclear <buffer>
62  call assert_equal("\n\n"
63        \        .. "!  foo           foobar", execute('abbrev'))
64
65  abclear
66   call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
67
68  %bwipe
69endfunc
70
71func Test_map_ctrl_c_insert()
72  " mapping of ctrl-c in Insert mode
73  set cpo-=< cpo-=k
74  inoremap <c-c> <ctrl-c>
75  cnoremap <c-c> dummy
76  cunmap <c-c>
77  call feedkeys("GoTEST2: CTRL-C |\<C-C>A|\<Esc>", "xt")
78  call assert_equal('TEST2: CTRL-C |<ctrl-c>A|', getline('$'))
79  unmap! <c-c>
80  set nomodified
81endfunc
82
83func Test_map_ctrl_c_visual()
84  " mapping of ctrl-c in Visual mode
85  vnoremap <c-c> :<C-u>$put ='vmap works'
86  call feedkeys("GV\<C-C>\<CR>", "xt")
87  call assert_equal('vmap works', getline('$'))
88  vunmap <c-c>
89  set nomodified
90endfunc
91
92func Test_map_langmap()
93  if !has('langmap')
94    return
95  endif
96
97  " check langmap applies in normal mode
98  set langmap=+- nolangremap
99  new
100  call setline(1, ['a', 'b', 'c'])
101  2
102  call assert_equal('b', getline('.'))
103  call feedkeys("+", "xt")
104  call assert_equal('a', getline('.'))
105
106  " check no remapping
107  map x +
108  2
109  call feedkeys("x", "xt")
110  call assert_equal('c', getline('.'))
111
112  " check with remapping
113  set langremap
114  2
115  call feedkeys("x", "xt")
116  call assert_equal('a', getline('.'))
117
118  unmap x
119  bwipe!
120
121  " 'langnoremap' follows 'langremap' and vise versa
122  set langremap
123  set langnoremap
124  call assert_equal(0, &langremap)
125  set langremap
126  call assert_equal(0, &langnoremap)
127  set nolangremap
128  call assert_equal(1, &langnoremap)
129
130  " check default values
131  set langnoremap&
132  call assert_equal(0, &langnoremap)
133  call assert_equal(1, &langremap)
134  set langremap&
135  call assert_equal(0, &langnoremap)
136  call assert_equal(1, &langremap)
137
138  " langmap should not apply in insert mode, 'langremap' doesn't matter
139  set langmap=+{ nolangremap
140  call feedkeys("Go+\<Esc>", "xt")
141  call assert_equal('+', getline('$'))
142  set langmap=+{ langremap
143  call feedkeys("Go+\<Esc>", "xt")
144  call assert_equal('+', getline('$'))
145
146  " langmap used for register name in insert mode.
147  call setreg('a', 'aaaa')
148  call setreg('b', 'bbbb')
149  call setreg('c', 'cccc')
150  set langmap=ab langremap
151  call feedkeys("Go\<C-R>a\<Esc>", "xt")
152  call assert_equal('bbbb', getline('$'))
153  call feedkeys("Go\<C-R>\<C-R>a\<Esc>", "xt")
154  call assert_equal('bbbb', getline('$'))
155  " mapping does not apply
156  imap c a
157  call feedkeys("Go\<C-R>c\<Esc>", "xt")
158  call assert_equal('cccc', getline('$'))
159  imap a c
160  call feedkeys("Go\<C-R>a\<Esc>", "xt")
161  call assert_equal('bbbb', getline('$'))
162
163  " langmap should not apply in Command-line mode
164  set langmap=+{ nolangremap
165  call feedkeys(":call append(line('$'), '+')\<CR>", "xt")
166  call assert_equal('+', getline('$'))
167
168  iunmap a
169  iunmap c
170  set nomodified
171endfunc
172
173func Test_map_feedkeys()
174  " issue #212 (feedkeys insert mapping at current position)
175  nnoremap . :call feedkeys(".", "in")<cr>
176  call setline('$', ['a b c d', 'a b c d'])
177  $-1
178  call feedkeys("0qqdw.ifoo\<Esc>qj0@q\<Esc>", "xt")
179  call assert_equal(['fooc d', 'fooc d'], getline(line('$') - 1, line('$')))
180  nunmap .
181  set nomodified
182endfunc
183
184func Test_map_cursor()
185  " <c-g>U<cursor> works only within a single line
186  imapclear
187  imap ( ()<c-g>U<left>
188  call feedkeys("G2o\<Esc>ki\<CR>Test1: text with a (here some more text\<Esc>k.", "xt")
189  call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 2))
190  call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 1))
191
192  " test undo
193  call feedkeys("G2o\<Esc>ki\<CR>Test2: text wit a (here some more text [und undo]\<C-G>u\<Esc>k.u", "xt")
194  call assert_equal('', getline(line('$') - 2))
195  call assert_equal('Test2: text wit a (here some more text [und undo])', getline(line('$') - 1))
196  set nomodified
197  imapclear
198endfunc
199
200func Test_map_cursor_ctrl_gU()
201  " <c-g>U<cursor> works only within a single line
202  nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left>
203  call setline(1, ['foo', 'foobar', '', 'foo'])
204  call cursor(1,2)
205  call feedkeys("c<*PREFIX\<esc>.", 'xt')
206  call assert_equal(['PREFIXfoo', 'foobar', '', 'PREFIXfoo'], getline(1,'$'))
207  " break undo manually
208  set ul=1000
209  exe ":norm! uu"
210  call assert_equal(['foo', 'foobar', '', 'foo'], getline(1,'$'))
211
212  " Test that it does not work if the cursor moves to the previous line
213  " 2 times <S-Left> move to the previous line
214  nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left><C-G>U<S-Left>
215  call setline(1, ['', ' foo', 'foobar', '', 'foo'])
216  call cursor(2,3)
217  call feedkeys("c<*PREFIX\<esc>.", 'xt')
218  call assert_equal(['PREFIXPREFIX', ' foo', 'foobar', '', 'foo'], getline(1,'$'))
219  nmapclear
220endfunc
221
222
223" This isn't actually testing a mapping, but similar use of CTRL-G U as above.
224func Test_break_undo()
225  set whichwrap=<,>,[,]
226  call feedkeys("G4o2k", "xt")
227  exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>."
228  call assert_equal('new line here', getline(line('$') - 3))
229  call assert_equal('Test3: text with a (parenthesis here', getline(line('$') - 2))
230  call assert_equal('new line here', getline(line('$') - 1))
231  set nomodified
232endfunc
233
234func Test_map_meta_quotes()
235  imap <M-"> foo
236  call feedkeys("Go-\<M-\">-\<Esc>", "xt")
237  call assert_equal("-foo-", getline('$'))
238  set nomodified
239  iunmap <M-">
240endfunc
241
242func Test_map_meta_multibyte()
243  imap <M-á> foo
244  call assert_match('i  <M-á>\s*foo', execute('imap'))
245  iunmap <M-á>
246endfunc
247
248func Test_abbr_after_line_join()
249  new
250  abbr foo bar
251  set backspace=indent,eol,start
252  exe "normal o\<BS>foo "
253  call assert_equal("bar ", getline(1))
254  bwipe!
255  unabbr foo
256  set backspace&
257endfunc
258
259func Test_map_timeout()
260  if !has('timers')
261    return
262  endif
263  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
272  let timer = timer_start(300, 'ExitInsert')
273  " 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
287  call timer_stop(timer)
288endfunc
289
290func Test_map_timeout_with_timer_interrupt()
291  if !has('job') || !has('timers')
292    return
293  endif
294
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>
301  set timeout timeoutlen=200
302
303  func ExitCb(job, status)
304    let g:timer = timer_start(1, {-> feedkeys("3\<Esc>", 't')})
305  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
320endfunc
321
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
337
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
353
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
407
408func Test_error_in_map_expr()
409  " Unlike CheckRunVimInTerminal this does work in a win32 console
410  CheckFeature terminal
411  if has('win32') && has('gui_running')
412    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
425  let buf = term_start(GetVimCommandCleanTerm() .. ' -S Xtest.vim', {'term_rows': 8})
426  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, '!')
431  call term_wait(buf, 100)
432  call term_sendkeys(buf, "\<CR>")
433  call term_wait(buf, 100)
434  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
445
446func Test_list_mappings()
447  " Remove default Mac mapping
448  silent! iunmap <D-v>
449
450  inoremap <C-M> CtrlM
451  inoremap <A-S> AltS
452  inoremap <S-/> ShiftSlash
453  call assert_equal([
454	\ 'i  <S-/>       * ShiftSlash',
455	\ 'i  <M-S>       * AltS',
456	\ 'i  <C-M>       * CtrlM',
457	\], execute('imap')->trim()->split("\n"))
458  iunmap <C-M>
459  iunmap <A-S>
460  call assert_equal(['i  <S-/>       * ShiftSlash'], execute('imap')->trim()->split("\n"))
461  iunmap <S-/>
462  call assert_equal(['No mapping found'], execute('imap')->trim()->split("\n"))
463endfunc
464