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
10source view_util.vim
11
12func Test_term_mouse_left_click()
13  new
14  let save_mouse = &mouse
15  let save_term = &term
16  let save_ttymouse = &ttymouse
17  call test_override('no_query_mouse', 1)
18  set mouse=a term=xterm
19  call setline(1, ['line 1', 'line 2', 'line 3 is a bit longer'])
20
21  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
22    let msg = 'ttymouse=' .. ttymouse_val
23    exe 'set ttymouse=' .. ttymouse_val
24    go
25    call assert_equal([0, 1, 1, 0], getpos('.'), msg)
26    let row = 2
27    let col = 6
28    call MouseLeftClick(row, col)
29    call MouseLeftRelease(row, col)
30    call assert_equal([0, 2, 6, 0], getpos('.'), msg)
31  endfor
32
33  let &mouse = save_mouse
34  let &term = save_term
35  let &ttymouse = save_ttymouse
36  call test_override('no_query_mouse', 0)
37  bwipe!
38endfunc
39
40func Test_xterm_mouse_right_click_extends_visual()
41  if has('mac')
42    throw "Skipped: test right click in visual mode does not work on macOs (why?)"
43  endif
44  let save_mouse = &mouse
45  let save_term = &term
46  let save_ttymouse = &ttymouse
47  call test_override('no_query_mouse', 1)
48  set mouse=a term=xterm
49
50  for visual_mode in ["v", "V", "\<C-V>"]
51    for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
52      let msg = 'visual=' .. visual_mode .. ' ttymouse=' .. ttymouse_val
53      exe 'set ttymouse=' .. ttymouse_val
54
55      call setline(1, repeat([repeat('-', 7)], 7))
56      call MouseLeftClick(4, 4)
57      call MouseLeftRelease(4, 4)
58      exe  "norm! " .. visual_mode
59
60      " Right click extends top left of visual area.
61      call MouseRightClick(2, 2)
62      call MouseRightRelease(2, 2)
63
64      " Right click extends bottom right of visual area.
65      call MouseRightClick(6, 6)
66      call MouseRightRelease(6, 6)
67      norm! r1gv
68
69      " Right click shrinks top left of visual area.
70      call MouseRightClick(3, 3)
71      call MouseRightRelease(3, 3)
72
73      " Right click shrinks bottom right of visual area.
74      call MouseRightClick(5, 5)
75      call MouseRightRelease(5, 5)
76      norm! r2
77
78      if visual_mode ==# 'v'
79        call assert_equal(['-------',
80              \            '-111111',
81              \            '1122222',
82              \            '2222222',
83              \            '2222211',
84              \            '111111-',
85              \            '-------'], getline(1, '$'), msg)
86      elseif visual_mode ==# 'V'
87        call assert_equal(['-------',
88              \            '1111111',
89              \            '2222222',
90              \            '2222222',
91              \            '2222222',
92              \            '1111111',
93              \            '-------'], getline(1, '$'), msg)
94      else
95        call assert_equal(['-------',
96              \            '-11111-',
97              \            '-12221-',
98              \            '-12221-',
99              \            '-12221-',
100              \            '-11111-',
101              \            '-------'], getline(1, '$'), msg)
102      endif
103    endfor
104  endfor
105
106  let &mouse = save_mouse
107  let &term = save_term
108  let &ttymouse = save_ttymouse
109  call test_override('no_query_mouse', 0)
110  bwipe!
111endfunc
112
113" Test that <C-LeftMouse> jumps to help tag and <C-RightMouse> jumps back.
114" Also test for g<LeftMouse> and g<RightMouse>.
115func Test_xterm_mouse_tagjump()
116  let save_mouse = &mouse
117  let save_term = &term
118  let save_ttymouse = &ttymouse
119  set mouse=a term=xterm
120
121  for ttymouse_val in g:Ttymouse_values
122    let msg = 'ttymouse=' .. ttymouse_val
123    exe 'set ttymouse=' .. ttymouse_val
124    help
125    /usr_02.txt
126    norm! zt
127
128    " CTRL-left click to jump to a tag
129    let row = 1
130    let col = 1
131    call MouseCtrlLeftClick(row, col)
132    call MouseLeftRelease(row, col)
133    call assert_match('usr_02.txt$', bufname('%'), msg)
134    call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg)
135
136    " CTRL-right click to pop a tag
137    call MouseCtrlRightClick(row, col)
138    call MouseRightRelease(row, col)
139    call assert_match('help.txt$', bufname('%'), msg)
140    call assert_equal('|usr_02.txt|', expand('<cWORD>'), msg)
141
142    " Jump to a tag
143    exe "normal \<C-]>"
144    call assert_match('usr_02.txt$', bufname('%'), msg)
145    call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg)
146
147    " Use CTRL-right click in insert mode to pop the tag
148    new
149    let str = 'iHello' .. MouseCtrlRightClickCode(row, col)
150          \ .. MouseRightReleaseCode(row, col) .. "\<C-C>"
151    call assert_fails('call feedkeys(str, "Lx!")', 'E37:', msg)
152    close!
153
154    " CTRL-right click with a count
155    let str = "4" .. MouseCtrlRightClickCode(row, col)
156          \ .. MouseRightReleaseCode(row, col)
157    call assert_fails('call feedkeys(str, "Lx!")', 'E555:', msg)
158    call assert_match('help.txt$', bufname('%'), msg)
159    call assert_equal(1, line('.'), msg)
160
161    " g<LeftMouse> to jump to a tag
162    /usr_02.txt
163    norm! zt
164    call test_setmouse(row, col)
165    exe "normal g\<LeftMouse>"
166    call assert_match('usr_02.txt$', bufname('%'), msg)
167    call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg)
168
169    " g<RightMouse> to pop to a tag
170    call test_setmouse(row, col)
171    exe "normal g\<RightMouse>"
172    call assert_match('help.txt$', bufname('%'), msg)
173    call assert_equal('|usr_02.txt|', expand('<cWORD>'), msg)
174
175    %bw!
176  endfor
177
178  let &mouse = save_mouse
179  let &term = save_term
180  let &ttymouse = save_ttymouse
181endfunc
182
183func Test_term_mouse_middle_click()
184  CheckFeature clipboard_working
185
186  new
187  let save_mouse = &mouse
188  let save_term = &term
189  let save_ttymouse = &ttymouse
190  call test_override('no_query_mouse', 1)
191  let save_quotestar = @*
192  let save_quoteplus = @+
193  set mouse=a term=xterm
194
195  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
196    let msg = 'ttymouse=' .. ttymouse_val
197    exe 'set ttymouse=' .. ttymouse_val
198    call setline(1, ['123456789', '123456789'])
199    let @* = 'abc'
200
201    " Middle-click in the middle of the line pastes text where clicked.
202    let row = 1
203    let col = 6
204    call MouseMiddleClick(row, col)
205    call MouseMiddleRelease(row, col)
206    call assert_equal(['12345abc6789', '123456789'], getline(1, '$'), msg)
207
208    " Middle-click beyond end of the line pastes text at the end of the line.
209    let col = 20
210    call MouseMiddleClick(row, col)
211    call MouseMiddleRelease(row, col)
212    call assert_equal(['12345abc6789abc', '123456789'], getline(1, '$'), msg)
213
214    " Middle-click beyond the last line pastes in the last line.
215    let row = 5
216    let col = 3
217    call MouseMiddleClick(row, col)
218    call MouseMiddleRelease(row, col)
219    call assert_equal(['12345abc6789abc', '12abc3456789'], getline(1, '$'), msg)
220
221    " Middle mouse click in operator pending mode beeps
222    call assert_beeps('exe "normal c\<MiddleMouse>"')
223
224    " Clicking middle mouse in visual mode, yanks the selection and pastes the
225    " clipboard contents
226    let save_clipboard = &clipboard
227    set clipboard=
228    let @" = ''
229    call cursor(1, 1)
230    call feedkeys("v3l" ..
231          \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7), 'Lx!')
232    call assert_equal(['12345abc6789abc', '12abc3abc456789'],
233          \ getline(1, '$'), msg)
234    call assert_equal('1234', @", msg)
235    let &clipboard = save_clipboard
236
237    " Clicking middle mouse in select mode, replaces the selected text with
238    " the clipboard contents
239    let @+ = 'xyz'
240    call cursor(1, 3)
241    exe "normal gh\<Right>\<Right>\<MiddleMouse>"
242    call assert_equal(['12xyzabc6789abc', '12abc3abc456789'],
243          \ getline(1, '$'), msg)
244
245    " Prefixing middle click with [ or ] fixes the indent after pasting.
246    %d
247    call setline(1, "    one two")
248    call setreg('r', 'red blue', 'l')
249    call test_setmouse(1, 5)
250    exe "normal \"r[\<MiddleMouse>"
251    call assert_equal('    red blue', getline(1), msg)
252    call test_setmouse(2, 5)
253    exe "normal \"r]\<MiddleMouse>"
254    call assert_equal('    red blue', getline(3), msg)
255    %d
256  endfor
257
258  let &mouse = save_mouse
259  let &term = save_term
260  let &ttymouse = save_ttymouse
261  call test_override('no_query_mouse', 0)
262  let @* = save_quotestar
263  let @+ = save_quotestar
264  bwipe!
265endfunc
266
267" If clipboard is not working, then clicking the middle mouse button in visual
268" mode, will copy and paste the selected text.
269func Test_term_mouse_middle_click_no_clipboard()
270  if has('clipboard_working')
271    throw 'Skipped: clipboard support works'
272    return
273  endif
274  new
275  let save_mouse = &mouse
276  let save_term = &term
277  let save_ttymouse = &ttymouse
278  call test_override('no_query_mouse', 1)
279  set mouse=a term=xterm
280
281  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
282    let msg = 'ttymouse=' .. ttymouse_val
283    exe 'set ttymouse=' .. ttymouse_val
284    call setline(1, ['123456789', '123456789'])
285
286    " Clicking middle mouse in visual mode, yanks the selection and pastes it
287    call cursor(1, 1)
288    call feedkeys("v3l" ..
289          \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7), 'Lx!')
290    call assert_equal(['123456789', '1234561234789'],
291          \ getline(1, '$'), msg)
292  endfor
293
294  call test_override('no_query_mouse', 0)
295  let &ttymouse = save_ttymouse
296  let &term = save_term
297  let &mouse = save_mouse
298  close!
299endfunc
300
301func Test_term_mouse_middle_click_insert_mode()
302  CheckFeature clipboard_working
303
304  new
305  let save_mouse = &mouse
306  let save_term = &term
307  let save_ttymouse = &ttymouse
308  call test_override('no_query_mouse', 1)
309  set mouse=a term=xterm
310
311  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
312    let msg = 'ttymouse=' .. ttymouse_val
313    exe 'set ttymouse=' .. ttymouse_val
314    call setline(1, ['123456789', '123456789'])
315    let @* = 'abc'
316
317    " Middle-click in inesrt mode doesn't move the cursor but inserts the
318    " contents of aregister
319    call cursor(1, 4)
320    call feedkeys('i' ..
321          \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7) ..
322          \ "\<C-C>", 'Lx!')
323    call assert_equal(['123abc456789', '123456789'],
324          \ getline(1, '$'), msg)
325    call assert_equal([1, 6], [line('.'), col('.')], msg)
326
327    " Middle-click in replace mode
328    call cursor(1, 1)
329    call feedkeys('$R' ..
330          \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7) ..
331          \ "\<C-C>", 'Lx!')
332    call assert_equal(['123abc45678abc', '123456789'],
333          \ getline(1, '$'), msg)
334    call assert_equal([1, 14], [line('.'), col('.')], msg)
335  endfor
336
337  let &mouse = save_mouse
338  let &term = save_term
339  let &ttymouse = save_ttymouse
340  call test_override('no_query_mouse', 0)
341  close!
342endfunc
343
344" Test for switching window using mouse in insert mode
345func Test_term_mouse_switch_win_insert_mode()
346  5new
347  let save_mouse = &mouse
348  let save_term = &term
349  let save_ttymouse = &ttymouse
350  call test_override('no_query_mouse', 1)
351  set mouse=a term=xterm ttymouse=xterm2
352
353  call feedkeys('ivim' ..
354        \ MouseLeftClickCode(8, 6) .. MouseLeftReleaseCode(8, 6) ..
355        \ "\<C-C>", 'Lx!')
356  call assert_equal(2, winnr())
357  wincmd w
358  call assert_equal('n', mode())
359  call assert_equal(['vim'], getline(1, '$'))
360
361  let &mouse = save_mouse
362  let &term = save_term
363  let &ttymouse = save_ttymouse
364  call test_override('no_query_mouse', 0)
365  close!
366endfunc
367
368" Test for using the mouse to increaes the height of the cmdline window
369func Test_mouse_cmdwin_resize()
370  let save_mouse = &mouse
371  let save_term = &term
372  let save_ttymouse = &ttymouse
373  call test_override('no_query_mouse', 1)
374  set mouse=a term=xterm ttymouse=xterm2
375  5new
376  redraw!
377
378  let h = 0
379  let row = &lines - &cmdwinheight - 2
380  call feedkeys("q:" ..
381        \ MouseLeftClickCode(row, 1) ..
382        \ MouseLeftDragCode(row - 1, 1) ..
383        \ MouseLeftReleaseCode(row - 2, 1) ..
384        \ "alet h = \<C-R>=winheight(0)\<CR>\<CR>", 'Lx!')
385  call assert_equal(&cmdwinheight + 2, h)
386
387  let &mouse = save_mouse
388  let &term = save_term
389  let &ttymouse = save_ttymouse
390  call test_override('no_query_mouse', 0)
391  close!
392endfunc
393
394" TODO: for unclear reasons this test fails if it comes after
395" Test_xterm_mouse_ctrl_click()
396func Test_1xterm_mouse_wheel()
397  new
398  let save_mouse = &mouse
399  let save_term = &term
400  let save_wrap = &wrap
401  let save_ttymouse = &ttymouse
402  set mouse=a term=xterm nowrap
403  call setline(1, range(100000000000000, 100000000000100))
404
405  for ttymouse_val in g:Ttymouse_values
406    let msg = 'ttymouse=' .. ttymouse_val
407    exe 'set ttymouse=' .. ttymouse_val
408    go
409    call assert_equal(1, line('w0'), msg)
410    call assert_equal([0, 1, 1, 0], getpos('.'), msg)
411
412    call MouseWheelDown(1, 1)
413    call assert_equal(4, line('w0'), msg)
414    call assert_equal([0, 4, 1, 0], getpos('.'), msg)
415
416    call MouseWheelDown(1, 1)
417    call assert_equal(7, line('w0'), msg)
418    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
419
420    call MouseWheelUp(1, 1)
421    call assert_equal(4, line('w0'), msg)
422    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
423
424    call MouseWheelUp(1, 1)
425    call assert_equal(1, line('w0'), msg)
426    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
427
428    if has('gui')
429      " Horizontal wheel scrolling currently only works when vim is
430      " compiled with gui enabled.
431      call MouseWheelRight(1, 1)
432      call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
433      call assert_equal([0, 7, 7, 0], getpos('.'), msg)
434
435      call MouseWheelRight(1, 1)
436      call assert_equal(13, 1 + virtcol(".") - wincol(), msg)
437      call assert_equal([0, 7, 13, 0], getpos('.'), msg)
438
439      call MouseWheelLeft(1, 1)
440      call assert_equal(7, 1 + virtcol(".") - wincol(), msg)
441      call assert_equal([0, 7, 13, 0], getpos('.'), msg)
442
443      call MouseWheelLeft(1, 1)
444      call assert_equal(1, 1 + virtcol(".") - wincol(), msg)
445      call assert_equal([0, 7, 13, 0], getpos('.'), msg)
446    endif
447  endfor
448
449  let &mouse = save_mouse
450  let &term = save_term
451  let &wrap = save_wrap
452  let &ttymouse = save_ttymouse
453  bwipe!
454endfunc
455
456" Test that dragging beyond the window (at the bottom and at the top)
457" scrolls window content by the number of lines beyond the window.
458func Test_term_mouse_drag_beyond_window()
459  let save_mouse = &mouse
460  let save_term = &term
461  let save_ttymouse = &ttymouse
462  call test_override('no_query_mouse', 1)
463  set mouse=a term=xterm
464  let col = 1
465  call setline(1, range(1, 100))
466
467  " Split into 3 windows, and go into the middle window
468  " so we test dragging mouse below and above the window.
469  2split
470  wincmd j
471  2split
472
473  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
474    let msg = 'ttymouse=' .. ttymouse_val
475    exe 'set ttymouse=' .. ttymouse_val
476
477    " Line #10 at the top.
478    norm! 10zt
479    redraw
480    call assert_equal(10, winsaveview().topline, msg)
481    call assert_equal(2, winheight(0), msg)
482
483    let row = 4
484    call MouseLeftClick(row, col)
485    call assert_equal(10, winsaveview().topline, msg)
486
487    " Drag downwards. We're still in the window so topline should
488    " not change yet.
489    let row += 1
490    call MouseLeftDrag(row, col)
491    call assert_equal(10, winsaveview().topline, msg)
492
493    " We now leave the window at the bottom, so the window content should
494    " scroll by 1 line, then 2 lines (etc) as we drag further away.
495    let row += 1
496    call MouseLeftDrag(row, col)
497    call assert_equal(11, winsaveview().topline, msg)
498
499    let row += 1
500    call MouseLeftDrag(row, col)
501    call assert_equal(13, winsaveview().topline, msg)
502
503    " Now drag upwards.
504    let row -= 1
505    call MouseLeftDrag(row, col)
506    call assert_equal(14, winsaveview().topline, msg)
507
508    " We're now back in the window so the topline should not change.
509    let row -= 1
510    call MouseLeftDrag(row, col)
511    call assert_equal(14, winsaveview().topline, msg)
512
513    let row -= 1
514    call MouseLeftDrag(row, col)
515    call assert_equal(14, winsaveview().topline, msg)
516
517    " We now leave the window at the top so the window content should
518    " scroll by 1 line, then 2, then 3 (etc) in the opposite direction.
519    let row -= 1
520    call MouseLeftDrag(row, col)
521    call assert_equal(13, winsaveview().topline, msg)
522
523    let row -= 1
524    call MouseLeftDrag(row, col)
525    call assert_equal(11, winsaveview().topline, msg)
526
527    let row -= 1
528    call MouseLeftDrag(row, col)
529    call assert_equal(8, winsaveview().topline, msg)
530
531    call MouseLeftRelease(row, col)
532    call assert_equal(8, winsaveview().topline, msg)
533    call assert_equal(2, winheight(0), msg)
534  endfor
535
536  let &mouse = save_mouse
537  let &term = save_term
538  let &ttymouse = save_ttymouse
539  call test_override('no_query_mouse', 0)
540  bwipe!
541endfunc
542
543func Test_term_mouse_drag_window_separator()
544  let save_mouse = &mouse
545  let save_term = &term
546  let save_ttymouse = &ttymouse
547  call test_override('no_query_mouse', 1)
548  set mouse=a term=xterm
549
550  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
551    let msg = 'ttymouse=' .. ttymouse_val
552    exe 'set ttymouse=' .. ttymouse_val
553
554    " Split horizontally and test dragging the horizontal window separator.
555    split
556    let rowseparator = winheight(0) + 1
557    let row = rowseparator
558    let col = 1
559
560    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
561    if ttymouse_val !=# 'xterm2' || row <= 223
562      call MouseLeftClick(row, col)
563      let row -= 1
564      call MouseLeftDrag(row, col)
565      call assert_equal(rowseparator - 1, winheight(0) + 1, msg)
566      let row += 1
567      call MouseLeftDrag(row, col)
568      call assert_equal(rowseparator, winheight(0) + 1, msg)
569      call MouseLeftRelease(row, col)
570      call assert_equal(rowseparator, winheight(0) + 1, msg)
571    endif
572    bwipe!
573
574    " Split vertically and test dragging the vertical window separator.
575    vsplit
576    let colseparator = winwidth(0) + 1
577    let row = 1
578    let col = colseparator
579
580    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
581    if ttymouse_val !=# 'xterm2' || col <= 223
582      call MouseLeftClick(row, col)
583      let col -= 1
584      call MouseLeftDrag(row, col)
585      call assert_equal(colseparator - 1, winwidth(0) + 1, msg)
586      let col += 1
587      call MouseLeftDrag(row, col)
588      call assert_equal(colseparator, winwidth(0) + 1, msg)
589      call MouseLeftRelease(row, col)
590      call assert_equal(colseparator, winwidth(0) + 1, msg)
591    endif
592    bwipe!
593  endfor
594
595  let &mouse = save_mouse
596  let &term = save_term
597  let &ttymouse = save_ttymouse
598  call test_override('no_query_mouse', 0)
599endfunc
600
601func Test_term_mouse_drag_statusline()
602  let save_mouse = &mouse
603  let save_term = &term
604  let save_ttymouse = &ttymouse
605  call test_override('no_query_mouse', 1)
606  let save_laststatus = &laststatus
607  set mouse=a term=xterm laststatus=2
608
609  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
610    let msg = 'ttymouse=' .. ttymouse_val
611    exe 'set ttymouse=' .. ttymouse_val
612
613    call assert_equal(1, &cmdheight, msg)
614    let rowstatusline = winheight(0) + 1
615    let row = rowstatusline
616    let col = 1
617
618    if ttymouse_val ==# 'xterm2' && row > 223
619      " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
620      continue
621    endif
622
623    call MouseLeftClick(row, col)
624    let row -= 1
625    call MouseLeftDrag(row, col)
626    call assert_equal(2, &cmdheight, msg)
627    call assert_equal(rowstatusline - 1, winheight(0) + 1, msg)
628    let row += 1
629    call MouseLeftDrag(row, col)
630    call assert_equal(1, &cmdheight, msg)
631    call assert_equal(rowstatusline, winheight(0) + 1, msg)
632    call MouseLeftRelease(row, col)
633    call assert_equal(1, &cmdheight, msg)
634    call assert_equal(rowstatusline, winheight(0) + 1, msg)
635  endfor
636
637  let &mouse = save_mouse
638  let &term = save_term
639  let &ttymouse = save_ttymouse
640  call test_override('no_query_mouse', 0)
641  let &laststatus = save_laststatus
642endfunc
643
644func Test_term_mouse_click_tab()
645  let save_mouse = &mouse
646  let save_term = &term
647  let save_ttymouse = &ttymouse
648  call test_override('no_query_mouse', 1)
649  set mouse=a term=xterm
650  let row = 1
651
652  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
653    let msg = 'ttymouse=' .. ttymouse_val
654    exe 'set ttymouse=' .. ttymouse_val
655    e Xfoo
656    tabnew Xbar
657
658    let a = split(execute(':tabs'), "\n")
659    call assert_equal(['Tab page 1',
660        \              '    Xfoo',
661        \              'Tab page 2',
662        \              '>   Xbar'], a, msg)
663
664    " Test clicking on tab names in the tabline at the top.
665    let col = 2
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        \              '>   Xfoo',
672        \              'Tab page 2',
673        \              '    Xbar'], a, msg)
674
675    let col = 9
676    call MouseLeftClick(row, col)
677    call MouseLeftRelease(row, col)
678    let a = split(execute(':tabs'), "\n")
679    call assert_equal(['Tab page 1',
680        \              '    Xfoo',
681        \              'Tab page 2',
682        \              '>   Xbar'], a, msg)
683
684    %bwipe!
685  endfor
686
687  let &mouse = save_mouse
688  let &term = save_term
689  let &ttymouse = save_ttymouse
690  call test_override('no_query_mouse', 0)
691endfunc
692
693func Test_term_mouse_click_X_to_close_tab()
694  let save_mouse = &mouse
695  let save_term = &term
696  let save_ttymouse = &ttymouse
697  call test_override('no_query_mouse', 1)
698  set mouse=a term=xterm
699  let row = 1
700  let col = &columns
701
702  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
703    if ttymouse_val ==# 'xterm2' && col > 223
704      " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
705      continue
706    endif
707    let msg = 'ttymouse=' .. ttymouse_val
708    exe 'set ttymouse=' .. ttymouse_val
709    e Xtab1
710    tabnew Xtab2
711    tabnew Xtab3
712    tabn 2
713
714    let a = split(execute(':tabs'), "\n")
715    call assert_equal(['Tab page 1',
716        \              '    Xtab1',
717        \              'Tab page 2',
718        \              '>   Xtab2',
719        \              'Tab page 3',
720        \              '    Xtab3'], a, msg)
721
722    " Click on "X" in tabline to close current tab i.e. Xtab2.
723    redraw
724    call MouseLeftClick(row, col)
725    call MouseLeftRelease(row, col)
726    let a = split(execute(':tabs'), "\n")
727    call assert_equal(['Tab page 1',
728        \              '    Xtab1',
729        \              'Tab page 2',
730        \              '>   Xtab3'], a, msg)
731
732    %bwipe!
733  endfor
734
735  let &mouse = save_mouse
736  let &term = save_term
737  let &ttymouse = save_ttymouse
738  call test_override('no_query_mouse', 0)
739endfunc
740
741func Test_term_mouse_drag_to_move_tab()
742  let save_mouse = &mouse
743  let save_term = &term
744  let save_ttymouse = &ttymouse
745  call test_override('no_query_mouse', 1)
746  " Set 'mousetime' to 1 to avoid recognizing a double-click in the loop
747  set mouse=a term=xterm mousetime=1
748  let row = 1
749
750  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
751    let msg = 'ttymouse=' .. ttymouse_val
752    exe 'set ttymouse=' .. ttymouse_val
753    e Xtab1
754    tabnew Xtab2
755
756    let a = split(execute(':tabs'), "\n")
757    call assert_equal(['Tab page 1',
758        \              '    Xtab1',
759        \              'Tab page 2',
760        \              '>   Xtab2'], a, msg)
761    redraw
762
763    " Click in tab2 and drag it to tab1.
764    " Check getcharmod() to verify that click is not
765    " interpreted as a spurious double-click.
766    call MouseLeftClick(row, 10)
767    call assert_equal(0, getcharmod(), msg)
768    for col in [9, 8, 7, 6]
769      call MouseLeftDrag(row, col)
770    endfor
771    call MouseLeftRelease(row, col)
772    let a = split(execute(':tabs'), "\n")
773    call assert_equal(['Tab page 1',
774        \              '>   Xtab2',
775        \              'Tab page 2',
776        \              '    Xtab1'], a, msg)
777
778    " Click elsewhere so that click in next iteration is not
779    " interpreted as unwanted double-click.
780    call MouseLeftClick(row, 11)
781    call MouseLeftRelease(row, 11)
782
783    %bwipe!
784  endfor
785
786  let &mouse = save_mouse
787  let &term = save_term
788  let &ttymouse = save_ttymouse
789  call test_override('no_query_mouse', 0)
790  set mousetime&
791endfunc
792
793func Test_term_mouse_double_click_to_create_tab()
794  let save_mouse = &mouse
795  let save_term = &term
796  let save_ttymouse = &ttymouse
797  call test_override('no_query_mouse', 1)
798  " Set 'mousetime' to a small value, so that double-click works but we don't
799  " have to wait long to avoid a triple-click.
800  set mouse=a term=xterm mousetime=200
801  let row = 1
802  let col = 10
803
804  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
805    let msg = 'ttymouse=' .. ttymouse_val
806    exe 'set ttymouse=' .. ttymouse_val
807    e Xtab1
808    tabnew Xtab2
809
810    let a = split(execute(':tabs'), "\n")
811    call assert_equal(['Tab page 1',
812        \              '    Xtab1',
813        \              'Tab page 2',
814        \              '>   Xtab2'], a, msg)
815
816    redraw
817    call MouseLeftClick(row, col)
818    " Check getcharmod() to verify that first click is not
819    " interpreted as a spurious double-click.
820    call assert_equal(0, getcharmod(), msg)
821    call MouseLeftRelease(row, col)
822    call MouseLeftClick(row, col)
823    call assert_equal(32, getcharmod(), msg) " double-click
824    call MouseLeftRelease(row, col)
825    let a = split(execute(':tabs'), "\n")
826    call assert_equal(['Tab page 1',
827        \              '    Xtab1',
828        \              'Tab page 2',
829        \              '>   [No Name]',
830        \              'Tab page 3',
831        \              '    Xtab2'], a, msg)
832
833    " Click elsewhere so that click in next iteration is not
834    " interpreted as unwanted double click.
835    call MouseLeftClick(row, col + 1)
836    call MouseLeftRelease(row, col + 1)
837
838    %bwipe!
839  endfor
840
841  let &mouse = save_mouse
842  let &term = save_term
843  let &ttymouse = save_ttymouse
844  call test_override('no_query_mouse', 0)
845  set mousetime&
846endfunc
847
848" Test double/triple/quadruple click in normal mode to visually select.
849func Test_term_mouse_multiple_clicks_to_visually_select()
850  let save_mouse = &mouse
851  let save_term = &term
852  let save_ttymouse = &ttymouse
853  call test_override('no_query_mouse', 1)
854  set mouse=a term=xterm mousetime=200
855  new
856
857  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
858    let msg = 'ttymouse=' .. ttymouse_val
859    exe 'set ttymouse=' .. ttymouse_val
860    call setline(1, ['foo [foo bar] foo', 'foo'])
861
862    " Double-click on word should visually select the word.
863    call MouseLeftClick(1, 2)
864    call assert_equal(0, getcharmod(), msg)
865    call MouseLeftRelease(1, 2)
866    call MouseLeftClick(1, 2)
867    call assert_equal(32, getcharmod(), msg) " double-click
868    call MouseLeftRelease(1, 2)
869    call assert_equal('v', mode(), msg)
870    norm! r1
871    call assert_equal(['111 [foo bar] foo', 'foo'], getline(1, '$'), msg)
872
873    " Double-click on opening square bracket should visually
874    " select the whole [foo bar].
875    call MouseLeftClick(1, 5)
876    call assert_equal(0, getcharmod(), msg)
877    call MouseLeftRelease(1, 5)
878    call MouseLeftClick(1, 5)
879    call assert_equal(32, getcharmod(), msg) " double-click
880    call MouseLeftRelease(1, 5)
881    call assert_equal('v', mode(), msg)
882    norm! r2
883    call assert_equal(['111 222222222 foo', 'foo'], getline(1, '$'), msg)
884
885    " Triple-click should visually select the whole line.
886    call MouseLeftClick(1, 3)
887    call assert_equal(0, getcharmod(), msg)
888    call MouseLeftRelease(1, 3)
889    call MouseLeftClick(1, 3)
890    call assert_equal(32, getcharmod(), msg) " double-click
891    call MouseLeftRelease(1, 3)
892    call MouseLeftClick(1, 3)
893    call assert_equal(64, getcharmod(), msg) " triple-click
894    call MouseLeftRelease(1, 3)
895    call assert_equal('V', mode(), msg)
896    norm! r3
897    call assert_equal(['33333333333333333', 'foo'], getline(1, '$'), msg)
898
899    " Quadruple-click should start visual block select.
900    call MouseLeftClick(1, 2)
901    call assert_equal(0, getcharmod(), msg)
902    call MouseLeftRelease(1, 2)
903    call MouseLeftClick(1, 2)
904    call assert_equal(32, getcharmod(), msg) " double-click
905    call MouseLeftRelease(1, 2)
906    call MouseLeftClick(1, 2)
907    call assert_equal(64, getcharmod(), msg) " triple-click
908    call MouseLeftRelease(1, 2)
909    call MouseLeftClick(1, 2)
910    call assert_equal(96, getcharmod(), msg) " quadruple-click
911    call MouseLeftRelease(1, 2)
912    call assert_equal("\<c-v>", mode(), msg)
913    norm! r4
914    call assert_equal(['34333333333333333', 'foo'], getline(1, '$'), msg)
915
916    " Double-click on a space character should visually select all the
917    " consecutive space characters.
918    %d
919    call setline(1, '    one two')
920    call MouseLeftClick(1, 2)
921    call MouseLeftRelease(1, 2)
922    call MouseLeftClick(1, 2)
923    call MouseLeftRelease(1, 2)
924    call assert_equal('v', mode(), msg)
925    norm! r1
926    call assert_equal(['1111one two'], getline(1, '$'), msg)
927
928    " Double-click on a word with exclusive selection
929    set selection=exclusive
930    let @" = ''
931    call MouseLeftClick(1, 10)
932    call MouseLeftRelease(1, 10)
933    call MouseLeftClick(1, 10)
934    call MouseLeftRelease(1, 10)
935    norm! y
936    call assert_equal('two', @", msg)
937
938    " Double click to select a block of text with exclusive selection
939    %d
940    call setline(1, 'one (two) three')
941    call MouseLeftClick(1, 5)
942    call MouseLeftRelease(1, 5)
943    call MouseLeftClick(1, 5)
944    call MouseLeftRelease(1, 5)
945    norm! y
946    call assert_equal(5, col("'<"), msg)
947    call assert_equal(10, col("'>"), msg)
948
949    call MouseLeftClick(1, 9)
950    call MouseLeftRelease(1, 9)
951    call MouseLeftClick(1, 9)
952    call MouseLeftRelease(1, 9)
953    norm! y
954    call assert_equal(5, col("'<"), msg)
955    call assert_equal(10, col("'>"), msg)
956    set selection&
957
958    " Click somewhere else so that the clicks above is not combined with the
959    " clicks in the next iteration.
960    call MouseRightClick(3, 10)
961    call MouseRightRelease(3, 10)
962  endfor
963
964  let &mouse = save_mouse
965  let &term = save_term
966  let &ttymouse = save_ttymouse
967  set mousetime&
968  call test_override('no_query_mouse', 0)
969  bwipe!
970endfunc
971
972" Test for selecting text in visual blockwise mode using Alt-LeftClick
973func Test_mouse_alt_leftclick()
974  let save_mouse = &mouse
975  let save_term = &term
976  let save_ttymouse = &ttymouse
977  call test_override('no_query_mouse', 1)
978  set mouse=a term=xterm mousetime=200
979  set mousemodel=popup
980  new
981  call setline(1, 'one (two) three')
982
983  for ttymouse_val in g:Ttymouse_values
984    let msg = 'ttymouse=' .. ttymouse_val
985    exe 'set ttymouse=' .. ttymouse_val
986
987    " Left click with the Alt modifier key should extend the selection in
988    " blockwise visual mode.
989    let @" = ''
990    call MouseLeftClick(1, 3)
991    call MouseLeftRelease(1, 3)
992    call MouseAltLeftClick(1, 11)
993    call MouseLeftRelease(1, 11)
994    call assert_equal("\<C-V>", mode(), msg)
995    normal! y
996    call assert_equal('e (two) t', @")
997  endfor
998
999  let &mouse = save_mouse
1000  let &term = save_term
1001  let &ttymouse = save_ttymouse
1002  set mousetime& mousemodel&
1003  call test_override('no_query_mouse', 0)
1004  close!
1005endfunc
1006
1007func Test_xterm_mouse_click_in_fold_columns()
1008  new
1009  let save_mouse = &mouse
1010  let save_term = &term
1011  let save_ttymouse = &ttymouse
1012  let save_foldcolumn = &foldcolumn
1013  set mouse=a term=xterm foldcolumn=3 ttymouse=xterm2
1014
1015  " Create 2 nested folds.
1016  call setline(1, range(1, 7))
1017  2,6fold
1018  norm! zR
1019  4,5fold
1020  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
1021        \           map(range(1, 7), 'foldclosed(v:val)'))
1022
1023  " Click in "+" of inner fold in foldcolumn should open it.
1024  redraw
1025  let row = 4
1026  let col = 2
1027  call MouseLeftClick(row, col)
1028  call MouseLeftRelease(row, col)
1029  call assert_equal([-1, -1, -1, -1, -1, -1, -1],
1030        \           map(range(1, 7), 'foldclosed(v:val)'))
1031
1032  " Click in "-" of outer fold in foldcolumn should close it.
1033  redraw
1034  let row = 2
1035  let col = 1
1036  call MouseLeftClick(row, col)
1037  call MouseLeftRelease(row, col)
1038  call assert_equal([-1, 2, 2, 2, 2, 2, -1],
1039        \           map(range(1, 7), 'foldclosed(v:val)'))
1040  norm! zR
1041
1042  " Click in "|" of inner fold in foldcolumn should close it.
1043  redraw
1044  let row = 5
1045  let col = 2
1046  call MouseLeftClick(row, col)
1047  call MouseLeftRelease(row, col)
1048  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
1049        \           map(range(1, 7), 'foldclosed(v:val)'))
1050
1051  let &foldcolumn = save_foldcolumn
1052  let &ttymouse = save_ttymouse
1053  let &term = save_term
1054  let &mouse = save_mouse
1055  bwipe!
1056endfunc
1057
1058" Left or right click in Ex command line sets position of the cursor.
1059func Test_term_mouse_click_in_cmdline_to_set_pos()
1060  let save_mouse = &mouse
1061  let save_term = &term
1062  let save_ttymouse = &ttymouse
1063  call test_override('no_query_mouse', 1)
1064  set mouse=a term=xterm
1065  let row = &lines
1066
1067  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
1068    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
1069    if ttymouse_val !=# 'xterm2' || row <= 223
1070      let msg = 'ttymouse=' .. ttymouse_val
1071      exe 'set ttymouse=' .. ttymouse_val
1072
1073
1074      call feedkeys(':"3456789'
1075            \       .. MouseLeftClickCode(row, 7)
1076            \       .. MouseLeftReleaseCode(row, 7) .. 'L'
1077            \       .. MouseRightClickCode(row, 4)
1078            \       .. MouseRightReleaseCode(row, 4) .. 'R'
1079            \       .. "\<CR>", 'Lx!')
1080      call assert_equal('"3R456L789', @:, msg)
1081    endif
1082  endfor
1083
1084  let &mouse = save_mouse
1085  let &term = save_term
1086  let &ttymouse = save_ttymouse
1087  set mousetime&
1088  call test_override('no_query_mouse', 0)
1089endfunc
1090
1091" Middle click in command line pastes at position of cursor.
1092func Test_term_mouse_middle_click_in_cmdline_to_paste()
1093  CheckFeature clipboard_working
1094  let save_mouse = &mouse
1095  let save_term = &term
1096  let save_ttymouse = &ttymouse
1097  call test_override('no_query_mouse', 1)
1098  set mouse=a term=xterm
1099  let row = &lines
1100  " Column values does not matter, paste is done at position of cursor.
1101  let col = 1
1102  let @* = 'paste'
1103
1104  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
1105    let msg = 'ttymouse=' .. ttymouse_val
1106    exe 'set ttymouse=' .. ttymouse_val
1107
1108    call feedkeys(":\"->"
1109          \       .. MouseMiddleReleaseCode(row, col)
1110          \       .. MouseMiddleClickCode(row, col)
1111          \       .. "<-"
1112          \       .. MouseMiddleReleaseCode(row, col)
1113          \       .. MouseMiddleClickCode(row, col)
1114          \       .. "\<CR>", 'Lx!')
1115    call assert_equal('"->paste<-paste', @:, msg)
1116  endfor
1117
1118  let &mouse = save_mouse
1119  let &term = save_term
1120  let &ttymouse = save_ttymouse
1121  let @* = ''
1122  call test_override('no_query_mouse', 0)
1123endfunc
1124
1125" Test for making sure S-Middlemouse doesn't do anything
1126func Test_term_mouse_shift_middle_click()
1127  new
1128  let save_mouse = &mouse
1129  let save_term = &term
1130  let save_ttymouse = &ttymouse
1131  call test_override('no_query_mouse', 1)
1132  set mouse=a term=xterm ttymouse=xterm2 mousemodel=
1133
1134  call test_setmouse(1, 1)
1135  exe "normal \<S-MiddleMouse>"
1136  call assert_equal([''], getline(1, '$'))
1137  call assert_equal(1, winnr())
1138
1139  let &mouse = save_mouse
1140  let &term = save_term
1141  let &ttymouse = save_ttymouse
1142  set mousemodel&
1143  call test_override('no_query_mouse', 0)
1144  close!
1145endfunc
1146
1147" Test for using mouse in visual mode
1148func Test_term_mouse_visual_mode()
1149  new
1150  let save_mouse = &mouse
1151  let save_term = &term
1152  let save_ttymouse = &ttymouse
1153  call test_override('no_query_mouse', 1)
1154  set term=xterm ttymouse=xterm2
1155
1156  " If visual mode is not present in 'mouse', then left click should not
1157  " do anything in visal mode.
1158  call setline(1, ['one two three four'])
1159  set mouse=nci
1160  call cursor(1, 5)
1161  let @" = ''
1162  call feedkeys("ve"
1163        \ .. MouseLeftClickCode(1, 15) .. MouseLeftReleaseCode(1, 15)
1164        \ .. 'y', 'Lx!')
1165  call assert_equal(5, col('.'))
1166  call assert_equal('two', @")
1167
1168  " Pressing right click in visual mode should change the visual selection
1169  " if 'mousemodel' doesn't contain popup.
1170  " Right click after the visual selection
1171  set mousemodel=
1172  set mouse=a
1173  call test_setmouse(1, 13)
1174  exe "normal 5|ve\<RightMouse>y"
1175  call assert_equal('two three', @")
1176  call assert_equal(5, col('.'))
1177
1178  " Right click before the visual selection
1179  call test_setmouse(1, 9)
1180  exe "normal 15|ve\<RightMouse>y"
1181  call assert_equal('three four', @")
1182  call assert_equal(9, col('.'))
1183
1184  " Right click inside the selection closer to the start of the selection
1185  call test_setmouse(1, 7)
1186  exe "normal 5|vee\<RightMouse>lly"
1187  call assert_equal('three', @")
1188  call assert_equal(9, col('.'))
1189  call assert_equal(9, col("'<"))
1190  call assert_equal(13, col("'>"))
1191
1192  " Right click inside the selection closer to the end of the selection
1193  call test_setmouse(1, 11)
1194  exe "normal 5|vee\<RightMouse>ly"
1195  call assert_equal('two thre', @")
1196  call assert_equal(5, col('.'))
1197  call assert_equal(5, col("'<"))
1198  call assert_equal(12, col("'>"))
1199
1200  " Multi-line selection. Right click inside thse selection.
1201  call setline(1, repeat(['aaaaaa'], 7))
1202  call test_setmouse(3, 1)
1203  exe "normal ggVG\<RightMouse>y"
1204  call assert_equal(3, line("'<"))
1205  call test_setmouse(5, 1)
1206  exe "normal ggVG\<RightMouse>y"
1207  call assert_equal(5, line("'>"))
1208
1209  " Click right in the middle line of the selection
1210  call test_setmouse(4, 3)
1211  exe "normal ggVG$\<RightMouse>y"
1212  call assert_equal(4, line("'<"))
1213  call test_setmouse(4, 4)
1214  exe "normal ggVG$\<RightMouse>y"
1215  call assert_equal(4, line("'>"))
1216
1217  set mousemodel&
1218  let &mouse = save_mouse
1219  let &term = save_term
1220  let &ttymouse = save_ttymouse
1221  call test_override('no_query_mouse', 0)
1222  close!
1223endfunc
1224
1225" Test for displaying the popup menu using the right mouse click
1226func Test_term_mouse_popup_menu()
1227  CheckFeature menu
1228  new
1229  call setline(1, 'popup menu test')
1230  let save_mouse = &mouse
1231  let save_term = &term
1232  let save_ttymouse = &ttymouse
1233  let save_mousemodel = &mousemodel
1234  call test_override('no_query_mouse', 1)
1235  set mouse=a term=xterm mousemodel=popup
1236
1237  menu PopUp.foo :let g:menustr = 'foo'<CR>
1238  menu PopUp.bar :let g:menustr = 'bar'<CR>
1239  menu PopUp.baz :let g:menustr = 'baz'<CR>
1240
1241  for ttymouse_val in g:Ttymouse_values
1242    let msg = 'ttymouse=' .. ttymouse_val
1243    exe 'set ttymouse=' .. ttymouse_val
1244    let g:menustr = ''
1245    call feedkeys(MouseRightClickCode(1, 4)
1246		\ .. MouseRightReleaseCode(1, 4) .. "\<Down>\<Down>\<CR>", "x")
1247    call assert_equal('bar', g:menustr, msg)
1248  endfor
1249
1250  unmenu PopUp
1251  let &mouse = save_mouse
1252  let &term = save_term
1253  let &ttymouse = save_ttymouse
1254  let &mousemodel = save_mousemodel
1255  call test_override('no_query_mouse', 0)
1256  close!
1257endfunc
1258
1259" Test for 'mousemodel' set to popup_setpos to move the cursor where the popup
1260" menu is displayed.
1261func Test_term_mouse_popup_menu_setpos()
1262  CheckFeature menu
1263  5new
1264  call setline(1, ['the dish ran away with the spoon',
1265        \ 'the cow jumped over the moon' ])
1266  let save_mouse = &mouse
1267  let save_term = &term
1268  let save_ttymouse = &ttymouse
1269  let save_mousemodel = &mousemodel
1270  call test_override('no_query_mouse', 1)
1271  set mouse=a term=xterm mousemodel=popup_setpos
1272
1273  nmenu PopUp.foo :let g:menustr = 'foo'<CR>
1274  nmenu PopUp.bar :let g:menustr = 'bar'<CR>
1275  nmenu PopUp.baz :let g:menustr = 'baz'<CR>
1276  vmenu PopUp.foo y:<C-U>let g:menustr = 'foo'<CR>
1277  vmenu PopUp.bar y:<C-U>let g:menustr = 'bar'<CR>
1278  vmenu PopUp.baz y:<C-U>let g:menustr = 'baz'<CR>
1279
1280  for ttymouse_val in g:Ttymouse_values
1281    let msg = 'ttymouse=' .. ttymouse_val
1282    exe 'set ttymouse=' .. ttymouse_val
1283    let g:menustr = ''
1284    call cursor(1, 1)
1285    call feedkeys(MouseRightClickCode(1, 5)
1286		\ .. MouseRightReleaseCode(1, 5) .. "\<Down>\<Down>\<CR>", "x")
1287    call assert_equal('bar', g:menustr, msg)
1288    call assert_equal([1, 5], [line('.'), col('.')], msg)
1289
1290    " Test for right click in visual mode inside the selection
1291    let @" = ''
1292    call cursor(1, 10)
1293    call feedkeys('vee' .. MouseRightClickCode(1, 12)
1294		\ .. MouseRightReleaseCode(1, 12) .. "\<Down>\<CR>", "x")
1295    call assert_equal([1, 10], [line('.'), col('.')], msg)
1296    call assert_equal('ran away', @", msg)
1297
1298    " Test for right click in visual mode before the selection
1299    let @" = ''
1300    call cursor(1, 10)
1301    call feedkeys('vee' .. MouseRightClickCode(1, 2)
1302		\ .. MouseRightReleaseCode(1, 2) .. "\<Down>\<CR>", "x")
1303    call assert_equal([1, 2], [line('.'), col('.')], msg)
1304    call assert_equal('', @", msg)
1305
1306    " Test for right click in visual mode after the selection
1307    let @" = ''
1308    call cursor(1, 10)
1309    call feedkeys('vee' .. MouseRightClickCode(1, 20)
1310		\ .. MouseRightReleaseCode(1, 20) .. "\<Down>\<CR>", "x")
1311    call assert_equal([1, 20], [line('.'), col('.')], msg)
1312    call assert_equal('', @", msg)
1313
1314    " Test for right click in block-wise visual mode inside the selection
1315    let @" = ''
1316    call cursor(1, 16)
1317    call feedkeys("\<C-V>j3l" .. MouseRightClickCode(2, 17)
1318		\ .. MouseRightReleaseCode(2, 17) .. "\<Down>\<CR>", "x")
1319    call assert_equal([1, 16], [line('.'), col('.')], msg)
1320    call assert_equal("\<C-V>4", getregtype('"'), msg)
1321
1322    " Test for right click in block-wise visual mode outside the selection
1323    let @" = ''
1324    call cursor(1, 16)
1325    call feedkeys("\<C-V>j3l" .. MouseRightClickCode(2, 2)
1326		\ .. MouseRightReleaseCode(2, 2) .. "\<Down>\<CR>", "x")
1327    call assert_equal([2, 2], [line('.'), col('.')], msg)
1328    call assert_equal('v', getregtype('"'), msg)
1329    call assert_equal('', @", msg)
1330
1331    " Try clicking on the status line
1332    let @" = ''
1333    call cursor(1, 10)
1334    call feedkeys('vee' .. MouseRightClickCode(6, 2)
1335		\ .. MouseRightReleaseCode(6, 2) .. "\<Down>\<CR>", "x")
1336    call assert_equal([1, 10], [line('.'), col('.')], msg)
1337    call assert_equal('ran away', @", msg)
1338
1339    " Try clicking outside the window
1340    let @" = ''
1341    call cursor(7, 2)
1342    call feedkeys('vee' .. MouseRightClickCode(7, 2)
1343		\ .. MouseRightReleaseCode(7, 2) .. "\<Down>\<CR>", "x")
1344    call assert_equal(2, winnr(), msg)
1345    call assert_equal('', @", msg)
1346    wincmd w
1347  endfor
1348
1349  unmenu PopUp
1350  let &mouse = save_mouse
1351  let &term = save_term
1352  let &ttymouse = save_ttymouse
1353  let &mousemodel = save_mousemodel
1354  call test_override('no_query_mouse', 0)
1355  close!
1356endfunc
1357
1358" Test for searching for the word under the cursor using Shift-Right or
1359" Shift-Left click.
1360func Test_term_mouse_search()
1361  new
1362  let save_mouse = &mouse
1363  let save_term = &term
1364  let save_ttymouse = &ttymouse
1365  call test_override('no_query_mouse', 1)
1366  set mouse=a term=xterm ttymouse=xterm2
1367  set mousemodel=
1368
1369  " In normal mode, Shift-Left or Shift-Right click should search for the word
1370  " under the cursor.
1371  call setline(1, ['one two three four', 'four three two one'])
1372  call test_setmouse(1, 4)
1373  exe "normal \<S-LeftMouse>"
1374  call assert_equal([2, 12], [line('.'), col('.')])
1375  call test_setmouse(2, 16)
1376  exe "normal \<S-RightMouse>"
1377  call assert_equal([1, 1], [line('.'), col('.')])
1378
1379  " In visual mode, Shift-Left or Shift-Right click should search for the word
1380  " under the cursor and extend the selection.
1381  call test_setmouse(1, 4)
1382  exe "normal 4|ve\<S-LeftMouse>y"
1383  call assert_equal([2, 12], [line("'>"), col("'>")])
1384  call test_setmouse(2, 16)
1385  exe "normal 2G16|ve\<S-RightMouse>y"
1386  call assert_equal([1, 1], [line("'<"), col("'<")])
1387
1388  set mousemodel&
1389  let &mouse = save_mouse
1390  let &term = save_term
1391  let &ttymouse = save_ttymouse
1392  call test_override('no_query_mouse', 0)
1393  close!
1394endfunc
1395
1396" Test for selecting an entry in the quickfix/location list window using the
1397" mouse.
1398func Test_term_mouse_quickfix_window()
1399  let save_mouse = &mouse
1400  let save_term = &term
1401  let save_ttymouse = &ttymouse
1402  call test_override('no_query_mouse', 1)
1403  set mouse=a term=xterm ttymouse=xterm2
1404  set mousemodel=
1405
1406  cgetexpr "Xfile1:1:L1"
1407  copen 5
1408  call test_setmouse(&lines - 7, 1)
1409  exe "normal \<2-LeftMouse>"
1410  call assert_equal('Xfile1', @%)
1411  %bw!
1412
1413  lgetexpr "Xfile2:1:L1"
1414  lopen 5
1415  call test_setmouse(&lines - 7, 1)
1416  exe "normal \<2-LeftMouse>"
1417  call assert_equal('Xfile2', @%)
1418  %bw!
1419
1420  set mousemodel&
1421  let &mouse = save_mouse
1422  let &term = save_term
1423  let &ttymouse = save_ttymouse
1424  call test_override('no_query_mouse', 0)
1425endfunc
1426
1427" Test for the 'h' flag in the 'mouse' option. Using mouse in the help window.
1428func Test_term_mouse_help_window()
1429  let save_mouse = &mouse
1430  let save_term = &term
1431  let save_ttymouse = &ttymouse
1432  call test_override('no_query_mouse', 1)
1433  set mouse=h term=xterm mousetime=200
1434
1435  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
1436    let msg = 'ttymouse=' .. ttymouse_val
1437    exe 'set ttymouse=' .. ttymouse_val
1438    help
1439    let @" = ''
1440    call MouseLeftClick(2, 5)
1441    call MouseLeftRelease(2, 5)
1442    call MouseLeftClick(1, 1)
1443    call MouseLeftDrag(1, 10)
1444    call MouseLeftRelease(1, 10)
1445    norm! y
1446    call assert_equal('*help.txt*', @", msg)
1447    helpclose
1448
1449    " Click somewhere else to make sure the left click above is not combined
1450    " with the next left click and treated as a double click
1451    call MouseRightClick(5, 10)
1452    call MouseRightRelease(5, 10)
1453  endfor
1454
1455  let &mouse = save_mouse
1456  let &term = save_term
1457  let &ttymouse = save_ttymouse
1458  set mousetime&
1459  call test_override('no_query_mouse', 0)
1460  %bw!
1461endfunc
1462
1463" Test for the translation of various mouse terminal codes
1464func Test_mouse_termcodes()
1465  let save_mouse = &mouse
1466  let save_term = &term
1467  let save_ttymouse = &ttymouse
1468  call test_override('no_query_mouse', 1)
1469  set mouse=a term=xterm mousetime=200
1470
1471  new
1472  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
1473    let msg = 'ttymouse=' .. ttymouse_val
1474    exe 'set ttymouse=' .. ttymouse_val
1475
1476    let mouse_codes = [
1477          \ ["\<LeftMouse>", "<LeftMouse>"],
1478          \ ["\<MiddleMouse>", "<MiddleMouse>"],
1479          \ ["\<RightMouse>", "<RightMouse>"],
1480          \ ["\<S-LeftMouse>", "<S-LeftMouse>"],
1481          \ ["\<S-MiddleMouse>", "<S-MiddleMouse>"],
1482          \ ["\<S-RightMouse>", "<S-RightMouse>"],
1483          \ ["\<C-LeftMouse>", "<C-LeftMouse>"],
1484          \ ["\<C-MiddleMouse>", "<C-MiddleMouse>"],
1485          \ ["\<C-RightMouse>", "<C-RightMouse>"],
1486          \ ["\<M-LeftMouse>", "<M-LeftMouse>"],
1487          \ ["\<M-MiddleMouse>", "<M-MiddleMouse>"],
1488          \ ["\<M-RightMouse>", "<M-RightMouse>"],
1489          \ ["\<2-LeftMouse>", "<2-LeftMouse>"],
1490          \ ["\<2-MiddleMouse>", "<2-MiddleMouse>"],
1491          \ ["\<2-RightMouse>", "<2-RightMouse>"],
1492          \ ["\<3-LeftMouse>", "<3-LeftMouse>"],
1493          \ ["\<3-MiddleMouse>", "<3-MiddleMouse>"],
1494          \ ["\<3-RightMouse>", "<3-RightMouse>"],
1495          \ ["\<4-LeftMouse>", "<4-LeftMouse>"],
1496          \ ["\<4-MiddleMouse>", "<4-MiddleMouse>"],
1497          \ ["\<4-RightMouse>", "<4-RightMouse>"],
1498          \ ["\<LeftDrag>", "<LeftDrag>"],
1499          \ ["\<MiddleDrag>", "<MiddleDrag>"],
1500          \ ["\<RightDrag>", "<RightDrag>"],
1501          \ ["\<LeftRelease>", "<LeftRelease>"],
1502          \ ["\<MiddleRelease>", "<MiddleRelease>"],
1503          \ ["\<RightRelease>", "<RightRelease>"],
1504          \ ["\<ScrollWheelUp>", "<ScrollWheelUp>"],
1505          \ ["\<S-ScrollWheelUp>", "<S-ScrollWheelUp>"],
1506          \ ["\<C-ScrollWheelUp>", "<C-ScrollWheelUp>"],
1507          \ ["\<ScrollWheelDown>", "<ScrollWheelDown>"],
1508          \ ["\<S-ScrollWheelDown>", "<S-ScrollWheelDown>"],
1509          \ ["\<C-ScrollWheelDown>", "<C-ScrollWheelDown>"],
1510          \ ["\<ScrollWheelLeft>", "<ScrollWheelLeft>"],
1511          \ ["\<S-ScrollWheelLeft>", "<S-ScrollWheelLeft>"],
1512          \ ["\<C-ScrollWheelLeft>", "<C-ScrollWheelLeft>"],
1513          \ ["\<ScrollWheelRight>", "<ScrollWheelRight>"],
1514          \ ["\<S-ScrollWheelRight>", "<S-ScrollWheelRight>"],
1515          \ ["\<C-ScrollWheelRight>", "<C-ScrollWheelRight>"]
1516          \ ]
1517
1518    for [code, outstr] in mouse_codes
1519      exe "normal ggC\<C-K>" . code
1520      call assert_equal(outstr, getline(1), msg)
1521    endfor
1522  endfor
1523
1524  let &mouse = save_mouse
1525  let &term = save_term
1526  let &ttymouse = save_ttymouse
1527  set mousetime&
1528  call test_override('no_query_mouse', 0)
1529  %bw!
1530endfunc
1531
1532" This only checks if the sequence is recognized.
1533func Test_term_rgb_response()
1534  set t_RF=x
1535  set t_RB=y
1536
1537  " response to t_RF, 4 digits
1538  let red = 0x12
1539  let green = 0x34
1540  let blue = 0x56
1541  let seq = printf("\<Esc>]10;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
1542  call feedkeys(seq, 'Lx!')
1543  call assert_equal(seq, v:termrfgresp)
1544
1545  " response to t_RF, 2 digits
1546  let red = 0x78
1547  let green = 0x9a
1548  let blue = 0xbc
1549  let seq = printf("\<Esc>]10;rgb:%02x/%02x/%02x\x07", red, green, blue)
1550  call feedkeys(seq, 'Lx!')
1551  call assert_equal(seq, v:termrfgresp)
1552
1553  " response to t_RB, 4 digits, dark
1554  set background=light
1555  eval 'background'->test_option_not_set()
1556  let red = 0x29
1557  let green = 0x4a
1558  let blue = 0x6b
1559  let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
1560  call feedkeys(seq, 'Lx!')
1561  call assert_equal(seq, v:termrbgresp)
1562  call assert_equal('dark', &background)
1563
1564  " response to t_RB, 4 digits, light
1565  set background=dark
1566  call test_option_not_set('background')
1567  let red = 0x81
1568  let green = 0x63
1569  let blue = 0x65
1570  let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
1571  call feedkeys(seq, 'Lx!')
1572  call assert_equal(seq, v:termrbgresp)
1573  call assert_equal('light', &background)
1574
1575  " response to t_RB, 2 digits, dark
1576  set background=light
1577  call test_option_not_set('background')
1578  let red = 0x47
1579  let green = 0x59
1580  let blue = 0x5b
1581  let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue)
1582  call feedkeys(seq, 'Lx!')
1583  call assert_equal(seq, v:termrbgresp)
1584  call assert_equal('dark', &background)
1585
1586  " response to t_RB, 2 digits, light
1587  set background=dark
1588  call test_option_not_set('background')
1589  let red = 0x83
1590  let green = 0xa4
1591  let blue = 0xc2
1592  let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue)
1593  call feedkeys(seq, 'Lx!')
1594  call assert_equal(seq, v:termrbgresp)
1595  call assert_equal('light', &background)
1596
1597  set t_RF= t_RB=
1598endfunc
1599
1600" This only checks if the sequence is recognized.
1601" This must be after other tests, because it has side effects to xterm
1602" properties.
1603func Test_xx01_term_style_response()
1604  " Termresponse is only parsed when t_RV is not empty.
1605  set t_RV=x
1606  call test_override('term_props', 1)
1607
1608  " send the termresponse to trigger requesting the XT codes
1609  let seq = "\<Esc>[>41;337;0c"
1610  call feedkeys(seq, 'Lx!')
1611  call assert_equal(seq, v:termresponse)
1612
1613  let seq = "\<Esc>P1$r2 q\<Esc>\\"
1614  call feedkeys(seq, 'Lx!')
1615  call assert_equal(seq, v:termstyleresp)
1616
1617  call assert_equal(#{
1618        \ cursor_style: 'u',
1619        \ cursor_blink_mode: 'u',
1620        \ underline_rgb: 'u',
1621        \ mouse: 's'
1622        \ }, terminalprops())
1623
1624  set t_RV=
1625  call test_override('term_props', 0)
1626endfunc
1627
1628" This checks the iTerm2 version response.
1629" This must be after other tests, because it has side effects to xterm
1630" properties.
1631func Test_xx02_iTerm2_response()
1632  " Termresponse is only parsed when t_RV is not empty.
1633  set t_RV=x
1634  call test_override('term_props', 1)
1635
1636  " Old versions of iTerm2 used a different style term response.
1637  set ttymouse=xterm
1638  call test_option_not_set('ttymouse')
1639  let seq = "\<Esc>[>0;95;c"
1640  call feedkeys(seq, 'Lx!')
1641  call assert_equal(seq, v:termresponse)
1642  call assert_equal('xterm', &ttymouse)
1643
1644  set ttymouse=xterm
1645  call test_option_not_set('ttymouse')
1646  let seq = "\<Esc>[>0;95;0c"
1647  call feedkeys(seq, 'Lx!')
1648  call assert_equal(seq, v:termresponse)
1649  call assert_equal('sgr', &ttymouse)
1650
1651  call assert_equal(#{
1652        \ cursor_style: 'n',
1653        \ cursor_blink_mode: 'u',
1654        \ underline_rgb: 'u',
1655        \ mouse: 's'
1656        \ }, terminalprops())
1657
1658  set t_RV=
1659  call test_override('term_props', 0)
1660endfunc
1661
1662" This checks the libvterm version response.
1663" This must be after other tests, because it has side effects to xterm
1664" properties.
1665func Test_xx03_libvterm_response()
1666  " Termresponse is only parsed when t_RV is not empty.
1667  set t_RV=x
1668  call test_override('term_props', 1)
1669
1670  set ttymouse=xterm
1671  call test_option_not_set('ttymouse')
1672  let seq = "\<Esc>[>0;100;0c"
1673  call feedkeys(seq, 'Lx!')
1674  call assert_equal(seq, v:termresponse)
1675  call assert_equal('sgr', &ttymouse)
1676
1677  call assert_equal(#{
1678        \ cursor_style: 'n',
1679        \ cursor_blink_mode: 'u',
1680        \ underline_rgb: 'u',
1681        \ mouse: 's'
1682        \ }, terminalprops())
1683
1684  set t_RV=
1685  call test_override('term_props', 0)
1686endfunc
1687
1688" This checks the Mac Terminal.app version response.
1689" This must be after other tests, because it has side effects to xterm
1690" properties.
1691func Test_xx04_Mac_Terminal_response()
1692  " Termresponse is only parsed when t_RV is not empty.
1693  set t_RV=x
1694  call test_override('term_props', 1)
1695
1696  set ttymouse=xterm
1697  " t_8u is not reset
1698  let &t_8u = "\<Esc>[58;2;%lu;%lu;%lum"
1699  call test_option_not_set('ttymouse')
1700  let seq = "\<Esc>[>1;95;0c"
1701  call feedkeys(seq, 'Lx!')
1702  call assert_equal(seq, v:termresponse)
1703  call assert_equal('sgr', &ttymouse)
1704
1705  call assert_equal(#{
1706        \ cursor_style: 'n',
1707        \ cursor_blink_mode: 'u',
1708        \ underline_rgb: 'y',
1709        \ mouse: 's'
1710        \ }, terminalprops())
1711  call assert_equal("\<Esc>[58;2;%lu;%lu;%lum", &t_8u)
1712
1713  " Reset is_not_xterm and is_mac_terminal.
1714  set t_RV=
1715  set term=xterm
1716  set t_RV=x
1717  call test_override('term_props', 0)
1718endfunc
1719
1720" This checks the mintty version response.
1721" This must be after other tests, because it has side effects to xterm
1722" properties.
1723func Test_xx05_mintty_response()
1724  " Termresponse is only parsed when t_RV is not empty.
1725  set t_RV=x
1726  call test_override('term_props', 1)
1727
1728  set ttymouse=xterm
1729  call test_option_not_set('ttymouse')
1730  let seq = "\<Esc>[>77;20905;0c"
1731  call feedkeys(seq, 'Lx!')
1732  call assert_equal(seq, v:termresponse)
1733  call assert_equal('sgr', &ttymouse)
1734
1735  call assert_equal(#{
1736        \ cursor_style: 'n',
1737        \ cursor_blink_mode: 'u',
1738        \ underline_rgb: 'y',
1739        \ mouse: 's'
1740        \ }, terminalprops())
1741
1742  set t_RV=
1743  call test_override('term_props', 0)
1744endfunc
1745
1746" This checks the screen version response.
1747" This must be after other tests, because it has side effects to xterm
1748" properties.
1749func Test_xx06_screen_response()
1750  " Termresponse is only parsed when t_RV is not empty.
1751  set t_RV=x
1752  call test_override('term_props', 1)
1753
1754  " Old versions of screen don't support SGR mouse mode.
1755  set ttymouse=xterm
1756  call test_option_not_set('ttymouse')
1757  let seq = "\<Esc>[>83;40500;0c"
1758  call feedkeys(seq, 'Lx!')
1759  call assert_equal(seq, v:termresponse)
1760  call assert_equal('xterm', &ttymouse)
1761
1762  " screen supports SGR mouse mode starting in version 4.7.
1763  set ttymouse=xterm
1764  call test_option_not_set('ttymouse')
1765  let seq = "\<Esc>[>83;40700;0c"
1766  call feedkeys(seq, 'Lx!')
1767  call assert_equal(seq, v:termresponse)
1768  call assert_equal('sgr', &ttymouse)
1769
1770  call assert_equal(#{
1771        \ cursor_style: 'n',
1772        \ cursor_blink_mode: 'n',
1773        \ underline_rgb: 'y',
1774        \ mouse: 's'
1775        \ }, terminalprops())
1776
1777  set t_RV=
1778  call test_override('term_props', 0)
1779endfunc
1780
1781" This checks the xterm version response.
1782" This must be after other tests, because it has side effects to xterm
1783" properties.
1784func Test_xx07_xterm_response()
1785  " Termresponse is only parsed when t_RV is not empty.
1786  set t_RV=x
1787  call test_override('term_props', 1)
1788
1789  " Do Terminal.app first to check that is_mac_terminal is reset.
1790  set ttymouse=xterm
1791  call test_option_not_set('ttymouse')
1792  let seq = "\<Esc>[>1;95;0c"
1793  call feedkeys(seq, 'Lx!')
1794  call assert_equal(seq, v:termresponse)
1795  call assert_equal('sgr', &ttymouse)
1796
1797  " xterm < 95: "xterm" (actually unmodified)
1798  set t_RV=
1799  set term=xterm
1800  set t_RV=x
1801  set ttymouse=xterm
1802  call test_option_not_set('ttymouse')
1803  let seq = "\<Esc>[>0;94;0c"
1804  call feedkeys(seq, 'Lx!')
1805  call assert_equal(seq, v:termresponse)
1806  call assert_equal('xterm', &ttymouse)
1807
1808  call assert_equal(#{
1809        \ cursor_style: 'n',
1810        \ cursor_blink_mode: 'u',
1811        \ underline_rgb: 'y',
1812        \ mouse: 'u'
1813        \ }, terminalprops())
1814
1815  " xterm >= 95 < 277 "xterm2"
1816  set ttymouse=xterm
1817  call test_option_not_set('ttymouse')
1818  let seq = "\<Esc>[>0;267;0c"
1819  call feedkeys(seq, 'Lx!')
1820  call assert_equal(seq, v:termresponse)
1821  call assert_equal('xterm2', &ttymouse)
1822
1823  call assert_equal(#{
1824        \ cursor_style: 'n',
1825        \ cursor_blink_mode: 'u',
1826        \ underline_rgb: 'u',
1827        \ mouse: '2'
1828        \ }, terminalprops())
1829
1830  " xterm >= 277: "sgr"
1831  set ttymouse=xterm
1832  call test_option_not_set('ttymouse')
1833  let seq = "\<Esc>[>0;277;0c"
1834  call feedkeys(seq, 'Lx!')
1835  call assert_equal(seq, v:termresponse)
1836  call assert_equal('sgr', &ttymouse)
1837
1838  call assert_equal(#{
1839        \ cursor_style: 'n',
1840        \ cursor_blink_mode: 'u',
1841        \ underline_rgb: 'u',
1842        \ mouse: 's'
1843        \ }, terminalprops())
1844
1845  " xterm >= 279: "sgr" and cursor_style not reset; also check t_8u reset
1846  set ttymouse=xterm
1847  call test_option_not_set('ttymouse')
1848  let &t_8u = "\<Esc>[58;2;%lu;%lu;%lum"
1849  let seq = "\<Esc>[>0;279;0c"
1850  call feedkeys(seq, 'Lx!')
1851  call assert_equal(seq, v:termresponse)
1852  call assert_equal('sgr', &ttymouse)
1853
1854  call assert_equal(#{
1855        \ cursor_style: 'u',
1856        \ cursor_blink_mode: 'u',
1857        \ underline_rgb: 'u',
1858        \ mouse: 's'
1859        \ }, terminalprops())
1860  call assert_equal('', &t_8u)
1861
1862  set t_RV=
1863  call test_override('term_props', 0)
1864endfunc
1865
1866func Test_get_termcode()
1867  try
1868    let k1 = &t_k1
1869  catch /E113/
1870    throw 'Skipped: Unable to query termcodes'
1871  endtry
1872  set t_k1=
1873  set t_k1&
1874  call assert_equal(k1, &t_k1)
1875
1876  " use external termcap first
1877  set nottybuiltin
1878  set t_k1=
1879  set t_k1&
1880  " when using external termcap may get something else, but it must not be
1881  " empty, since we would fallback to the builtin one.
1882  call assert_notequal('', &t_k1)
1883
1884  if &term =~ 'xterm'
1885    " use internal termcap first
1886    let term_save = &term
1887    let &term = 'builtin_' .. &term
1888    set t_k1=
1889    set t_k1&
1890    call assert_equal(k1, &t_k1)
1891    let &term = term_save
1892  endif
1893
1894  set ttybuiltin
1895endfunc
1896
1897func Test_list_builtin_terminals()
1898  let buf = RunVimInTerminal('', #{rows: 14})
1899  call term_sendkeys(buf, ":set cmdheight=3\<CR>")
1900  call term_wait(buf, 100)
1901  call term_sendkeys(buf, ":set term=xxx\<CR>")
1902  call term_wait(buf, 100)
1903  call assert_match('builtin_dumb', term_getline(buf, 11))
1904  call assert_match('Not found in termcap', term_getline(buf, 12))
1905  call StopVimInTerminal(buf)
1906endfunc
1907
1908func GetEscCodeCSI27(key, modifier)
1909  let key = printf("%d", char2nr(a:key))
1910  let mod = printf("%d", a:modifier)
1911  return "\<Esc>[27;" .. mod .. ';' .. key .. '~'
1912endfunc
1913
1914func GetEscCodeCSIu(key, modifier)
1915  let key = printf("%d", char2nr(a:key))
1916  let mod = printf("%d", a:modifier)
1917  return "\<Esc>[" .. key .. ';' .. mod .. 'u'
1918endfunc
1919
1920" This checks the CSI sequences when in modifyOtherKeys mode.
1921" The mode doesn't need to be enabled, the codes are always detected.
1922func RunTest_modifyOtherKeys(func)
1923  new
1924  set timeoutlen=10
1925
1926  " Shift-X is sent as 'X' with the shift modifier
1927  call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!')
1928  call assert_equal('X', getline(1))
1929
1930  " Ctrl-i is Tab
1931  call setline(1, '')
1932  call feedkeys('a' .. a:func('i', 5) .. "\<Esc>", 'Lx!')
1933  call assert_equal("\t", getline(1))
1934
1935  " Ctrl-I is also Tab
1936  call setline(1, '')
1937  call feedkeys('a' .. a:func('I', 5) .. "\<Esc>", 'Lx!')
1938  call assert_equal("\t", getline(1))
1939
1940  " Alt-x is ø
1941  call setline(1, '')
1942  call feedkeys('a' .. a:func('x', 3) .. "\<Esc>", 'Lx!')
1943  call assert_equal("ø", getline(1))
1944
1945  " Meta-x is also ø
1946  call setline(1, '')
1947  call feedkeys('a' .. a:func('x', 9) .. "\<Esc>", 'Lx!')
1948  call assert_equal("ø", getline(1))
1949
1950  " Alt-X is Ø
1951  call setline(1, '')
1952  call feedkeys('a' .. a:func('X', 3) .. "\<Esc>", 'Lx!')
1953  call assert_equal("Ø", getline(1))
1954
1955  " Meta-X is ø
1956  call setline(1, '')
1957  call feedkeys('a' .. a:func('X', 9) .. "\<Esc>", 'Lx!')
1958  call assert_equal("Ø", getline(1))
1959
1960  " Ctrl-6 is Ctrl-^
1961  split aaa
1962  edit bbb
1963  call feedkeys(a:func('6', 5), 'Lx!')
1964  call assert_equal("aaa", bufname())
1965  bwipe aaa
1966  bwipe bbb
1967
1968  bwipe!
1969  set timeoutlen&
1970endfunc
1971
1972func Test_modifyOtherKeys_basic()
1973  call RunTest_modifyOtherKeys(function('GetEscCodeCSI27'))
1974  call RunTest_modifyOtherKeys(function('GetEscCodeCSIu'))
1975endfunc
1976
1977func Test_modifyOtherKeys_no_mapping()
1978  set timeoutlen=10
1979
1980  let @a = 'aaa'
1981  call feedkeys(":let x = '" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a'\<CR>", 'Lx!')
1982  call assert_equal("let x = 'aaa'", @:)
1983
1984  new
1985  call feedkeys("a" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a\<Esc>", 'Lx!')
1986  call assert_equal("aaa", getline(1))
1987  bwipe!
1988
1989  new
1990  call feedkeys("axx\<CR>yy" .. GetEscCodeCSI27('G', 5) .. GetEscCodeCSI27('K', 5) .. "a\<Esc>", 'Lx!')
1991  call assert_equal("axx", getline(1))
1992  call assert_equal("yy", getline(2))
1993  bwipe!
1994
1995  set timeoutlen&
1996endfunc
1997
1998func RunTest_mapping_shift(key, func)
1999  call setline(1, '')
2000  if a:key == '|'
2001    exe 'inoremap \| xyz'
2002  else
2003    exe 'inoremap ' .. a:key .. ' xyz'
2004  endif
2005  call feedkeys('a' .. a:func(a:key, 2) .. "\<Esc>", 'Lx!')
2006  call assert_equal("xyz", getline(1))
2007  if a:key == '|'
2008    exe 'iunmap \|'
2009  else
2010    exe 'iunmap ' .. a:key
2011  endif
2012endfunc
2013
2014func Test_modifyOtherKeys_mapped()
2015  set timeoutlen=10
2016  imap ' <C-W>
2017  imap <C-W><C-A> c-a
2018  call setline(1, '')
2019
2020  " single quote is turned into single byte CTRL-W
2021  " CTRL-A is added with a separate modifier, and needs to be simplified before
2022  " the mapping can match.
2023  call feedkeys("a'" .. GetEscCodeCSI27('A', 5) .. "\<Esc>", 'Lx!')
2024  call assert_equal('c-a', getline(1))
2025
2026  iunmap '
2027  iunmap <C-W><C-A>
2028  set timeoutlen&
2029endfunc
2030
2031func RunTest_mapping_works_with_shift(func)
2032  new
2033  set timeoutlen=10
2034
2035  call RunTest_mapping_shift('@', a:func)
2036  call RunTest_mapping_shift('A', a:func)
2037  call RunTest_mapping_shift('Z', a:func)
2038  call RunTest_mapping_shift('^', a:func)
2039  call RunTest_mapping_shift('_', a:func)
2040  call RunTest_mapping_shift('{', a:func)
2041  call RunTest_mapping_shift('|', a:func)
2042  call RunTest_mapping_shift('}', a:func)
2043  call RunTest_mapping_shift('~', a:func)
2044
2045  bwipe!
2046  set timeoutlen&
2047endfunc
2048
2049func Test_mapping_works_with_shift_plain()
2050  call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27'))
2051  call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu'))
2052endfunc
2053
2054func RunTest_mapping_mods(map, key, func, code)
2055  call setline(1, '')
2056  exe 'inoremap ' .. a:map .. ' xyz'
2057  call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!')
2058  call assert_equal("xyz", getline(1))
2059  exe 'iunmap ' .. a:map
2060endfunc
2061
2062func RunTest_mapping_works_with_mods(func, mods, code)
2063  new
2064  set timeoutlen=10
2065
2066  if a:mods !~ 'S'
2067    " Shift by itself has no effect
2068    call RunTest_mapping_mods('<' .. a:mods .. '-@>', '@', a:func, a:code)
2069  endif
2070  call RunTest_mapping_mods('<' .. a:mods .. '-A>', 'A', a:func, a:code)
2071  call RunTest_mapping_mods('<' .. a:mods .. '-Z>', 'Z', a:func, a:code)
2072  if a:mods !~ 'S'
2073    " with Shift code is always upper case
2074    call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'a', a:func, a:code)
2075    call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'z', a:func, a:code)
2076  endif
2077  if a:mods != 'A'
2078    " with Alt code is not in upper case
2079    call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'A', a:func, a:code)
2080    call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'Z', a:func, a:code)
2081  endif
2082  call RunTest_mapping_mods('<' .. a:mods .. '-á>', 'á', a:func, a:code)
2083  if a:mods !~ 'S'
2084    " Shift by itself has no effect
2085    call RunTest_mapping_mods('<' .. a:mods .. '-^>', '^', a:func, a:code)
2086    call RunTest_mapping_mods('<' .. a:mods .. '-_>', '_', a:func, a:code)
2087    call RunTest_mapping_mods('<' .. a:mods .. '-{>', '{', a:func, a:code)
2088    call RunTest_mapping_mods('<' .. a:mods .. '-\|>', '|', a:func, a:code)
2089    call RunTest_mapping_mods('<' .. a:mods .. '-}>', '}', a:func, a:code)
2090    call RunTest_mapping_mods('<' .. a:mods .. '-~>', '~', a:func, a:code)
2091  endif
2092
2093  bwipe!
2094  set timeoutlen&
2095endfunc
2096
2097func Test_mapping_works_with_shift()
2098  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S', 2)
2099  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S', 2)
2100endfunc
2101
2102func Test_mapping_works_with_ctrl()
2103  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C', 5)
2104  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C', 5)
2105endfunc
2106
2107func Test_mapping_works_with_shift_ctrl()
2108  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S', 6)
2109  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S', 6)
2110endfunc
2111
2112" Below we also test the "u" code with Alt, This works, but libvterm would not
2113" send the Alt key like this but by prefixing an Esc.
2114
2115func Test_mapping_works_with_alt()
2116  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'A', 3)
2117  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'A', 3)
2118endfunc
2119
2120func Test_mapping_works_with_shift_alt()
2121  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S-A', 4)
2122  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S-A', 4)
2123endfunc
2124
2125func Test_mapping_works_with_ctrl_alt()
2126  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-A', 7)
2127  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-A', 7)
2128endfunc
2129
2130func Test_mapping_works_with_shift_ctrl_alt()
2131  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 8)
2132  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8)
2133endfunc
2134
2135func Test_insert_literal()
2136  set timeoutlen=10
2137  new
2138  " CTRL-V CTRL-X inserts a ^X
2139  call feedkeys('a' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
2140  call assert_equal("\<C-X>", getline(1))
2141
2142  call setline(1, '')
2143  call feedkeys('a' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
2144  call assert_equal("\<C-X>", getline(1))
2145
2146  " CTRL-SHIFT-V CTRL-X inserts escape sequence
2147  call setline(1, '')
2148  call feedkeys('a' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
2149  call assert_equal("\<Esc>[88;5u", getline(1))
2150
2151  call setline(1, '')
2152  call feedkeys('a' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
2153  call assert_equal("\<Esc>[27;5;88~", getline(1))
2154
2155  bwipe!
2156  set timeoutlen&
2157endfunc
2158
2159func Test_cmdline_literal()
2160  set timeoutlen=10
2161
2162  " CTRL-V CTRL-Y inserts a ^Y
2163  call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2164  call assert_equal("\"\<C-Y>", @:)
2165
2166  call feedkeys(':' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2167  call assert_equal("\"\<C-Y>", @:)
2168
2169  " CTRL-SHIFT-V CTRL-Y inserts escape sequence
2170  call feedkeys(':' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2171  call assert_equal("\"\<Esc>[89;5u", @:)
2172
2173  call setline(1, '')
2174  call feedkeys(':' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2175  call assert_equal("\"\<Esc>[27;5;89~", @:)
2176
2177  set timeoutlen&
2178endfunc
2179
2180" Test for translation of special key codes (<xF1>, <xF2>, etc.)
2181func Test_Keycode_Tranlsation()
2182  let keycodes = [
2183        \ ["<xUp>", "<Up>"],
2184        \ ["<xDown>", "<Down>"],
2185        \ ["<xLeft>", "<Left>"],
2186        \ ["<xRight>", "<Right>"],
2187        \ ["<xHome>", "<Home>"],
2188        \ ["<xEnd>", "<End>"],
2189        \ ["<zHome>", "<Home>"],
2190        \ ["<zEnd>", "<End>"],
2191        \ ["<xF1>", "<F1>"],
2192        \ ["<xF2>", "<F2>"],
2193        \ ["<xF3>", "<F3>"],
2194        \ ["<xF4>", "<F4>"],
2195        \ ["<S-xF1>", "<S-F1>"],
2196        \ ["<S-xF2>", "<S-F2>"],
2197        \ ["<S-xF3>", "<S-F3>"],
2198        \ ["<S-xF4>", "<S-F4>"]]
2199  for [k1, k2] in keycodes
2200    exe "nnoremap " .. k1 .. " 2wx"
2201    call assert_true(maparg(k1, 'n', 0, 1).lhs == k2)
2202    exe "nunmap " .. k1
2203  endfor
2204endfunc
2205
2206" vim: shiftwidth=2 sts=2 expandtab
2207