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  call test_option_not_set('ttymouse')
1017  let seq = "\<Esc>[>1;95;0c"
1018  call feedkeys(seq, 'Lx!')
1019  call assert_equal(seq, v:termresponse)
1020  call assert_equal('sgr', &ttymouse)
1021
1022  call assert_equal(#{
1023        \ cursor_style: 'n',
1024        \ cursor_blink_mode: 'u',
1025        \ underline_rgb: 'y',
1026        \ mouse: 's'
1027        \ }, terminalprops())
1028
1029  " Reset is_not_xterm and is_mac_terminal.
1030  set t_RV=
1031  set term=xterm
1032  set t_RV=x
1033  call test_override('term_props', 0)
1034endfunc
1035
1036" This checks the mintty version response.
1037" This must be after other tests, because it has side effects to xterm
1038" properties.
1039func Test_xx05_mintty_response()
1040  " Termresponse is only parsed when t_RV is not empty.
1041  set t_RV=x
1042  call test_override('term_props', 1)
1043
1044  set ttymouse=xterm
1045  call test_option_not_set('ttymouse')
1046  let seq = "\<Esc>[>77;20905;0c"
1047  call feedkeys(seq, 'Lx!')
1048  call assert_equal(seq, v:termresponse)
1049  call assert_equal('sgr', &ttymouse)
1050
1051  call assert_equal(#{
1052        \ cursor_style: 'n',
1053        \ cursor_blink_mode: 'u',
1054        \ underline_rgb: 'y',
1055        \ mouse: 's'
1056        \ }, terminalprops())
1057
1058  set t_RV=
1059  call test_override('term_props', 0)
1060endfunc
1061
1062" This checks the screen version response.
1063" This must be after other tests, because it has side effects to xterm
1064" properties.
1065func Test_xx06_screen_response()
1066  " Termresponse is only parsed when t_RV is not empty.
1067  set t_RV=x
1068  call test_override('term_props', 1)
1069
1070  " Old versions of screen don't support SGR mouse mode.
1071  set ttymouse=xterm
1072  call test_option_not_set('ttymouse')
1073  let seq = "\<Esc>[>83;40500;0c"
1074  call feedkeys(seq, 'Lx!')
1075  call assert_equal(seq, v:termresponse)
1076  call assert_equal('xterm', &ttymouse)
1077
1078  " screen supports SGR mouse mode starting in version 4.7.
1079  set ttymouse=xterm
1080  call test_option_not_set('ttymouse')
1081  let seq = "\<Esc>[>83;40700;0c"
1082  call feedkeys(seq, 'Lx!')
1083  call assert_equal(seq, v:termresponse)
1084  call assert_equal('sgr', &ttymouse)
1085
1086  call assert_equal(#{
1087        \ cursor_style: 'n',
1088        \ cursor_blink_mode: 'n',
1089        \ underline_rgb: 'y',
1090        \ mouse: 's'
1091        \ }, terminalprops())
1092
1093  set t_RV=
1094  call test_override('term_props', 0)
1095endfunc
1096
1097" This checks the xterm version response.
1098" This must be after other tests, because it has side effects to xterm
1099" properties.
1100func Test_xx07_xterm_response()
1101  " Termresponse is only parsed when t_RV is not empty.
1102  set t_RV=x
1103  call test_override('term_props', 1)
1104
1105  " Do Terminal.app first to check that is_mac_terminal is reset.
1106  set ttymouse=xterm
1107  call test_option_not_set('ttymouse')
1108  let seq = "\<Esc>[>1;95;0c"
1109  call feedkeys(seq, 'Lx!')
1110  call assert_equal(seq, v:termresponse)
1111  call assert_equal('sgr', &ttymouse)
1112
1113  " xterm < 95: "xterm" (actually unmodified)
1114  set t_RV=
1115  set term=xterm
1116  set t_RV=x
1117  set ttymouse=xterm
1118  call test_option_not_set('ttymouse')
1119  let seq = "\<Esc>[>0;94;0c"
1120  call feedkeys(seq, 'Lx!')
1121  call assert_equal(seq, v:termresponse)
1122  call assert_equal('xterm', &ttymouse)
1123
1124  call assert_equal(#{
1125        \ cursor_style: 'n',
1126        \ cursor_blink_mode: 'u',
1127        \ underline_rgb: 'y',
1128        \ mouse: 'u'
1129        \ }, terminalprops())
1130
1131  " xterm >= 95 < 277 "xterm2"
1132  set ttymouse=xterm
1133  call test_option_not_set('ttymouse')
1134  let seq = "\<Esc>[>0;267;0c"
1135  call feedkeys(seq, 'Lx!')
1136  call assert_equal(seq, v:termresponse)
1137  call assert_equal('xterm2', &ttymouse)
1138
1139  call assert_equal(#{
1140        \ cursor_style: 'n',
1141        \ cursor_blink_mode: 'u',
1142        \ underline_rgb: 'u',
1143        \ mouse: '2'
1144        \ }, terminalprops())
1145
1146  " xterm >= 277: "sgr"
1147  set ttymouse=xterm
1148  call test_option_not_set('ttymouse')
1149  let seq = "\<Esc>[>0;277;0c"
1150  call feedkeys(seq, 'Lx!')
1151  call assert_equal(seq, v:termresponse)
1152  call assert_equal('sgr', &ttymouse)
1153
1154  call assert_equal(#{
1155        \ cursor_style: 'n',
1156        \ cursor_blink_mode: 'u',
1157        \ underline_rgb: 'u',
1158        \ mouse: 's'
1159        \ }, terminalprops())
1160
1161  " xterm >= 279: "sgr" and cursor_style not reset
1162  set ttymouse=xterm
1163  call test_option_not_set('ttymouse')
1164  let seq = "\<Esc>[>0;279;0c"
1165  call feedkeys(seq, 'Lx!')
1166  call assert_equal(seq, v:termresponse)
1167  call assert_equal('sgr', &ttymouse)
1168
1169  call assert_equal(#{
1170        \ cursor_style: 'u',
1171        \ cursor_blink_mode: 'u',
1172        \ underline_rgb: 'u',
1173        \ mouse: 's'
1174        \ }, terminalprops())
1175
1176  set t_RV=
1177  call test_override('term_props', 0)
1178endfunc
1179
1180func Test_get_termcode()
1181  try
1182    let k1 = &t_k1
1183  catch /E113/
1184    throw 'Skipped: Unable to query termcodes'
1185  endtry
1186  set t_k1=
1187  set t_k1&
1188  call assert_equal(k1, &t_k1)
1189
1190  " use external termcap first
1191  set nottybuiltin
1192  set t_k1=
1193  set t_k1&
1194  " when using external termcap may get something else, but it must not be
1195  " empty, since we would fallback to the builtin one.
1196  call assert_notequal('', &t_k1)
1197
1198  if &term =~ 'xterm'
1199    " use internal termcap first
1200    let term_save = &term
1201    let &term = 'builtin_' .. &term
1202    set t_k1=
1203    set t_k1&
1204    call assert_equal(k1, &t_k1)
1205    let &term = term_save
1206  endif
1207
1208  set ttybuiltin
1209endfunc
1210
1211func GetEscCodeCSI27(key, modifier)
1212  let key = printf("%d", char2nr(a:key))
1213  let mod = printf("%d", a:modifier)
1214  return "\<Esc>[27;" .. mod .. ';' .. key .. '~'
1215endfunc
1216
1217func GetEscCodeCSIu(key, modifier)
1218  let key = printf("%d", char2nr(a:key))
1219  let mod = printf("%d", a:modifier)
1220  return "\<Esc>[" .. key .. ';' .. mod .. 'u'
1221endfunc
1222
1223" This checks the CSI sequences when in modifyOtherKeys mode.
1224" The mode doesn't need to be enabled, the codes are always detected.
1225func RunTest_modifyOtherKeys(func)
1226  new
1227  set timeoutlen=10
1228
1229  " Shift-X is sent as 'X' with the shift modifier
1230  call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!')
1231  call assert_equal('X', getline(1))
1232
1233  " Ctrl-i is Tab
1234  call setline(1, '')
1235  call feedkeys('a' .. a:func('i', 5) .. "\<Esc>", 'Lx!')
1236  call assert_equal("\t", getline(1))
1237
1238  " Ctrl-I is also Tab
1239  call setline(1, '')
1240  call feedkeys('a' .. a:func('I', 5) .. "\<Esc>", 'Lx!')
1241  call assert_equal("\t", getline(1))
1242
1243  " Alt-x is ø
1244  call setline(1, '')
1245  call feedkeys('a' .. a:func('x', 3) .. "\<Esc>", 'Lx!')
1246  call assert_equal("ø", getline(1))
1247
1248  " Meta-x is also ø
1249  call setline(1, '')
1250  call feedkeys('a' .. a:func('x', 9) .. "\<Esc>", 'Lx!')
1251  call assert_equal("ø", getline(1))
1252
1253  " Alt-X is Ø
1254  call setline(1, '')
1255  call feedkeys('a' .. a:func('X', 3) .. "\<Esc>", 'Lx!')
1256  call assert_equal("Ø", getline(1))
1257
1258  " Meta-X is ø
1259  call setline(1, '')
1260  call feedkeys('a' .. a:func('X', 9) .. "\<Esc>", 'Lx!')
1261  call assert_equal("Ø", getline(1))
1262
1263  " Ctrl-6 is Ctrl-^
1264  split aaa
1265  edit bbb
1266  call feedkeys(a:func('6', 5), 'Lx!')
1267  call assert_equal("aaa", bufname())
1268  bwipe aaa
1269  bwipe bbb
1270
1271  bwipe!
1272  set timeoutlen&
1273endfunc
1274
1275func Test_modifyOtherKeys_basic()
1276  call RunTest_modifyOtherKeys(function('GetEscCodeCSI27'))
1277  call RunTest_modifyOtherKeys(function('GetEscCodeCSIu'))
1278endfunc
1279
1280func Test_modifyOtherKeys_no_mapping()
1281  set timeoutlen=10
1282
1283  let @a = 'aaa'
1284  call feedkeys(":let x = '" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a'\<CR>", 'Lx!')
1285  call assert_equal("let x = 'aaa'", @:)
1286
1287  new
1288  call feedkeys("a" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a\<Esc>", 'Lx!')
1289  call assert_equal("aaa", getline(1))
1290  bwipe!
1291
1292  new
1293  call feedkeys("axx\<CR>yy" .. GetEscCodeCSI27('G', 5) .. GetEscCodeCSI27('K', 5) .. "a\<Esc>", 'Lx!')
1294  call assert_equal("axx", getline(1))
1295  call assert_equal("yy", getline(2))
1296  bwipe!
1297
1298  set timeoutlen&
1299endfunc
1300
1301func RunTest_mapping_shift(key, func)
1302  call setline(1, '')
1303  if a:key == '|'
1304    exe 'inoremap \| xyz'
1305  else
1306    exe 'inoremap ' .. a:key .. ' xyz'
1307  endif
1308  call feedkeys('a' .. a:func(a:key, 2) .. "\<Esc>", 'Lx!')
1309  call assert_equal("xyz", getline(1))
1310  if a:key == '|'
1311    exe 'iunmap \|'
1312  else
1313    exe 'iunmap ' .. a:key
1314  endif
1315endfunc
1316
1317func Test_modifyOtherKeys_mapped()
1318  set timeoutlen=10
1319  imap ' <C-W>
1320  imap <C-W><C-A> c-a
1321  call setline(1, '')
1322
1323  " single quote is turned into single byte CTRL-W
1324  " CTRL-A is added with a separate modifier, and needs to be simplified before
1325  " the mapping can match.
1326  call feedkeys("a'" .. GetEscCodeCSI27('A', 5) .. "\<Esc>", 'Lx!')
1327  call assert_equal('c-a', getline(1))
1328
1329  iunmap '
1330  iunmap <C-W><C-A>
1331  set timeoutlen&
1332endfunc
1333
1334func RunTest_mapping_works_with_shift(func)
1335  new
1336  set timeoutlen=10
1337
1338  call RunTest_mapping_shift('@', a:func)
1339  call RunTest_mapping_shift('A', a:func)
1340  call RunTest_mapping_shift('Z', a:func)
1341  call RunTest_mapping_shift('^', a:func)
1342  call RunTest_mapping_shift('_', a:func)
1343  call RunTest_mapping_shift('{', a:func)
1344  call RunTest_mapping_shift('|', a:func)
1345  call RunTest_mapping_shift('}', a:func)
1346  call RunTest_mapping_shift('~', a:func)
1347
1348  bwipe!
1349  set timeoutlen&
1350endfunc
1351
1352func Test_mapping_works_with_shift_plain()
1353  call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27'))
1354  call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu'))
1355endfunc
1356
1357func RunTest_mapping_mods(map, key, func, code)
1358  call setline(1, '')
1359  exe 'inoremap ' .. a:map .. ' xyz'
1360  call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!')
1361  call assert_equal("xyz", getline(1))
1362  exe 'iunmap ' .. a:map
1363endfunc
1364
1365func RunTest_mapping_works_with_mods(func, mods, code)
1366  new
1367  set timeoutlen=10
1368
1369  if a:mods !~ 'S'
1370    " Shift by itself has no effect
1371    call RunTest_mapping_mods('<' .. a:mods .. '-@>', '@', a:func, a:code)
1372  endif
1373  call RunTest_mapping_mods('<' .. a:mods .. '-A>', 'A', a:func, a:code)
1374  call RunTest_mapping_mods('<' .. a:mods .. '-Z>', 'Z', a:func, a:code)
1375  if a:mods !~ 'S'
1376    " with Shift code is always upper case
1377    call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'a', a:func, a:code)
1378    call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'z', a:func, a:code)
1379  endif
1380  if a:mods != 'A'
1381    " with Alt code is not in 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  call RunTest_mapping_mods('<' .. a:mods .. '-á>', 'á', a:func, a:code)
1386  if a:mods !~ 'S'
1387    " Shift by itself has no effect
1388    call RunTest_mapping_mods('<' .. a:mods .. '-^>', '^', a:func, a:code)
1389    call RunTest_mapping_mods('<' .. a:mods .. '-_>', '_', a:func, a:code)
1390    call RunTest_mapping_mods('<' .. a:mods .. '-{>', '{', a:func, a:code)
1391    call RunTest_mapping_mods('<' .. a:mods .. '-\|>', '|', a:func, a:code)
1392    call RunTest_mapping_mods('<' .. a:mods .. '-}>', '}', a:func, a:code)
1393    call RunTest_mapping_mods('<' .. a:mods .. '-~>', '~', a:func, a:code)
1394  endif
1395
1396  bwipe!
1397  set timeoutlen&
1398endfunc
1399
1400func Test_mapping_works_with_shift()
1401  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S', 2)
1402  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S', 2)
1403endfunc
1404
1405func Test_mapping_works_with_ctrl()
1406  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C', 5)
1407  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C', 5)
1408endfunc
1409
1410func Test_mapping_works_with_shift_ctrl()
1411  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S', 6)
1412  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S', 6)
1413endfunc
1414
1415" Below we also test the "u" code with Alt, This works, but libvterm would not
1416" send the Alt key like this but by prefixing an Esc.
1417
1418func Test_mapping_works_with_alt()
1419  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'A', 3)
1420  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'A', 3)
1421endfunc
1422
1423func Test_mapping_works_with_shift_alt()
1424  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S-A', 4)
1425  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S-A', 4)
1426endfunc
1427
1428func Test_mapping_works_with_ctrl_alt()
1429  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-A', 7)
1430  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-A', 7)
1431endfunc
1432
1433func Test_mapping_works_with_shift_ctrl_alt()
1434  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 8)
1435  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8)
1436endfunc
1437
1438func Test_insert_literal()
1439  set timeoutlen=10
1440  new
1441  " CTRL-V CTRL-X inserts a ^X
1442  call feedkeys('a' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
1443  call assert_equal("\<C-X>", getline(1))
1444
1445  call setline(1, '')
1446  call feedkeys('a' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
1447  call assert_equal("\<C-X>", getline(1))
1448
1449  " CTRL-SHIFT-V CTRL-X inserts escape sequence
1450  call setline(1, '')
1451  call feedkeys('a' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
1452  call assert_equal("\<Esc>[88;5u", getline(1))
1453
1454  call setline(1, '')
1455  call feedkeys('a' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
1456  call assert_equal("\<Esc>[27;5;88~", getline(1))
1457
1458  bwipe!
1459  set timeoutlen&
1460endfunc
1461
1462func Test_cmdline_literal()
1463  set timeoutlen=10
1464
1465  " CTRL-V CTRL-Y inserts a ^Y
1466  call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1467  call assert_equal("\"\<C-Y>", @:)
1468
1469  call feedkeys(':' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1470  call assert_equal("\"\<C-Y>", @:)
1471
1472  " CTRL-SHIFT-V CTRL-Y inserts escape sequence
1473  call feedkeys(':' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1474  call assert_equal("\"\<Esc>[89;5u", @:)
1475
1476  call setline(1, '')
1477  call feedkeys(':' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
1478  call assert_equal("\"\<Esc>[27;5;89~", @:)
1479
1480  set timeoutlen&
1481endfunc
1482
1483" Test for translation of special key codes (<xF1>, <xF2>, etc.)
1484func Test_Keycode_Tranlsation()
1485  let keycodes = [
1486        \ ["<xUp>", "<Up>"],
1487        \ ["<xDown>", "<Down>"],
1488        \ ["<xLeft>", "<Left>"],
1489        \ ["<xRight>", "<Right>"],
1490        \ ["<xHome>", "<Home>"],
1491        \ ["<xEnd>", "<End>"],
1492        \ ["<zHome>", "<Home>"],
1493        \ ["<zEnd>", "<End>"],
1494        \ ["<xF1>", "<F1>"],
1495        \ ["<xF2>", "<F2>"],
1496        \ ["<xF3>", "<F3>"],
1497        \ ["<xF4>", "<F4>"],
1498        \ ["<S-xF1>", "<S-F1>"],
1499        \ ["<S-xF2>", "<S-F2>"],
1500        \ ["<S-xF3>", "<S-F3>"],
1501        \ ["<S-xF4>", "<S-F4>"]]
1502  for [k1, k2] in keycodes
1503    exe "nnoremap " .. k1 .. " 2wx"
1504    call assert_true(maparg(k1, 'n', 0, 1).lhs == k2)
1505    exe "nunmap " .. k1
1506  endfor
1507endfunc
1508
1509" vim: shiftwidth=2 sts=2 expandtab
1510