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
11source term_util.vim
12
13func Test_term_mouse_left_click()
14  new
15  let save_mouse = &mouse
16  let save_term = &term
17  let save_ttymouse = &ttymouse
18  call test_override('no_query_mouse', 1)
19  set mouse=a term=xterm
20  call setline(1, ['line 1', 'line 2', 'line 3 is a bit longer'])
21
22  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
23    let msg = 'ttymouse=' .. ttymouse_val
24    exe 'set ttymouse=' .. ttymouse_val
25    go
26    call assert_equal([0, 1, 1, 0], getpos('.'), msg)
27    let row = 2
28    let col = 6
29    call MouseLeftClick(row, col)
30    call MouseLeftRelease(row, col)
31    call assert_equal([0, 2, 6, 0], getpos('.'), msg)
32  endfor
33
34  let &mouse = save_mouse
35  let &term = save_term
36  let &ttymouse = save_ttymouse
37  call test_override('no_query_mouse', 0)
38  bwipe!
39endfunc
40
41func Test_xterm_mouse_right_click_extends_visual()
42  if has('mac')
43    throw "Skipped: test right click in visual mode does not work on macOs (why?)"
44  endif
45  let save_mouse = &mouse
46  let save_term = &term
47  let save_ttymouse = &ttymouse
48  call test_override('no_query_mouse', 1)
49  set mouse=a term=xterm
50
51  for visual_mode in ["v", "V", "\<C-V>"]
52    for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
53      let msg = 'visual=' .. visual_mode .. ' ttymouse=' .. ttymouse_val
54      exe 'set ttymouse=' .. ttymouse_val
55
56      call setline(1, repeat([repeat('-', 7)], 7))
57      call MouseLeftClick(4, 4)
58      call MouseLeftRelease(4, 4)
59      exe  "norm! " .. visual_mode
60
61      " Right click extends top left of visual area.
62      call MouseRightClick(2, 2)
63      call MouseRightRelease(2, 2)
64
65      " Right click extends bottom right of visual area.
66      call MouseRightClick(6, 6)
67      call MouseRightRelease(6, 6)
68      norm! r1gv
69
70      " Right click shrinks top left of visual area.
71      call MouseRightClick(3, 3)
72      call MouseRightRelease(3, 3)
73
74      " Right click shrinks bottom right of visual area.
75      call MouseRightClick(5, 5)
76      call MouseRightRelease(5, 5)
77      norm! r2
78
79      if visual_mode ==# 'v'
80        call assert_equal(['-------',
81              \            '-111111',
82              \            '1122222',
83              \            '2222222',
84              \            '2222211',
85              \            '111111-',
86              \            '-------'], getline(1, '$'), msg)
87      elseif visual_mode ==# 'V'
88        call assert_equal(['-------',
89              \            '1111111',
90              \            '2222222',
91              \            '2222222',
92              \            '2222222',
93              \            '1111111',
94              \            '-------'], getline(1, '$'), msg)
95      else
96        call assert_equal(['-------',
97              \            '-11111-',
98              \            '-12221-',
99              \            '-12221-',
100              \            '-12221-',
101              \            '-11111-',
102              \            '-------'], getline(1, '$'), msg)
103      endif
104    endfor
105  endfor
106
107  let &mouse = save_mouse
108  let &term = save_term
109  let &ttymouse = save_ttymouse
110  call test_override('no_query_mouse', 0)
111  bwipe!
112endfunc
113
114" Test that <C-LeftMouse> jumps to help tag and <C-RightMouse> jumps back.
115" Also test for g<LeftMouse> and g<RightMouse>.
116func Test_xterm_mouse_tagjump()
117  let save_mouse = &mouse
118  let save_term = &term
119  let save_ttymouse = &ttymouse
120  set mouse=a term=xterm
121
122  for ttymouse_val in g:Ttymouse_values
123    let msg = 'ttymouse=' .. ttymouse_val
124    exe 'set ttymouse=' .. ttymouse_val
125    help
126    /usr_02.txt
127    norm! zt
128
129    " CTRL-left click to jump to a tag
130    let row = 1
131    let col = 1
132    call MouseCtrlLeftClick(row, col)
133    call MouseLeftRelease(row, col)
134    call assert_match('usr_02.txt$', bufname('%'), msg)
135    call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg)
136
137    " CTRL-right click to pop a tag
138    call MouseCtrlRightClick(row, col)
139    call MouseRightRelease(row, col)
140    call assert_match('help.txt$', bufname('%'), msg)
141    call assert_equal('|usr_02.txt|', expand('<cWORD>'), msg)
142
143    " Jump to a tag
144    exe "normal \<C-]>"
145    call assert_match('usr_02.txt$', bufname('%'), msg)
146    call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg)
147
148    " Use CTRL-right click in insert mode to pop the tag
149    new
150    let str = 'iHello' .. MouseCtrlRightClickCode(row, col)
151          \ .. MouseRightReleaseCode(row, col) .. "\<C-C>"
152    call assert_fails('call feedkeys(str, "Lx!")', 'E37:', msg)
153    close!
154
155    " CTRL-right click with a count
156    let str = "4" .. MouseCtrlRightClickCode(row, col)
157          \ .. MouseRightReleaseCode(row, col)
158    call assert_fails('call feedkeys(str, "Lx!")', 'E555:', msg)
159    call assert_match('help.txt$', bufname('%'), msg)
160    call assert_equal(1, line('.'), msg)
161
162    " g<LeftMouse> to jump to a tag
163    /usr_02.txt
164    norm! zt
165    call test_setmouse(row, col)
166    exe "normal g\<LeftMouse>"
167    call assert_match('usr_02.txt$', bufname('%'), msg)
168    call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg)
169
170    " g<RightMouse> to pop to a tag
171    call test_setmouse(row, col)
172    exe "normal g\<RightMouse>"
173    call assert_match('help.txt$', bufname('%'), msg)
174    call assert_equal('|usr_02.txt|', expand('<cWORD>'), msg)
175
176    %bw!
177  endfor
178
179  let &mouse = save_mouse
180  let &term = save_term
181  let &ttymouse = save_ttymouse
182endfunc
183
184func Test_term_mouse_middle_click()
185  CheckFeature clipboard_working
186
187  new
188  let save_mouse = &mouse
189  let save_term = &term
190  let save_ttymouse = &ttymouse
191  call test_override('no_query_mouse', 1)
192  let save_quotestar = @*
193  let save_quoteplus = @+
194  set mouse=a term=xterm
195
196  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
197    let msg = 'ttymouse=' .. ttymouse_val
198    exe 'set ttymouse=' .. ttymouse_val
199    call setline(1, ['123456789', '123456789'])
200    let @* = 'abc'
201
202    " Middle-click in the middle of the line pastes text where clicked.
203    let row = 1
204    let col = 6
205    call MouseMiddleClick(row, col)
206    call MouseMiddleRelease(row, col)
207    call assert_equal(['12345abc6789', '123456789'], getline(1, '$'), msg)
208
209    " Middle-click beyond end of the line pastes text at the end of the line.
210    let col = 20
211    call MouseMiddleClick(row, col)
212    call MouseMiddleRelease(row, col)
213    call assert_equal(['12345abc6789abc', '123456789'], getline(1, '$'), msg)
214
215    " Middle-click beyond the last line pastes in the last line.
216    let row = 5
217    let col = 3
218    call MouseMiddleClick(row, col)
219    call MouseMiddleRelease(row, col)
220    call assert_equal(['12345abc6789abc', '12abc3456789'], getline(1, '$'), msg)
221
222    " Middle mouse click in operator pending mode beeps
223    call assert_beeps('exe "normal c\<MiddleMouse>"')
224
225    " Clicking middle mouse in visual mode, yanks the selection and pastes the
226    " clipboard contents
227    let save_clipboard = &clipboard
228    set clipboard=
229    let @" = ''
230    call cursor(1, 1)
231    call feedkeys("v3l" ..
232          \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7), 'Lx!')
233    call assert_equal(['12345abc6789abc', '12abc3abc456789'],
234          \ getline(1, '$'), msg)
235    call assert_equal('1234', @", msg)
236    let &clipboard = save_clipboard
237
238    " Clicking middle mouse in select mode, replaces the selected text with
239    " the clipboard contents
240    let @+ = 'xyz'
241    call cursor(1, 3)
242    exe "normal gh\<Right>\<Right>\<MiddleMouse>"
243    call assert_equal(['12xyzabc6789abc', '12abc3abc456789'],
244          \ getline(1, '$'), msg)
245
246    " Prefixing middle click with [ or ] fixes the indent after pasting.
247    %d
248    call setline(1, "    one two")
249    call setreg('r', 'red blue', 'l')
250    call test_setmouse(1, 5)
251    exe "normal \"r[\<MiddleMouse>"
252    call assert_equal('    red blue', getline(1), msg)
253    call test_setmouse(2, 5)
254    exe "normal \"r]\<MiddleMouse>"
255    call assert_equal('    red blue', getline(3), msg)
256    %d
257  endfor
258
259  let &mouse = save_mouse
260  let &term = save_term
261  let &ttymouse = save_ttymouse
262  call test_override('no_query_mouse', 0)
263  let @* = save_quotestar
264  let @+ = save_quotestar
265  bwipe!
266endfunc
267
268" If clipboard is not working, then clicking the middle mouse button in visual
269" mode, will copy and paste the selected text.
270func Test_term_mouse_middle_click_no_clipboard()
271  if has('clipboard_working')
272    throw 'Skipped: clipboard support works'
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
855  " 'mousetime' must be sufficiently large, or else the test is flaky when
856  " using a ssh connection with X forwarding; i.e. ssh -X (issue #7563).
857  set mouse=a term=xterm mousetime=600
858  new
859
860  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
861    let msg = 'ttymouse=' .. ttymouse_val
862    exe 'set ttymouse=' .. ttymouse_val
863    call setline(1, ['foo [foo bar] foo', 'foo'])
864
865    " Double-click on word should visually select the word.
866    call MouseLeftClick(1, 2)
867    call assert_equal(0, getcharmod(), msg)
868    call MouseLeftRelease(1, 2)
869    call MouseLeftClick(1, 2)
870    call assert_equal(32, getcharmod(), msg) " double-click
871    call MouseLeftRelease(1, 2)
872    call assert_equal('v', mode(), msg)
873    norm! r1
874    call assert_equal(['111 [foo bar] foo', 'foo'], getline(1, '$'), msg)
875
876    " Double-click on opening square bracket should visually
877    " select the whole [foo bar].
878    call MouseLeftClick(1, 5)
879    call assert_equal(0, getcharmod(), msg)
880    call MouseLeftRelease(1, 5)
881    call MouseLeftClick(1, 5)
882    call assert_equal(32, getcharmod(), msg) " double-click
883    call MouseLeftRelease(1, 5)
884    call assert_equal('v', mode(), msg)
885    norm! r2
886    call assert_equal(['111 222222222 foo', 'foo'], getline(1, '$'), msg)
887
888    " Triple-click should visually select the whole line.
889    call MouseLeftClick(1, 3)
890    call assert_equal(0, getcharmod(), msg)
891    call MouseLeftRelease(1, 3)
892    call MouseLeftClick(1, 3)
893    call assert_equal(32, getcharmod(), msg) " double-click
894    call MouseLeftRelease(1, 3)
895    call MouseLeftClick(1, 3)
896    call assert_equal(64, getcharmod(), msg) " triple-click
897    call MouseLeftRelease(1, 3)
898    call assert_equal('V', mode(), msg)
899    norm! r3
900    call assert_equal(['33333333333333333', 'foo'], getline(1, '$'), msg)
901
902    " Quadruple-click should start visual block select.
903    call MouseLeftClick(1, 2)
904    call assert_equal(0, getcharmod(), msg)
905    call MouseLeftRelease(1, 2)
906    call MouseLeftClick(1, 2)
907    call assert_equal(32, getcharmod(), msg) " double-click
908    call MouseLeftRelease(1, 2)
909    call MouseLeftClick(1, 2)
910    call assert_equal(64, getcharmod(), msg) " triple-click
911    call MouseLeftRelease(1, 2)
912    call MouseLeftClick(1, 2)
913    call assert_equal(96, getcharmod(), msg) " quadruple-click
914    call MouseLeftRelease(1, 2)
915    call assert_equal("\<c-v>", mode(), msg)
916    norm! r4
917    call assert_equal(['34333333333333333', 'foo'], getline(1, '$'), msg)
918
919    " Double-click on a space character should visually select all the
920    " consecutive space characters.
921    %d
922    call setline(1, '    one two')
923    call MouseLeftClick(1, 2)
924    call MouseLeftRelease(1, 2)
925    call MouseLeftClick(1, 2)
926    call MouseLeftRelease(1, 2)
927    call assert_equal('v', mode(), msg)
928    norm! r1
929    call assert_equal(['1111one two'], getline(1, '$'), msg)
930
931    " Double-click on a word with exclusive selection
932    set selection=exclusive
933    let @" = ''
934    call MouseLeftClick(1, 10)
935    call MouseLeftRelease(1, 10)
936    call MouseLeftClick(1, 10)
937    call MouseLeftRelease(1, 10)
938    norm! y
939    call assert_equal('two', @", msg)
940
941    " Double click to select a block of text with exclusive selection
942    %d
943    call setline(1, 'one (two) three')
944    call MouseLeftClick(1, 5)
945    call MouseLeftRelease(1, 5)
946    call MouseLeftClick(1, 5)
947    call MouseLeftRelease(1, 5)
948    norm! y
949    call assert_equal(5, col("'<"), msg)
950    call assert_equal(10, col("'>"), msg)
951
952    call MouseLeftClick(1, 9)
953    call MouseLeftRelease(1, 9)
954    call MouseLeftClick(1, 9)
955    call MouseLeftRelease(1, 9)
956    norm! y
957    call assert_equal(5, col("'<"), msg)
958    call assert_equal(10, col("'>"), msg)
959    set selection&
960
961    " Click somewhere else so that the clicks above is not combined with the
962    " clicks in the next iteration.
963    call MouseRightClick(3, 10)
964    call MouseRightRelease(3, 10)
965  endfor
966
967  let &mouse = save_mouse
968  let &term = save_term
969  let &ttymouse = save_ttymouse
970  set mousetime&
971  call test_override('no_query_mouse', 0)
972  bwipe!
973endfunc
974
975" Test for selecting text in visual blockwise mode using Alt-LeftClick
976func Test_mouse_alt_leftclick()
977  let save_mouse = &mouse
978  let save_term = &term
979  let save_ttymouse = &ttymouse
980  call test_override('no_query_mouse', 1)
981  set mouse=a term=xterm mousetime=200
982  set mousemodel=popup
983  new
984  call setline(1, 'one (two) three')
985
986  for ttymouse_val in g:Ttymouse_values
987    let msg = 'ttymouse=' .. ttymouse_val
988    exe 'set ttymouse=' .. ttymouse_val
989
990    " Left click with the Alt modifier key should extend the selection in
991    " blockwise visual mode.
992    let @" = ''
993    call MouseLeftClick(1, 3)
994    call MouseLeftRelease(1, 3)
995    call MouseAltLeftClick(1, 11)
996    call MouseLeftRelease(1, 11)
997    call assert_equal("\<C-V>", mode(), msg)
998    normal! y
999    call assert_equal('e (two) t', @")
1000  endfor
1001
1002  let &mouse = save_mouse
1003  let &term = save_term
1004  let &ttymouse = save_ttymouse
1005  set mousetime& mousemodel&
1006  call test_override('no_query_mouse', 0)
1007  close!
1008endfunc
1009
1010func Test_xterm_mouse_click_in_fold_columns()
1011  new
1012  let save_mouse = &mouse
1013  let save_term = &term
1014  let save_ttymouse = &ttymouse
1015  let save_foldcolumn = &foldcolumn
1016  set mouse=a term=xterm foldcolumn=3 ttymouse=xterm2
1017
1018  " Create 2 nested folds.
1019  call setline(1, range(1, 7))
1020  2,6fold
1021  norm! zR
1022  4,5fold
1023  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
1024        \           map(range(1, 7), 'foldclosed(v:val)'))
1025
1026  " Click in "+" of inner fold in foldcolumn should open it.
1027  redraw
1028  let row = 4
1029  let col = 2
1030  call MouseLeftClick(row, col)
1031  call MouseLeftRelease(row, col)
1032  call assert_equal([-1, -1, -1, -1, -1, -1, -1],
1033        \           map(range(1, 7), 'foldclosed(v:val)'))
1034
1035  " Click in "-" of outer fold in foldcolumn should close it.
1036  redraw
1037  let row = 2
1038  let col = 1
1039  call MouseLeftClick(row, col)
1040  call MouseLeftRelease(row, col)
1041  call assert_equal([-1, 2, 2, 2, 2, 2, -1],
1042        \           map(range(1, 7), 'foldclosed(v:val)'))
1043  norm! zR
1044
1045  " Click in "|" of inner fold in foldcolumn should close it.
1046  redraw
1047  let row = 5
1048  let col = 2
1049  call MouseLeftClick(row, col)
1050  call MouseLeftRelease(row, col)
1051  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
1052        \           map(range(1, 7), 'foldclosed(v:val)'))
1053
1054  let &foldcolumn = save_foldcolumn
1055  let &ttymouse = save_ttymouse
1056  let &term = save_term
1057  let &mouse = save_mouse
1058  bwipe!
1059endfunc
1060
1061" Left or right click in Ex command line sets position of the cursor.
1062func Test_term_mouse_click_in_cmdline_to_set_pos()
1063  let save_mouse = &mouse
1064  let save_term = &term
1065  let save_ttymouse = &ttymouse
1066  call test_override('no_query_mouse', 1)
1067  set mouse=a term=xterm
1068  let row = &lines
1069
1070  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
1071    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
1072    if ttymouse_val !=# 'xterm2' || row <= 223
1073      let msg = 'ttymouse=' .. ttymouse_val
1074      exe 'set ttymouse=' .. ttymouse_val
1075
1076
1077      call feedkeys(':"3456789'
1078            \       .. MouseLeftClickCode(row, 7)
1079            \       .. MouseLeftReleaseCode(row, 7) .. 'L'
1080            \       .. MouseRightClickCode(row, 4)
1081            \       .. MouseRightReleaseCode(row, 4) .. 'R'
1082            \       .. "\<CR>", 'Lx!')
1083      call assert_equal('"3R456L789', @:, msg)
1084    endif
1085  endfor
1086
1087  let &mouse = save_mouse
1088  let &term = save_term
1089  let &ttymouse = save_ttymouse
1090  set mousetime&
1091  call test_override('no_query_mouse', 0)
1092endfunc
1093
1094" Middle click in command line pastes at position of cursor.
1095func Test_term_mouse_middle_click_in_cmdline_to_paste()
1096  CheckFeature clipboard_working
1097  let save_mouse = &mouse
1098  let save_term = &term
1099  let save_ttymouse = &ttymouse
1100  call test_override('no_query_mouse', 1)
1101  set mouse=a term=xterm
1102  let row = &lines
1103  " Column values does not matter, paste is done at position of cursor.
1104  let col = 1
1105  let @* = 'paste'
1106
1107  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
1108    let msg = 'ttymouse=' .. ttymouse_val
1109    exe 'set ttymouse=' .. ttymouse_val
1110
1111    call feedkeys(":\"->"
1112          \       .. MouseMiddleReleaseCode(row, col)
1113          \       .. MouseMiddleClickCode(row, col)
1114          \       .. "<-"
1115          \       .. MouseMiddleReleaseCode(row, col)
1116          \       .. MouseMiddleClickCode(row, col)
1117          \       .. "\<CR>", 'Lx!')
1118    call assert_equal('"->paste<-paste', @:, msg)
1119  endfor
1120
1121  let &mouse = save_mouse
1122  let &term = save_term
1123  let &ttymouse = save_ttymouse
1124  let @* = ''
1125  call test_override('no_query_mouse', 0)
1126endfunc
1127
1128" Test for making sure S-Middlemouse doesn't do anything
1129func Test_term_mouse_shift_middle_click()
1130  new
1131  let save_mouse = &mouse
1132  let save_term = &term
1133  let save_ttymouse = &ttymouse
1134  call test_override('no_query_mouse', 1)
1135  set mouse=a term=xterm ttymouse=xterm2 mousemodel=
1136
1137  call test_setmouse(1, 1)
1138  exe "normal \<S-MiddleMouse>"
1139  call assert_equal([''], getline(1, '$'))
1140  call assert_equal(1, winnr())
1141
1142  let &mouse = save_mouse
1143  let &term = save_term
1144  let &ttymouse = save_ttymouse
1145  set mousemodel&
1146  call test_override('no_query_mouse', 0)
1147  close!
1148endfunc
1149
1150" Test for using mouse in visual mode
1151func Test_term_mouse_visual_mode()
1152  new
1153  let save_mouse = &mouse
1154  let save_term = &term
1155  let save_ttymouse = &ttymouse
1156  call test_override('no_query_mouse', 1)
1157  set term=xterm ttymouse=xterm2
1158
1159  " If visual mode is not present in 'mouse', then left click should not
1160  " do anything in visal mode.
1161  call setline(1, ['one two three four'])
1162  set mouse=nci
1163  call cursor(1, 5)
1164  let @" = ''
1165  call feedkeys("ve"
1166        \ .. MouseLeftClickCode(1, 15) .. MouseLeftReleaseCode(1, 15)
1167        \ .. 'y', 'Lx!')
1168  call assert_equal(5, col('.'))
1169  call assert_equal('two', @")
1170
1171  " Pressing right click in visual mode should change the visual selection
1172  " if 'mousemodel' doesn't contain popup.
1173  " Right click after the visual selection
1174  set mousemodel=
1175  set mouse=a
1176  call test_setmouse(1, 13)
1177  exe "normal 5|ve\<RightMouse>y"
1178  call assert_equal('two three', @")
1179  call assert_equal(5, col('.'))
1180
1181  " Right click before the visual selection
1182  call test_setmouse(1, 9)
1183  exe "normal 15|ve\<RightMouse>y"
1184  call assert_equal('three four', @")
1185  call assert_equal(9, col('.'))
1186
1187  " Right click inside the selection closer to the start of the selection
1188  call test_setmouse(1, 7)
1189  exe "normal 5|vee\<RightMouse>lly"
1190  call assert_equal('three', @")
1191  call assert_equal(9, col('.'))
1192  call assert_equal(9, col("'<"))
1193  call assert_equal(13, col("'>"))
1194
1195  " Right click inside the selection closer to the end of the selection
1196  call test_setmouse(1, 11)
1197  exe "normal 5|vee\<RightMouse>ly"
1198  call assert_equal('two thre', @")
1199  call assert_equal(5, col('.'))
1200  call assert_equal(5, col("'<"))
1201  call assert_equal(12, col("'>"))
1202
1203  " Multi-line selection. Right click inside thse selection.
1204  call setline(1, repeat(['aaaaaa'], 7))
1205  call test_setmouse(3, 1)
1206  exe "normal ggVG\<RightMouse>y"
1207  call assert_equal(3, line("'<"))
1208  call test_setmouse(5, 1)
1209  exe "normal ggVG\<RightMouse>y"
1210  call assert_equal(5, line("'>"))
1211
1212  " Click right in the middle line of the selection
1213  call test_setmouse(4, 3)
1214  exe "normal ggVG$\<RightMouse>y"
1215  call assert_equal(4, line("'<"))
1216  call test_setmouse(4, 4)
1217  exe "normal ggVG$\<RightMouse>y"
1218  call assert_equal(4, line("'>"))
1219
1220  set mousemodel&
1221  let &mouse = save_mouse
1222  let &term = save_term
1223  let &ttymouse = save_ttymouse
1224  call test_override('no_query_mouse', 0)
1225  close!
1226endfunc
1227
1228" Test for displaying the popup menu using the right mouse click
1229func Test_term_mouse_popup_menu()
1230  CheckFeature menu
1231  new
1232  call setline(1, 'popup menu test')
1233  let save_mouse = &mouse
1234  let save_term = &term
1235  let save_ttymouse = &ttymouse
1236  let save_mousemodel = &mousemodel
1237  call test_override('no_query_mouse', 1)
1238  set mouse=a term=xterm mousemodel=popup
1239
1240  menu PopUp.foo :let g:menustr = 'foo'<CR>
1241  menu PopUp.bar :let g:menustr = 'bar'<CR>
1242  menu PopUp.baz :let g:menustr = 'baz'<CR>
1243
1244  for ttymouse_val in g:Ttymouse_values
1245    let msg = 'ttymouse=' .. ttymouse_val
1246    exe 'set ttymouse=' .. ttymouse_val
1247    let g:menustr = ''
1248    call feedkeys(MouseRightClickCode(1, 4)
1249		\ .. MouseRightReleaseCode(1, 4) .. "\<Down>\<Down>\<CR>", "x")
1250    call assert_equal('bar', g:menustr, msg)
1251  endfor
1252
1253  unmenu PopUp
1254  let &mouse = save_mouse
1255  let &term = save_term
1256  let &ttymouse = save_ttymouse
1257  let &mousemodel = save_mousemodel
1258  call test_override('no_query_mouse', 0)
1259  close!
1260endfunc
1261
1262" Test for 'mousemodel' set to popup_setpos to move the cursor where the popup
1263" menu is displayed.
1264func Test_term_mouse_popup_menu_setpos()
1265  CheckFeature menu
1266  5new
1267  call setline(1, ['the dish ran away with the spoon',
1268        \ 'the cow jumped over the moon' ])
1269  let save_mouse = &mouse
1270  let save_term = &term
1271  let save_ttymouse = &ttymouse
1272  let save_mousemodel = &mousemodel
1273  call test_override('no_query_mouse', 1)
1274  set mouse=a term=xterm mousemodel=popup_setpos
1275
1276  nmenu PopUp.foo :let g:menustr = 'foo'<CR>
1277  nmenu PopUp.bar :let g:menustr = 'bar'<CR>
1278  nmenu PopUp.baz :let g:menustr = 'baz'<CR>
1279  vmenu PopUp.foo y:<C-U>let g:menustr = 'foo'<CR>
1280  vmenu PopUp.bar y:<C-U>let g:menustr = 'bar'<CR>
1281  vmenu PopUp.baz y:<C-U>let g:menustr = 'baz'<CR>
1282
1283  for ttymouse_val in g:Ttymouse_values
1284    let msg = 'ttymouse=' .. ttymouse_val
1285    exe 'set ttymouse=' .. ttymouse_val
1286    let g:menustr = ''
1287    call cursor(1, 1)
1288    call feedkeys(MouseRightClickCode(1, 5)
1289		\ .. MouseRightReleaseCode(1, 5) .. "\<Down>\<Down>\<CR>", "x")
1290    call assert_equal('bar', g:menustr, msg)
1291    call assert_equal([1, 5], [line('.'), col('.')], msg)
1292
1293    " Test for right click in visual mode inside the selection
1294    let @" = ''
1295    call cursor(1, 10)
1296    call feedkeys('vee' .. MouseRightClickCode(1, 12)
1297		\ .. MouseRightReleaseCode(1, 12) .. "\<Down>\<CR>", "x")
1298    call assert_equal([1, 10], [line('.'), col('.')], msg)
1299    call assert_equal('ran away', @", msg)
1300
1301    " Test for right click in visual mode before the selection
1302    let @" = ''
1303    call cursor(1, 10)
1304    call feedkeys('vee' .. MouseRightClickCode(1, 2)
1305		\ .. MouseRightReleaseCode(1, 2) .. "\<Down>\<CR>", "x")
1306    call assert_equal([1, 2], [line('.'), col('.')], msg)
1307    call assert_equal('', @", msg)
1308
1309    " Test for right click in visual mode after the selection
1310    let @" = ''
1311    call cursor(1, 10)
1312    call feedkeys('vee' .. MouseRightClickCode(1, 20)
1313		\ .. MouseRightReleaseCode(1, 20) .. "\<Down>\<CR>", "x")
1314    call assert_equal([1, 20], [line('.'), col('.')], msg)
1315    call assert_equal('', @", msg)
1316
1317    " Test for right click in block-wise visual mode inside the selection
1318    let @" = ''
1319    call cursor(1, 16)
1320    call feedkeys("\<C-V>j3l" .. MouseRightClickCode(2, 17)
1321		\ .. MouseRightReleaseCode(2, 17) .. "\<Down>\<CR>", "x")
1322    call assert_equal([1, 16], [line('.'), col('.')], msg)
1323    call assert_equal("\<C-V>4", getregtype('"'), msg)
1324
1325    " Test for right click in block-wise visual mode outside the selection
1326    let @" = ''
1327    call cursor(1, 16)
1328    call feedkeys("\<C-V>j3l" .. MouseRightClickCode(2, 2)
1329		\ .. MouseRightReleaseCode(2, 2) .. "\<Down>\<CR>", "x")
1330    call assert_equal([2, 2], [line('.'), col('.')], msg)
1331    call assert_equal('v', getregtype('"'), msg)
1332    call assert_equal('', @", msg)
1333
1334    " Try clicking on the status line
1335    let @" = ''
1336    call cursor(1, 10)
1337    call feedkeys('vee' .. MouseRightClickCode(6, 2)
1338		\ .. MouseRightReleaseCode(6, 2) .. "\<Down>\<CR>", "x")
1339    call assert_equal([1, 10], [line('.'), col('.')], msg)
1340    call assert_equal('ran away', @", msg)
1341
1342    " Try clicking outside the window
1343    let @" = ''
1344    call cursor(7, 2)
1345    call feedkeys('vee' .. MouseRightClickCode(7, 2)
1346		\ .. MouseRightReleaseCode(7, 2) .. "\<Down>\<CR>", "x")
1347    call assert_equal(2, winnr(), msg)
1348    call assert_equal('', @", msg)
1349    wincmd w
1350  endfor
1351
1352  unmenu PopUp
1353  let &mouse = save_mouse
1354  let &term = save_term
1355  let &ttymouse = save_ttymouse
1356  let &mousemodel = save_mousemodel
1357  call test_override('no_query_mouse', 0)
1358  close!
1359endfunc
1360
1361" Test for searching for the word under the cursor using Shift-Right or
1362" Shift-Left click.
1363func Test_term_mouse_search()
1364  new
1365  let save_mouse = &mouse
1366  let save_term = &term
1367  let save_ttymouse = &ttymouse
1368  call test_override('no_query_mouse', 1)
1369  set mouse=a term=xterm ttymouse=xterm2
1370  set mousemodel=
1371
1372  " In normal mode, Shift-Left or Shift-Right click should search for the word
1373  " under the cursor.
1374  call setline(1, ['one two three four', 'four three two one'])
1375  call test_setmouse(1, 4)
1376  exe "normal \<S-LeftMouse>"
1377  call assert_equal([2, 12], [line('.'), col('.')])
1378  call test_setmouse(2, 16)
1379  exe "normal \<S-RightMouse>"
1380  call assert_equal([1, 1], [line('.'), col('.')])
1381
1382  " In visual mode, Shift-Left or Shift-Right click should search for the word
1383  " under the cursor and extend the selection.
1384  call test_setmouse(1, 4)
1385  exe "normal 4|ve\<S-LeftMouse>y"
1386  call assert_equal([2, 12], [line("'>"), col("'>")])
1387  call test_setmouse(2, 16)
1388  exe "normal 2G16|ve\<S-RightMouse>y"
1389  call assert_equal([1, 1], [line("'<"), col("'<")])
1390
1391  set mousemodel&
1392  let &mouse = save_mouse
1393  let &term = save_term
1394  let &ttymouse = save_ttymouse
1395  call test_override('no_query_mouse', 0)
1396  close!
1397endfunc
1398
1399" Test for selecting an entry in the quickfix/location list window using the
1400" mouse.
1401func Test_term_mouse_quickfix_window()
1402  let save_mouse = &mouse
1403  let save_term = &term
1404  let save_ttymouse = &ttymouse
1405  call test_override('no_query_mouse', 1)
1406  set mouse=a term=xterm ttymouse=xterm2
1407  set mousemodel=
1408
1409  cgetexpr "Xfile1:1:L1"
1410  copen 5
1411  call test_setmouse(&lines - 7, 1)
1412  exe "normal \<2-LeftMouse>"
1413  call assert_equal('Xfile1', @%)
1414  %bw!
1415
1416  lgetexpr "Xfile2:1:L1"
1417  lopen 5
1418  call test_setmouse(&lines - 7, 1)
1419  exe "normal \<2-LeftMouse>"
1420  call assert_equal('Xfile2', @%)
1421  %bw!
1422
1423  set mousemodel&
1424  let &mouse = save_mouse
1425  let &term = save_term
1426  let &ttymouse = save_ttymouse
1427  call test_override('no_query_mouse', 0)
1428endfunc
1429
1430" Test for the 'h' flag in the 'mouse' option. Using mouse in the help window.
1431func Test_term_mouse_help_window()
1432  let save_mouse = &mouse
1433  let save_term = &term
1434  let save_ttymouse = &ttymouse
1435  call test_override('no_query_mouse', 1)
1436  set mouse=h term=xterm mousetime=200
1437
1438  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
1439    let msg = 'ttymouse=' .. ttymouse_val
1440    exe 'set ttymouse=' .. ttymouse_val
1441    help
1442    let @" = ''
1443    call MouseLeftClick(2, 5)
1444    call MouseLeftRelease(2, 5)
1445    call MouseLeftClick(1, 1)
1446    call MouseLeftDrag(1, 10)
1447    call MouseLeftRelease(1, 10)
1448    norm! y
1449    call assert_equal('*help.txt*', @", msg)
1450    helpclose
1451
1452    " Click somewhere else to make sure the left click above is not combined
1453    " with the next left click and treated as a double click
1454    call MouseRightClick(5, 10)
1455    call MouseRightRelease(5, 10)
1456  endfor
1457
1458  let &mouse = save_mouse
1459  let &term = save_term
1460  let &ttymouse = save_ttymouse
1461  set mousetime&
1462  call test_override('no_query_mouse', 0)
1463  %bw!
1464endfunc
1465
1466" Test for the translation of various mouse terminal codes
1467func Test_mouse_termcodes()
1468  let save_mouse = &mouse
1469  let save_term = &term
1470  let save_ttymouse = &ttymouse
1471  call test_override('no_query_mouse', 1)
1472  set mouse=a term=xterm mousetime=200
1473
1474  new
1475  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
1476    let msg = 'ttymouse=' .. ttymouse_val
1477    exe 'set ttymouse=' .. ttymouse_val
1478
1479    let mouse_codes = [
1480          \ ["\<LeftMouse>", "<LeftMouse>"],
1481          \ ["\<MiddleMouse>", "<MiddleMouse>"],
1482          \ ["\<RightMouse>", "<RightMouse>"],
1483          \ ["\<S-LeftMouse>", "<S-LeftMouse>"],
1484          \ ["\<S-MiddleMouse>", "<S-MiddleMouse>"],
1485          \ ["\<S-RightMouse>", "<S-RightMouse>"],
1486          \ ["\<C-LeftMouse>", "<C-LeftMouse>"],
1487          \ ["\<C-MiddleMouse>", "<C-MiddleMouse>"],
1488          \ ["\<C-RightMouse>", "<C-RightMouse>"],
1489          \ ["\<M-LeftMouse>", "<M-LeftMouse>"],
1490          \ ["\<M-MiddleMouse>", "<M-MiddleMouse>"],
1491          \ ["\<M-RightMouse>", "<M-RightMouse>"],
1492          \ ["\<2-LeftMouse>", "<2-LeftMouse>"],
1493          \ ["\<2-MiddleMouse>", "<2-MiddleMouse>"],
1494          \ ["\<2-RightMouse>", "<2-RightMouse>"],
1495          \ ["\<3-LeftMouse>", "<3-LeftMouse>"],
1496          \ ["\<3-MiddleMouse>", "<3-MiddleMouse>"],
1497          \ ["\<3-RightMouse>", "<3-RightMouse>"],
1498          \ ["\<4-LeftMouse>", "<4-LeftMouse>"],
1499          \ ["\<4-MiddleMouse>", "<4-MiddleMouse>"],
1500          \ ["\<4-RightMouse>", "<4-RightMouse>"],
1501          \ ["\<LeftDrag>", "<LeftDrag>"],
1502          \ ["\<MiddleDrag>", "<MiddleDrag>"],
1503          \ ["\<RightDrag>", "<RightDrag>"],
1504          \ ["\<LeftRelease>", "<LeftRelease>"],
1505          \ ["\<MiddleRelease>", "<MiddleRelease>"],
1506          \ ["\<RightRelease>", "<RightRelease>"],
1507          \ ["\<ScrollWheelUp>", "<ScrollWheelUp>"],
1508          \ ["\<S-ScrollWheelUp>", "<S-ScrollWheelUp>"],
1509          \ ["\<C-ScrollWheelUp>", "<C-ScrollWheelUp>"],
1510          \ ["\<ScrollWheelDown>", "<ScrollWheelDown>"],
1511          \ ["\<S-ScrollWheelDown>", "<S-ScrollWheelDown>"],
1512          \ ["\<C-ScrollWheelDown>", "<C-ScrollWheelDown>"],
1513          \ ["\<ScrollWheelLeft>", "<ScrollWheelLeft>"],
1514          \ ["\<S-ScrollWheelLeft>", "<S-ScrollWheelLeft>"],
1515          \ ["\<C-ScrollWheelLeft>", "<C-ScrollWheelLeft>"],
1516          \ ["\<ScrollWheelRight>", "<ScrollWheelRight>"],
1517          \ ["\<S-ScrollWheelRight>", "<S-ScrollWheelRight>"],
1518          \ ["\<C-ScrollWheelRight>", "<C-ScrollWheelRight>"]
1519          \ ]
1520
1521    for [code, outstr] in mouse_codes
1522      exe "normal ggC\<C-K>" . code
1523      call assert_equal(outstr, getline(1), msg)
1524    endfor
1525  endfor
1526
1527  let &mouse = save_mouse
1528  let &term = save_term
1529  let &ttymouse = save_ttymouse
1530  set mousetime&
1531  call test_override('no_query_mouse', 0)
1532  %bw!
1533endfunc
1534
1535" This only checks if the sequence is recognized.
1536func Test_term_rgb_response()
1537  set t_RF=x
1538  set t_RB=y
1539
1540  " response to t_RF, 4 digits
1541  let red = 0x12
1542  let green = 0x34
1543  let blue = 0x56
1544  let seq = printf("\<Esc>]10;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
1545  call feedkeys(seq, 'Lx!')
1546  call assert_equal(seq, v:termrfgresp)
1547
1548  " response to t_RF, 2 digits
1549  let red = 0x78
1550  let green = 0x9a
1551  let blue = 0xbc
1552  let seq = printf("\<Esc>]10;rgb:%02x/%02x/%02x\x07", red, green, blue)
1553  call feedkeys(seq, 'Lx!')
1554  call assert_equal(seq, v:termrfgresp)
1555
1556  " response to t_RB, 4 digits, dark
1557  set background=light
1558  eval 'background'->test_option_not_set()
1559  let red = 0x29
1560  let green = 0x4a
1561  let blue = 0x6b
1562  let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
1563  call feedkeys(seq, 'Lx!')
1564  call assert_equal(seq, v:termrbgresp)
1565  call assert_equal('dark', &background)
1566
1567  " response to t_RB, 4 digits, light
1568  set background=dark
1569  call test_option_not_set('background')
1570  let red = 0x81
1571  let green = 0x63
1572  let blue = 0x65
1573  let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue)
1574  call feedkeys(seq, 'Lx!')
1575  call assert_equal(seq, v:termrbgresp)
1576  call assert_equal('light', &background)
1577
1578  " response to t_RB, 2 digits, dark
1579  set background=light
1580  call test_option_not_set('background')
1581  let red = 0x47
1582  let green = 0x59
1583  let blue = 0x5b
1584  let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue)
1585  call feedkeys(seq, 'Lx!')
1586  call assert_equal(seq, v:termrbgresp)
1587  call assert_equal('dark', &background)
1588
1589  " response to t_RB, 2 digits, light
1590  set background=dark
1591  call test_option_not_set('background')
1592  let red = 0x83
1593  let green = 0xa4
1594  let blue = 0xc2
1595  let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue)
1596  call feedkeys(seq, 'Lx!')
1597  call assert_equal(seq, v:termrbgresp)
1598  call assert_equal('light', &background)
1599
1600  set t_RF= t_RB=
1601endfunc
1602
1603" This only checks if the sequence is recognized.
1604" This must be after other tests, because it has side effects to xterm
1605" properties.
1606func Test_xx01_term_style_response()
1607  " Termresponse is only parsed when t_RV is not empty.
1608  set t_RV=x
1609  call test_override('term_props', 1)
1610
1611  " send the termresponse to trigger requesting the XT codes
1612  let seq = "\<Esc>[>41;337;0c"
1613  call feedkeys(seq, 'Lx!')
1614  call assert_equal(seq, v:termresponse)
1615
1616  let seq = "\<Esc>P1$r2 q\<Esc>\\"
1617  call feedkeys(seq, 'Lx!')
1618  call assert_equal(seq, v:termstyleresp)
1619
1620  call assert_equal(#{
1621        \ cursor_style: 'u',
1622        \ cursor_blink_mode: 'u',
1623        \ underline_rgb: 'u',
1624        \ mouse: 's'
1625        \ }, terminalprops())
1626
1627  set t_RV=
1628  call test_override('term_props', 0)
1629endfunc
1630
1631" This checks the iTerm2 version response.
1632" This must be after other tests, because it has side effects to xterm
1633" properties.
1634func Test_xx02_iTerm2_response()
1635  " Termresponse is only parsed when t_RV is not empty.
1636  set t_RV=x
1637  call test_override('term_props', 1)
1638
1639  " Old versions of iTerm2 used a different style term response.
1640  set ttymouse=xterm
1641  call test_option_not_set('ttymouse')
1642  let seq = "\<Esc>[>0;95;c"
1643  call feedkeys(seq, 'Lx!')
1644  call assert_equal(seq, v:termresponse)
1645  call assert_equal('xterm', &ttymouse)
1646
1647  set ttymouse=xterm
1648  call test_option_not_set('ttymouse')
1649  let seq = "\<Esc>[>0;95;0c"
1650  call feedkeys(seq, 'Lx!')
1651  call assert_equal(seq, v:termresponse)
1652  call assert_equal('sgr', &ttymouse)
1653
1654  call assert_equal(#{
1655        \ cursor_style: 'n',
1656        \ cursor_blink_mode: 'u',
1657        \ underline_rgb: 'u',
1658        \ mouse: 's'
1659        \ }, terminalprops())
1660
1661  set t_RV=
1662  call test_override('term_props', 0)
1663endfunc
1664
1665" This checks the libvterm version response.
1666" This must be after other tests, because it has side effects to xterm
1667" properties.
1668func Test_xx03_libvterm_response()
1669  " Termresponse is only parsed when t_RV is not empty.
1670  set t_RV=x
1671  call test_override('term_props', 1)
1672
1673  set ttymouse=xterm
1674  call test_option_not_set('ttymouse')
1675  let seq = "\<Esc>[>0;100;0c"
1676  call feedkeys(seq, 'Lx!')
1677  call assert_equal(seq, v:termresponse)
1678  call assert_equal('sgr', &ttymouse)
1679
1680  call assert_equal(#{
1681        \ cursor_style: 'n',
1682        \ cursor_blink_mode: 'u',
1683        \ underline_rgb: 'u',
1684        \ mouse: 's'
1685        \ }, terminalprops())
1686
1687  set t_RV=
1688  call test_override('term_props', 0)
1689endfunc
1690
1691" This checks the Mac Terminal.app version response.
1692" This must be after other tests, because it has side effects to xterm
1693" properties.
1694func Test_xx04_Mac_Terminal_response()
1695  " Termresponse is only parsed when t_RV is not empty.
1696  set t_RV=x
1697  call test_override('term_props', 1)
1698
1699  set ttymouse=xterm
1700  " t_8u is not reset
1701  let &t_8u = "\<Esc>[58;2;%lu;%lu;%lum"
1702  call test_option_not_set('ttymouse')
1703  let seq = "\<Esc>[>1;95;0c"
1704  call feedkeys(seq, 'Lx!')
1705  call assert_equal(seq, v:termresponse)
1706  call assert_equal('sgr', &ttymouse)
1707
1708  call assert_equal(#{
1709        \ cursor_style: 'n',
1710        \ cursor_blink_mode: 'u',
1711        \ underline_rgb: 'y',
1712        \ mouse: 's'
1713        \ }, terminalprops())
1714  call assert_equal("\<Esc>[58;2;%lu;%lu;%lum", &t_8u)
1715
1716  " Reset is_not_xterm and is_mac_terminal.
1717  set t_RV=
1718  set term=xterm
1719  set t_RV=x
1720  call test_override('term_props', 0)
1721endfunc
1722
1723" This checks the mintty version response.
1724" This must be after other tests, because it has side effects to xterm
1725" properties.
1726func Test_xx05_mintty_response()
1727  " Termresponse is only parsed when t_RV is not empty.
1728  set t_RV=x
1729  call test_override('term_props', 1)
1730
1731  set ttymouse=xterm
1732  call test_option_not_set('ttymouse')
1733  let seq = "\<Esc>[>77;20905;0c"
1734  call feedkeys(seq, 'Lx!')
1735  call assert_equal(seq, v:termresponse)
1736  call assert_equal('sgr', &ttymouse)
1737
1738  call assert_equal(#{
1739        \ cursor_style: 'n',
1740        \ cursor_blink_mode: 'u',
1741        \ underline_rgb: 'y',
1742        \ mouse: 's'
1743        \ }, terminalprops())
1744
1745  set t_RV=
1746  call test_override('term_props', 0)
1747endfunc
1748
1749" This checks the screen version response.
1750" This must be after other tests, because it has side effects to xterm
1751" properties.
1752func Test_xx06_screen_response()
1753  " Termresponse is only parsed when t_RV is not empty.
1754  set t_RV=x
1755  call test_override('term_props', 1)
1756
1757  " Old versions of screen don't support SGR mouse mode.
1758  set ttymouse=xterm
1759  call test_option_not_set('ttymouse')
1760  let seq = "\<Esc>[>83;40500;0c"
1761  call feedkeys(seq, 'Lx!')
1762  call assert_equal(seq, v:termresponse)
1763  call assert_equal('xterm', &ttymouse)
1764
1765  " screen supports SGR mouse mode starting in version 4.7.
1766  set ttymouse=xterm
1767  call test_option_not_set('ttymouse')
1768  let seq = "\<Esc>[>83;40700;0c"
1769  call feedkeys(seq, 'Lx!')
1770  call assert_equal(seq, v:termresponse)
1771  call assert_equal('sgr', &ttymouse)
1772
1773  call assert_equal(#{
1774        \ cursor_style: 'n',
1775        \ cursor_blink_mode: 'n',
1776        \ underline_rgb: 'y',
1777        \ mouse: 's'
1778        \ }, terminalprops())
1779
1780  set t_RV=
1781  call test_override('term_props', 0)
1782endfunc
1783
1784" This checks the xterm version response.
1785" This must be after other tests, because it has side effects to xterm
1786" properties.
1787func Test_xx07_xterm_response()
1788  " Termresponse is only parsed when t_RV is not empty.
1789  set t_RV=x
1790  call test_override('term_props', 1)
1791
1792  " Do Terminal.app first to check that is_mac_terminal is reset.
1793  set ttymouse=xterm
1794  call test_option_not_set('ttymouse')
1795  let seq = "\<Esc>[>1;95;0c"
1796  call feedkeys(seq, 'Lx!')
1797  call assert_equal(seq, v:termresponse)
1798  call assert_equal('sgr', &ttymouse)
1799
1800  " xterm < 95: "xterm" (actually unmodified)
1801  set t_RV=
1802  set term=xterm
1803  set t_RV=x
1804  set ttymouse=xterm
1805  call test_option_not_set('ttymouse')
1806  let seq = "\<Esc>[>0;94;0c"
1807  call feedkeys(seq, 'Lx!')
1808  call assert_equal(seq, v:termresponse)
1809  call assert_equal('xterm', &ttymouse)
1810
1811  call assert_equal(#{
1812        \ cursor_style: 'n',
1813        \ cursor_blink_mode: 'u',
1814        \ underline_rgb: 'y',
1815        \ mouse: 'u'
1816        \ }, terminalprops())
1817
1818  " xterm >= 95 < 277 "xterm2"
1819  set ttymouse=xterm
1820  call test_option_not_set('ttymouse')
1821  let seq = "\<Esc>[>0;267;0c"
1822  call feedkeys(seq, 'Lx!')
1823  call assert_equal(seq, v:termresponse)
1824  call assert_equal('xterm2', &ttymouse)
1825
1826  call assert_equal(#{
1827        \ cursor_style: 'n',
1828        \ cursor_blink_mode: 'u',
1829        \ underline_rgb: 'u',
1830        \ mouse: '2'
1831        \ }, terminalprops())
1832
1833  " xterm >= 277: "sgr"
1834  set ttymouse=xterm
1835  call test_option_not_set('ttymouse')
1836  let seq = "\<Esc>[>0;277;0c"
1837  call feedkeys(seq, 'Lx!')
1838  call assert_equal(seq, v:termresponse)
1839  call assert_equal('sgr', &ttymouse)
1840
1841  call assert_equal(#{
1842        \ cursor_style: 'n',
1843        \ cursor_blink_mode: 'u',
1844        \ underline_rgb: 'u',
1845        \ mouse: 's'
1846        \ }, terminalprops())
1847
1848  " xterm >= 279: "sgr" and cursor_style not reset; also check t_8u reset
1849  set ttymouse=xterm
1850  call test_option_not_set('ttymouse')
1851  let &t_8u = "\<Esc>[58;2;%lu;%lu;%lum"
1852  let seq = "\<Esc>[>0;279;0c"
1853  call feedkeys(seq, 'Lx!')
1854  call assert_equal(seq, v:termresponse)
1855  call assert_equal('sgr', &ttymouse)
1856
1857  call assert_equal(#{
1858        \ cursor_style: 'u',
1859        \ cursor_blink_mode: 'u',
1860        \ underline_rgb: 'u',
1861        \ mouse: 's'
1862        \ }, terminalprops())
1863  call assert_equal('', &t_8u)
1864
1865  set t_RV=
1866  call test_override('term_props', 0)
1867endfunc
1868
1869func Test_get_termcode()
1870  try
1871    let k1 = &t_k1
1872  catch /E113/
1873    throw 'Skipped: Unable to query termcodes'
1874  endtry
1875  set t_k1=
1876  set t_k1&
1877  call assert_equal(k1, &t_k1)
1878
1879  " use external termcap first
1880  set nottybuiltin
1881  set t_k1=
1882  set t_k1&
1883  " when using external termcap may get something else, but it must not be
1884  " empty, since we would fallback to the builtin one.
1885  call assert_notequal('', &t_k1)
1886
1887  if &term =~ 'xterm'
1888    " use internal termcap first
1889    let term_save = &term
1890    let &term = 'builtin_' .. &term
1891    set t_k1=
1892    set t_k1&
1893    call assert_equal(k1, &t_k1)
1894    let &term = term_save
1895  endif
1896
1897  set ttybuiltin
1898endfunc
1899
1900func Test_list_builtin_terminals()
1901  CheckRunVimInTerminal
1902  call RunVimInTerminal('', #{rows: 14})
1903  call term_sendkeys('', ":set cmdheight=3\<CR>")
1904  call TermWait('', 100)
1905  call term_sendkeys('', ":set term=xxx\<CR>")
1906  call TermWait('', 100)
1907  call assert_match('builtin_dumb', term_getline('', 11))
1908  call assert_match('Not found in termcap', term_getline('', 12))
1909  call StopVimInTerminal('')
1910endfunc
1911
1912func GetEscCodeCSI27(key, modifier)
1913  let key = printf("%d", char2nr(a:key))
1914  let mod = printf("%d", a:modifier)
1915  return "\<Esc>[27;" .. mod .. ';' .. key .. '~'
1916endfunc
1917
1918func GetEscCodeCSIu(key, modifier)
1919  let key = printf("%d", char2nr(a:key))
1920  let mod = printf("%d", a:modifier)
1921  return "\<Esc>[" .. key .. ';' .. mod .. 'u'
1922endfunc
1923
1924" This checks the CSI sequences when in modifyOtherKeys mode.
1925" The mode doesn't need to be enabled, the codes are always detected.
1926func RunTest_modifyOtherKeys(func)
1927  new
1928  set timeoutlen=10
1929
1930  " Shift-X is sent as 'X' with the shift modifier
1931  call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!')
1932  call assert_equal('X', getline(1))
1933
1934  " Ctrl-i is Tab
1935  call setline(1, '')
1936  call feedkeys('a' .. a:func('i', 5) .. "\<Esc>", 'Lx!')
1937  call assert_equal("\t", getline(1))
1938
1939  " Ctrl-I is also Tab
1940  call setline(1, '')
1941  call feedkeys('a' .. a:func('I', 5) .. "\<Esc>", 'Lx!')
1942  call assert_equal("\t", getline(1))
1943
1944  " Alt-x is ø
1945  call setline(1, '')
1946  call feedkeys('a' .. a:func('x', 3) .. "\<Esc>", 'Lx!')
1947  call assert_equal("ø", getline(1))
1948
1949  " Meta-x is also ø
1950  call setline(1, '')
1951  call feedkeys('a' .. a:func('x', 9) .. "\<Esc>", 'Lx!')
1952  call assert_equal("ø", getline(1))
1953
1954  " Alt-X is Ø
1955  call setline(1, '')
1956  call feedkeys('a' .. a:func('X', 3) .. "\<Esc>", 'Lx!')
1957  call assert_equal("Ø", getline(1))
1958
1959  " Meta-X is ø
1960  call setline(1, '')
1961  call feedkeys('a' .. a:func('X', 9) .. "\<Esc>", 'Lx!')
1962  call assert_equal("Ø", getline(1))
1963
1964  " Ctrl-6 is Ctrl-^
1965  split aaa
1966  edit bbb
1967  call feedkeys(a:func('6', 5), 'Lx!')
1968  call assert_equal("aaa", bufname())
1969  bwipe aaa
1970  bwipe bbb
1971
1972  " Ctrl-V X 33 is 3
1973  call setline(1, '')
1974  call feedkeys("a\<C-V>" .. a:func('X', 2) .. "33\<Esc>", 'Lx!')
1975  call assert_equal("3", getline(1))
1976
1977  " Ctrl-V U 12345 is Unicode 12345
1978  call setline(1, '')
1979  call feedkeys("a\<C-V>" .. a:func('U', 2) .. "12345\<Esc>", 'Lx!')
1980  call assert_equal("\U12345", getline(1))
1981
1982  bwipe!
1983  set timeoutlen&
1984endfunc
1985
1986func Test_modifyOtherKeys_basic()
1987  call RunTest_modifyOtherKeys(function('GetEscCodeCSI27'))
1988  call RunTest_modifyOtherKeys(function('GetEscCodeCSIu'))
1989endfunc
1990
1991func Test_modifyOtherKeys_no_mapping()
1992  set timeoutlen=10
1993
1994  let @a = 'aaa'
1995  call feedkeys(":let x = '" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a'\<CR>", 'Lx!')
1996  call assert_equal("let x = 'aaa'", @:)
1997
1998  new
1999  call feedkeys("a" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a\<Esc>", 'Lx!')
2000  call assert_equal("aaa", getline(1))
2001  bwipe!
2002
2003  new
2004  call feedkeys("axx\<CR>yy" .. GetEscCodeCSI27('G', 5) .. GetEscCodeCSI27('K', 5) .. "a\<Esc>", 'Lx!')
2005  call assert_equal("axx", getline(1))
2006  call assert_equal("yy", getline(2))
2007  bwipe!
2008
2009  set timeoutlen&
2010endfunc
2011
2012func RunTest_mapping_shift(key, func)
2013  call setline(1, '')
2014  if a:key == '|'
2015    exe 'inoremap \| xyz'
2016  else
2017    exe 'inoremap ' .. a:key .. ' xyz'
2018  endif
2019  call feedkeys('a' .. a:func(a:key, 2) .. "\<Esc>", 'Lx!')
2020  call assert_equal("xyz", getline(1))
2021  if a:key == '|'
2022    exe 'iunmap \|'
2023  else
2024    exe 'iunmap ' .. a:key
2025  endif
2026endfunc
2027
2028func Test_modifyOtherKeys_mapped()
2029  set timeoutlen=10
2030  imap ' <C-W>
2031  imap <C-W><C-A> c-a
2032  call setline(1, '')
2033
2034  " single quote is turned into single byte CTRL-W
2035  " CTRL-A is added with a separate modifier, and needs to be simplified before
2036  " the mapping can match.
2037  call feedkeys("a'" .. GetEscCodeCSI27('A', 5) .. "\<Esc>", 'Lx!')
2038  call assert_equal('c-a', getline(1))
2039
2040  iunmap '
2041  iunmap <C-W><C-A>
2042  set timeoutlen&
2043endfunc
2044
2045" Whether Shift-Tab sends "ESC [ Z" or "ESC [ 27 ; 2 ; 9 ~" is unpredictable,
2046" both should work.
2047func Test_modifyOtherKeys_shift_tab()
2048  set timeoutlen=10
2049
2050  call setline(1, '')
2051  call feedkeys("a\<C-K>" .. GetEscCodeCSI27("\t", '2') .. "\<Esc>", 'Lx!')
2052  eval getline(1)->assert_equal('<S-Tab>')
2053
2054  call setline(1, '')
2055  call feedkeys("a\<C-K>\<Esc>[Z\<Esc>", 'Lx!')
2056  eval getline(1)->assert_equal('<S-Tab>')
2057
2058  set timeoutlen&
2059  bwipe!
2060endfunc
2061
2062func RunTest_mapping_works_with_shift(func)
2063  new
2064  set timeoutlen=10
2065
2066  call RunTest_mapping_shift('@', a:func)
2067  call RunTest_mapping_shift('A', a:func)
2068  call RunTest_mapping_shift('Z', a:func)
2069  call RunTest_mapping_shift('^', a:func)
2070  call RunTest_mapping_shift('_', a:func)
2071  call RunTest_mapping_shift('{', a:func)
2072  call RunTest_mapping_shift('|', a:func)
2073  call RunTest_mapping_shift('}', a:func)
2074  call RunTest_mapping_shift('~', a:func)
2075
2076  bwipe!
2077  set timeoutlen&
2078endfunc
2079
2080func Test_mapping_works_with_shift_plain()
2081  call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27'))
2082  call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu'))
2083endfunc
2084
2085func RunTest_mapping_mods(map, key, func, code)
2086  call setline(1, '')
2087  exe 'inoremap ' .. a:map .. ' xyz'
2088  call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!')
2089  call assert_equal("xyz", getline(1))
2090  exe 'iunmap ' .. a:map
2091endfunc
2092
2093func RunTest_mapping_works_with_mods(func, mods, code)
2094  new
2095  set timeoutlen=10
2096
2097  if a:mods !~ 'S'
2098    " Shift by itself has no effect
2099    call RunTest_mapping_mods('<' .. a:mods .. '-@>', '@', a:func, a:code)
2100  endif
2101  call RunTest_mapping_mods('<' .. a:mods .. '-A>', 'A', a:func, a:code)
2102  call RunTest_mapping_mods('<' .. a:mods .. '-Z>', 'Z', a:func, a:code)
2103  if a:mods !~ 'S'
2104    " with Shift code is always upper case
2105    call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'a', a:func, a:code)
2106    call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'z', a:func, a:code)
2107  endif
2108  if a:mods != 'A'
2109    " with Alt code is not in upper case
2110    call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'A', a:func, a:code)
2111    call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'Z', a:func, a:code)
2112  endif
2113  call RunTest_mapping_mods('<' .. a:mods .. '-á>', 'á', a:func, a:code)
2114  if a:mods !~ 'S'
2115    " Shift by itself has no effect
2116    call RunTest_mapping_mods('<' .. a:mods .. '-^>', '^', a:func, a:code)
2117    call RunTest_mapping_mods('<' .. a:mods .. '-_>', '_', a:func, a:code)
2118    call RunTest_mapping_mods('<' .. a:mods .. '-{>', '{', a:func, a:code)
2119    call RunTest_mapping_mods('<' .. a:mods .. '-\|>', '|', a:func, a:code)
2120    call RunTest_mapping_mods('<' .. a:mods .. '-}>', '}', a:func, a:code)
2121    call RunTest_mapping_mods('<' .. a:mods .. '-~>', '~', a:func, a:code)
2122  endif
2123
2124  bwipe!
2125  set timeoutlen&
2126endfunc
2127
2128func Test_mapping_works_with_shift()
2129  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S', 2)
2130  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S', 2)
2131endfunc
2132
2133func Test_mapping_works_with_ctrl()
2134  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C', 5)
2135  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C', 5)
2136
2137  new
2138  set timeoutlen=10
2139
2140  " CTRL-@ actually produces the code for CTRL-2, which is converted
2141  call RunTest_mapping_mods('<C-@>', '2', function('GetEscCodeCSI27'), 5)
2142  call RunTest_mapping_mods('<C-@>', '2', function('GetEscCodeCSIu'), 5)
2143
2144  " CTRL-^ actually produces the code for CTRL-6, which is converted
2145  call RunTest_mapping_mods('<C-^>', '6', function('GetEscCodeCSI27'), 5)
2146  call RunTest_mapping_mods('<C-^>', '6', function('GetEscCodeCSIu'), 5)
2147
2148  " CTRL-_ actually produces the code for CTRL--, which is converted
2149  call RunTest_mapping_mods('<C-_>', '-', function('GetEscCodeCSI27'), 5)
2150  call RunTest_mapping_mods('<C-_>', '-', function('GetEscCodeCSIu'), 5)
2151
2152  bwipe!
2153  set timeoutlen&
2154endfunc
2155
2156func Test_mapping_works_with_shift_ctrl()
2157  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S', 6)
2158  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S', 6)
2159
2160  new
2161  set timeoutlen=10
2162
2163  " Ctrl-Shift-[ actually produces CTRL-Shift-{ which is mapped as <C-{>
2164  call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSI27'), 6)
2165  call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSIu'), 6)
2166
2167  " Ctrl-Shift-] actually produces CTRL-Shift-} which is mapped as <C-}>
2168  call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSI27'), 6)
2169  call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSIu'), 6)
2170
2171  " Ctrl-Shift-\ actually produces CTRL-Shift-| which is mapped as <C-|>
2172  call RunTest_mapping_mods('<C-\|>', '|', function('GetEscCodeCSI27'), 6)
2173  call RunTest_mapping_mods('<C-\|>', '|', function('GetEscCodeCSIu'), 6)
2174
2175  bwipe!
2176  set timeoutlen&
2177endfunc
2178
2179" Below we also test the "u" code with Alt, This works, but libvterm would not
2180" send the Alt key like this but by prefixing an Esc.
2181
2182func Test_mapping_works_with_alt()
2183  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'A', 3)
2184  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'A', 3)
2185endfunc
2186
2187func Test_mapping_works_with_shift_alt()
2188  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S-A', 4)
2189  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S-A', 4)
2190endfunc
2191
2192func Test_mapping_works_with_alt_and_shift()
2193  new
2194  set timeoutlen=10
2195
2196  " mapping <A-?> works even though the code is A-S-?
2197  for c in ['!', '$', '+', ':', '?', '^', '~']
2198    call RunTest_mapping_mods('<A-' .. c .. '>', c, function('GetEscCodeCSI27'), 4)
2199    call RunTest_mapping_mods('<A-' .. c .. '>', c, function('GetEscCodeCSIu'), 4)
2200  endfor
2201
2202  bwipe!
2203  set timeoutlen&
2204endfunc
2205
2206func Test_mapping_works_with_ctrl_alt()
2207  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-A', 7)
2208  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-A', 7)
2209endfunc
2210
2211func Test_mapping_works_with_shift_ctrl_alt()
2212  call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 8)
2213  call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8)
2214endfunc
2215
2216func Test_insert_literal()
2217  set timeoutlen=10
2218  new
2219  " CTRL-V CTRL-X inserts a ^X
2220  call feedkeys('a' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
2221  call assert_equal("\<C-X>", getline(1))
2222
2223  call setline(1, '')
2224  call feedkeys('a' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
2225  call assert_equal("\<C-X>", getline(1))
2226
2227  " CTRL-SHIFT-V CTRL-X inserts escape sequence
2228  call setline(1, '')
2229  call feedkeys('a' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!')
2230  call assert_equal("\<Esc>[88;5u", getline(1))
2231
2232  call setline(1, '')
2233  call feedkeys('a' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!')
2234  call assert_equal("\<Esc>[27;5;88~", getline(1))
2235
2236  bwipe!
2237  set timeoutlen&
2238endfunc
2239
2240func Test_cmdline_literal()
2241  set timeoutlen=10
2242
2243  " CTRL-V CTRL-Y inserts a ^Y
2244  call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2245  call assert_equal("\"\<C-Y>", @:)
2246
2247  call feedkeys(':' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2248  call assert_equal("\"\<C-Y>", @:)
2249
2250  " CTRL-SHIFT-V CTRL-Y inserts escape sequence
2251  call feedkeys(':' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2252  call assert_equal("\"\<Esc>[89;5u", @:)
2253
2254  call setline(1, '')
2255  call feedkeys(':' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!')
2256  call assert_equal("\"\<Esc>[27;5;89~", @:)
2257
2258  set timeoutlen&
2259endfunc
2260
2261" Test for translation of special key codes (<xF1>, <xF2>, etc.)
2262func Test_Keycode_Tranlsation()
2263  let keycodes = [
2264        \ ["<xUp>", "<Up>"],
2265        \ ["<xDown>", "<Down>"],
2266        \ ["<xLeft>", "<Left>"],
2267        \ ["<xRight>", "<Right>"],
2268        \ ["<xHome>", "<Home>"],
2269        \ ["<xEnd>", "<End>"],
2270        \ ["<zHome>", "<Home>"],
2271        \ ["<zEnd>", "<End>"],
2272        \ ["<xF1>", "<F1>"],
2273        \ ["<xF2>", "<F2>"],
2274        \ ["<xF3>", "<F3>"],
2275        \ ["<xF4>", "<F4>"],
2276        \ ["<S-xF1>", "<S-F1>"],
2277        \ ["<S-xF2>", "<S-F2>"],
2278        \ ["<S-xF3>", "<S-F3>"],
2279        \ ["<S-xF4>", "<S-F4>"]]
2280  for [k1, k2] in keycodes
2281    exe "nnoremap " .. k1 .. " 2wx"
2282    call assert_true(maparg(k1, 'n', 0, 1).lhs == k2)
2283    exe "nunmap " .. k1
2284  endfor
2285endfunc
2286
2287" vim: shiftwidth=2 sts=2 expandtab
2288