1" Tests for decoding escape sequences sent by the terminal.
2
3" This only works for Unix in a terminal
4source check.vim
5CheckNotGui
6CheckUnix
7
8source shared.vim
9source mouse.vim
10
11func Test_term_mouse_left_click()
12  new
13  let save_mouse = &mouse
14  let save_term = &term
15  let save_ttymouse = &ttymouse
16  call test_override('no_query_mouse', 1)
17  set mouse=a term=xterm
18  call setline(1, ['line 1', 'line 2', 'line 3 is a bit longer'])
19
20  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
21    let msg = 'ttymouse=' .. ttymouse_val
22    exe 'set ttymouse=' .. ttymouse_val
23    go
24    call assert_equal([0, 1, 1, 0], getpos('.'), msg)
25    let row = 2
26    let col = 6
27    call MouseLeftClick(row, col)
28    call MouseLeftRelease(row, col)
29    call assert_equal([0, 2, 6, 0], getpos('.'), msg)
30  endfor
31
32  let &mouse = save_mouse
33  let &term = save_term
34  let &ttymouse = save_ttymouse
35  call test_override('no_query_mouse', 0)
36  bwipe!
37endfunc
38
39func Test_xterm_mouse_right_click_extends_visual()
40  if has('mac')
41    throw "Skipped: test right click in visual mode does not work on macOs (why?)"
42  endif
43  let save_mouse = &mouse
44  let save_term = &term
45  let save_ttymouse = &ttymouse
46  call test_override('no_query_mouse', 1)
47  set mouse=a term=xterm
48
49  for visual_mode in ["v", "V", "\<C-V>"]
50    for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
51      let msg = 'visual=' .. visual_mode .. ' ttymouse=' .. ttymouse_val
52      exe 'set ttymouse=' .. ttymouse_val
53
54      call setline(1, repeat([repeat('-', 7)], 7))
55      call MouseLeftClick(4, 4)
56      call MouseLeftRelease(4, 4)
57      exe  "norm! " .. visual_mode
58
59      " Right click extends top left of visual area.
60      call MouseRightClick(2, 2)
61      call MouseRightRelease(2, 2)
62
63      " Right click extends bottom right of visual area.
64      call MouseRightClick(6, 6)
65      call MouseRightRelease(6, 6)
66      norm! r1gv
67
68      " Right click shrinks top left of visual area.
69      call MouseRightClick(3, 3)
70      call MouseRightRelease(3, 3)
71
72      " Right click shrinks bottom right of visual area.
73      call MouseRightClick(5, 5)
74      call MouseRightRelease(5, 5)
75      norm! r2
76
77      if visual_mode ==# 'v'
78        call assert_equal(['-------',
79              \            '-111111',
80              \            '1122222',
81              \            '2222222',
82              \            '2222211',
83              \            '111111-',
84              \            '-------'], getline(1, '$'), msg)
85      elseif visual_mode ==# 'V'
86        call assert_equal(['-------',
87              \            '1111111',
88              \            '2222222',
89              \            '2222222',
90              \            '2222222',
91              \            '1111111',
92              \            '-------'], getline(1, '$'), msg)
93      else
94        call assert_equal(['-------',
95              \            '-11111-',
96              \            '-12221-',
97              \            '-12221-',
98              \            '-12221-',
99              \            '-11111-',
100              \            '-------'], getline(1, '$'), msg)
101      endif
102    endfor
103  endfor
104
105  let &mouse = save_mouse
106  let &term = save_term
107  let &ttymouse = save_ttymouse
108  call test_override('no_query_mouse', 0)
109  bwipe!
110endfunc
111
112" Test that <C-LeftMouse> jumps to help tag and <C-RightMouse> jumps back.
113func Test_xterm_mouse_ctrl_click()
114  let save_mouse = &mouse
115  let save_term = &term
116  let save_ttymouse = &ttymouse
117  set mouse=a term=xterm
118
119  for ttymouse_val in g:Ttymouse_values
120    let msg = 'ttymouse=' .. ttymouse_val
121    exe 'set ttymouse=' .. ttymouse_val
122    help
123    /usr_02.txt
124    norm! zt
125    let row = 1
126    let col = 1
127    call MouseCtrlLeftClick(row, col)
128    call MouseLeftRelease(row, col)
129    call assert_match('usr_02.txt$', bufname('%'), msg)
130    call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg)
131
132    call MouseCtrlRightClick(row, col)
133    call MouseRightRelease(row, col)
134    call assert_match('help.txt$', bufname('%'), msg)
135    call assert_equal('|usr_02.txt|', expand('<cWORD>'), msg)
136
137    helpclose
138  endfor
139
140  let &mouse = save_mouse
141  let &term = save_term
142  let &ttymouse = save_ttymouse
143endfunc
144
145func Test_term_mouse_middle_click()
146  CheckFeature clipboard_working
147
148  new
149  let save_mouse = &mouse
150  let save_term = &term
151  let save_ttymouse = &ttymouse
152  call test_override('no_query_mouse', 1)
153  let save_quotestar = @*
154  let @* = 'abc'
155  set mouse=a term=xterm
156
157  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
158    let msg = 'ttymouse=' .. ttymouse_val
159    exe 'set ttymouse=' .. ttymouse_val
160    call setline(1, ['123456789', '123456789'])
161
162    " Middle-click in the middle of the line pastes text where clicked.
163    let row = 1
164    let col = 6
165    call MouseMiddleClick(row, col)
166    call MouseMiddleRelease(row, col)
167    call assert_equal(['12345abc6789', '123456789'], getline(1, '$'), msg)
168
169    " Middle-click beyond end of the line pastes text at the end of the line.
170    let col = 20
171    call MouseMiddleClick(row, col)
172    call MouseMiddleRelease(row, col)
173    call assert_equal(['12345abc6789abc', '123456789'], getline(1, '$'), msg)
174
175    " Middle-click beyond the last line pastes in the last line.
176    let row = 5
177    let col = 3
178    call MouseMiddleClick(row, col)
179    call MouseMiddleRelease(row, col)
180    call assert_equal(['12345abc6789abc', '12abc3456789'], getline(1, '$'), msg)
181  endfor
182
183  let &mouse = save_mouse
184  let &term = save_term
185  let &ttymouse = save_ttymouse
186  call test_override('no_query_mouse', 0)
187  let @* = save_quotestar
188  bwipe!
189endfunc
190
191" TODO: for unclear reasons this test fails if it comes after
192" Test_xterm_mouse_ctrl_click()
193func Test_1xterm_mouse_wheel()
194  new
195  let save_mouse = &mouse
196  let save_term = &term
197  let save_wrap = &wrap
198  let save_ttymouse = &ttymouse
199  set mouse=a term=xterm nowrap
200  call setline(1, range(100000000000000, 100000000000100))
201
202  for ttymouse_val in g:Ttymouse_values
203    let msg = 'ttymouse=' .. ttymouse_val
204    exe 'set ttymouse=' .. ttymouse_val
205    go
206    call assert_equal(1, line('w0'), msg)
207    call assert_equal([0, 1, 1, 0], getpos('.'), msg)
208
209    call MouseWheelDown(1, 1)
210    call assert_equal(4, line('w0'), msg)
211    call assert_equal([0, 4, 1, 0], getpos('.'), msg)
212
213    call MouseWheelDown(1, 1)
214    call assert_equal(7, line('w0'), msg)
215    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
216
217    call MouseWheelUp(1, 1)
218    call assert_equal(4, line('w0'), msg)
219    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
220
221    call MouseWheelUp(1, 1)
222    call assert_equal(1, line('w0'), msg)
223    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
224
225    if has('gui')
226      " Horizontal wheel scrolling currently only works when vim is
227      " compiled with gui enabled.
228      call MouseWheelRight(1, 1)
229      call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
230      call assert_equal([0, 7, 7, 0], getpos('.'), msg)
231
232      call MouseWheelRight(1, 1)
233      call assert_equal(13, 1 + virtcol(".") - wincol(), msg)
234      call assert_equal([0, 7, 13, 0], getpos('.'), msg)
235
236      call MouseWheelLeft(1, 1)
237      call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
238      call assert_equal([0, 7, 13, 0], getpos('.'), msg)
239
240      call MouseWheelLeft(1, 1)
241      call assert_equal(1, 1 + virtcol(".") - wincol(), msg)
242      call assert_equal([0, 7, 13, 0], getpos('.'), msg)
243    endif
244  endfor
245
246  let &mouse = save_mouse
247  let &term = save_term
248  let &wrap = save_wrap
249  let &ttymouse = save_ttymouse
250  bwipe!
251endfunc
252
253" Test that dragging beyond the window (at the bottom and at the top)
254" scrolls window content by the number of lines beyond the window.
255func Test_term_mouse_drag_beyond_window()
256  let save_mouse = &mouse
257  let save_term = &term
258  let save_ttymouse = &ttymouse
259  call test_override('no_query_mouse', 1)
260  set mouse=a term=xterm
261  let col = 1
262  call setline(1, range(1, 100))
263
264  " Split into 3 windows, and go into the middle window
265  " so we test dragging mouse below and above the window.
266  2split
267  wincmd j
268  2split
269
270  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
271    let msg = 'ttymouse=' .. ttymouse_val
272    exe 'set ttymouse=' .. ttymouse_val
273
274    " Line #10 at the top.
275    norm! 10zt
276    redraw
277    call assert_equal(10, winsaveview().topline, msg)
278    call assert_equal(2, winheight(0), msg)
279
280    let row = 4
281    call MouseLeftClick(row, col)
282    call assert_equal(10, winsaveview().topline, msg)
283
284    " Drag downwards. We're still in the window so topline should
285    " not change yet.
286    let row += 1
287    call MouseLeftDrag(row, col)
288    call assert_equal(10, winsaveview().topline, msg)
289
290    " We now leave the window at the bottom, so the window content should
291    " scroll by 1 line, then 2 lines (etc) as we drag further away.
292    let row += 1
293    call MouseLeftDrag(row, col)
294    call assert_equal(11, winsaveview().topline, msg)
295
296    let row += 1
297    call MouseLeftDrag(row, col)
298    call assert_equal(13, winsaveview().topline, msg)
299
300    " Now drag upwards.
301    let row -= 1
302    call MouseLeftDrag(row, col)
303    call assert_equal(14, winsaveview().topline, msg)
304
305    " We're now back in the window so the topline should not change.
306    let row -= 1
307    call MouseLeftDrag(row, col)
308    call assert_equal(14, winsaveview().topline, msg)
309
310    let row -= 1
311    call MouseLeftDrag(row, col)
312    call assert_equal(14, winsaveview().topline, msg)
313
314    " We now leave the window at the top so the window content should
315    " scroll by 1 line, then 2, then 3 (etc) in the opposite direction.
316    let row -= 1
317    call MouseLeftDrag(row, col)
318    call assert_equal(13, winsaveview().topline, msg)
319
320    let row -= 1
321    call MouseLeftDrag(row, col)
322    call assert_equal(11, winsaveview().topline, msg)
323
324    let row -= 1
325    call MouseLeftDrag(row, col)
326    call assert_equal(8, winsaveview().topline, msg)
327
328    call MouseLeftRelease(row, col)
329    call assert_equal(8, winsaveview().topline, msg)
330    call assert_equal(2, winheight(0), msg)
331  endfor
332
333  let &mouse = save_mouse
334  let &term = save_term
335  let &ttymouse = save_ttymouse
336  call test_override('no_query_mouse', 0)
337  bwipe!
338endfunc
339
340func Test_term_mouse_drag_window_separator()
341  let save_mouse = &mouse
342  let save_term = &term
343  let save_ttymouse = &ttymouse
344  call test_override('no_query_mouse', 1)
345  set mouse=a term=xterm
346
347  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
348    let msg = 'ttymouse=' .. ttymouse_val
349    exe 'set ttymouse=' .. ttymouse_val
350
351    " Split horizontally and test dragging the horizontal window separator.
352    split
353    let rowseparator = winheight(0) + 1
354    let row = rowseparator
355    let col = 1
356
357    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
358    if ttymouse_val !=# 'xterm2' || row <= 223
359      call MouseLeftClick(row, col)
360      let row -= 1
361      call MouseLeftDrag(row, col)
362      call assert_equal(rowseparator - 1, winheight(0) + 1, msg)
363      let row += 1
364      call MouseLeftDrag(row, col)
365      call assert_equal(rowseparator, winheight(0) + 1, msg)
366      call MouseLeftRelease(row, col)
367      call assert_equal(rowseparator, winheight(0) + 1, msg)
368    endif
369    bwipe!
370
371    " Split vertically and test dragging the vertical window separator.
372    vsplit
373    let colseparator = winwidth(0) + 1
374    let row = 1
375    let col = colseparator
376
377    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
378    if ttymouse_val !=# 'xterm2' || col <= 223
379      call MouseLeftClick(row, col)
380      let col -= 1
381      call MouseLeftDrag(row, col)
382      call assert_equal(colseparator - 1, winwidth(0) + 1, msg)
383      let col += 1
384      call MouseLeftDrag(row, col)
385      call assert_equal(colseparator, winwidth(0) + 1, msg)
386      call MouseLeftRelease(row, col)
387      call assert_equal(colseparator, winwidth(0) + 1, msg)
388    endif
389    bwipe!
390  endfor
391
392  let &mouse = save_mouse
393  let &term = save_term
394  let &ttymouse = save_ttymouse
395  call test_override('no_query_mouse', 0)
396endfunc
397
398func Test_term_mouse_drag_statusline()
399  let save_mouse = &mouse
400  let save_term = &term
401  let save_ttymouse = &ttymouse
402  call test_override('no_query_mouse', 1)
403  let save_laststatus = &laststatus
404  set mouse=a term=xterm laststatus=2
405
406  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
407    let msg = 'ttymouse=' .. ttymouse_val
408    exe 'set ttymouse=' .. ttymouse_val
409
410    call assert_equal(1, &cmdheight, msg)
411    let rowstatusline = winheight(0) + 1
412    let row = rowstatusline
413    let col = 1
414
415    if ttymouse_val ==# 'xterm2' && row > 223
416      " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
417      continue
418    endif
419
420    call MouseLeftClick(row, col)
421    let row -= 1
422    call MouseLeftDrag(row, col)
423    call assert_equal(2, &cmdheight, msg)
424    call assert_equal(rowstatusline - 1, winheight(0) + 1, msg)
425    let row += 1
426    call MouseLeftDrag(row, col)
427    call assert_equal(1, &cmdheight, msg)
428    call assert_equal(rowstatusline, winheight(0) + 1, msg)
429    call MouseLeftRelease(row, col)
430    call assert_equal(1, &cmdheight, msg)
431    call assert_equal(rowstatusline, winheight(0) + 1, msg)
432  endfor
433
434  let &mouse = save_mouse
435  let &term = save_term
436  let &ttymouse = save_ttymouse
437  call test_override('no_query_mouse', 0)
438  let &laststatus = save_laststatus
439endfunc
440
441func Test_term_mouse_click_tab()
442  let save_mouse = &mouse
443  let save_term = &term
444  let save_ttymouse = &ttymouse
445  call test_override('no_query_mouse', 1)
446  set mouse=a term=xterm
447  let row = 1
448
449  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
450    let msg = 'ttymouse=' .. ttymouse_val
451    exe 'set ttymouse=' .. ttymouse_val
452    e Xfoo
453    tabnew Xbar
454
455    let a = split(execute(':tabs'), "\n")
456    call assert_equal(['Tab page 1',
457        \              '    Xfoo',
458        \              'Tab page 2',
459        \              '>   Xbar'], a, msg)
460
461    " Test clicking on tab names in the tabline at the top.
462    let col = 2
463    redraw
464    call MouseLeftClick(row, col)
465    call MouseLeftRelease(row, col)
466    let a = split(execute(':tabs'), "\n")
467    call assert_equal(['Tab page 1',
468        \              '>   Xfoo',
469        \              'Tab page 2',
470        \              '    Xbar'], a, msg)
471
472    let col = 9
473    call MouseLeftClick(row, col)
474    call MouseLeftRelease(row, col)
475    let a = split(execute(':tabs'), "\n")
476    call assert_equal(['Tab page 1',
477        \              '    Xfoo',
478        \              'Tab page 2',
479        \              '>   Xbar'], a, msg)
480
481    %bwipe!
482  endfor
483
484  let &mouse = save_mouse
485  let &term = save_term
486  let &ttymouse = save_ttymouse
487  call test_override('no_query_mouse', 0)
488endfunc
489
490func Test_term_mouse_click_X_to_close_tab()
491  let save_mouse = &mouse
492  let save_term = &term
493  let save_ttymouse = &ttymouse
494  call test_override('no_query_mouse', 1)
495  set mouse=a term=xterm
496  let row = 1
497  let col = &columns
498
499  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
500    if ttymouse_val ==# 'xterm2' && col > 223
501      " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
502      continue
503    endif
504    let msg = 'ttymouse=' .. ttymouse_val
505    exe 'set ttymouse=' .. ttymouse_val
506    e Xtab1
507    tabnew Xtab2
508    tabnew Xtab3
509    tabn 2
510
511    let a = split(execute(':tabs'), "\n")
512    call assert_equal(['Tab page 1',
513        \              '    Xtab1',
514        \              'Tab page 2',
515        \              '>   Xtab2',
516        \              'Tab page 3',
517        \              '    Xtab3'], a, msg)
518
519    " Click on "X" in tabline to close current tab i.e. Xtab2.
520    redraw
521    call MouseLeftClick(row, col)
522    call MouseLeftRelease(row, col)
523    let a = split(execute(':tabs'), "\n")
524    call assert_equal(['Tab page 1',
525        \              '    Xtab1',
526        \              'Tab page 2',
527        \              '>   Xtab3'], a, msg)
528
529    %bwipe!
530  endfor
531
532  let &mouse = save_mouse
533  let &term = save_term
534  let &ttymouse = save_ttymouse
535  call test_override('no_query_mouse', 0)
536endfunc
537
538func Test_term_mouse_drag_to_move_tab()
539  let save_mouse = &mouse
540  let save_term = &term
541  let save_ttymouse = &ttymouse
542  call test_override('no_query_mouse', 1)
543  " Set 'mousetime' to 1 to avoid recognizing a double-click in the loop
544  set mouse=a term=xterm mousetime=1
545  let row = 1
546
547  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
548    let msg = 'ttymouse=' .. ttymouse_val
549    exe 'set ttymouse=' .. ttymouse_val
550    e Xtab1
551    tabnew Xtab2
552
553    let a = split(execute(':tabs'), "\n")
554    call assert_equal(['Tab page 1',
555        \              '    Xtab1',
556        \              'Tab page 2',
557        \              '>   Xtab2'], a, msg)
558    redraw
559
560    " Click in tab2 and drag it to tab1.
561    " Check getcharmod() to verify that click is not
562    " interpreted as a spurious double-click.
563    call MouseLeftClick(row, 10)
564    call assert_equal(0, getcharmod(), msg)
565    for col in [9, 8, 7, 6]
566      call MouseLeftDrag(row, col)
567    endfor
568    call MouseLeftRelease(row, col)
569    let a = split(execute(':tabs'), "\n")
570    call assert_equal(['Tab page 1',
571        \              '>   Xtab2',
572        \              'Tab page 2',
573        \              '    Xtab1'], a, msg)
574
575    " Click elsewhere so that click in next iteration is not
576    " interpreted as unwanted double-click.
577    call MouseLeftClick(row, 11)
578    call MouseLeftRelease(row, 11)
579
580    %bwipe!
581  endfor
582
583  let &mouse = save_mouse
584  let &term = save_term
585  let &ttymouse = save_ttymouse
586  call test_override('no_query_mouse', 0)
587  set mousetime&
588endfunc
589
590func Test_term_mouse_double_click_to_create_tab()
591  let save_mouse = &mouse
592  let save_term = &term
593  let save_ttymouse = &ttymouse
594  call test_override('no_query_mouse', 1)
595  " Set 'mousetime' to a small value, so that double-click works but we don't
596  " have to wait long to avoid a triple-click.
597  set mouse=a term=xterm mousetime=200
598  let row = 1
599  let col = 10
600
601  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
602    let msg = 'ttymouse=' .. ttymouse_val
603    exe 'set ttymouse=' .. ttymouse_val
604    e Xtab1
605    tabnew Xtab2
606
607    let a = split(execute(':tabs'), "\n")
608    call assert_equal(['Tab page 1',
609        \              '    Xtab1',
610        \              'Tab page 2',
611        \              '>   Xtab2'], a, msg)
612
613    redraw
614    call MouseLeftClick(row, col)
615    " Check getcharmod() to verify that first click is not
616    " interpreted as a spurious double-click.
617    call assert_equal(0, getcharmod(), msg)
618    call MouseLeftRelease(row, col)
619    call MouseLeftClick(row, col)
620    call assert_equal(32, getcharmod(), msg) " double-click
621    call MouseLeftRelease(row, col)
622    let a = split(execute(':tabs'), "\n")
623    call assert_equal(['Tab page 1',
624        \              '    Xtab1',
625        \              'Tab page 2',
626        \              '>   [No Name]',
627        \              'Tab page 3',
628        \              '    Xtab2'], a, msg)
629
630    " Click elsewhere so that click in next iteration is not
631    " interpreted as unwanted double click.
632    call MouseLeftClick(row, col + 1)
633    call MouseLeftRelease(row, col + 1)
634
635    %bwipe!
636  endfor
637
638  let &mouse = save_mouse
639  let &term = save_term
640  let &ttymouse = save_ttymouse
641  call test_override('no_query_mouse', 0)
642  set mousetime&
643endfunc
644
645" Test double/triple/quadruple click in normal mode to visually select.
646func Test_term_mouse_multiple_clicks_to_visually_select()
647  let save_mouse = &mouse
648  let save_term = &term
649  let save_ttymouse = &ttymouse
650  call test_override('no_query_mouse', 1)
651  set mouse=a term=xterm mousetime=200
652  new
653
654  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
655    let msg = 'ttymouse=' .. ttymouse_val
656    exe 'set ttymouse=' .. ttymouse_val
657    call setline(1, ['foo [foo bar] foo', 'foo'])
658
659    " Double-click on word should visually select the word.
660    call MouseLeftClick(1, 2)
661    call assert_equal(0, getcharmod(), msg)
662    call MouseLeftRelease(1, 2)
663    call MouseLeftClick(1, 2)
664    call assert_equal(32, getcharmod(), msg) " double-click
665    call MouseLeftRelease(1, 2)
666    call assert_equal('v', mode(), msg)
667    norm! r1
668    call assert_equal(['111 [foo bar] foo', 'foo'], getline(1, '$'), msg)
669
670    " Double-click on opening square bracket should visually
671    " select the whole [foo bar].
672    call MouseLeftClick(1, 5)
673    call assert_equal(0, getcharmod(), msg)
674    call MouseLeftRelease(1, 5)
675    call MouseLeftClick(1, 5)
676    call assert_equal(32, getcharmod(), msg) " double-click
677    call MouseLeftRelease(1, 5)
678    call assert_equal('v', mode(), msg)
679    norm! r2
680    call assert_equal(['111 222222222 foo', 'foo'], getline(1, '$'), msg)
681
682    " Triple-click should visually select the whole line.
683    call MouseLeftClick(1, 3)
684    call assert_equal(0, getcharmod(), msg)
685    call MouseLeftRelease(1, 3)
686    call MouseLeftClick(1, 3)
687    call assert_equal(32, getcharmod(), msg) " double-click
688    call MouseLeftRelease(1, 3)
689    call MouseLeftClick(1, 3)
690    call assert_equal(64, getcharmod(), msg) " triple-click
691    call MouseLeftRelease(1, 3)
692    call assert_equal('V', mode(), msg)
693    norm! r3
694    call assert_equal(['33333333333333333', 'foo'], getline(1, '$'), msg)
695
696    " Quadruple-click should start visual block select.
697    call MouseLeftClick(1, 2)
698    call assert_equal(0, getcharmod(), msg)
699    call MouseLeftRelease(1, 2)
700    call MouseLeftClick(1, 2)
701    call assert_equal(32, getcharmod(), msg) " double-click
702    call MouseLeftRelease(1, 2)
703    call MouseLeftClick(1, 2)
704    call assert_equal(64, getcharmod(), msg) " triple-click
705    call MouseLeftRelease(1, 2)
706    call MouseLeftClick(1, 2)
707    call assert_equal(96, getcharmod(), msg) " quadruple-click
708    call MouseLeftRelease(1, 2)
709    call assert_equal("\<c-v>", mode(), msg)
710    norm! r4
711    call assert_equal(['34333333333333333', 'foo'], getline(1, '$'), msg)
712  endfor
713
714  let &mouse = save_mouse
715  let &term = save_term
716  let &ttymouse = save_ttymouse
717  set mousetime&
718  call test_override('no_query_mouse', 0)
719  bwipe!
720endfunc
721
722func Test_xterm_mouse_click_in_fold_columns()
723  new
724  let save_mouse = &mouse
725  let save_term = &term
726  let save_ttymouse = &ttymouse
727  let save_foldcolumn = &foldcolumn
728  set mouse=a term=xterm foldcolumn=3 ttymouse=xterm2
729
730  " Create 2 nested folds.
731  call setline(1, range(1, 7))
732  2,6fold
733  norm! zR
734  4,5fold
735  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
736        \           map(range(1, 7), 'foldclosed(v:val)'))
737
738  " Click in "+" of inner fold in foldcolumn should open it.
739  redraw
740  let row = 4
741  let col = 2
742  call MouseLeftClick(row, col)
743  call MouseLeftRelease(row, col)
744  call assert_equal([-1, -1, -1, -1, -1, -1, -1],
745        \           map(range(1, 7), 'foldclosed(v:val)'))
746
747  " Click in "-" of outer fold in foldcolumn should close it.
748  redraw
749  let row = 2
750  let col = 1
751  call MouseLeftClick(row, col)
752  call MouseLeftRelease(row, col)
753  call assert_equal([-1, 2, 2, 2, 2, 2, -1],
754        \           map(range(1, 7), 'foldclosed(v:val)'))
755  norm! zR
756
757  " Click in "|" of inner fold in foldcolumn should close it.
758  redraw
759  let row = 5
760  let col = 2
761  call MouseLeftClick(row, col)
762  call MouseLeftRelease(row, col)
763  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
764        \           map(range(1, 7), 'foldclosed(v:val)'))
765
766  let &foldcolumn = save_foldcolumn
767  let &ttymouse = save_ttymouse
768  let &term = save_term
769  let &mouse = save_mouse
770  bwipe!
771endfunc
772
773" Left or right click in Ex command line sets position of the cursor.
774func Test_term_mouse_click_in_cmdline_to_set_pos()
775  let save_mouse = &mouse
776  let save_term = &term
777  let save_ttymouse = &ttymouse
778  call test_override('no_query_mouse', 1)
779  set mouse=a term=xterm
780  let row = &lines
781
782  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
783    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
784    if ttymouse_val !=# 'xterm2' || row <= 223
785      let msg = 'ttymouse=' .. ttymouse_val
786      exe 'set ttymouse=' .. ttymouse_val
787
788
789      call feedkeys(':"3456789'
790            \       .. MouseLeftClickCode(row, 7)
791            \       .. MouseLeftReleaseCode(row, 7) .. 'L'
792            \       .. MouseRightClickCode(row, 4)
793            \       .. MouseRightReleaseCode(row, 4) .. 'R'
794            \       .. "\<CR>", 'Lx!')
795      call assert_equal('"3R456L789', @:, msg)
796    endif
797  endfor
798
799  let &mouse = save_mouse
800  let &term = save_term
801  let &ttymouse = save_ttymouse
802  set mousetime&
803  call test_override('no_query_mouse', 0)
804endfunc
805
806" Middle click in command line pastes at position of cursor.
807func Test_term_mouse_middle_click_in_cmdline_to_paste()
808  CheckFeature clipboard_working
809  let save_mouse = &mouse
810  let save_term = &term
811  let save_ttymouse = &ttymouse
812  call test_override('no_query_mouse', 1)
813  set mouse=a term=xterm
814  let row = &lines
815  " Column values does not matter, paste is done at position of cursor.
816  let col = 1
817  let @* = 'paste'
818
819  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
820    let msg = 'ttymouse=' .. ttymouse_val
821    exe 'set ttymouse=' .. ttymouse_val
822
823    call feedkeys(":\"->"
824          \       .. MouseMiddleReleaseCode(row, col)
825          \       .. MouseMiddleClickCode(row, col)
826          \       .. "<-"
827          \       .. MouseMiddleReleaseCode(row, col)
828          \       .. MouseMiddleClickCode(row, col)
829          \       .. "\<CR>", 'Lx!')
830    call assert_equal('"->paste<-paste', @:, msg)
831  endfor
832
833  let &mouse = save_mouse
834  let &term = save_term
835  let &ttymouse = save_ttymouse
836  let @* = ''
837  call test_override('no_query_mouse', 0)
838endfunc
839
840" Test for displaying the popup menu using the right mouse click
841func Test_mouse_popup_menu()
842  CheckFeature menu
843  new
844  call setline(1, 'popup menu test')
845  let save_mouse = &mouse
846  let save_term = &term
847  let save_ttymouse = &ttymouse
848  let save_mousemodel = &mousemodel
849  call test_override('no_query_mouse', 1)
850  set mouse=a term=xterm mousemodel=popup
851
852  menu PopUp.foo :let g:menustr = 'foo'<CR>
853  menu PopUp.bar :let g:menustr = 'bar'<CR>
854  menu PopUp.baz :let g:menustr = 'baz'<CR>
855
856  for ttymouse_val in g:Ttymouse_values
857    exe 'set ttymouse=' .. ttymouse_val
858    let g:menustr = ''
859    call feedkeys(MouseRightClickCode(1, 4)
860		\ .. MouseRightReleaseCode(1, 4) .. "\<Down>\<Down>\<CR>", "x")
861    call assert_equal('bar', g:menustr)
862  endfor
863
864  unmenu PopUp
865  let &mouse = save_mouse
866  let &term = save_term
867  let &ttymouse = save_ttymouse
868  let &mousemodel = save_mousemodel
869  call test_override('no_query_mouse', 0)
870  close!
871endfunc
872
873" This only checks if the sequence is recognized.
874func Test_term_rgb_response()
875  set t_RF=x
876  set t_RB=y
877
878  " response to t_RF, 4 digits
879  let red = 0x12
880  let green = 0x34
881  let blue = 0x56
882  let seq = printf("\<Esc>]10;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
883  call feedkeys(seq, 'Lx!')
884  call assert_equal(seq, v:termrfgresp)
885
886  " response to t_RF, 2 digits
887  let red = 0x78
888  let green = 0x9a
889  let blue = 0xbc
890  let seq = printf("\<Esc>]10;rgb:%02x/%02x/%02x\x07", red, green, blue)
891  call feedkeys(seq, 'Lx!')
892  call assert_equal(seq, v:termrfgresp)
893
894  " response to t_RB, 4 digits, dark
895  set background=light
896  eval 'background'->test_option_not_set()
897  let red = 0x29
898  let green = 0x4a
899  let blue = 0x6b
900  let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
901  call feedkeys(seq, 'Lx!')
902  call assert_equal(seq, v:termrbgresp)
903  call assert_equal('dark', &background)
904
905  " response to t_RB, 4 digits, light
906  set background=dark
907  call test_option_not_set('background')
908  let red = 0x81
909  let green = 0x63
910  let blue = 0x65
911  let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
912  call feedkeys(seq, 'Lx!')
913  call assert_equal(seq, v:termrbgresp)
914  call assert_equal('light', &background)
915
916  " response to t_RB, 2 digits, dark
917  set background=light
918  call test_option_not_set('background')
919  let red = 0x47
920  let green = 0x59
921  let blue = 0x5b
922  let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue)
923  call feedkeys(seq, 'Lx!')
924  call assert_equal(seq, v:termrbgresp)
925  call assert_equal('dark', &background)
926
927  " response to t_RB, 2 digits, light
928  set background=dark
929  call test_option_not_set('background')
930  let red = 0x83
931  let green = 0xa4
932  let blue = 0xc2
933  let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue)
934  call feedkeys(seq, 'Lx!')
935  call assert_equal(seq, v:termrbgresp)
936  call assert_equal('light', &background)
937
938  set t_RF= t_RB=
939endfunc
940
941" This only checks if the sequence is recognized.
942" This must be after other tests, because it has side effects to xterm
943" properties.
944func Test_xx01_term_style_response()
945  " Termresponse is only parsed when t_RV is not empty.
946  set t_RV=x
947  call test_override('term_props', 1)
948
949  " send the termresponse to trigger requesting the XT codes
950  let seq = "\<Esc>[>41;337;0c"
951  call feedkeys(seq, 'Lx!')
952  call assert_equal(seq, v:termresponse)
953
954  let seq = "\<Esc>P1$r2 q\<Esc>\\"
955  call feedkeys(seq, 'Lx!')
956  call assert_equal(seq, v:termstyleresp)
957
958  call assert_equal(#{
959        \ cursor_style: 'u',
960        \ cursor_blink_mode: 'u',
961        \ underline_rgb: 'u',
962        \ mouse: 's'
963        \ }, terminalprops())
964
965  set t_RV=
966  call test_override('term_props', 0)
967endfunc
968
969" This checks the iTerm2 version response.
970" This must be after other tests, because it has side effects to xterm
971" properties.
972func Test_xx02_iTerm2_response()
973  " Termresponse is only parsed when t_RV is not empty.
974  set t_RV=x
975  call test_override('term_props', 1)
976
977  " Old versions of iTerm2 used a different style term response.
978  set ttymouse=xterm
979  call test_option_not_set('ttymouse')
980  let seq = "\<Esc>[>0;95;c"
981  call feedkeys(seq, 'Lx!')
982  call assert_equal(seq, v:termresponse)
983  call assert_equal('xterm', &ttymouse)
984
985  set ttymouse=xterm
986  call test_option_not_set('ttymouse')
987  let seq = "\<Esc>[>0;95;0c"
988  call feedkeys(seq, 'Lx!')
989  call assert_equal(seq, v:termresponse)
990  call assert_equal('sgr', &ttymouse)
991
992  call assert_equal(#{
993        \ cursor_style: 'n',
994        \ cursor_blink_mode: 'u',
995        \ underline_rgb: 'u',
996        \ mouse: 's'
997        \ }, terminalprops())
998
999  set t_RV=
1000  call test_override('term_props', 0)
1001endfunc
1002
1003" This checks the libvterm version response.
1004" This must be after other tests, because it has side effects to xterm
1005" properties.
1006func Test_xx03_libvterm_response()
1007  " Termresponse is only parsed when t_RV is not empty.
1008  set t_RV=x
1009  call test_override('term_props', 1)
1010
1011  set ttymouse=xterm
1012  call test_option_not_set('ttymouse')
1013  let seq = "\<Esc>[>0;100;0c"
1014  call feedkeys(seq, 'Lx!')
1015  call assert_equal(seq, v:termresponse)
1016  call assert_equal('sgr', &ttymouse)
1017
1018  call assert_equal(#{
1019        \ cursor_style: 'n',
1020        \ cursor_blink_mode: 'u',
1021        \ underline_rgb: 'u',
1022        \ mouse: 's'
1023        \ }, terminalprops())
1024
1025  set t_RV=
1026  call test_override('term_props', 0)
1027endfunc
1028
1029" This checks the Mac Terminal.app version response.
1030" This must be after other tests, because it has side effects to xterm
1031" properties.
1032func Test_xx04_Mac_Terminal_response()
1033  " Termresponse is only parsed when t_RV is not empty.
1034  set t_RV=x
1035  call test_override('term_props', 1)
1036
1037  set ttymouse=xterm
1038  " t_8u is not reset
1039  let &t_8u = "\<Esc>[58;2;%lu;%lu;%lum"
1040  call test_option_not_set('ttymouse')
1041  let seq = "\<Esc>[>1;95;0c"
1042  call feedkeys(seq, 'Lx!')
1043  call assert_equal(seq, v:termresponse)
1044  call assert_equal('sgr', &ttymouse)
1045
1046  call assert_equal(#{
1047        \ cursor_style: 'n',
1048        \ cursor_blink_mode: 'u',
1049        \ underline_rgb: 'y',
1050        \ mouse: 's'
1051        \ }, terminalprops())
1052  call assert_equal("\<Esc>[58;2;%lu;%lu;%lum", &t_8u)
1053
1054  " Reset is_not_xterm and is_mac_terminal.
1055  set t_RV=
1056  set term=xterm
1057  set t_RV=x
1058  call test_override('term_props', 0)
1059endfunc
1060
1061" This checks the mintty version response.
1062" This must be after other tests, because it has side effects to xterm
1063" properties.
1064func Test_xx05_mintty_response()
1065  " Termresponse is only parsed when t_RV is not empty.
1066  set t_RV=x
1067  call test_override('term_props', 1)
1068
1069  set ttymouse=xterm
1070  call test_option_not_set('ttymouse')
1071  let seq = "\<Esc>[>77;20905;0c"
1072  call feedkeys(seq, 'Lx!')
1073  call assert_equal(seq, v:termresponse)
1074  call assert_equal('sgr', &ttymouse)
1075
1076  call assert_equal(#{
1077        \ cursor_style: 'n',
1078        \ cursor_blink_mode: 'u',
1079        \ underline_rgb: 'y',
1080        \ mouse: 's'
1081        \ }, terminalprops())
1082
1083  set t_RV=
1084  call test_override('term_props', 0)
1085endfunc
1086
1087" This checks the screen version response.
1088" This must be after other tests, because it has side effects to xterm
1089" properties.
1090func Test_xx06_screen_response()
1091  " Termresponse is only parsed when t_RV is not empty.
1092  set t_RV=x
1093  call test_override('term_props', 1)
1094
1095  " Old versions of screen don't support SGR mouse mode.
1096  set ttymouse=xterm
1097  call test_option_not_set('ttymouse')
1098  let seq = "\<Esc>[>83;40500;0c"
1099  call feedkeys(seq, 'Lx!')
1100  call assert_equal(seq, v:termresponse)
1101  call assert_equal('xterm', &ttymouse)
1102
1103  " screen supports SGR mouse mode starting in version 4.7.
1104  set ttymouse=xterm
1105  call test_option_not_set('ttymouse')
1106  let seq = "\<Esc>[>83;40700;0c"
1107  call feedkeys(seq, 'Lx!')
1108  call assert_equal(seq, v:termresponse)
1109  call assert_equal('sgr', &ttymouse)
1110
1111  call assert_equal(#{
1112        \ cursor_style: 'n',
1113        \ cursor_blink_mode: 'n',
1114        \ underline_rgb: 'y',
1115        \ mouse: 's'
1116        \ }, terminalprops())
1117
1118  set t_RV=
1119  call test_override('term_props', 0)
1120endfunc
1121
1122" This checks the xterm version response.
1123" This must be after other tests, because it has side effects to xterm
1124" properties.
1125func Test_xx07_xterm_response()
1126  " Termresponse is only parsed when t_RV is not empty.
1127  set t_RV=x
1128  call test_override('term_props', 1)
1129
1130  " Do Terminal.app first to check that is_mac_terminal is reset.
1131  set ttymouse=xterm
1132  call test_option_not_set('ttymouse')
1133  let seq = "\<Esc>[>1;95;0c"
1134  call feedkeys(seq, 'Lx!')
1135  call assert_equal(seq, v:termresponse)
1136  call assert_equal('sgr', &ttymouse)
1137
1138  " xterm < 95: "xterm" (actually unmodified)
1139  set t_RV=
1140  set term=xterm
1141  set t_RV=x
1142  set ttymouse=xterm
1143  call test_option_not_set('ttymouse')
1144  let seq = "\<Esc>[>0;94;0c"
1145  call feedkeys(seq, 'Lx!')
1146  call assert_equal(seq, v:termresponse)
1147  call assert_equal('xterm', &ttymouse)
1148
1149  call assert_equal(#{
1150        \ cursor_style: 'n',
1151        \ cursor_blink_mode: 'u',
1152        \ underline_rgb: 'y',
1153        \ mouse: 'u'
1154        \ }, terminalprops())
1155
1156  " xterm >= 95 < 277 "xterm2"
1157  set ttymouse=xterm
1158  call test_option_not_set('ttymouse')
1159  let seq = "\<Esc>[>0;267;0c"
1160  call feedkeys(seq, 'Lx!')
1161  call assert_equal(seq, v:termresponse)
1162  call assert_equal('xterm2', &ttymouse)
1163
1164  call assert_equal(#{
1165        \ cursor_style: 'n',
1166        \ cursor_blink_mode: 'u',
1167        \ underline_rgb: 'u',
1168        \ mouse: '2'
1169        \ }, terminalprops())
1170
1171  " xterm >= 277: "sgr"
1172  set ttymouse=xterm
1173  call test_option_not_set('ttymouse')
1174  let seq = "\<Esc>[>0;277;0c"
1175  call feedkeys(seq, 'Lx!')
1176  call assert_equal(seq, v:termresponse)
1177  call assert_equal('sgr', &ttymouse)
1178
1179  call assert_equal(#{
1180        \ cursor_style: 'n',
1181        \ cursor_blink_mode: 'u',
1182        \ underline_rgb: 'u',
1183        \ mouse: 's'
1184        \ }, terminalprops())
1185
1186  " xterm >= 279: "sgr" and cursor_style not reset; also check t_8u reset
1187  set ttymouse=xterm
1188  call test_option_not_set('ttymouse')
1189  let &t_8u = "\<Esc>[58;2;%lu;%lu;%lum"
1190  let seq = "\<Esc>[>0;279;0c"
1191  call feedkeys(seq, 'Lx!')
1192  call assert_equal(seq, v:termresponse)
1193  call assert_equal('sgr', &ttymouse)
1194
1195  call assert_equal(#{
1196        \ cursor_style: 'u',
1197        \ cursor_blink_mode: 'u',
1198        \ underline_rgb: 'u',
1199        \ mouse: 's'
1200        \ }, terminalprops())
1201  call assert_equal('', &t_8u)
1202
1203  set t_RV=
1204  call test_override('term_props', 0)
1205endfunc
1206
1207func Test_get_termcode()
1208  try
1209    let k1 = &t_k1
1210  catch /E113/
1211    throw 'Skipped: Unable to query termcodes'
1212  endtry
1213  set t_k1=
1214  set t_k1&
1215  call assert_equal(k1, &t_k1)
1216
1217  " use external termcap first
1218  set nottybuiltin
1219  set t_k1=
1220  set t_k1&
1221  " when using external termcap may get something else, but it must not be
1222  " empty, since we would fallback to the builtin one.
1223  call assert_notequal('', &t_k1)
1224
1225  if &term =~ 'xterm'
1226    " use internal termcap first
1227    let term_save = &term
1228    let &term = 'builtin_' .. &term
1229    set t_k1=
1230    set t_k1&
1231    call assert_equal(k1, &t_k1)
1232    let &term = term_save
1233  endif
1234
1235  set ttybuiltin
1236endfunc
1237
1238func GetEscCodeCSI27(key, modifier)
1239  let key = printf("%d", char2nr(a:key))
1240  let mod = printf("%d", a:modifier)
1241  return "\<Esc>[27;" .. mod .. ';' .. key .. '~'
1242endfunc
1243
1244func GetEscCodeCSIu(key, modifier)
1245  let key = printf("%d", char2nr(a:key))
1246  let mod = printf("%d", a:modifier)
1247  return "\<Esc>[" .. key .. ';' .. mod .. 'u'
1248endfunc
1249
1250" This checks the CSI sequences when in modifyOtherKeys mode.
1251" The mode doesn't need to be enabled, the codes are always detected.
1252func RunTest_modifyOtherKeys(func)
1253  new
1254  set timeoutlen=10
1255
1256  " Shift-X is sent as 'X' with the shift modifier
1257  call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!')
1258  call assert_equal('X', getline(1))
1259
1260  " Ctrl-i is Tab
1261  call setline(1, '')
1262  call feedkeys('a' .. a:func('i', 5) .. "\<Esc>", 'Lx!')
1263  call assert_equal("\t", getline(1))
1264
1265  " Ctrl-I is also Tab
1266  call setline(1, '')
1267  call feedkeys('a' .. a:func('I', 5) .. "\<Esc>", 'Lx!')
1268  call assert_equal("\t", getline(1))
1269
1270  " Alt-x is ø
1271  call setline(1, '')
1272  call feedkeys('a' .. a:func('x', 3) .. "\<Esc>", 'Lx!')
1273  call assert_equal("ø", getline(1))
1274
1275  " Meta-x is also ø
1276  call setline(1, '')
1277  call feedkeys('a' .. a:func('x', 9) .. "\<Esc>", 'Lx!')
1278  call assert_equal("ø", getline(1))
1279
1280  " Alt-X is Ø
1281  call setline(1, '')
1282  call feedkeys('a' .. a:func('X', 3) .. "\<Esc>", 'Lx!')
1283  call assert_equal("Ø", getline(1))
1284
1285  " Meta-X is ø
1286  call setline(1, '')
1287  call feedkeys('a' .. a:func('X', 9) .. "\<Esc>", 'Lx!')
1288  call assert_equal("Ø", getline(1))
1289
1290  " Ctrl-6 is Ctrl-^
1291  split aaa
1292  edit bbb
1293  call feedkeys(a:func('6', 5), 'Lx!')
1294  call assert_equal("aaa", bufname())
1295  bwipe aaa
1296  bwipe bbb
1297
1298  bwipe!
1299  set timeoutlen&
1300endfunc
1301
1302func Test_modifyOtherKeys_basic()
1303  call RunTest_modifyOtherKeys(function('GetEscCodeCSI27'))
1304  call RunTest_modifyOtherKeys(function('GetEscCodeCSIu'))
1305endfunc
1306
1307func Test_modifyOtherKeys_no_mapping()
1308  set timeoutlen=10
1309
1310  let @a = 'aaa'
1311  call feedkeys(":let x = '" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a'\<CR>", 'Lx!')
1312  call assert_equal("let x = 'aaa'", @:)
1313
1314  new
1315  call feedkeys("a" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a\<Esc>", 'Lx!')
1316  call assert_equal("aaa", getline(1))
1317  bwipe!
1318
1319  new
1320  call feedkeys("axx\<CR>yy" .. GetEscCodeCSI27('G', 5) .. GetEscCodeCSI27('K', 5) .. "a\<Esc>", 'Lx!')
1321  call assert_equal("axx", getline(1))
1322  call assert_equal("yy", getline(2))
1323  bwipe!
1324
1325  set timeoutlen&
1326endfunc
1327
1328func RunTest_mapping_shift(key, func)
1329  call setline(1, '')
1330  if a:key == '|'
1331    exe 'inoremap \| xyz'
1332  else
1333    exe 'inoremap ' .. a:key .. ' xyz'
1334  endif
1335  call feedkeys('a' .. a:func(a:key, 2) .. "\<Esc>", 'Lx!')
1336  call assert_equal("xyz", getline(1))
1337  if a:key == '|'
1338    exe 'iunmap \|'
1339  else
1340    exe 'iunmap ' .. a:key
1341  endif
1342endfunc
1343
1344func Test_modifyOtherKeys_mapped()
1345  set timeoutlen=10
1346  imap ' <C-W>
1347  imap <C-W><C-A> c-a
1348  call setline(1, '')
1349
1350  " single quote is turned into single byte CTRL-W
1351  " CTRL-A is added with a separate modifier, and needs to be simplified before
1352  " the mapping can match.
1353  call feedkeys("a'" .. GetEscCodeCSI27('A', 5) .. "\<Esc>", 'Lx!')
1354  call assert_equal('c-a', getline(1))
1355
1356  iunmap '
1357  iunmap <C-W><C-A>
1358  set timeoutlen&
1359endfunc
1360
1361func RunTest_mapping_works_with_shift(func)
1362  new
1363  set timeoutlen=10
1364
1365  call RunTest_mapping_shift('@', a:func)
1366  call RunTest_mapping_shift('A', a:func)
1367  call RunTest_mapping_shift('Z', a:func)
1368  call RunTest_mapping_shift('^', a:func)
1369  call RunTest_mapping_shift('_', a:func)
1370  call RunTest_mapping_shift('{', a:func)
1371  call RunTest_mapping_shift('|', a:func)
1372  call RunTest_mapping_shift('}', a:func)
1373  call RunTest_mapping_shift('~', a:func)
1374
1375  bwipe!
1376  set timeoutlen&
1377endfunc
1378
1379func Test_mapping_works_with_shift_plain()
1380  call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27'))
1381  call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu'))
1382endfunc
1383
1384func RunTest_mapping_mods(map, key, func, code)
1385  call setline(1, '')
1386  exe 'inoremap ' .. a:map .. ' xyz'
1387  call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!')
1388  call assert_equal("xyz", getline(1))
1389  exe 'iunmap ' .. a:map
1390endfunc
1391
1392func RunTest_mapping_works_with_mods(func, mods, code)
1393  new
1394  set timeoutlen=10
1395
1396  if a:mods !~ 'S'
1397    " Shift by itself has no effect
1398    call RunTest_mapping_mods('<' .. a:mods .. '-@>', '@', a:func, a:code)
1399  endif
1400  call RunTest_mapping_mods('<' .. a:mods .. '-A>', 'A', a:func, a:code)
1401  call RunTest_mapping_mods('<' .. a:mods .. '-Z>', 'Z', a:func, a:code)
1402  if a:mods !~ 'S'
1403    " with Shift code is always upper case
1404    call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'a', a:func, a:code)
1405    call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'z', a:func, a:code)
1406  endif
1407  if a:mods != 'A'
1408    " with Alt code is not in upper case
1409    call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'A', a:func, a:code)
1410    call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'Z', a:func, a:code)
1411  endif
1412  call RunTest_mapping_mods('<' .. a:mods .. '-á>', 'á', a:func, a:code)
1413  if a:mods !~ 'S'
1414    " Shift by itself has no effect
1415    call RunTest_mapping_mods('<' .. a:mods .. '-^>', '^', a:func, a:code)
1416    call RunTest_mapping_mods('<' .. a:mods .. '-_>', '_', a:func, a:code)
1417    call RunTest_mapping_mods('<' .. a:mods .. '-{>', '{', a:func, a:code)
1418    call RunTest_mapping_mods('<' .. a:mods .. '-\|>', '|', a:func, a:code)
1419    call RunTest_mapping_mods('<' .. a:mods .. '-}>', '}', a:func, a:code)
1420    call RunTest_mapping_mods('<' .. a:mods .. '-~>', '~', a:func, a:code)
1421  endif
1422
1423  bwipe!
1424  set timeoutlen&
1425endfunc
1426
1427func Test_mapping_works_with_shift()
1428  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S', 2)
1429  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S', 2)
1430endfunc
1431
1432func Test_mapping_works_with_ctrl()
1433  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C', 5)
1434  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C', 5)
1435endfunc
1436
1437func Test_mapping_works_with_shift_ctrl()
1438  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S', 6)
1439  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S', 6)
1440endfunc
1441
1442" Below we also test the "u" code with Alt, This works, but libvterm would not
1443" send the Alt key like this but by prefixing an Esc.
1444
1445func Test_mapping_works_with_alt()
1446  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'A', 3)
1447  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'A', 3)
1448endfunc
1449
1450func Test_mapping_works_with_shift_alt()
1451  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S-A', 4)
1452  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S-A', 4)
1453endfunc
1454
1455func Test_mapping_works_with_ctrl_alt()
1456  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-A', 7)
1457  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-A', 7)
1458endfunc
1459
1460func Test_mapping_works_with_shift_ctrl_alt()
1461  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 8)
1462  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8)
1463endfunc
1464
1465func Test_insert_literal()
1466  set timeoutlen=10
1467  new
1468  " CTRL-V CTRL-X inserts a ^X
1469  call feedkeys('a' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
1470  call assert_equal("\<C-X>", getline(1))
1471
1472  call setline(1, '')
1473  call feedkeys('a' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
1474  call assert_equal("\<C-X>", getline(1))
1475
1476  " CTRL-SHIFT-V CTRL-X inserts escape sequence
1477  call setline(1, '')
1478  call feedkeys('a' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
1479  call assert_equal("\<Esc>[88;5u", getline(1))
1480
1481  call setline(1, '')
1482  call feedkeys('a' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
1483  call assert_equal("\<Esc>[27;5;88~", getline(1))
1484
1485  bwipe!
1486  set timeoutlen&
1487endfunc
1488
1489func Test_cmdline_literal()
1490  set timeoutlen=10
1491
1492  " CTRL-V CTRL-Y inserts a ^Y
1493  call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1494  call assert_equal("\"\<C-Y>", @:)
1495
1496  call feedkeys(':' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1497  call assert_equal("\"\<C-Y>", @:)
1498
1499  " CTRL-SHIFT-V CTRL-Y inserts escape sequence
1500  call feedkeys(':' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1501  call assert_equal("\"\<Esc>[89;5u", @:)
1502
1503  call setline(1, '')
1504  call feedkeys(':' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1505  call assert_equal("\"\<Esc>[27;5;89~", @:)
1506
1507  set timeoutlen&
1508endfunc
1509
1510" Test for translation of special key codes (<xF1>, <xF2>, etc.)
1511func Test_Keycode_Tranlsation()
1512  let keycodes = [
1513        \ ["<xUp>", "<Up>"],
1514        \ ["<xDown>", "<Down>"],
1515        \ ["<xLeft>", "<Left>"],
1516        \ ["<xRight>", "<Right>"],
1517        \ ["<xHome>", "<Home>"],
1518        \ ["<xEnd>", "<End>"],
1519        \ ["<zHome>", "<Home>"],
1520        \ ["<zEnd>", "<End>"],
1521        \ ["<xF1>", "<F1>"],
1522        \ ["<xF2>", "<F2>"],
1523        \ ["<xF3>", "<F3>"],
1524        \ ["<xF4>", "<F4>"],
1525        \ ["<S-xF1>", "<S-F1>"],
1526        \ ["<S-xF2>", "<S-F2>"],
1527        \ ["<S-xF3>", "<S-F3>"],
1528        \ ["<S-xF4>", "<S-F4>"]]
1529  for [k1, k2] in keycodes
1530    exe "nnoremap " .. k1 .. " 2wx"
1531    call assert_true(maparg(k1, 'n', 0, 1).lhs == k2)
1532    exe "nunmap " .. k1
1533  endfor
1534endfunc
1535
1536" vim: shiftwidth=2 sts=2 expandtab
1537