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