Mercurial > vim
view src/testdir/test_termcodes.vim @ 34686:83875247fbc0 v9.1.0224
patch 9.1.0224: cursor may move too many lines over "right" & "below" virt text
Commit: https://github.com/vim/vim/commit/515f734e687f28f7199b2a8042197624d9f3ec15
Author: Dylan Thacker-Smith <dylan.ah.smith@gmail.com>
Date: Thu Mar 28 12:01:14 2024 +0100
patch 9.1.0224: cursor may move too many lines over "right" & "below" virt text
Problem: If a line has "right" & "below" virtual text properties,
where the "below" property may be stored first due to lack of
ordering between them, then the line height is calculated to
be 1 more and causes the cursor to far over the line.
Solution: Remove some unnecessary setting of a
`next_right_goes_below = TRUE` flag for "below" and "above"
text properties. (Dylan Thacker-Smith)
I modified a regression test I recently added to cover this case,
leveraging the fact that "after", "right" & "below" text properties are
being stored in the reverse of the order they are added in. The
previous version of this regression test was crafted to workaround this
issue so it can be addressed by this separate patch.
closes: #14317
Signed-off-by: Dylan Thacker-Smith <dylan.ah.smith@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 28 Mar 2024 12:15:03 +0100 |
parents | 695b50472e85 |
children | a20bd67056d7 |
line wrap: on
line source
" Tests for decoding escape sequences sent by the terminal. " This only works for Unix in a terminal source check.vim CheckNotGui CheckUnix source shared.vim source mouse.vim source view_util.vim source term_util.vim func Test_term_mouse_left_click() new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() call setline(1, ['line 1', 'line 2', 'line 3 is a bit longer']) for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val go call assert_equal([0, 1, 1, 0], getpos('.'), msg) let row = 2 let col = 6 call MouseLeftClick(row, col) call MouseLeftRelease(row, col) call assert_equal([0, 2, 6, 0], getpos('.'), msg) endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) bwipe! endfunc func Test_xterm_mouse_right_click_extends_visual() if has('mac') throw "Skipped: test right click in visual mode does not work on macOs (why?)" endif let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() for visual_mode in ["v", "V", "\<C-V>"] for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'visual=' .. visual_mode .. ' ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call setline(1, repeat([repeat('-', 7)], 7)) call MouseLeftClick(4, 4) call MouseLeftRelease(4, 4) exe "norm! " .. visual_mode " Right click extends top left of visual area. call MouseRightClick(2, 2) call MouseRightRelease(2, 2) " Right click extends bottom right of visual area. call MouseRightClick(6, 6) call MouseRightRelease(6, 6) norm! r1gv " Right click shrinks top left of visual area. call MouseRightClick(3, 3) call MouseRightRelease(3, 3) " Right click shrinks bottom right of visual area. call MouseRightClick(5, 5) call MouseRightRelease(5, 5) norm! r2 if visual_mode ==# 'v' call assert_equal(['-------', \ '-111111', \ '1122222', \ '2222222', \ '2222211', \ '111111-', \ '-------'], getline(1, '$'), msg) elseif visual_mode ==# 'V' call assert_equal(['-------', \ '1111111', \ '2222222', \ '2222222', \ '2222222', \ '1111111', \ '-------'], getline(1, '$'), msg) else call assert_equal(['-------', \ '-11111-', \ '-12221-', \ '-12221-', \ '-12221-', \ '-11111-', \ '-------'], getline(1, '$'), msg) endif endfor endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) bwipe! endfunc " Test that <C-LeftMouse> jumps to help tag and <C-RightMouse> jumps back. " Also test for g<LeftMouse> and g<RightMouse>. func Test_xterm_mouse_tagjump() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse set mouse=a term=xterm call WaitForResponses() for ttymouse_val in g:Ttymouse_values let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val help /usr_02.txt norm! zt " CTRL-left click to jump to a tag let row = 1 let col = 1 call MouseCtrlLeftClick(row, col) call MouseLeftRelease(row, col) call assert_match('usr_02.txt$', bufname('%'), msg) call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg) " CTRL-right click to pop a tag call MouseCtrlRightClick(row, col) call MouseRightRelease(row, col) call assert_match('help.txt$', bufname('%'), msg) call assert_equal('|usr_02.txt|', expand('<cWORD>'), msg) " Jump to a tag exe "normal \<C-]>" call assert_match('usr_02.txt$', bufname('%'), msg) call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg) " Use CTRL-right click in insert mode to pop the tag new let str = 'iHello' .. MouseCtrlRightClickCode(row, col) \ .. MouseRightReleaseCode(row, col) .. "\<C-C>" call assert_fails('call feedkeys(str, "Lx!")', 'E37:', msg) close! " CTRL-right click with a count let str = "4" .. MouseCtrlRightClickCode(row, col) \ .. MouseRightReleaseCode(row, col) call assert_fails('call feedkeys(str, "Lx!")', 'E555:', msg) call assert_match('help.txt$', bufname('%'), msg) call assert_equal(1, line('.'), msg) " g<LeftMouse> to jump to a tag /usr_02.txt norm! zt call test_setmouse(row, col) exe "normal g\<LeftMouse>" call assert_match('usr_02.txt$', bufname('%'), msg) call assert_equal('*usr_02.txt*', expand('<cWORD>'), msg) " g<RightMouse> to pop to a tag call test_setmouse(row, col) exe "normal g\<RightMouse>" call assert_match('help.txt$', bufname('%'), msg) call assert_equal('|usr_02.txt|', expand('<cWORD>'), msg) %bw! endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse endfunc func Test_term_mouse_middle_click() CheckFeature clipboard_working new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) let save_quotestar = @* let save_quoteplus = @+ set mouse=a term=xterm call WaitForResponses() for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call setline(1, ['123456789', '123456789']) let @* = 'abc' " Middle-click in the middle of the line pastes text where clicked. let row = 1 let col = 6 call MouseMiddleClick(row, col) call MouseMiddleRelease(row, col) call assert_equal(['12345abc6789', '123456789'], getline(1, '$'), msg) " Middle-click beyond end of the line pastes text at the end of the line. let col = 20 call MouseMiddleClick(row, col) call MouseMiddleRelease(row, col) call assert_equal(['12345abc6789abc', '123456789'], getline(1, '$'), msg) " Middle-click beyond the last line pastes in the last line. let row = 5 let col = 3 call MouseMiddleClick(row, col) call MouseMiddleRelease(row, col) call assert_equal(['12345abc6789abc', '12abc3456789'], getline(1, '$'), msg) " Middle mouse click in operator pending mode beeps call assert_beeps('exe "normal c\<MiddleMouse>"') " Clicking middle mouse in visual mode, yanks the selection and pastes the " clipboard contents let save_clipboard = &clipboard set clipboard= let @" = '' call cursor(1, 1) call feedkeys("v3l" .. \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7), 'Lx!') call assert_equal(['12345abc6789abc', '12abc3abc456789'], \ getline(1, '$'), msg) call assert_equal('1234', @", msg) let &clipboard = save_clipboard " Clicking middle mouse in select mode, replaces the selected text with " the clipboard contents let @+ = 'xyz' call cursor(1, 3) exe "normal gh\<Right>\<Right>\<MiddleMouse>" call assert_equal(['12xyzabc6789abc', '12abc3abc456789'], \ getline(1, '$'), msg) " Prefixing middle click with [ or ] fixes the indent after pasting. %d call setline(1, " one two") call setreg('r', 'red blue', 'l') call test_setmouse(1, 5) exe "normal \"r[\<MiddleMouse>" call assert_equal(' red blue', getline(1), msg) call test_setmouse(2, 5) exe "normal \"r]\<MiddleMouse>" call assert_equal(' red blue', getline(3), msg) %d endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) let @* = save_quotestar let @+ = save_quoteplus bwipe! endfunc " If clipboard is not working, then clicking the middle mouse button in visual " mode, will copy and paste the selected text. func Test_term_mouse_middle_click_no_clipboard() if has('clipboard_working') throw 'Skipped: clipboard support works' endif new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call setline(1, ['123456789', '123456789']) " Clicking middle mouse in visual mode, yanks the selection and pastes it call cursor(1, 1) call feedkeys("v3l" .. \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7), 'Lx!') call assert_equal(['123456789', '1234561234789'], \ getline(1, '$'), msg) endfor call test_override('no_query_mouse', 0) let &ttymouse = save_ttymouse let &term = save_term let &mouse = save_mouse close! endfunc func Test_term_mouse_middle_click_insert_mode() CheckFeature clipboard_working new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call setline(1, ['123456789', '123456789']) let @* = 'abc' " Middle-click in insert mode doesn't move the cursor but inserts the " contents of a register call cursor(1, 4) call feedkeys('i' .. \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7) .. \ "\<C-C>", 'Lx!') call assert_equal(['123abc456789', '123456789'], \ getline(1, '$'), msg) call assert_equal([1, 6], [line('.'), col('.')], msg) " Middle-click in replace mode call cursor(1, 1) call feedkeys('$R' .. \ MouseMiddleClickCode(2, 7) .. MouseMiddleReleaseCode(2, 7) .. \ "\<C-C>", 'Lx!') call assert_equal(['123abc45678abc', '123456789'], \ getline(1, '$'), msg) call assert_equal([1, 14], [line('.'), col('.')], msg) endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) close! endfunc " Test for switching window using mouse in insert mode func Test_term_mouse_switch_win_insert_mode() 5new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm ttymouse=xterm2 call WaitForResponses() call feedkeys('ivim' .. \ MouseLeftClickCode(8, 6) .. MouseLeftReleaseCode(8, 6) .. \ "\<C-C>", 'Lx!') call assert_equal(2, winnr()) wincmd w call assert_equal('n', mode()) call assert_equal(['vim'], getline(1, '$')) let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) close! endfunc " Test for using the mouse to increase the height of the cmdline window func Test_mouse_cmdwin_resize() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm ttymouse=xterm2 call WaitForResponses() 5new redraw! let h = 0 let row = &lines - &cmdwinheight - 2 call feedkeys("q:" .. \ MouseLeftClickCode(row, 1) .. \ MouseLeftDragCode(row - 1, 1) .. \ MouseLeftReleaseCode(row - 2, 1) .. \ "alet h = \<C-R>=winheight(0)\<CR>\<CR>", 'Lx!') call assert_equal(&cmdwinheight + 2, h) let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) close! endfunc " TODO: for unclear reasons this test fails if it comes after " Test_xterm_mouse_ctrl_click() func Test_1xterm_mouse_wheel() new let save_mouse = &mouse let save_term = &term let save_wrap = &wrap let save_ttymouse = &ttymouse set mouse=a term=xterm nowrap call WaitForResponses() call setline(1, range(100000000000000, 100000000000100)) for ttymouse_val in g:Ttymouse_values let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val go call assert_equal(1, line('w0'), msg) call assert_equal([0, 1, 1, 0], getpos('.'), msg) call MouseWheelDown(1, 1) call assert_equal(4, line('w0'), msg) call assert_equal([0, 4, 1, 0], getpos('.'), msg) call MouseWheelDown(1, 1) call assert_equal(7, line('w0'), msg) call assert_equal([0, 7, 1, 0], getpos('.'), msg) call MouseWheelUp(1, 1) call assert_equal(4, line('w0'), msg) call assert_equal([0, 7, 1, 0], getpos('.'), msg) call MouseWheelUp(1, 1) call assert_equal(1, line('w0'), msg) call assert_equal([0, 7, 1, 0], getpos('.'), msg) call MouseWheelRight(1, 1) call assert_equal(7, 1 + virtcol(".") - wincol(), msg) call assert_equal([0, 7, 7, 0], getpos('.'), msg) call MouseWheelRight(1, 1) call assert_equal(13, 1 + virtcol(".") - wincol(), msg) call assert_equal([0, 7, 13, 0], getpos('.'), msg) call MouseWheelLeft(1, 1) call assert_equal(7, 1 + virtcol(".") - wincol(), msg) call assert_equal([0, 7, 13, 0], getpos('.'), msg) call MouseWheelLeft(1, 1) call assert_equal(1, 1 + virtcol(".") - wincol(), msg) call assert_equal([0, 7, 13, 0], getpos('.'), msg) endfor let &mouse = save_mouse let &term = save_term let &wrap = save_wrap let &ttymouse = save_ttymouse bwipe! endfunc " Test that dragging beyond the window (at the bottom and at the top) " scrolls window content by the number of lines beyond the window. func Test_term_mouse_drag_beyond_window() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() let col = 1 call setline(1, range(1, 100)) " Split into 3 windows, and go into the middle window " so we test dragging mouse below and above the window. 2split wincmd j 2split for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val " Line #10 at the top. norm! 10zt redraw call assert_equal(10, winsaveview().topline, msg) call assert_equal(2, winheight(0), msg) let row = 4 call MouseLeftClick(row, col) call assert_equal(10, winsaveview().topline, msg) " Drag downwards. We're still in the window so topline should " not change yet. let row += 1 call MouseLeftDrag(row, col) call assert_equal(10, winsaveview().topline, msg) " We now leave the window at the bottom, so the window content should " scroll by 1 line, then 2 lines (etc) as we drag further away. let row += 1 call MouseLeftDrag(row, col) call assert_equal(11, winsaveview().topline, msg) let row += 1 call MouseLeftDrag(row, col) call assert_equal(13, winsaveview().topline, msg) " Now drag upwards. let row -= 1 call MouseLeftDrag(row, col) call assert_equal(14, winsaveview().topline, msg) " We're now back in the window so the topline should not change. let row -= 1 call MouseLeftDrag(row, col) call assert_equal(14, winsaveview().topline, msg) let row -= 1 call MouseLeftDrag(row, col) call assert_equal(14, winsaveview().topline, msg) " We now leave the window at the top so the window content should " scroll by 1 line, then 2, then 3 (etc) in the opposite direction. let row -= 1 call MouseLeftDrag(row, col) call assert_equal(13, winsaveview().topline, msg) let row -= 1 call MouseLeftDrag(row, col) call assert_equal(11, winsaveview().topline, msg) let row -= 1 call MouseLeftDrag(row, col) call assert_equal(8, winsaveview().topline, msg) call MouseLeftRelease(row, col) call assert_equal(8, winsaveview().topline, msg) call assert_equal(2, winheight(0), msg) endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) bwipe! endfunc func Test_term_mouse_drag_window_separator() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val " Split horizontally and test dragging the horizontal window separator. split let rowseparator = winheight(0) + 1 let row = rowseparator let col = 1 " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported. if ttymouse_val !=# 'xterm2' || row <= 223 call MouseLeftClick(row, col) let row -= 1 call MouseLeftDrag(row, col) call assert_equal(rowseparator - 1, winheight(0) + 1, msg) let row += 1 call MouseLeftDrag(row, col) call assert_equal(rowseparator, winheight(0) + 1, msg) call MouseLeftRelease(row, col) call assert_equal(rowseparator, winheight(0) + 1, msg) endif bwipe! " Split vertically and test dragging the vertical window separator. vsplit let colseparator = winwidth(0) + 1 let row = 1 let col = colseparator " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported. if ttymouse_val !=# 'xterm2' || col <= 223 call MouseLeftClick(row, col) let col -= 1 call MouseLeftDrag(row, col) call assert_equal(colseparator - 1, winwidth(0) + 1, msg) let col += 1 call MouseLeftDrag(row, col) call assert_equal(colseparator, winwidth(0) + 1, msg) call MouseLeftRelease(row, col) call assert_equal(colseparator, winwidth(0) + 1, msg) endif bwipe! endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) endfunc func Test_term_mouse_drag_statusline() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) let save_laststatus = &laststatus set mouse=a term=xterm laststatus=2 call WaitForResponses() for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call assert_equal(1, &cmdheight, msg) let rowstatusline = winheight(0) + 1 let row = rowstatusline let col = 1 if ttymouse_val ==# 'xterm2' && row > 223 " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported. continue endif call MouseLeftClick(row, col) let row -= 1 call MouseLeftDrag(row, col) call assert_equal(2, &cmdheight, msg) call assert_equal(rowstatusline - 1, winheight(0) + 1, msg) let row += 1 call MouseLeftDrag(row, col) call assert_equal(1, &cmdheight, msg) call assert_equal(rowstatusline, winheight(0) + 1, msg) call MouseLeftRelease(row, col) call assert_equal(1, &cmdheight, msg) call assert_equal(rowstatusline, winheight(0) + 1, msg) endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) let &laststatus = save_laststatus endfunc func Test_term_mouse_click_tab() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() let row = 1 for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val e Xfoo tabnew Xbar let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xfoo', \ 'Tab page 2', \ '> Xbar'], a, msg) " Test clicking on tab names in the tabline at the top. let col = 2 redraw call MouseLeftClick(row, col) call MouseLeftRelease(row, col) let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ '> Xfoo', \ 'Tab page 2', \ ' Xbar'], a, msg) let col = 9 call MouseLeftClick(row, col) call MouseLeftRelease(row, col) let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xfoo', \ 'Tab page 2', \ '> Xbar'], a, msg) %bwipe! endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) endfunc func Test_term_mouse_click_X_to_close_tab() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() let row = 1 let col = &columns for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm if ttymouse_val ==# 'xterm2' && col > 223 " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported. continue endif let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val e Xtab1 tabnew Xtab2 tabnew Xtab3 tabn 2 let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xtab1', \ 'Tab page 2', \ '> Xtab2', \ 'Tab page 3', \ ' Xtab3'], a, msg) " Click on "X" in tabline to close current tab i.e. Xtab2. redraw call MouseLeftClick(row, col) call MouseLeftRelease(row, col) let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xtab1', \ 'Tab page 2', \ '> Xtab3'], a, msg) %bwipe! endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) endfunc func Test_term_mouse_drag_to_move_tab() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) " Set 'mousetime' to 1 to avoid recognizing a double-click in the loop set mouse=a term=xterm mousetime=1 call WaitForResponses() let row = 1 for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val e Xtab1 tabnew Xtab2 let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xtab1', \ 'Tab page 2', \ '> Xtab2'], a, msg) redraw " Click in tab2 and drag it to tab1. " Check getcharmod() to verify that click is not " interpreted as a spurious double-click. call MouseLeftClick(row, 10) call assert_equal(0, getcharmod(), msg) for col in [9, 8, 7, 6] call MouseLeftDrag(row, col) endfor call MouseLeftRelease(row, col) let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ '> Xtab2', \ 'Tab page 2', \ ' Xtab1'], a, msg) " Switch to tab1 tabnext let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xtab2', \ 'Tab page 2', \ '> Xtab1'], a, msg) " Click in tab2 and drag it to tab1. " This time it is non-current tab. call MouseLeftClick(row, 6) call assert_equal(0, getcharmod(), msg) for col in [7, 8, 9, 10] call MouseLeftDrag(row, col) endfor call MouseLeftRelease(row, col) let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xtab1', \ 'Tab page 2', \ '> Xtab2'], a, msg) " Click elsewhere so that click in next iteration is not " interpreted as unwanted double-click. call MouseLeftClick(row, 11) call MouseLeftRelease(row, 11) %bwipe! endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) set mousetime& endfunc func Test_term_mouse_double_click_to_create_tab() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) " Set 'mousetime' to a small value, so that double-click works but we don't " have to wait long to avoid a triple-click. set mouse=a term=xterm mousetime=200 call WaitForResponses() let row = 1 let col = 10 for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val e Xtab1 tabnew Xtab2 let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xtab1', \ 'Tab page 2', \ '> Xtab2'], a, msg) redraw call MouseLeftClick(row, col) " Check getcharmod() to verify that first click is not " interpreted as a spurious double-click. call assert_equal(0, getcharmod(), msg) call MouseLeftRelease(row, col) call MouseLeftClick(row, col) call assert_equal(32, getcharmod(), msg) " double-click call MouseLeftRelease(row, col) let a = split(execute(':tabs'), "\n") call assert_equal(['Tab page 1', \ ' Xtab1', \ 'Tab page 2', \ '> [No Name]', \ 'Tab page 3', \ ' Xtab2'], a, msg) " Click elsewhere so that click in next iteration is not " interpreted as unwanted double click. call MouseLeftClick(row, col + 1) call MouseLeftRelease(row, col + 1) %bwipe! endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) set mousetime& endfunc " Test double/triple/quadruple click in normal mode to visually select. func Test_term_mouse_multiple_clicks_to_visually_select() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) " 'mousetime' must be sufficiently large, or else the test is flaky when " using a ssh connection with X forwarding; i.e. ssh -X (issue #7563). set mouse=a term=xterm mousetime=600 call WaitForResponses() new for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call setline(1, ['foo [foo bar] foo', 'foo']) " Double-click on word should visually select the word. call MouseLeftClick(1, 2) call assert_equal(0, getcharmod(), msg) call MouseLeftRelease(1, 2) call MouseLeftClick(1, 2) call assert_equal(32, getcharmod(), msg) " double-click call MouseLeftRelease(1, 2) call assert_equal('v', mode(), msg) norm! r1 call assert_equal(['111 [foo bar] foo', 'foo'], getline(1, '$'), msg) " Double-click on opening square bracket should visually " select the whole [foo bar]. call MouseLeftClick(1, 5) call assert_equal(0, getcharmod(), msg) call MouseLeftRelease(1, 5) call MouseLeftClick(1, 5) call assert_equal(32, getcharmod(), msg) " double-click call MouseLeftRelease(1, 5) call assert_equal('v', mode(), msg) norm! r2 call assert_equal(['111 222222222 foo', 'foo'], getline(1, '$'), msg) " Triple-click should visually select the whole line. call MouseLeftClick(1, 3) call assert_equal(0, getcharmod(), msg) call MouseLeftRelease(1, 3) call MouseLeftClick(1, 3) call assert_equal(32, getcharmod(), msg) " double-click call MouseLeftRelease(1, 3) call MouseLeftClick(1, 3) call assert_equal(64, getcharmod(), msg) " triple-click call MouseLeftRelease(1, 3) call assert_equal('V', mode(), msg) norm! r3 call assert_equal(['33333333333333333', 'foo'], getline(1, '$'), msg) " Quadruple-click should start visual block select. call MouseLeftClick(1, 2) call assert_equal(0, getcharmod(), msg) call MouseLeftRelease(1, 2) call MouseLeftClick(1, 2) call assert_equal(32, getcharmod(), msg) " double-click call MouseLeftRelease(1, 2) call MouseLeftClick(1, 2) call assert_equal(64, getcharmod(), msg) " triple-click call MouseLeftRelease(1, 2) call MouseLeftClick(1, 2) call assert_equal(96, getcharmod(), msg) " quadruple-click call MouseLeftRelease(1, 2) call assert_equal("\<c-v>", mode(), msg) norm! r4 call assert_equal(['34333333333333333', 'foo'], getline(1, '$'), msg) " Double-click on a space character should visually select all the " consecutive space characters. %d call setline(1, ' one two') call MouseLeftClick(1, 2) call MouseLeftRelease(1, 2) call MouseLeftClick(1, 2) call MouseLeftRelease(1, 2) call assert_equal('v', mode(), msg) norm! r1 call assert_equal(['1111one two'], getline(1, '$'), msg) " Double-click on a word with exclusive selection set selection=exclusive let @" = '' call MouseLeftClick(1, 10) call MouseLeftRelease(1, 10) call MouseLeftClick(1, 10) call MouseLeftRelease(1, 10) norm! y call assert_equal('two', @", msg) " Double click to select a block of text with exclusive selection %d call setline(1, 'one (two) three') call MouseLeftClick(1, 5) call MouseLeftRelease(1, 5) call MouseLeftClick(1, 5) call MouseLeftRelease(1, 5) norm! y call assert_equal(5, col("'<"), msg) call assert_equal(10, col("'>"), msg) call MouseLeftClick(1, 9) call MouseLeftRelease(1, 9) call MouseLeftClick(1, 9) call MouseLeftRelease(1, 9) norm! y call assert_equal(5, col("'<"), msg) call assert_equal(10, col("'>"), msg) set selection& " Click somewhere else so that the clicks above is not combined with the " clicks in the next iteration. call MouseRightClick(3, 10) call MouseRightRelease(3, 10) endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse set mousetime& call test_override('no_query_mouse', 0) bwipe! endfunc " Test for selecting text in visual blockwise mode using Alt-LeftClick func Test_mouse_alt_leftclick() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm mousetime=200 set mousemodel=popup call WaitForResponses() new call setline(1, 'one (two) three') for ttymouse_val in g:Ttymouse_values let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val " Left click with the Alt modifier key should extend the selection in " blockwise visual mode. let @" = '' call MouseLeftClick(1, 3) call MouseLeftRelease(1, 3) call MouseAltLeftClick(1, 11) call MouseLeftRelease(1, 11) call assert_equal("\<C-V>", mode(), msg) normal! y call assert_equal('e (two) t', @") endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse set mousetime& mousemodel& call test_override('no_query_mouse', 0) close! endfunc func Test_xterm_mouse_click_in_fold_columns() new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse let save_foldcolumn = &foldcolumn set mouse=a term=xterm foldcolumn=3 ttymouse=xterm2 call WaitForResponses() " Create 2 nested folds. call setline(1, range(1, 7)) 2,6fold norm! zR 4,5fold call assert_equal([-1, -1, -1, 4, 4, -1, -1], \ map(range(1, 7), 'foldclosed(v:val)')) " Click in "+" of inner fold in foldcolumn should open it. redraw let row = 4 let col = 2 call MouseLeftClick(row, col) call MouseLeftRelease(row, col) call assert_equal([-1, -1, -1, -1, -1, -1, -1], \ map(range(1, 7), 'foldclosed(v:val)')) " Click in "-" of outer fold in foldcolumn should close it. redraw let row = 2 let col = 1 call MouseLeftClick(row, col) call MouseLeftRelease(row, col) call assert_equal([-1, 2, 2, 2, 2, 2, -1], \ map(range(1, 7), 'foldclosed(v:val)')) norm! zR " Click in "|" of inner fold in foldcolumn should close it. redraw let row = 5 let col = 2 call MouseLeftClick(row, col) call MouseLeftRelease(row, col) call assert_equal([-1, -1, -1, 4, 4, -1, -1], \ map(range(1, 7), 'foldclosed(v:val)')) let &foldcolumn = save_foldcolumn let &ttymouse = save_ttymouse let &term = save_term let &mouse = save_mouse bwipe! endfunc " Left or right click in Ex command line sets position of the cursor. func Test_term_mouse_click_in_cmdline_to_set_pos() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() let row = &lines for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported. if ttymouse_val !=# 'xterm2' || row <= 223 let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call feedkeys(':"3456789' \ .. MouseLeftClickCode(row, 7) \ .. MouseLeftReleaseCode(row, 7) .. 'L' \ .. MouseRightClickCode(row, 4) \ .. MouseRightReleaseCode(row, 4) .. 'R' \ .. "\<CR>", 'Lx!') call assert_equal('"3R456L789', @:, msg) endif endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse set mousetime& call test_override('no_query_mouse', 0) endfunc " Middle click in command line pastes at position of cursor. func Test_term_mouse_middle_click_in_cmdline_to_paste() CheckFeature clipboard_working let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm call WaitForResponses() let row = &lines " Column values does not matter, paste is done at position of cursor. let col = 1 let @* = 'paste' for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val call feedkeys(":\"->" \ .. MouseMiddleReleaseCode(row, col) \ .. MouseMiddleClickCode(row, col) \ .. "<-" \ .. MouseMiddleReleaseCode(row, col) \ .. MouseMiddleClickCode(row, col) \ .. "\<CR>", 'Lx!') call assert_equal('"->paste<-paste', @:, msg) endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse let @* = '' call test_override('no_query_mouse', 0) endfunc " Test for making sure S-Middlemouse doesn't do anything func Test_term_mouse_shift_middle_click() new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm ttymouse=xterm2 mousemodel= call WaitForResponses() call test_setmouse(1, 1) exe "normal \<S-MiddleMouse>" call assert_equal([''], getline(1, '$')) call assert_equal(1, winnr()) let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse set mousemodel& call test_override('no_query_mouse', 0) close! endfunc " Test for using mouse in visual mode func Test_term_mouse_visual_mode() new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set term=xterm ttymouse=xterm2 call WaitForResponses() " If visual mode is not present in 'mouse', then left click should not " do anything in visal mode. call setline(1, ['one two three four']) set mouse=nci call cursor(1, 5) let @" = '' call feedkeys("ve" \ .. MouseLeftClickCode(1, 15) .. MouseLeftReleaseCode(1, 15) \ .. 'y', 'Lx!') call assert_equal(5, col('.')) call assert_equal('two', @") " Pressing right click in visual mode should change the visual selection " if 'mousemodel' doesn't contain popup. " Right click after the visual selection set mousemodel= set mouse=a call test_setmouse(1, 13) exe "normal 5|ve\<RightMouse>y" call assert_equal('two three', @") call assert_equal(5, col('.')) " Right click before the visual selection call test_setmouse(1, 9) exe "normal 15|ve\<RightMouse>y" call assert_equal('three four', @") call assert_equal(9, col('.')) " Right click inside the selection closer to the start of the selection call test_setmouse(1, 7) exe "normal 5|vee\<RightMouse>lly" call assert_equal('three', @") call assert_equal(9, col('.')) call assert_equal(9, col("'<")) call assert_equal(13, col("'>")) " Right click inside the selection closer to the end of the selection call test_setmouse(1, 11) exe "normal 5|vee\<RightMouse>ly" call assert_equal('two thre', @") call assert_equal(5, col('.')) call assert_equal(5, col("'<")) call assert_equal(12, col("'>")) " Multi-line selection. Right click inside the selection. call setline(1, repeat(['aaaaaa'], 7)) call test_setmouse(3, 1) exe "normal ggVG\<RightMouse>y" call assert_equal(3, line("'<")) call test_setmouse(5, 1) exe "normal ggVG\<RightMouse>y" call assert_equal(5, line("'>")) " Click right in the middle line of the selection call test_setmouse(4, 3) exe "normal ggVG$\<RightMouse>y" call assert_equal(4, line("'<")) call test_setmouse(4, 4) exe "normal ggVG$\<RightMouse>y" call assert_equal(4, line("'>")) set mousemodel& let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) close! endfunc " Test for displaying the popup menu using the right mouse click func Test_term_mouse_popup_menu() CheckFeature menu new call setline(1, 'popup menu test') let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse let save_mousemodel = &mousemodel call test_override('no_query_mouse', 1) set mouse=a term=xterm mousemodel=popup call WaitForResponses() menu PopUp.foo :let g:menustr = 'foo'<CR> menu PopUp.bar :let g:menustr = 'bar'<CR> menu PopUp.baz :let g:menustr = 'baz'<CR> for ttymouse_val in g:Ttymouse_values let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val let g:menustr = '' call feedkeys(MouseRightClickCode(1, 4) \ .. MouseRightReleaseCode(1, 4) .. "\<Down>\<Down>\<CR>", "x") call assert_equal('bar', g:menustr, msg) endfor unmenu PopUp let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse let &mousemodel = save_mousemodel call test_override('no_query_mouse', 0) close! endfunc " Test for 'mousemodel' set to popup_setpos to move the cursor where the popup " menu is displayed. func Test_term_mouse_popup_menu_setpos() CheckFeature menu 5new call setline(1, ['the dish ran away with the spoon', \ 'the cow jumped over the moon' ]) let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse let save_mousemodel = &mousemodel call test_override('no_query_mouse', 1) set mouse=a term=xterm mousemodel=popup_setpos call WaitForResponses() nmenu PopUp.foo :let g:menustr = 'foo'<CR> nmenu PopUp.bar :let g:menustr = 'bar'<CR> nmenu PopUp.baz :let g:menustr = 'baz'<CR> vmenu PopUp.foo y:<C-U>let g:menustr = 'foo'<CR> vmenu PopUp.bar y:<C-U>let g:menustr = 'bar'<CR> vmenu PopUp.baz y:<C-U>let g:menustr = 'baz'<CR> for ttymouse_val in g:Ttymouse_values let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val let g:menustr = '' call cursor(1, 1) call feedkeys(MouseRightClickCode(1, 5) \ .. MouseRightReleaseCode(1, 5) .. "\<Down>\<Down>\<CR>", "x") call assert_equal('bar', g:menustr, msg) call assert_equal([1, 5], [line('.'), col('.')], msg) " Test for right click in visual mode inside the selection let @" = '' call cursor(1, 10) call feedkeys('vee' .. MouseRightClickCode(1, 12) \ .. MouseRightReleaseCode(1, 12) .. "\<Down>\<CR>", "x") call assert_equal([1, 10], [line('.'), col('.')], msg) call assert_equal('ran away', @", msg) " Test for right click in visual mode right before the selection let @" = '' call cursor(1, 10) call feedkeys('vee' .. MouseRightClickCode(1, 9) \ .. MouseRightReleaseCode(1, 9) .. "\<Down>\<CR>", "x") call assert_equal([1, 9], [line('.'), col('.')], msg) call assert_equal('', @", msg) " Test for right click in visual mode right after the selection let @" = '' call cursor(1, 10) call feedkeys('vee' .. MouseRightClickCode(1, 18) \ .. MouseRightReleaseCode(1, 18) .. "\<Down>\<CR>", "x") call assert_equal([1, 18], [line('.'), col('.')], msg) call assert_equal('', @", msg) " Test for right click in block-wise visual mode inside the selection let @" = '' call cursor(1, 16) call feedkeys("\<C-V>j3l" .. MouseRightClickCode(2, 17) \ .. MouseRightReleaseCode(2, 17) .. "\<Down>\<CR>", "x") call assert_equal([1, 16], [line('.'), col('.')], msg) call assert_equal("\<C-V>4", getregtype('"'), msg) " Test for right click in block-wise visual mode outside the selection let @" = '' call cursor(1, 16) call feedkeys("\<C-V>j3l" .. MouseRightClickCode(2, 2) \ .. MouseRightReleaseCode(2, 2) .. "\<Down>\<CR>", "x") call assert_equal([2, 2], [line('.'), col('.')], msg) call assert_equal('v', getregtype('"'), msg) call assert_equal('', @", msg) " Test for right click in line-wise visual mode inside the selection let @" = '' call cursor(1, 16) call feedkeys("V" .. MouseRightClickCode(1, 10) \ .. MouseRightReleaseCode(1, 10) .. "\<Down>\<CR>", "x") call assert_equal([1, 1], [line('.'), col('.')], msg) " After yanking, the cursor goes to 1,1 call assert_equal("V", getregtype('"'), msg) call assert_equal(1, len(getreg('"', 1, v:true)), msg) " Test for right click in multi-line line-wise visual mode inside the selection let @" = '' call cursor(1, 16) call feedkeys("Vj" .. MouseRightClickCode(2, 20) \ .. MouseRightReleaseCode(2, 20) .. "\<Down>\<CR>", "x") call assert_equal([1, 1], [line('.'), col('.')], msg) " After yanking, the cursor goes to 1,1 call assert_equal("V", getregtype('"'), msg) call assert_equal(2, len(getreg('"', 1, v:true)), msg) " Test for right click in line-wise visual mode outside the selection let @" = '' call cursor(1, 16) call feedkeys("V" .. MouseRightClickCode(2, 10) \ .. MouseRightReleaseCode(2, 10) .. "\<Down>\<CR>", "x") call assert_equal([2, 10], [line('.'), col('.')], msg) call assert_equal("", @", msg) " Try clicking on the status line let @" = '' call cursor(1, 10) call feedkeys('vee' .. MouseRightClickCode(6, 2) \ .. MouseRightReleaseCode(6, 2) .. "\<Down>\<CR>", "x") call assert_equal([1, 10], [line('.'), col('.')], msg) call assert_equal('ran away', @", msg) " Try clicking outside the window let @" = '' call cursor(2, 2) call feedkeys('vee' .. MouseRightClickCode(7, 2) \ .. MouseRightReleaseCode(7, 2) .. "\<Down>\<CR>", "x") call assert_equal(2, winnr(), msg) call assert_equal('', @", msg) wincmd w endfor unmenu PopUp let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse let &mousemodel = save_mousemodel call test_override('no_query_mouse', 0) close! endfunc " Test for searching for the word under the cursor using Shift-Right or " Shift-Left click. func Test_term_mouse_search() new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm ttymouse=xterm2 set mousemodel= call WaitForResponses() " In normal mode, Shift-Left or Shift-Right click should search for the word " under the cursor. call setline(1, ['one two three four', 'four three two one']) call test_setmouse(1, 4) exe "normal \<S-LeftMouse>" call assert_equal([2, 12], [line('.'), col('.')]) call test_setmouse(2, 16) exe "normal \<S-RightMouse>" call assert_equal([1, 1], [line('.'), col('.')]) " In visual mode, Shift-Left or Shift-Right click should search for the word " under the cursor and extend the selection. call test_setmouse(1, 4) exe "normal 4|ve\<S-LeftMouse>y" call assert_equal([2, 12], [line("'>"), col("'>")]) call test_setmouse(2, 16) exe "normal 2G16|ve\<S-RightMouse>y" call assert_equal([1, 1], [line("'<"), col("'<")]) set mousemodel& let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) close! endfunc " Test for selecting an entry in the quickfix/location list window using the " mouse. func Test_term_mouse_quickfix_window() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm ttymouse=xterm2 set mousemodel= call WaitForResponses() cgetexpr "Xfile1:1:L1" copen 5 call test_setmouse(&lines - 7, 1) exe "normal \<2-LeftMouse>" call assert_equal('Xfile1', @%) %bw! lgetexpr "Xfile2:1:L1" lopen 5 call test_setmouse(&lines - 7, 1) exe "normal \<2-LeftMouse>" call assert_equal('Xfile2', @%) %bw! set mousemodel& let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) endfunc " Test for the 'h' flag in the 'mouse' option. Using mouse in the help window. func Test_term_mouse_help_window() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=h term=xterm mousetime=200 call WaitForResponses() for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val help let @" = '' call MouseLeftClick(2, 5) call MouseLeftRelease(2, 5) call MouseLeftClick(1, 1) call MouseLeftDrag(1, 10) call MouseLeftRelease(1, 10) norm! y call assert_equal('*help.txt*', @", msg) helpclose " Click somewhere else to make sure the left click above is not combined " with the next left click and treated as a double click call MouseRightClick(5, 10) call MouseRightRelease(5, 10) endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse set mousetime& call test_override('no_query_mouse', 0) %bw! endfunc " Test for the translation of various mouse terminal codes func Test_mouse_termcodes() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=xterm mousetime=200 call WaitForResponses() new for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm let msg = 'ttymouse=' .. ttymouse_val exe 'set ttymouse=' .. ttymouse_val let mouse_codes = [ \ ["\<LeftMouse>", "<LeftMouse>"], \ ["\<MiddleMouse>", "<MiddleMouse>"], \ ["\<RightMouse>", "<RightMouse>"], \ ["\<S-LeftMouse>", "<S-LeftMouse>"], \ ["\<S-MiddleMouse>", "<S-MiddleMouse>"], \ ["\<S-RightMouse>", "<S-RightMouse>"], \ ["\<C-LeftMouse>", "<C-LeftMouse>"], \ ["\<C-MiddleMouse>", "<C-MiddleMouse>"], \ ["\<C-RightMouse>", "<C-RightMouse>"], \ ["\<M-LeftMouse>", "<M-LeftMouse>"], \ ["\<M-MiddleMouse>", "<M-MiddleMouse>"], \ ["\<M-RightMouse>", "<M-RightMouse>"], \ ["\<2-LeftMouse>", "<2-LeftMouse>"], \ ["\<2-MiddleMouse>", "<2-MiddleMouse>"], \ ["\<2-RightMouse>", "<2-RightMouse>"], \ ["\<3-LeftMouse>", "<3-LeftMouse>"], \ ["\<3-MiddleMouse>", "<3-MiddleMouse>"], \ ["\<3-RightMouse>", "<3-RightMouse>"], \ ["\<4-LeftMouse>", "<4-LeftMouse>"], \ ["\<4-MiddleMouse>", "<4-MiddleMouse>"], \ ["\<4-RightMouse>", "<4-RightMouse>"], \ ["\<LeftDrag>", "<LeftDrag>"], \ ["\<MiddleDrag>", "<MiddleDrag>"], \ ["\<RightDrag>", "<RightDrag>"], \ ["\<LeftRelease>", "<LeftRelease>"], \ ["\<MiddleRelease>", "<MiddleRelease>"], \ ["\<RightRelease>", "<RightRelease>"], \ ["\<ScrollWheelUp>", "<ScrollWheelUp>"], \ ["\<S-ScrollWheelUp>", "<S-ScrollWheelUp>"], \ ["\<C-ScrollWheelUp>", "<C-ScrollWheelUp>"], \ ["\<ScrollWheelDown>", "<ScrollWheelDown>"], \ ["\<S-ScrollWheelDown>", "<S-ScrollWheelDown>"], \ ["\<C-ScrollWheelDown>", "<C-ScrollWheelDown>"], \ ["\<ScrollWheelLeft>", "<ScrollWheelLeft>"], \ ["\<S-ScrollWheelLeft>", "<S-ScrollWheelLeft>"], \ ["\<C-ScrollWheelLeft>", "<C-ScrollWheelLeft>"], \ ["\<ScrollWheelRight>", "<ScrollWheelRight>"], \ ["\<S-ScrollWheelRight>", "<S-ScrollWheelRight>"], \ ["\<C-ScrollWheelRight>", "<C-ScrollWheelRight>"] \ ] for [code, outstr] in mouse_codes exe "normal ggC\<C-K>" . code call assert_equal(outstr, getline(1), msg) endfor endfor let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse set mousetime& call test_override('no_query_mouse', 0) %bw! endfunc " This only checks if the sequence is recognized. func Test_term_rgb_response() set t_RF=x set t_RB=y " response to t_RF, 4 digits let red = 0x12 let green = 0x34 let blue = 0x56 let seq = printf("\<Esc>]10;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termrfgresp) " response to t_RF, 2 digits let red = 0x78 let green = 0x9a let blue = 0xbc let seq = printf("\<Esc>]10;rgb:%02x/%02x/%02x\x07", red, green, blue) call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termrfgresp) " response to t_RB, 4 digits, dark set background=light eval 'background'->test_option_not_set() let red = 0x29 let green = 0x4a let blue = 0x6b let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termrbgresp) call assert_equal('dark', &background) " response to t_RB, 4 digits, light set background=dark call test_option_not_set('background') let red = 0x81 let green = 0x63 let blue = 0x65 let seq = printf("\<Esc>]11;rgb:%02x00/%02x00/%02x00\x07", red, green, blue) call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termrbgresp) call assert_equal('light', &background) " response to t_RB, 2 digits, dark set background=light call test_option_not_set('background') let red = 0x47 let green = 0x59 let blue = 0x5b let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue) call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termrbgresp) call assert_equal('dark', &background) " response to t_RB, 2 digits, light set background=dark call test_option_not_set('background') let red = 0x83 let green = 0xa4 let blue = 0xc2 let seq = printf("\<Esc>]11;rgb:%02x/%02x/%02x\x07", red, green, blue) call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termrbgresp) call assert_equal('light', &background) set t_RF= t_RB= endfunc " This only checks if the sequence is recognized. " This must be after other tests, because it has side effects to xterm " properties. func Test_xx01_term_style_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) " send the termresponse to trigger requesting the XT codes let seq = "\<Esc>[>41;337;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) let seq = "\<Esc>P1$r2 q\<Esc>\\" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termstyleresp) call assert_equal(#{ \ cursor_style: 'u', \ cursor_blink_mode: 'u', \ underline_rgb: 'u', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) set t_RV= call test_override('term_props', 0) endfunc " This checks the iTerm2 version response. " This must be after other tests, because it has side effects to xterm " properties. func Test_xx02_iTerm2_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) " Old versions of iTerm2 used a different style term response. set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>0;95;c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('xterm', &ttymouse) set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>0;95;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'u', \ underline_rgb: 'u', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) set t_RV= call test_override('term_props', 0) endfunc func Run_libvterm_konsole_response(code) set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>0;" .. a:code .. ";0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'u', \ underline_rgb: 'u', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) endfunc " This checks the libvterm version response. " This must be after other tests, because it has side effects to xterm " properties. func Test_xx03_libvterm_konsole_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) " libvterm call Run_libvterm_konsole_response(100) " Konsole call Run_libvterm_konsole_response(115) set t_RV= call test_override('term_props', 0) endfunc " This checks the Mac Terminal.app version response. " This must be after other tests, because it has side effects to xterm " properties. func Test_xx04_Mac_Terminal_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) set ttymouse=xterm " t_8u is not reset let &t_8u = "\<Esc>[58;2;%lu;%lu;%lum" call test_option_not_set('ttymouse') let seq = "\<Esc>[>1;95;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'u', \ underline_rgb: 'y', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) call assert_equal("\<Esc>[58;2;%lu;%lu;%lum", &t_8u) " Reset is_not_xterm and is_mac_terminal. set t_RV= set term=xterm set t_RV=x call test_override('term_props', 0) endfunc " This checks the mintty version response. " This must be after other tests, because it has side effects to xterm " properties. func Test_xx05_mintty_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>77;20905;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'u', \ underline_rgb: 'y', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) set t_RV= call test_override('term_props', 0) endfunc " This checks the screen version response. " This must be after other tests, because it has side effects to xterm " properties. func Test_xx06_screen_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) " Old versions of screen don't support SGR mouse mode. set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>83;40500;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('xterm', &ttymouse) " screen supports SGR mouse mode starting in version 4.7. set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>83;40700;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'n', \ underline_rgb: 'y', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) set t_RV= call test_override('term_props', 0) endfunc func Do_check_t_8u_set_reset(set_by_user) set ttymouse=xterm call test_option_not_set('ttymouse') let default_value = "\<Esc>[58;2;%lu;%lu;%lum" let &t_8u = default_value if !a:set_by_user call test_option_not_set('t_8u') endif let seq = "\<Esc>[>0;279;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'u', \ cursor_blink_mode: 'u', \ underline_rgb: 'u', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) call assert_equal(a:set_by_user ? default_value : '', &t_8u) endfunc " This checks the xterm version response. " This must be after other tests, because it has side effects to xterm " properties. func Test_xx07_xterm_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) " Do Terminal.app first to check that is_mac_terminal is reset. set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>1;95;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) " xterm < 95: "xterm" (actually unmodified) set t_RV= set term=xterm call WaitForResponses() set t_RV=x set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>0;94;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('xterm', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'u', \ underline_rgb: 'y', \ mouse: 'u', \ kitty: 'u', \ }, terminalprops()) " xterm >= 95 < 277 "xterm2" set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>0;267;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('xterm2', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'u', \ underline_rgb: 'u', \ mouse: '2', \ kitty: 'u', \ }, terminalprops()) " xterm >= 277: "sgr" set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>0;277;0c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'n', \ cursor_blink_mode: 'u', \ underline_rgb: 'u', \ mouse: 's', \ kitty: 'u', \ }, terminalprops()) " xterm >= 279: "sgr" and cursor_style not reset; also check t_8u reset, " except when it was set by the user call Do_check_t_8u_set_reset(0) call Do_check_t_8u_set_reset(1) set t_RV= call test_override('term_props', 0) endfunc func Test_xx08_kitty_response() " Termresponse is only parsed when t_RV is not empty. set t_RV=x call test_override('term_props', 1) set ttymouse=xterm call test_option_not_set('ttymouse') let seq = "\<Esc>[>1;4001;12c" call feedkeys(seq, 'Lx!') call assert_equal(seq, v:termresponse) call assert_equal('sgr', &ttymouse) call assert_equal(#{ \ cursor_style: 'u', \ cursor_blink_mode: 'u', \ underline_rgb: 'y', \ mouse: 's', \ kitty: 'y', \ }, terminalprops()) set t_RV= call test_override('term_props', 0) endfunc func Test_focus_events() let save_term = &term let save_ttymouse = &ttymouse set term=xterm ttymouse=xterm2 call WaitForResponses() au FocusGained * let g:focus_gained += 1 au FocusLost * let g:focus_lost += 1 let g:focus_gained = 0 let g:focus_lost = 0 call feedkeys("\<Esc>[O", "Lx!") call assert_equal(1, g:focus_lost) call feedkeys("\<Esc>[I", "Lx!") call assert_equal(1, g:focus_gained) " still works when 'ttymouse' is empty set ttymouse= call feedkeys("\<Esc>[O", "Lx!") call assert_equal(2, g:focus_lost) call feedkeys("\<Esc>[I", "Lx!") call assert_equal(2, g:focus_gained) au! FocusGained au! FocusLost let &term = save_term let &ttymouse = save_ttymouse endfunc func Test_get_termcode() try let k1 = &t_k1 catch /E113/ throw 'Skipped: Unable to query termcodes' endtry set t_k1= set t_k1& call assert_equal(k1, &t_k1) " use external termcap first set nottybuiltin set t_k1= set t_k1& " when using external termcap may get something else, but it must not be " empty, since we would fallback to the builtin one. call assert_notequal('', &t_k1) if &term =~ 'xterm' " use internal termcap first let term_save = &term let &term = 'builtin_' .. &term set t_k1= set t_k1& call assert_equal(k1, &t_k1) let &term = term_save endif set ttybuiltin endfunc func Test_list_builtin_terminals() CheckRunVimInTerminal call RunVimInTerminal('', #{rows: 14}) call term_sendkeys('', ":set cmdheight=3\<CR>") call TermWait('', 100) call term_sendkeys('', ":set term=xxx\<CR>") call TermWait('', 100) " Check that the list ends in "builtin_dumb" and "builtin_debug". let dumb_idx = 0 for n in range(8, 12) if term_getline('', n) =~ 'builtin_dumb' let dumb_idx = n break endif endfor call assert_notequal(0, dumb_idx, 'builtin_dumb not found') call assert_match('builtin_dumb', term_getline('', dumb_idx)) call assert_match('builtin_debug', term_getline('', dumb_idx + 1)) call assert_match('Not found in termcap', term_getline('', dumb_idx + 2)) call StopVimInTerminal('') endfunc " This checks the CSI sequences when in modifyOtherKeys mode. " The mode doesn't need to be enabled, the codes are always detected. func RunTest_modifyOtherKeys(func) new set timeoutlen=10 " Shift-X is sent as 'X' with the shift modifier call feedkeys('a' .. a:func('X', 2) .. "\<Esc>", 'Lx!') call assert_equal('X', getline(1)) " Ctrl-i is Tab call setline(1, '') call feedkeys('a' .. a:func('i', 5) .. "\<Esc>", 'Lx!') call assert_equal("\t", getline(1)) " Ctrl-I is also Tab call setline(1, '') call feedkeys('a' .. a:func('I', 5) .. "\<Esc>", 'Lx!') call assert_equal("\t", getline(1)) " Alt-x is ø call setline(1, '') call feedkeys('a' .. a:func('x', 3) .. "\<Esc>", 'Lx!') call assert_equal("ø", getline(1)) " Meta-x is also ø call setline(1, '') call feedkeys('a' .. a:func('x', 9) .. "\<Esc>", 'Lx!') call assert_equal("ø", getline(1)) " Alt-X is Ø call setline(1, '') call feedkeys('a' .. a:func('X', 3) .. "\<Esc>", 'Lx!') call assert_equal("Ø", getline(1)) " Meta-X is ø call setline(1, '') call feedkeys('a' .. a:func('X', 9) .. "\<Esc>", 'Lx!') call assert_equal("Ø", getline(1)) " Ctrl-6 is Ctrl-^ split aaa edit bbb call feedkeys(a:func('6', 5), 'Lx!') call assert_equal("aaa", bufname()) bwipe aaa bwipe bbb " Ctrl-V X 33 is 3 call setline(1, '') call feedkeys("a\<C-V>" .. a:func('X', 2) .. "33\<Esc>", 'Lx!') call assert_equal("3", getline(1)) " Ctrl-V U 12345 is Unicode 12345 call setline(1, '') call feedkeys("a\<C-V>" .. a:func('U', 2) .. "12345\<Esc>", 'Lx!') call assert_equal("\U12345", getline(1)) bwipe! set timeoutlen& endfunc func Test_modifyOtherKeys_basic() call RunTest_modifyOtherKeys(function('GetEscCodeCSI27')) call RunTest_modifyOtherKeys(function('GetEscCodeCSIu')) endfunc func Test_modifyOtherKeys_no_mapping() set timeoutlen=10 let @a = 'aaa' call feedkeys(":let x = '" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a'\<CR>", 'Lx!') call assert_equal("let x = 'aaa'", @:) new call feedkeys("a" .. GetEscCodeCSI27('R', 5) .. GetEscCodeCSI27('R', 5) .. "a\<Esc>", 'Lx!') call assert_equal("aaa", getline(1)) bwipe! new call feedkeys("axx\<CR>yy" .. GetEscCodeCSI27('G', 5) .. GetEscCodeCSI27('K', 5) .. "a\<Esc>", 'Lx!') call assert_equal("axx", getline(1)) call assert_equal("yy", getline(2)) bwipe! set timeoutlen& endfunc func Test_CSIu_keys_without_modifiers() " make this execute faster set timeoutlen=10 call WaitForResponses() " Escape sent as `CSI 27 u` should act as normal escape and not undo call setline(1, 'a') call feedkeys('a' .. GetEscCodeCSIuWithoutModifier("\e"), 'Lx!') call assert_equal('n', mode()) call assert_equal('a', getline(1)) " Tab sent as `CSI 9 u` should work call setline(1, '') call feedkeys('a' .. GetEscCodeCSIuWithoutModifier("\t") .. "\<Esc>", 'Lx!') call assert_equal("\t", getline(1)) set timeoutlen& endfunc " Check that when DEC mouse codes are recognized a special key is handled. func Test_ignore_dec_mouse() silent !infocmp gnome >/dev/null 2>&1 if v:shell_error != 0 throw 'Skipped: gnome entry missing in the terminfo db' endif new let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse call test_override('no_query_mouse', 1) set mouse=a term=gnome ttymouse= call WaitForResponses() execute "set <xF1>=\<Esc>[1;*P" nnoremap <S-F1> agot it<Esc> call feedkeys("\<Esc>[1;2P", 'Lx!') call assert_equal('got it', getline(1)) let &mouse = save_mouse let &term = save_term let &ttymouse = save_ttymouse call test_override('no_query_mouse', 0) bwipe! endfunc func RunTest_mapping_shift(key, func) call setline(1, '') if a:key == '|' exe 'inoremap \| xyz' else exe 'inoremap ' .. a:key .. ' xyz' endif call feedkeys('a' .. a:func(a:key, 2) .. "\<Esc>", 'Lx!') call assert_equal("xyz", getline(1)) if a:key == '|' exe 'iunmap \|' else exe 'iunmap ' .. a:key endif endfunc func Test_modifyOtherKeys_mapped() set timeoutlen=10 imap ' <C-W> imap <C-W><C-A> c-a call setline(1, '') " single quote is turned into single byte CTRL-W " CTRL-A is added with a separate modifier, and needs to be simplified before " the mapping can match. call feedkeys("a'" .. GetEscCodeCSI27('A', 5) .. "\<Esc>", 'Lx!') call assert_equal('c-a', getline(1)) iunmap ' iunmap <C-W><C-A> set timeoutlen& endfunc func Test_modifyOtherKeys_ambiguous_mapping() new set timeoutlen=10 map <C-J> a map <C-J>x <Nop> call setline(1, 'x') " CTRL-J b should have trigger the <C-J> mapping and then insert "b" call feedkeys(GetEscCodeCSI27('J', 5) .. "b\<Esc>", 'Lx!') call assert_equal('xb', getline(1)) unmap <C-J> unmap <C-J>x " if a special character is following there should be a check for a termcode nnoremap s aX<Esc> nnoremap s<BS> aY<Esc> set t_kb= call setline(1, 'x') call feedkeys("s\x08", 'Lx!') call assert_equal('xY', getline(1)) set timeoutlen& bwipe! endfunc " Whether Shift-Tab sends "ESC [ Z" or "ESC [ 27 ; 2 ; 9 ~" is unpredictable, " both should work. func Test_modifyOtherKeys_shift_tab() set timeoutlen=10 call setline(1, '') call feedkeys("a\<C-K>" .. GetEscCodeCSI27("\t", '2') .. "\<Esc>", 'Lx!') eval getline(1)->assert_equal('<S-Tab>') call setline(1, '') call feedkeys("a\<C-K>\<Esc>[Z\<Esc>", 'Lx!') eval getline(1)->assert_equal('<S-Tab>') set timeoutlen& bwipe! endfunc func RunTest_mapping_works_with_shift(func) new set timeoutlen=10 call RunTest_mapping_shift('@', a:func) call RunTest_mapping_shift('A', a:func) call RunTest_mapping_shift('Z', a:func) call RunTest_mapping_shift('^', a:func) call RunTest_mapping_shift('_', a:func) call RunTest_mapping_shift('{', a:func) call RunTest_mapping_shift('|', a:func) call RunTest_mapping_shift('}', a:func) call RunTest_mapping_shift('~', a:func) bwipe! set timeoutlen& endfunc func Test_mapping_works_with_shift_plain() call RunTest_mapping_works_with_shift(function('GetEscCodeCSI27')) call RunTest_mapping_works_with_shift(function('GetEscCodeCSIu')) endfunc func RunTest_mapping_mods(map, key, func, code) call setline(1, '') exe 'inoremap ' .. a:map .. ' xyz' call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!') call assert_equal("xyz", getline(1)) exe 'iunmap ' .. a:map endfunc func RunTest_mapping_works_with_mods(func, mods, code) new set timeoutlen=10 if a:mods !~ 'S' " Shift by itself has no effect call RunTest_mapping_mods('<' .. a:mods .. '-@>', '@', a:func, a:code) endif call RunTest_mapping_mods('<' .. a:mods .. '-A>', 'A', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-Z>', 'Z', a:func, a:code) if a:mods !~ 'S' " with Shift code is always upper case call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'a', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'z', a:func, a:code) endif if a:mods != 'A' " with Alt code is not in upper case call RunTest_mapping_mods('<' .. a:mods .. '-a>', 'A', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-z>', 'Z', a:func, a:code) endif call RunTest_mapping_mods('<' .. a:mods .. '-á>', 'á', a:func, a:code) if a:mods !~ 'S' " Shift by itself has no effect call RunTest_mapping_mods('<' .. a:mods .. '-^>', '^', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-_>', '_', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-{>', '{', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-\|>', '|', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-}>', '}', a:func, a:code) call RunTest_mapping_mods('<' .. a:mods .. '-~>', '~', a:func, a:code) endif bwipe! set timeoutlen& endfunc func Test_mapping_works_with_shift() call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S', 2) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S', 2) endfunc func Test_mapping_works_with_ctrl() call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C', 5) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C', 5) new set timeoutlen=10 " CTRL-@ actually produces the code for CTRL-2, which is converted call RunTest_mapping_mods('<C-@>', '2', function('GetEscCodeCSI27'), 5) call RunTest_mapping_mods('<C-@>', '2', function('GetEscCodeCSIu'), 5) " CTRL-^ actually produces the code for CTRL-6, which is converted call RunTest_mapping_mods('<C-^>', '6', function('GetEscCodeCSI27'), 5) call RunTest_mapping_mods('<C-^>', '6', function('GetEscCodeCSIu'), 5) " CTRL-_ actually produces the code for CTRL--, which is converted call RunTest_mapping_mods('<C-_>', '-', function('GetEscCodeCSI27'), 5) call RunTest_mapping_mods('<C-_>', '-', function('GetEscCodeCSIu'), 5) bwipe! set timeoutlen& endfunc func Test_mapping_works_with_shift_ctrl() call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S', 6) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S', 6) new set timeoutlen=10 " Ctrl-Shift-[ actually produces CTRL-Shift-{ which is mapped as <C-{> call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSI27'), 6) call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSIu'), 6) " Ctrl-Shift-] actually produces CTRL-Shift-} which is mapped as <C-}> call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSI27'), 6) call RunTest_mapping_mods('<C-{>', '{', function('GetEscCodeCSIu'), 6) " Ctrl-Shift-\ actually produces CTRL-Shift-| which is mapped as <C-|> call RunTest_mapping_mods('<C-\|>', '|', function('GetEscCodeCSI27'), 6) call RunTest_mapping_mods('<C-\|>', '|', function('GetEscCodeCSIu'), 6) bwipe! set timeoutlen& endfunc " Below we also test the "u" code with Alt, This works, but libvterm would not " send the Alt key like this but by prefixing an Esc. func Test_mapping_works_with_alt() call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'A', 3) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'A', 3) endfunc func Test_mapping_works_with_shift_alt() call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'S-A', 4) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'S-A', 4) endfunc func Test_mapping_works_with_alt_and_shift() new set timeoutlen=10 " mapping <A-?> works even though the code is A-S-? for c in ['!', '$', '+', ':', '?', '^', '~'] call RunTest_mapping_mods('<A-' .. c .. '>', c, function('GetEscCodeCSI27'), 4) call RunTest_mapping_mods('<A-' .. c .. '>', c, function('GetEscCodeCSIu'), 4) endfor bwipe! set timeoutlen& endfunc func Test_mapping_works_with_ctrl_alt() call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-A', 7) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-A', 7) endfunc func Test_mapping_works_with_shift_ctrl_alt() call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 8) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8) endfunc func Test_mapping_works_with_unknown_modifiers() new set timeoutlen=10 for Func in [function('GetEscCodeCSI27'), function('GetEscCodeCSIu')] call RunTest_mapping_mods('<C-z>', 'z', Func, 5) " Add 16, 32, 64 or 128 for modifiers we currently don't support. call RunTest_mapping_mods('<C-z>', 'z', Func, 5 + 16) call RunTest_mapping_mods('<C-z>', 'z', Func, 5 + 32) call RunTest_mapping_mods('<C-z>', 'z', Func, 5 + 64) call RunTest_mapping_mods('<C-z>', 'z', Func, 5 + 128) call RunTest_mapping_mods('<S-X>', 'X', Func, 2) " Add 16, 32, 64 or 128 for modifiers we currently don't support. call RunTest_mapping_mods('<S-X>', 'X', Func, 2 + 16) call RunTest_mapping_mods('<S-X>', 'X', Func, 2 + 32) call RunTest_mapping_mods('<S-X>', 'X', Func, 2 + 64) call RunTest_mapping_mods('<S-X>', 'X', Func, 2 + 128) endfor bwipe! set timeoutlen& endfunc func RunTest_mapping_funckey(map, func, key, code) call setline(1, '') exe 'inoremap ' .. a:map .. ' xyz' call feedkeys('a' .. a:func(a:key, a:code) .. "\<Esc>", 'Lx!') call assert_equal("xyz", getline(1), 'mapping ' .. a:map) exe 'iunmap ' .. a:map endfunc func Test_mapping_kitty_function_keys() new set timeoutlen=10 " Function keys made with CSI and ending in [ABCDEFHPQRS]. " 'E' is keypad BEGIN, not supported let maps = [ \ ['<Up>', 'A', 0], \ ['<S-Up>', 'A', 2], \ ['<C-Up>', 'A', 5], \ ['<C-S-Up>', 'A', 6], \ \ ['<Down>', 'B', 0], \ ['<S-Down>', 'B', 2], \ ['<C-Down>', 'B', 5], \ ['<C-S-Down>', 'B', 6], \ \ ['<Right>', 'C', 0], \ ['<S-Right>', 'C', 2], \ ['<C-Right>', 'C', 5], \ ['<C-S-Right>', 'C', 6], \ \ ['<Left>', 'D', 0], \ ['<S-Left>', 'D', 2], \ ['<C-Left>', 'D', 5], \ ['<C-S-Left>', 'D', 6], \ \ ['<End>', 'F', 0], \ ['<S-End>', 'F', 2], \ ['<C-End>', 'F', 5], \ ['<C-S-End>', 'F', 6], \ \ ['<Home>', 'H', 0], \ ['<S-Home>', 'H', 2], \ ['<C-Home>', 'H', 5], \ ['<C-S-Home>', 'H', 6], \ \ ['<F1>', 'P', 0], \ ['<S-F1>', 'P', 2], \ ['<C-F1>', 'P', 5], \ ['<C-S-F1>', 'P', 6], \ \ ['<F2>', 'Q', 0], \ ['<S-F2>', 'Q', 2], \ ['<C-F2>', 'Q', 5], \ ['<C-S-F2>', 'Q', 6], \ \ ['<F3>', 'R', 0], \ ['<S-F3>', 'R', 2], \ ['<C-F3>', 'R', 5], \ ['<C-S-F3>', 'R', 6], \ \ ['<F4>', 'S', 0], \ ['<S-F4>', 'S', 2], \ ['<C-F4>', 'S', 5], \ ['<C-S-F4>', 'S', 6], \ ] for map in maps call RunTest_mapping_funckey(map[0], function('GetEscCodeFunckey'), map[1], map[2]) endfor bwipe! set timeoutlen& endfunc func Test_insert_literal() set timeoutlen=10 call WaitForResponses() new " CTRL-V CTRL-X inserts a ^X call feedkeys('a' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!') call assert_equal("\<C-X>", getline(1)) call setline(1, '') call feedkeys('a' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!') call assert_equal("\<C-X>", getline(1)) " CTRL-SHIFT-V CTRL-X inserts escape sequence call setline(1, '') call feedkeys('a' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('X', '5') .. "\<Esc>", 'Lx!') call assert_equal("\<Esc>[88;5u", getline(1)) call setline(1, '') call feedkeys('a' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('X', '5') .. "\<Esc>", 'Lx!') call assert_equal("\<Esc>[27;5;88~", getline(1)) bwipe! set timeoutlen& endfunc func Test_cmdline_literal() set timeoutlen=10 " CTRL-V CTRL-Y inserts a ^Y call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!') call assert_equal("\"\<C-Y>", @:) call feedkeys(':' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!') call assert_equal("\"\<C-Y>", @:) " CTRL-SHIFT-V CTRL-Y inserts escape sequence call feedkeys(':' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!') call assert_equal("\"\<Esc>[89;5u", @:) call setline(1, '') call feedkeys(':' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('Y', '5') .. "\<C-B>\"\<CR>", 'Lx!') call assert_equal("\"\<Esc>[27;5;89~", @:) set timeoutlen& endfunc func Test_mapping_esc() set timeoutlen=10 new nnoremap <Up> iHello<Esc> nnoremap <Esc> <Nop> call feedkeys(substitute(&t_ku, '\*', '', 'g'), 'Lx!') call assert_equal("Hello", getline(1)) bwipe! nunmap <Up> nunmap <Esc> set timeoutlen& endfunc " Test for translation of special key codes (<xF1>, <xF2>, etc.) func Test_Keycode_Translation() let keycodes = [ \ ["<xUp>", "<Up>"], \ ["<xDown>", "<Down>"], \ ["<xLeft>", "<Left>"], \ ["<xRight>", "<Right>"], \ ["<xHome>", "<Home>"], \ ["<xEnd>", "<End>"], \ ["<zHome>", "<Home>"], \ ["<zEnd>", "<End>"], \ ["<xF1>", "<F1>"], \ ["<xF2>", "<F2>"], \ ["<xF3>", "<F3>"], \ ["<xF4>", "<F4>"], \ ["<S-xF1>", "<S-F1>"], \ ["<S-xF2>", "<S-F2>"], \ ["<S-xF3>", "<S-F3>"], \ ["<S-xF4>", "<S-F4>"]] for [k1, k2] in keycodes exe "nnoremap " .. k1 .. " 2wx" call assert_true(maparg(k1, 'n', 0, 1).lhs == k2) exe "nunmap " .. k1 endfor endfunc " Test for terminal keycodes that doesn't have termcap entries func Test_special_term_keycodes() new " Test for <xHome>, <S-xHome> and <C-xHome> " send <K_SPECIAL> <KS_EXTRA> keycode call feedkeys("i\<C-K>\x80\xfd\x3f\n", 'xt') " send <K_SPECIAL> <KS_MODIFIER> bitmap <K_SPECIAL> <KS_EXTRA> keycode call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x3f\n", 'xt') call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x3f\n", 'xt') " Test for <xEnd>, <S-xEnd> and <C-xEnd> call feedkeys("i\<C-K>\x80\xfd\x3d\n", 'xt') call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x3d\n", 'xt') call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x3d\n", 'xt') " Test for <zHome>, <S-zHome> and <C-zHome> call feedkeys("i\<C-K>\x80\xfd\x40\n", 'xt') call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x40\n", 'xt') call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x40\n", 'xt') " Test for <zEnd>, <S-zEnd> and <C-zEnd> call feedkeys("i\<C-K>\x80\xfd\x3e\n", 'xt') call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x3e\n", 'xt') call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x3e\n", 'xt') " Test for <xUp>, <xDown>, <xLeft> and <xRight> call feedkeys("i\<C-K>\x80\xfd\x41\n", 'xt') call feedkeys("i\<C-K>\x80\xfd\x42\n", 'xt') call feedkeys("i\<C-K>\x80\xfd\x43\n", 'xt') call feedkeys("i\<C-K>\x80\xfd\x44\n", 'xt') call assert_equal(['<Home>', '<S-Home>', '<C-Home>', \ '<End>', '<S-End>', '<C-End>', \ '<Home>', '<S-Home>', '<C-Home>', \ '<End>', '<S-End>', '<C-End>', \ '<Up>', '<Down>', '<Left>', '<Right>', ''], getline(1, '$')) bw! endfunc func Test_home_key_works() " The '@' character in K_HOME must only match "1" when followed by ";", " otherwise this code for Home is not recognized: "<Esc>[1~" " Set termcap values like "xterm" uses them. Except using F2 for xHome, " because that termcap entry can't be set here. let save_K1 = exists('&t_K1') ? &t_K1 : '' let save_kh = exists('&t_kh') ? &t_kh : '' let save_k2 = exists('&t_k2') ? &t_k2 : '' let save_k3 = exists('&t_k3') ? &t_k3 : '' let save_end = exists('&t_@7') ? &t_@7 : '' let &t_K1 = "\<Esc>[1;*~" " <kHome> let &t_kh = "\<Esc>[@;*H" " <Home> let &t_k2 = "\<Esc>O*H" " use <F2> for <xHome> let &t_k3 = "\<Esc>[7;*~" " use <F3> for <zHome> let &t_@7 = "\<Esc>[@;*F" " <End> new call feedkeys("i\<C-K>\<Esc>OH\n\<Esc>", 'tx') call feedkeys("i\<C-K>\<Esc>[1~\n\<Esc>", 'tx') call assert_equal([ \ '<F2>', \ '<kHome>', \ ''], getline(1, '$')) bwipe! let &t_K1 = save_K1 let &t_kh = save_kh let &t_k2 = save_k2 let &t_k3 = save_k3 let &t_@7 = save_end endfunc func Test_terminal_builtin_without_gui() CheckNotMSWindows " builtin_gui should not be output by :set term=xxx let output = systemlist("TERM=dumb " .. v:progpath .. " --clean -c ':set t_ti= t_te=' -c 'set term=xxx' -c ':q!'") redraw! call map(output, {_, val -> trim(val)}) call assert_equal(-1, index(output, 'builtin_gui')) call assert_notequal(-1, index(output, 'builtin_dumb')) endfunc " vim: shiftwidth=2 sts=2 expandtab