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