1" Tests for decoding escape sequences sent by the terminal.
2
3" This only works for Unix in a terminal
4if has('gui_running') || !has('unix')
5  finish
6endif
7
8" Helper function to emit a terminal escape code.
9func TerminalEscapeCode(code_xterm, code_sgr, row, col, m)
10  if &ttymouse ==# 'xterm2'
11    " need to use byte encoding here.
12    let str = list2str([a:code_xterm, a:col + 0x20, a:row + 0x20])
13    if has('iconv')
14      let bytes = iconv(str, 'utf-8', 'latin1')
15    else
16      " Hopefully the numbers are not too big.
17      let bytes = str
18    endif
19    call feedkeys("\<Esc>[M" .. bytes, 'Lx!')
20  elseif &ttymouse ==# 'sgr'
21    call feedkeys(printf("\<Esc>[<%d;%d;%d%s", a:code_sgr, a:col, a:row, a:m), 'Lx!')
22  endif
23endfunc
24
25func MouseLeftClick(row, col)
26  call TerminalEscapeCode(0x20, 0, a:row, a:col, 'M')
27endfunc
28
29func MouseLeftRelease(row, col)
30  call TerminalEscapeCode(0x23, 3, a:row, a:col, 'm')
31endfunc
32
33func MouseLeftDrag(row, col)
34  call TerminalEscapeCode(0x43, 0x20, a:row, a:col, 'M')
35endfunc
36
37func MouseWheelUp(row, col)
38  call TerminalEscapeCode(0x40, 0x40, a:row, a:col, 'M')
39endfunc
40
41func MouseWheelDown(row, col)
42  call TerminalEscapeCode(0x41, 0x41, a:row, a:col, 'M')
43endfunc
44
45func Test_xterm_mouse_click()
46  new
47  let save_mouse = &mouse
48  let save_term = &term
49  let save_ttymouse = &ttymouse
50  set mouse=a term=xterm
51  call setline(1, ['line 1', 'line 2', 'line 3 is a bit longer'])
52
53  for ttymouse_val in ['xterm2', 'sgr']
54    let msg = 'ttymouse=' .. ttymouse_val
55    exe 'set ttymouse=' . ttymouse_val
56    go
57    call assert_equal([0, 1, 1, 0], getpos('.'), msg)
58    let row = 2
59    let col = 6
60    call MouseLeftClick(row, col)
61    call MouseLeftRelease(row, col)
62    call assert_equal([0, 2, 6, 0], getpos('.'), msg)
63  endfor
64
65  let &mouse = save_mouse
66  let &term = save_term
67  let &ttymouse = save_ttymouse
68  bwipe!
69endfunc
70
71func Test_xterm_mouse_wheel()
72  new
73  let save_mouse = &mouse
74  let save_term = &term
75  let save_ttymouse = &ttymouse
76  set mouse=a term=xterm
77  call setline(1, range(1, 100))
78
79  for ttymouse_val in ['xterm2', 'sgr']
80    let msg = 'ttymouse=' .. ttymouse_val
81    exe 'set ttymouse=' . ttymouse_val
82    go
83    call assert_equal(1, line('w0'), msg)
84    call assert_equal([0, 1, 1, 0], getpos('.'), msg)
85
86    call MouseWheelDown(1, 1)
87    call assert_equal(4, line('w0'), msg)
88    call assert_equal([0, 4, 1, 0], getpos('.'), msg)
89
90    call MouseWheelDown(1, 1)
91    call assert_equal(7, line('w0'), msg)
92    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
93
94    call MouseWheelUp(1, 1)
95    call assert_equal(4, line('w0'), msg)
96    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
97
98    call MouseWheelUp(1, 1)
99    call assert_equal(1, line('w0'), msg)
100    call assert_equal([0, 7, 1, 0], getpos('.'), msg)
101  endfor
102
103  let &mouse = save_mouse
104  let &term = save_term
105  let &ttymouse = save_ttymouse
106  bwipe!
107endfunc
108
109func Test_xterm_mouse_drag_window_separator()
110  let save_mouse = &mouse
111  let save_term = &term
112  let save_ttymouse = &ttymouse
113  set mouse=a term=xterm
114
115  for ttymouse_val in ['xterm2', 'sgr']
116    let msg = 'ttymouse=' .. ttymouse_val
117    exe 'set ttymouse=' . ttymouse_val
118
119    " Split horizontally and test dragging the horizontal window separator.
120    split
121    let rowseparator = winheight(0) + 1
122    let row = rowseparator
123    let col = 1
124
125    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
126    if ttymouse_val !=# 'xterm2' || row <= 223
127      call MouseLeftClick(row, col)
128      let row -= 1
129      call MouseLeftDrag(row, col)
130      call assert_equal(rowseparator - 1, winheight(0) + 1, msg)
131      let row += 1
132      call MouseLeftDrag(row, col)
133      call assert_equal(rowseparator, winheight(0) + 1, msg)
134      call MouseLeftRelease(row, col)
135      call assert_equal(rowseparator, winheight(0) + 1, msg)
136    endif
137    bwipe!
138
139    " Split vertically and test dragging the vertical window separator.
140    vsplit
141    let colseparator = winwidth(0) + 1
142    let row = 1
143    let col = colseparator
144
145    " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
146    if ttymouse_val !=# 'xterm2' || col <= 223
147      call MouseLeftClick(row, col)
148      let col -= 1
149      call MouseLeftDrag(row, col)
150      call assert_equal(colseparator - 1, winwidth(0) + 1, msg)
151      let col += 1
152      call MouseLeftDrag(row, col)
153      call assert_equal(colseparator, winwidth(0) + 1, msg)
154      call MouseLeftRelease(row, col)
155      call assert_equal(colseparator, winwidth(0) + 1, msg)
156    endif
157    bwipe!
158  endfor
159
160  let &mouse = save_mouse
161  let &term = save_term
162  let &ttymouse = save_ttymouse
163endfunc
164
165func Test_xterm_mouse_drag_statusline()
166  let save_mouse = &mouse
167  let save_term = &term
168  let save_ttymouse = &ttymouse
169  let save_laststatus = &laststatus
170  set mouse=a term=xterm laststatus=2
171
172  for ttymouse_val in ['xterm2', 'sgr']
173    let msg = 'ttymouse=' .. ttymouse_val
174    exe 'set ttymouse=' . ttymouse_val
175
176    call assert_equal(1, &cmdheight, msg)
177    let rowstatusline = winheight(0) + 1
178    let row = rowstatusline
179    let col = 1
180
181    if ttymouse_val ==# 'xterm2' && row > 223
182      " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
183      continue
184    endif
185
186    call MouseLeftClick(row, col)
187    let row -= 1
188    call MouseLeftDrag(row, col)
189    call assert_equal(2, &cmdheight, msg)
190    call assert_equal(rowstatusline - 1, winheight(0) + 1, msg)
191    let row += 1
192    call MouseLeftDrag(row, col)
193    call assert_equal(1, &cmdheight, msg)
194    call assert_equal(rowstatusline, winheight(0) + 1, msg)
195    call MouseLeftRelease(row, col)
196    call assert_equal(1, &cmdheight, msg)
197    call assert_equal(rowstatusline, winheight(0) + 1, msg)
198  endfor
199
200  let &mouse = save_mouse
201  let &term = save_term
202  let &ttymouse = save_ttymouse
203  let &laststatus = save_laststatus
204endfunc
205
206func Test_xterm_mouse_click_tab()
207  let save_mouse = &mouse
208  let save_term = &term
209  let save_ttymouse = &ttymouse
210  set mouse=a term=xterm
211  let row = 1
212
213  for ttymouse_val in ['xterm2', 'sgr']
214    let msg = 'ttymouse=' .. ttymouse_val
215    exe 'set ttymouse=' . ttymouse_val
216    e Xfoo
217    tabnew Xbar
218
219    let a = split(execute(':tabs'), "\n")
220    call assert_equal(['Tab page 1',
221        \              '    Xfoo',
222        \              'Tab page 2',
223        \              '>   Xbar'], a, msg)
224
225    " Test clicking on tab names in the tabline at the top.
226    let col = 2
227    redraw
228    call MouseLeftClick(row, col)
229    call MouseLeftRelease(row, col)
230    let a = split(execute(':tabs'), "\n")
231    call assert_equal(['Tab page 1',
232        \              '>   Xfoo',
233        \              'Tab page 2',
234        \              '    Xbar'], a, msg)
235
236    let col = 9
237    call MouseLeftClick(row, col)
238    call MouseLeftRelease(row, col)
239    let a = split(execute(':tabs'), "\n")
240    call assert_equal(['Tab page 1',
241        \              '    Xfoo',
242        \              'Tab page 2',
243        \              '>   Xbar'], a, msg)
244
245    %bwipe!
246  endfor
247
248  let &mouse = save_mouse
249  let &term = save_term
250  let &ttymouse = save_ttymouse
251endfunc
252
253func Test_xterm_mouse_click_X_to_close_tab()
254  let save_mouse = &mouse
255  let save_term = &term
256  let save_ttymouse = &ttymouse
257  set mouse=a term=xterm
258  let row = 1
259  let col = &columns
260
261  for ttymouse_val in ['xterm2', 'sgr']
262    if ttymouse_val ==# 'xterm2' && col > 223
263      " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
264      continue
265    endif
266    let msg = 'ttymouse=' .. ttymouse_val
267    exe 'set ttymouse=' . ttymouse_val
268    e Xtab1
269    tabnew Xtab2
270    tabnew Xtab3
271    tabn 2
272
273    let a = split(execute(':tabs'), "\n")
274    call assert_equal(['Tab page 1',
275        \              '    Xtab1',
276        \              'Tab page 2',
277        \              '>   Xtab2',
278        \              'Tab page 3',
279        \              '    Xtab3'], a, msg)
280
281    " Click on "X" in tabline to close current tab i.e. Xtab2.
282    redraw
283    call MouseLeftClick(row, col)
284    call MouseLeftRelease(row, col)
285    let a = split(execute(':tabs'), "\n")
286    call assert_equal(['Tab page 1',
287        \              '    Xtab1',
288        \              'Tab page 2',
289        \              '>   Xtab3'], a, msg)
290
291    %bwipe!
292  endfor
293
294  let &mouse = save_mouse
295  let &term = save_term
296  let &ttymouse = save_ttymouse
297endfunc
298
299func Test_xterm_mouse_drag_to_move_tab()
300  let save_mouse = &mouse
301  let save_term = &term
302  let save_ttymouse = &ttymouse
303  " Set 'mousetime' to 1 to avoid recognizing a double-click in the loop
304  set mouse=a term=xterm mousetime=1
305  let row = 1
306
307  for ttymouse_val in ['xterm2', 'sgr']
308    let msg = 'ttymouse=' .. ttymouse_val
309    exe 'set ttymouse=' . ttymouse_val
310    e Xtab1
311    tabnew Xtab2
312
313    let a = split(execute(':tabs'), "\n")
314    call assert_equal(['Tab page 1',
315        \              '    Xtab1',
316        \              'Tab page 2',
317        \              '>   Xtab2'], a, msg)
318    redraw
319
320    " Click in tab2 and drag it to tab1.
321    " Check getcharmod() to verify that click is not
322    " interpreted as a spurious double-click.
323    call MouseLeftClick(row, 10)
324    call assert_equal(0, getcharmod(), msg)
325    for col in [9, 8, 7, 6]
326      call MouseLeftDrag(row, col)
327    endfor
328    call MouseLeftRelease(row, col)
329    let a = split(execute(':tabs'), "\n")
330    call assert_equal(['Tab page 1',
331        \              '>   Xtab2',
332        \              'Tab page 2',
333        \              '    Xtab1'], a, msg)
334
335    " brief sleep to avoid causing a double-click
336    sleep 20m
337    %bwipe!
338  endfor
339
340  let &mouse = save_mouse
341  let &term = save_term
342  let &ttymouse = save_ttymouse
343  set mousetime&
344endfunc
345
346func Test_xterm_mouse_double_click_to_create_tab()
347  let save_mouse = &mouse
348  let save_term = &term
349  let save_ttymouse = &ttymouse
350  " Set 'mousetime' to a small value, so that double-click works but we don't
351  " have to wait long to avoid a triple-click.
352  set mouse=a term=xterm mousetime=100
353  let row = 1
354  let col = 10
355
356  for ttymouse_val in ['xterm2', 'sgr']
357    let msg = 'ttymouse=' .. ttymouse_val
358    exe 'set ttymouse=' . ttymouse_val
359    e Xtab1
360    tabnew Xtab2
361
362    let a = split(execute(':tabs'), "\n")
363    call assert_equal(['Tab page 1',
364        \              '    Xtab1',
365        \              'Tab page 2',
366        \              '>   Xtab2'], a, msg)
367
368    redraw
369    call MouseLeftClick(row, col)
370    " Check getcharmod() to verify that first click is not
371    " interpreted as a spurious double-click.
372    call assert_equal(0, getcharmod(), msg)
373    call MouseLeftRelease(row, col)
374    call MouseLeftClick(row, col)
375    call assert_equal(32, getcharmod(), msg) " double-click
376    call MouseLeftRelease(row, col)
377    let a = split(execute(':tabs'), "\n")
378    call assert_equal(['Tab page 1',
379        \              '    Xtab1',
380        \              'Tab page 2',
381        \              '>   [No Name]',
382        \              'Tab page 3',
383        \              '    Xtab2'], a, msg)
384
385    if ttymouse_val !=# 'sgr'
386      " We need to sleep, or else MouseLeftClick() in next loop
387      " iteration will be interpreted as a spurious triple-click.
388      sleep 100m
389    endif
390    %bwipe!
391  endfor
392
393  let &mouse = save_mouse
394  let &term = save_term
395  let &ttymouse = save_ttymouse
396  set mousetime&
397endfunc
398
399func Test_xterm_mouse_click_in_fold_columns()
400  new
401  let save_mouse = &mouse
402  let save_term = &term
403  let save_ttymouse = &ttymouse
404  let save_foldcolumn = &foldcolumn
405  set mouse=a term=xterm foldcolumn=3 ttymouse=xterm2
406
407  " Create 2 nested folds.
408  call setline(1, range(1, 7))
409  2,6fold
410  norm! zR
411  4,5fold
412  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
413        \           map(range(1, 7), 'foldclosed(v:val)'))
414
415  " Click in "+" of inner fold in foldcolumn should open it.
416  redraw
417  let row = 4
418  let col = 2
419  call MouseLeftClick(row, col)
420  call MouseLeftRelease(row, col)
421  call assert_equal([-1, -1, -1, -1, -1, -1, -1],
422        \           map(range(1, 7), 'foldclosed(v:val)'))
423
424  " Click in "-" of outer fold in foldcolumn should close it.
425  redraw
426  let row = 2
427  let col = 1
428  call MouseLeftClick(row, col)
429  call MouseLeftRelease(row, col)
430  call assert_equal([-1, 2, 2, 2, 2, 2, -1],
431        \           map(range(1, 7), 'foldclosed(v:val)'))
432  norm! zR
433
434  " Click in "|" of inner fold in foldcolumn should close it.
435  redraw
436  let row = 5
437  let col = 2
438  call MouseLeftClick(row, col)
439  call MouseLeftRelease(row, col)
440  call assert_equal([-1, -1, -1, 4, 4, -1, -1],
441        \           map(range(1, 7), 'foldclosed(v:val)'))
442
443  let &foldcolumn = save_foldcolumn
444  let &ttymouse = save_ttymouse
445  let &term = save_term
446  let &mouse = save_mouse
447  bwipe!
448endfunc
449