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