Mercurial > vim
view src/testdir/test_gui.vim @ 34420:c5a945f7f3da v9.1.0133
patch 9.1.0133: MS-Windows: ligatures not rendering correctly
Commit: https://github.com/vim/vim/commit/8b1e749ca6ca6d09a174c57de6999f69393ee567
Author: Erik S. V. Jansson <caffeineviking@gmail.com>
Date: Sat Feb 24 14:26:52 2024 +0100
patch 9.1.0133: MS-Windows: ligatures not rendering correctly
Problem: font ligatures don't render correctly in the Win32 GUI-version
of gvim even when set rop=type:directx is used. Setting
guiligatures also doesn't make any difference. This leads to
broken font ligatures when the cursor passes through them. It
does not recover from this, and they remain broken until you
re-render the whole buffer (e.g. by using Ctrl+L).
Solution: the problem is that we only re-draw the current and previous
character in gui_undraw_cursor() and only have the special case
for GTK when it comes to rendering ligatures. So let's enable
gui_adjust_undraw_cursor_for_ligatures() to also happen for
Win32 GUI if guiligatures is setup correctly (all this does is
expand the range of gui_undraw_cursor() with ligature characters).
related: #9181
related: #12901
closes: #14084
Signed-off-by: Erik S. V. Jansson <caffeineviking@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 24 Feb 2024 14:45:03 +0100 |
parents | 995b539939c4 |
children | d4b4476bf768 |
line wrap: on
line source
" Tests specifically for the GUI source shared.vim source check.vim CheckCanRunGui source setup_gui.vim func Setup() call GUISetUpCommon() endfunc func TearDown() call GUITearDownCommon() endfunc " Test for resetting "secure" flag after GUI has started. " Must be run first, since it starts the GUI on Unix. func Test_1_set_secure() set exrc secure gui -f call assert_equal(1, has('gui_running')) endfunc " As for non-GUI, a balloon_show() test was already added with patch 8.0.0401 func Test_balloon_show() CheckFeature balloon_eval " This won't do anything but must not crash either. call balloon_show('hi!') endfunc func Test_colorscheme() call assert_equal('16777216', &t_Co) let colorscheme_saved = exists('g:colors_name') ? g:colors_name : 'default' let g:color_count = 0 augroup TestColors au! au ColorScheme * let g:color_count += 1 \ | let g:after_colors = g:color_count \ | let g:color_after = expand('<amatch>') au ColorSchemePre * let g:color_count += 1 \ | let g:before_colors = g:color_count \ | let g:color_pre = expand('<amatch>') augroup END colorscheme torte redraw! call assert_equal('dark', &background) call assert_equal(1, g:before_colors) call assert_equal(2, g:after_colors) call assert_equal('torte', g:color_pre) call assert_equal('torte', g:color_after) call assert_equal("\ntorte", execute('colorscheme')) let a = substitute(execute('hi Search'), "\n\\s\\+", ' ', 'g') " FIXME: temporarily check less while the colorscheme changes " call assert_match("\nSearch xxx term=reverse cterm=reverse ctermfg=196 ctermbg=16 gui=reverse guifg=#ff0000 guibg=#000000", a) call assert_match("\nSearch xxx term=reverse ", a) call assert_fails('colorscheme does_not_exist', 'E185:') call assert_equal('does_not_exist', g:color_pre) call assert_equal('torte', g:color_after) exec 'colorscheme' colorscheme_saved augroup TestColors au! augroup END unlet g:color_count g:after_colors g:before_colors redraw! endfunc func Test_getfontname_with_arg() CheckX11BasedGui if has('gui_motif') " Invalid font name. The result should be an empty string. call assert_equal('', getfontname('notexist')) " Valid font name. This is usually the real name of 7x13 by default. let fname = '-Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO8859-1' call assert_match(fname, getfontname(fname)) elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3') " Invalid font name. The result should be the name plus the default size. call assert_equal('notexist 10', getfontname('notexist')) call assert_equal('', getfontname('*')) " Valid font name. This is usually the real name of Monospace by default. let fname = 'Bitstream Vera Sans Mono 12' call assert_equal(fname, getfontname(fname)) endif endfunc func Test_getfontname_without_arg() CheckX11BasedGui let fname = getfontname() if has('gui_kde') " 'expected' is the value specified by SetUp() above. call assert_equal('Courier 10 Pitch/8/-1/5/50/0/0/0/0/0', fname) elseif has('gui_motif') " 'expected' is DFLT_FONT of gui_x11.c or its real name. let pat = '\(7x13\)\|\(\c-Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO8859-1\)' call assert_match(pat, fname) elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3') " 'expected' is DEFAULT_FONT of gui_gtk_x11.c. call assert_equal('Monospace 10', fname) endif endfunc func Test_getwinpos() CheckX11 call assert_match('Window position: X \d\+, Y \d\+', execute('winpos')) call assert_true(getwinposx() >= 0) call assert_true(getwinposy() >= 0) call assert_equal([getwinposx(), getwinposy()], getwinpos()) endfunc func Test_quoteplus() CheckX11BasedGui let g:test_is_flaky = 1 let quoteplus_saved = @+ let test_call = 'Can you hear me?' let test_response = 'Yes, I can.' let testee = 'VIMRUNTIME=' .. $VIMRUNTIME .. '; export VIMRUNTIME;' \ .. GetVimCommand() .. ' --noplugin --not-a-term -c ''%s''' " Ignore the "failed to create input context" error. let cmd = 'call test_ignore_error("E285") | ' \ . 'gui -f | ' \ . 'call feedkeys("' \ . '\"+p' \ . ':s/' . test_call . '/' . test_response . '/\<CR>' \ . '\"+yis' \ . ':q!\<CR>", "tx")' let run_vimtest = printf(testee, cmd) " Set the quoteplus register to test_call, and another gvim will launched. " Then, it first tries to paste the content of its own quotedplus register " onto it. Second, it tries to substitute test_response for the pasted " sentence. If the sentence is identical to test_call, the substitution " should succeed. Third, it tries to yank the result of the substitution " to its own quoteplus register, and last it quits. When system() " returns, the content of the quoteplus register should be identical to " test_response if those quoteplus registers are synchronized properly " with/through the X11 clipboard. let @+ = test_call call system(run_vimtest) call assert_equal(test_response, @+) let @+ = quoteplus_saved endfunc func Test_gui_read_stdin() CheckUnix call writefile(['some', 'lines'], 'Xstdin', 'D') let script =<< trim END call writefile(getline(1, '$'), 'XstdinOK') qa! END call writefile(script, 'Xscript', 'D') " Cannot use --not-a-term here, the "reading from stdin" message would not be " displayed. " However, when using XIM we might get E285, do use it then. if has('xim') let vimcmd = GetVimCommand() else let vimcmd = substitute(GetVimCommand(), '--not-a-term', '', '') endif call system('cat Xstdin | ' .. vimcmd .. ' -f -g -S Xscript -') call assert_equal(['some', 'lines'], readfile('XstdinOK')) call delete('XstdinOK') endfunc func Test_set_background() let background_saved = &background set background& call assert_equal('light', &background) set background=dark call assert_equal('dark', &background) let &background = background_saved endfunc func Test_set_balloondelay() CheckOption balloondelay let balloondelay_saved = &balloondelay " Check if the default value is identical to that described in the manual. set balloondelay& call assert_equal(600, &balloondelay) " Edge cases " XXX This fact should be hidden so that people won't be tempted to write " plugin/TimeMachine.vim. TODO Add reasonable range checks to the source " code. set balloondelay=-1 call assert_equal(-1, &balloondelay) " Though it's possible to interpret the zero delay to be 'as soon as " possible' or even 'indefinite', its actual meaning depends on the GUI " toolkit in use after all. set balloondelay=0 call assert_equal(0, &balloondelay) set balloondelay=1 call assert_equal(1, &balloondelay) " Since p_bdelay is of type long currently, the upper bound can be " impractically huge and machine-dependent. Practically, it's sufficient " to check if balloondelay works with 0x7fffffff (32 bits) for now. set balloondelay=2147483647 call assert_equal(2147483647, &balloondelay) let &balloondelay = balloondelay_saved endfunc func Test_set_ballooneval() CheckOption ballooneval let ballooneval_saved = &ballooneval set ballooneval& call assert_equal(0, &ballooneval) set ballooneval call assert_notequal(0, &ballooneval) set noballooneval call assert_equal(0, &ballooneval) let &ballooneval = ballooneval_saved endfunc func Test_set_balloonexpr() CheckOption balloonexpr let balloonexpr_saved = &balloonexpr " Default value set balloonexpr& call assert_equal('', &balloonexpr) " User-defined function new func MyBalloonExpr() return 'Cursor is at line ' . v:beval_lnum . \', column ' . v:beval_col . \ ' of file ' . bufname(v:beval_bufnr) . \ ' on word "' . v:beval_text . '"' . \ ' in window ' . v:beval_winid . ' (#' . v:beval_winnr . ')' endfunc setl balloonexpr=MyBalloonExpr() setl ballooneval call assert_equal('MyBalloonExpr()', &balloonexpr) " TODO Read non-empty text, place the pointer at a character of a word, " and check if the content of the balloon is the same as what is expected. " Also, check if textlock works as expected. setl balloonexpr& call assert_equal('', &balloonexpr) delfunc MyBalloonExpr " Using a script-local function func s:NewBalloonExpr() endfunc set balloonexpr=s:NewBalloonExpr() call assert_equal(expand('<SID>') .. 'NewBalloonExpr()', &balloonexpr) set balloonexpr=<SID>NewBalloonExpr() call assert_equal(expand('<SID>') .. 'NewBalloonExpr()', &balloonexpr) delfunc s:NewBalloonExpr bwipe! " Multiline support if has('balloon_multiline') " Multiline balloon using NL new func MyBalloonFuncForMultilineUsingNL() return "Multiline\nSupported\nBalloon\nusing NL" endfunc setl balloonexpr=MyBalloonFuncForMultilineUsingNL() setl ballooneval call assert_equal('MyBalloonFuncForMultilineUsingNL()', &balloonexpr) " TODO Read non-empty text, place the pointer at a character of a word, " and check if the content of the balloon is the same as what is " expected. Also, check if textlock works as expected. setl balloonexpr& delfunc MyBalloonFuncForMultilineUsingNL bwipe! " Multiline balloon using List new func MyBalloonFuncForMultilineUsingList() return [ 'Multiline', 'Supported', 'Balloon', 'using List' ] endfunc setl balloonexpr=MyBalloonFuncForMultilineUsingList() setl ballooneval call assert_equal('MyBalloonFuncForMultilineUsingList()', &balloonexpr) " TODO Read non-empty text, place the pointer at a character of a word, " and check if the content of the balloon is the same as what is " expected. Also, check if textlock works as expected. setl balloonexpr& delfunc MyBalloonFuncForMultilineUsingList bwipe! endif let &balloonexpr = balloonexpr_saved endfunc " Invalid arguments are tested with test_options in conjunction with segfaults " caused by them (Patch 8.0.0357, 24922ec233). func Test_set_guicursor() let guicursor_saved = &guicursor let default = [ \ "n-v-c:block-Cursor/lCursor", \ "ve:ver35-Cursor", \ "o:hor50-Cursor", \ "i-ci:ver25-Cursor/lCursor", \ "r-cr:hor20-Cursor/lCursor", \ "sm:block-Cursor-blinkwait175-blinkoff150-blinkon175" \ ] " Default Value set guicursor& call assert_equal(join(default, ','), &guicursor) " Argument List Example 1 let opt_list = copy(default) let opt_list[0] = "n-c-v:block-nCursor" exec "set guicursor=" . join(opt_list, ',') call assert_equal(join(opt_list, ','), &guicursor) unlet opt_list " Argument List Example 2 let opt_list = copy(default) let opt_list[3] = "i-ci:ver30-iCursor-blinkwait300-blinkon200-blinkoff150" exec "set guicursor=" . join(opt_list, ',') call assert_equal(join(opt_list, ','), &guicursor) unlet opt_list " 'a' Mode set guicursor& let &guicursor .= ',a:blinkon0' call assert_equal(join(default, ',') . ",a:blinkon0", &guicursor) let &guicursor = guicursor_saved endfunc func Test_set_guifont_errors() if has('win32') " Invalid font names are accepted in GTK GUI call assert_fails('set guifont=xa1bc23d7f', 'E596:') endif " This only works if 'renderoptions' exists and does not work for Windows XP " and older. if exists('+renderoptions') && windowsversion() !~ '^[345]\.' " doing this four times used to cause a crash set renderoptions=type:directx for i in range(5) set guifont= endfor set renderoptions= for i in range(5) set guifont= endfor endif endfunc func Test_set_guifont() CheckX11BasedGui let guifont_saved = &guifont if has('xfontset') " Prevent 'guifontset' from canceling 'guifont'. let guifontset_saved = &guifontset set guifontset= endif if has('gui_motif') " Non-empty font list with invalid font names. " " This test is twofold: (1) It checks if the command fails as expected " when there are no loadable fonts found in the list. (2) It checks if " 'guifont' remains the same after the command loads none of the fonts " listed. let flist = &guifont call assert_fails('set guifont=-notexist1-*,-notexist2-*') call assert_equal(flist, &guifont) " Non-empty font list with a valid font name. Should pick up the first " valid font. set guifont=-notexist1-*,fixed,-notexist2-* let pat = '\(fixed\)\|\(\c-Misc-Fixed-Medium-R-SemiCondensed--13-120-75-75-C-60-ISO8859-1\)' call assert_match(pat, getfontname()) " Empty list. Should fallback to the built-in default. set guifont= let pat = '\(7x13\)\|\(\c-Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO8859-1\)' call assert_match(pat, getfontname()) elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3') " For GTK, what we refer to as 'font names' in our manual are actually " 'initial font patterns'. A valid font which matches the 'canonical font " pattern' constructed from a given 'initial pattern' is to be looked up " and loaded. That explains why the GTK GUIs appear to accept 'invalid " font names'. " " Non-empty list. Should always pick up the first element, no matter how " strange it is, as explained above. set guifont=(´・ω・`)\ 12,Courier\ 12 call assert_equal('(´・ω・`) 12', getfontname()) " Empty list. Should fallback to the built-in default. set guifont= call assert_equal('Monospace 10', getfontname()) endif if has('xfontset') let &guifontset = guifontset_saved endif let &guifont = guifont_saved endfunc func Test_set_guifontset() CheckFeature xfontset let skipped = '' call assert_fails('set guifontset=*', 'E597:') let ctype_saved = v:ctype " First, since XCreateFontSet(3) is very sensitive to locale, fonts must " be chosen meticulously. let font_head = '-misc-fixed-medium-r-normal--14' let font_aw70 = font_head . '-130-75-75-c-70' let font_aw140 = font_head . '-130-75-75-c-140' let font_jisx0201 = font_aw70 . '-jisx0201.1976-0' let font_jisx0208 = font_aw140 . '-jisx0208.1983-0' let full_XLFDs = join([ font_jisx0208, font_jisx0201 ], ',') let short_XLFDs = join([ font_aw140, font_aw70 ], ',') let singleton = font_head . '-*' let aliases = 'k14,r14' " Second, among 'locales', look up such a locale that gets 'set " guifontset=' to work successfully with every fontset specified with " 'fontsets'. let locales = [ 'ja_JP.UTF-8', 'ja_JP.eucJP', 'ja_JP.SJIS' ] let fontsets = [ full_XLFDs, short_XLFDs, singleton, aliases ] let feasible = 0 for locale in locales try exec 'language ctype' locale catch /^Vim\%((\a\+)\)\=:E197/ continue endtry let done = 0 for fontset in fontsets try exec 'set guifontset=' . fontset catch /^Vim\%((\a\+)\)\=:E\%(250\|252\|234\|597\|598\)/ break endtry let done += 1 endfor if done == len(fontsets) let feasible = 1 break endif endfor " Third, give a set of tests if it is found feasible. if !feasible let skipped = g:not_hosted else " N.B. 'v:ctype' has already been set to an appropriate value in the " previous loop. for fontset in fontsets exec 'set guifontset=' . fontset call assert_equal(fontset, &guifontset) endfor endif " Finally, restore ctype. exec 'language ctype' ctype_saved if !empty(skipped) throw skipped endif endfunc func Test_set_guifontwide() CheckX11BasedGui call assert_fails('set guifontwide=*', 'E533:') if has('gui_gtk') let guifont_saved = &guifont let guifontwide_saved = &guifontwide let fc_match = exepath('fc-match') if empty(fc_match) let skipped = g:not_hosted else let &guifont = system('fc-match -f "%{family[0]} %{size}" monospace:size=10:lang=en') let wide = system('fc-match -f "%{family[0]} %{size}" monospace:size=10:lang=ja') exec 'set guifontwide=' . fnameescape(wide) call assert_equal(wide, &guifontwide) endif let &guifontwide = guifontwide_saved let &guifont = guifont_saved elseif has('gui_motif') " guifontwide is premised upon the xfontset feature. if !has('xfontset') let skipped = g:not_supported . 'xfontset' else let encoding_saved = &encoding let guifont_saved = &guifont let guifontset_saved = &guifontset let guifontwide_saved = &guifontwide let nfont = '-misc-fixed-medium-r-normal-*-18-120-100-100-c-90-iso10646-1' let wfont = '-misc-fixed-medium-r-normal-*-18-120-100-100-c-180-iso10646-1' set encoding=utf-8 " Case 1: guifontset is empty set guifontset= " Case 1-1: Automatic selection set guifontwide= exec 'set guifont=' . nfont call assert_equal(wfont, &guifontwide) " Case 1-2: Manual selection exec 'set guifontwide=' . wfont exec 'set guifont=' . nfont call assert_equal(wfont, &guifontwide) " Case 2: guifontset is invalid try set guifontset=-*-notexist-* call assert_report("'set guifontset=-*-notexist-*' should have failed") catch call assert_exception('E598:') endtry " Case 2-1: Automatic selection set guifontwide= exec 'set guifont=' . nfont call assert_equal(wfont, &guifontwide) " Case 2-2: Manual selection exec 'set guifontwide=' . wfont exec 'set guifont=' . nfont call assert_equal(wfont, &guifontwide) let &guifontwide = guifontwide_saved let &guifontset = guifontset_saved let &guifont = guifont_saved let &encoding = encoding_saved endif endif endfunc func Test_expand_guifont() if has('gui_win32') let guifont_saved = &guifont let guifontwide_saved = &guifontwide " Test recalling existing option, and suggesting current font size set guifont=Courier\ New:h11:cANSI call assert_equal('Courier\ New:h11:cANSI', getcompletion('set guifont=', 'cmdline')[0]) call assert_equal('h11', getcompletion('set guifont=Lucida\ Console:', 'cmdline')[0]) " Test auto-completion working for font names call assert_equal(['Courier\ New'], getcompletion('set guifont=Couri*ew$', 'cmdline')) call assert_equal(['Courier\ New'], getcompletion('set guifontwide=Couri*ew$', 'cmdline')) " Make sure non-monospace fonts are filtered out call assert_equal([], getcompletion('set guifont=Arial', 'cmdline')) call assert_equal([], getcompletion('set guifontwide=Arial', 'cmdline')) " Test auto-completion working for font options call assert_notequal(-1, index(getcompletion('set guifont=Courier\ New:', 'cmdline'), 'b')) call assert_equal(['cDEFAULT'], getcompletion('set guifont=Courier\ New:cD*T', 'cmdline')) call assert_equal(['qCLEARTYPE'], getcompletion('set guifont=Courier\ New:qC*TYPE', 'cmdline')) let &guifontwide = guifontwide_saved let &guifont = guifont_saved elseif has('gui_gtk') let guifont_saved = &guifont let guifontwide_saved = &guifontwide " Test recalling default and existing option set guifont= call assert_equal('Monospace\ 10', getcompletion('set guifont=', 'cmdline')[0]) set guifont=Monospace\ 9 call assert_equal('Monospace\ 9', getcompletion('set guifont=', 'cmdline')[0]) " Test auto-completion working for font names call assert_equal(['Monospace'], getcompletion('set guifont=Mono*pace$', 'cmdline')) call assert_equal(['Monospace'], getcompletion('set guifontwide=Mono*pace$', 'cmdline')) " Make sure non-monospace fonts are filtered out only in 'guifont' call assert_equal([], getcompletion('set guifont=Sans$', 'cmdline')) call assert_equal(['Sans'], getcompletion('set guifontwide=Sans$', 'cmdline')) let &guifontwide = guifontwide_saved let &guifont = guifont_saved else call assert_equal([], getcompletion('set guifont=', 'cmdline')) endif endfunc func Test_set_guiligatures() CheckX11BasedGui if has('gui_gtk') || has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3') || has('win32') " Try correct value set guiligatures=<>=ab call assert_equal("<>=ab", &guiligatures) " Try to throw error try set guiligatures=<>=šab call assert_report("'set guiligatures=<>=šab should have failed") catch call assert_exception('E1243:') endtry endif endfunc func Test_set_guiheadroom() CheckX11BasedGui " Since this script is to be read together with '-U NONE', the default " value must be preserved. call assert_equal(50, &guiheadroom) endfunc func Test_set_guioptions() let guioptions_saved = &guioptions let duration = '200m' if has('win32') " Default Value set guioptions& call assert_equal('egmrLtT', &guioptions) else " Default Value set guioptions& call assert_equal('aegimrLtT', &guioptions) " To activate scrollbars of type 'L' or 'R'. wincmd v redraw! " Remove all default GUI ornaments set guioptions-=T exec 'sleep' . duration call assert_equal('aegimrLt', &guioptions) set guioptions-=t exec 'sleep' . duration call assert_equal('aegimrL', &guioptions) set guioptions-=L exec 'sleep' . duration call assert_equal('aegimr', &guioptions) set guioptions-=r exec 'sleep' . duration call assert_equal('aegim', &guioptions) set guioptions-=m exec 'sleep' . duration call assert_equal('aegi', &guioptions) " Try non-default GUI ornaments set guioptions+=l exec 'sleep' . duration call assert_equal('aegil', &guioptions) set guioptions-=l exec 'sleep' . duration call assert_equal('aegi', &guioptions) set guioptions+=R exec 'sleep' . duration call assert_equal('aegiR', &guioptions) set guioptions-=R exec 'sleep' . duration call assert_equal('aegi', &guioptions) set guioptions+=b exec 'sleep' . duration call assert_equal('aegib', &guioptions) set guioptions+=h exec 'sleep' . duration call assert_equal('aegibh', &guioptions) set guioptions-=h exec 'sleep' . duration call assert_equal('aegib', &guioptions) set guioptions-=b exec 'sleep' . duration call assert_equal('aegi', &guioptions) set guioptions+=v exec 'sleep' . duration call assert_equal('aegiv', &guioptions) set guioptions-=v exec 'sleep' . duration call assert_equal('aegi', &guioptions) if has('gui_motif') set guioptions+=F exec 'sleep' . duration call assert_equal('aegiF', &guioptions) set guioptions-=F exec 'sleep' . duration call assert_equal('aegi', &guioptions) endif if has('gui_gtk3') set guioptions+=d exec 'sleep' . duration call assert_equal('aegid', &guioptions) set guioptions-=d exec 'sleep' . duration call assert_equal('aegi', &guioptions) endif " Restore GUI ornaments to the default state. set guioptions+=m exec 'sleep' . duration call assert_equal('aegim', &guioptions) set guioptions+=r exec 'sleep' . duration call assert_equal('aegimr', &guioptions) set guioptions+=L exec 'sleep' . duration call assert_equal('aegimrL', &guioptions) set guioptions+=t exec 'sleep' . duration call assert_equal('aegimrLt', &guioptions) set guioptions+=T exec 'sleep' . duration call assert_equal("aegimrLtT", &guioptions) wincmd o redraw! endif let &guioptions = guioptions_saved endfunc func Test_scrollbars() " this test sometimes fails on CI let g:test_is_flaky = 1 " buffer with 200 lines new call setline(1, repeat(['one', 'two'], 100)) set guioptions+=rlb " scroll to move line 11 at top, moves the cursor there let args = #{which: 'left', value: 10, dragging: 0} call test_gui_event('scrollbar', args) redraw call assert_equal(1, winline()) call assert_equal(11, line('.')) " FIXME: This test should also pass with Motif and 24 lines if &lines > 24 || !has('gui_motif') " scroll to move line 1 at top, cursor stays in line 11 let args = #{which: 'right', value: 0, dragging: 0} call test_gui_event('scrollbar', args) redraw call assert_equal(11, winline()) call assert_equal(11, line('.')) endif set nowrap call setline(11, repeat('x', 150)) redraw call assert_equal(1, wincol()) set number redraw call assert_equal(5, wincol()) set nonumber redraw call assert_equal(1, col('.')) " scroll to character 11, cursor is moved let args = #{which: 'hor', value: 10, dragging: 0} call test_gui_event('scrollbar', args) redraw call assert_equal(1, wincol()) set number redraw call assert_equal(5, wincol()) set nonumber redraw call assert_equal(11, col('.')) " Invalid arguments call assert_false(test_gui_event('scrollbar', {})) call assert_false(test_gui_event('scrollbar', #{value: 10, dragging: 0})) call assert_false(test_gui_event('scrollbar', #{which: 'hor', dragging: 0})) call assert_false(test_gui_event('scrollbar', #{which: 'hor', value: 1})) call assert_fails("call test_gui_event('scrollbar', #{which: 'a', value: 1, dragging: 0})", 'E475:') set guioptions& set wrap& bwipe! endfunc func Test_menu() CheckFeature quickfix " Check Help menu exists let help_menu = execute('menu Help') call assert_match('Overview', help_menu) " Check Help menu works emenu Help.Overview call assert_equal('help', &buftype) close " Check deleting menu doesn't cause trouble. aunmenu Help if exists(':tlmenu') tlunmenu Help endif call assert_fails('menu Help', 'E329:') endfunc func Test_set_guipty() let guipty_saved = &guipty " Default Value set guipty& call assert_equal(1, &guipty) set noguipty call assert_equal(0, &guipty) let &guipty = guipty_saved endfunc func Test_encoding_conversion() " GTK supports conversion between 'encoding' and "utf-8" CheckFeature gui_gtk let encoding_saved = &encoding set encoding=latin1 " would be nice if we could take a screenshot intro " sets the window title edit SomeFile let &encoding = encoding_saved endfunc func Test_shell_command() new r !echo hello call assert_equal('hello', substitute(getline(2), '\W', '', 'g')) bwipe! endfunc func Test_syntax_colortest() runtime syntax/colortest.vim redraw! sleep 200m bwipe! endfunc func Test_set_term() " It's enough to check the current value since setting 'term' to anything " other than builtin_gui makes no sense at all. call assert_equal('builtin_gui', &term) call assert_fails('set term=xterm', 'E530:') endfunc func Test_windowid_variable() if (g:x11_based_gui && empty($WAYLAND_DISPLAY)) || has('win32') call assert_true(v:windowid > 0) else call assert_equal(0, v:windowid) endif endfunc " Test "vim -g" and also the GUIEnter autocommand. func Test_gui_dash_g() let cmd = GetVimCommand('Xscriptgui') call writefile([""], "Xtestgui", 'D') let lines =<< trim END au GUIEnter * call writefile(["insertmode: " . &insertmode], "Xtestgui") au GUIEnter * qall END call writefile(lines, 'Xscriptgui', 'D') call system(cmd . ' -g') call WaitForAssert({-> assert_equal(['insertmode: 0'], readfile('Xtestgui'))}) endfunc " Test "vim -7" and also the GUIEnter autocommand. func Test_gui_dash_y() let cmd = GetVimCommand('Xscriptgui') call writefile([""], "Xtestgui", 'D') let lines =<< trim END au GUIEnter * call writefile(["insertmode: " . &insertmode], "Xtestgui") au GUIEnter * qall END call writefile(lines, 'Xscriptgui', 'D') call system(cmd . ' -y') call WaitForAssert({-> assert_equal(['insertmode: 1'], readfile('Xtestgui'))}) endfunc " Test for "!" option in 'guioptions'. Use a terminal for running external " commands func Test_gui_run_cmd_in_terminal() CheckFeature terminal let save_guioptions = &guioptions set guioptions+=! if has('win32') let cmd = 'type' else " assume all the other systems have a cat command let cmd = 'cat' endif exe "silent !" . cmd . " test_gui.vim" " TODO: how to check that the command ran in a separate terminal? " Maybe check for $TERM (dumb vs xterm) in the spawned shell? let &guioptions = save_guioptions endfunc func Test_gui_recursive_mapping() nmap ' <C-W> nmap <C-W>a :let didit = 1<CR> call feedkeys("'a", 'xt') call assert_equal(1, didit) nunmap ' nunmap <C-W>a endfunc " Test GUI mouse events func Test_gui_mouse_event() " Low level input isn't 100% reliable let g:test_is_flaky = 1 set mousemodel=extend call test_override('no_query_mouse', 1) new call setline(1, ['one two three', 'four five six']) call cursor(1, 1) redraw! " place the cursor using left click and release in normal mode let args = #{button: 0, row: 2, col: 4, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 eval 'mouse'->test_gui_event(args) call feedkeys("\<Esc>", 'Lx!') call assert_equal([0, 2, 4, 0], getpos('.')) " select and yank a word let @" = '' let args = #{button: 0, row: 1, col: 9, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.multiclick = 1 call test_gui_event('mouse', args) let args.button = 3 let args.multiclick = 0 call test_gui_event('mouse', args) call feedkeys("y", 'Lx!') call assert_equal('three', @") " create visual selection using right click let @" = '' let args = #{button: 0, row: 2, col: 6, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) let args = #{button: 2, row: 2, col: 13, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("y", 'Lx!') call assert_equal('five six', @") " paste using middle mouse button let @* = 'abc ' call feedkeys('""', 'Lx!') let args = #{button: 1, row: 1, col: 9, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("\<Esc>", 'Lx!') call assert_equal(['one two abc three', 'four five six'], getline(1, '$')) " extend visual selection using right click in visual mode let @" = '' call cursor(1, 1) call feedkeys('v', 'Lx!') let args = #{button: 2, row: 1, col: 17, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("y", 'Lx!') call assert_equal('one two abc three', @") " extend visual selection using mouse drag let @" = '' call cursor(1, 1) let args = #{button: 0, row: 2, col: 1, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args = #{button: 0x43, row: 2, col: 9, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 0x3 call test_gui_event('mouse', args) call feedkeys("y", 'Lx!') call assert_equal('four five', @") " select text by moving the mouse let @" = '' call cursor(1, 1) redraw! let args = #{button: 0, row: 1, col: 4, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 0x700 let args.col = 9 call test_gui_event('mouse', args) let args.col = 13 call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("y", 'Lx!') call assert_equal(' two abc t', @") " Using mouse in insert mode call cursor(1, 1) call feedkeys('i', 't') let args = #{button: 0, row: 2, col: 11, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("po\<Esc>", 'Lx!') call assert_equal(['one two abc three', 'four five posix'], getline(1, '$')) %d _ set scrolloff=0 call setline(1, range(1, 100)) " scroll up let args = #{button: 0x200, row: 2, col: 1, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) call test_gui_event('mouse', args) call test_gui_event('mouse', args) call feedkeys("H", 'Lx!') call assert_equal(10, line('.')) " scroll down let args = #{button: 0x100, row: 2, col: 1, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) call test_gui_event('mouse', args) call feedkeys("H", 'Lx!') call assert_equal(4, line('.')) set scrolloff& %d _ set nowrap call setline(1, range(10)->join('')->repeat(10)) " scroll left let args = #{button: 0x500, row: 1, col: 5, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.col = 10 call test_gui_event('mouse', args) let args.col = 15 call test_gui_event('mouse', args) call feedkeys('g0', 'Lx!') call assert_equal(19, col('.')) " scroll right let args = #{button: 0x600, row: 1, col: 15, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.col = 10 call test_gui_event('mouse', args) call feedkeys('g0', 'Lx!') call assert_equal(7, col('.')) set wrap& %d _ call setline(1, repeat([repeat('a', 60)], 10)) " record various mouse events let mouseEventNames = [ \ 'LeftMouse', 'LeftRelease', '2-LeftMouse', '3-LeftMouse', \ 'S-LeftMouse', 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse', \ 'MiddleRelease', '2-MiddleMouse', '3-MiddleMouse', \ 'S-MiddleMouse', 'A-MiddleMouse', 'C-MiddleMouse', \ 'RightMouse', 'RightRelease', '2-RightMouse', \ '3-RightMouse', 'S-RightMouse', 'A-RightMouse', 'C-RightMouse', \ 'X1Mouse', 'S-X1Mouse', 'A-X1Mouse', 'C-X1Mouse', 'X2Mouse', \ 'S-X2Mouse', 'A-X2Mouse', 'C-X2Mouse' \ ] let mouseEventCodes = map(copy(mouseEventNames), "'<' .. v:val .. '>'") let g:events = [] for e in mouseEventCodes exe 'nnoremap ' .. e .. ' <Cmd>call add(g:events, "' .. \ substitute(e, '[<>]', '', 'g') .. '")<CR>' endfor " Test various mouse buttons (0 - Left, 1 - Middle, 2 - Right, 0x300 - X1, " 0x300- X2) for button in [0, 1, 2, 0x300, 0x400] " Single click let args = #{button: button, row: 2, col: 5, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) " Double/Triple click is supported by only the Left/Middle/Right mouse " buttons if button <= 2 " Double Click let args.button = button call test_gui_event('mouse', args) let args.multiclick = 1 call test_gui_event('mouse', args) let args.button = 3 let args.multiclick = 0 call test_gui_event('mouse', args) " Triple Click let args.button = button call test_gui_event('mouse', args) let args.multiclick = 1 call test_gui_event('mouse', args) call test_gui_event('mouse', args) let args.button = 3 let args.multiclick = 0 call test_gui_event('mouse', args) endif " Shift click let args = #{button: button, row: 3, col: 7, multiclick: 0, modifiers: 4} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) " Alt click let args.button = button let args.modifiers = 8 call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) " Ctrl click let args.button = button let args.modifiers = 16 call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("\<Esc>", 'Lx!') endfor call assert_equal(['LeftMouse', 'LeftRelease', 'LeftMouse', '2-LeftMouse', \ 'LeftMouse', '2-LeftMouse', '3-LeftMouse', 'S-LeftMouse', \ 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse', 'MiddleRelease', \ 'MiddleMouse', '2-MiddleMouse', 'MiddleMouse', '2-MiddleMouse', \ '3-MiddleMouse', 'S-MiddleMouse', 'A-MiddleMouse', 'C-MiddleMouse', \ 'RightMouse', 'RightRelease', 'RightMouse', '2-RightMouse', \ 'RightMouse', '2-RightMouse', '3-RightMouse', 'S-RightMouse', \ 'A-RightMouse', 'C-RightMouse', 'X1Mouse', 'S-X1Mouse', 'A-X1Mouse', \ 'C-X1Mouse', 'X2Mouse', 'S-X2Mouse', 'A-X2Mouse', 'C-X2Mouse'], \ g:events) for e in mouseEventCodes exe 'nunmap ' .. e endfor " modeless selection set mouse= let save_guioptions = &guioptions set guioptions+=A %d _ call setline(1, ['one two three', 'four five sixteen']) call cursor(1, 1) redraw! " Double click should select the word and copy it to clipboard let @* = '' let args = #{button: 0, row: 2, col: 11, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.multiclick = 1 call test_gui_event('mouse', args) let args.button = 3 let args.multiclick = 0 call test_gui_event('mouse', args) call feedkeys("\<Esc>", 'Lx!') call assert_equal([0, 1, 1, 0], getpos('.')) call assert_equal('sixteen', @*) " Right click should extend the selection from cursor call cursor(1, 6) redraw! let @* = '' let args = #{button: 2, row: 1, col: 11, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("\<Esc>", 'Lx!') call assert_equal([0, 1, 6, 0], getpos('.')) call assert_equal('wo thr', @*) " Middle click should paste the clipboard contents call cursor(2, 1) redraw! let args = #{button: 1, row: 1, col: 11, multiclick: 0, modifiers: 0} call test_gui_event('mouse', args) let args.button = 3 call test_gui_event('mouse', args) call feedkeys("\<Esc>", 'Lx!') call assert_equal([0, 2, 7, 0], getpos('.')) call assert_equal('wo thrfour five sixteen', getline(2)) set mouse& let &guioptions = save_guioptions bw! call test_override('no_query_mouse', 0) set mousemodel& endfunc " Test invalid parameters for test_gui_event() func Test_gui_event_mouse_fails() call test_override('no_query_mouse', 1) new call setline(1, ['one two three', 'four five six']) set mousemodel=extend let args = #{row: 2, col: 4, multiclick: 0, modifiers: 0} call assert_false(test_gui_event('mouse', args)) let args = #{button: 0, col: 4, multiclick: 0, modifiers: 0} call assert_false(test_gui_event('mouse', args)) let args = #{button: 0, row: 2, multiclick: 0, modifiers: 0} call assert_false(test_gui_event('mouse', args)) let args = #{button: 0, row: 2, col: 4, modifiers: 0} call assert_false(test_gui_event('mouse', args)) let args = #{button: 0, row: 2, col: 4, multiclick: 0} call assert_false(test_gui_event('mouse', args)) " Error cases for test_gui_event() call assert_fails("call test_gui_event('a1b2c3', args)", 'E475:') call assert_fails("call test_gui_event([], args)", 'E1174:') call assert_fails("call test_gui_event('abc', [])", 'E1206:') call assert_fails("call test_gui_event(test_null_string(), {})", 'E475:') call assert_false(test_gui_event('mouse', test_null_dict())) bw! call test_override('no_query_mouse', 0) set mousemodel& endfunc " Move the mouse to the top-left in preparation for mouse events func PrepareForMouseEvent(args) call extend(a:args, #{row: 1, col: 1}) call test_gui_event('mouse', a:args) let g:eventlist = [] call feedkeys('', 'Lx!') " Wait a bit for the event. I may not come if the mouse didn't move, wait up " to 100 msec. for n in range(10) if len(g:eventlist) > 0 break endif sleep 10m endfor let g:eventlist = [] endfunc func MouseWasMoved() let pos = getmousepos() call add(g:eventlist, #{row: pos.screenrow, col: pos.screencol}) endfunc func Test_gui_mouse_move_event() let args = #{move: 1, button: 0, multiclick: 0, modifiers: 0} " by default, no mouse move events are generated set mousemev& call assert_false(&mousemev) let g:eventlist = [] nnoremap <special> <silent> <MouseMove> :call MouseWasMoved()<CR> " start at mouse pos (1,1), clear counter call PrepareForMouseEvent(args) call extend(args, #{row: 3, col: 30, cell: v:true}) call test_gui_event('mouse', args) call feedkeys('', 'Lx!') call extend(args, #{row: 10, col: 30, cell: v:true}) call test_gui_event('mouse', args) call feedkeys('', 'Lx!') " no events since 'mousemev' is off call assert_equal([], g:eventlist) " turn on mouse events and try the same thing set mousemev call PrepareForMouseEvent(args) call extend(args, #{row: 3, col: 30, cell: v:true}) call test_gui_event('mouse', args) call feedkeys('', 'Lx!') call extend(args, #{row: 10, col: 30, cell: v:true}) call test_gui_event('mouse', args) call feedkeys('', 'Lx!') " FIXME: on MS-Windows we get a stray event first if has('win32') && len(g:eventlist) == 3 let g:eventlist = g:eventlist[1 : ] endif call assert_equal([#{row: 3, col: 30}, #{row: 10, col: 30}], g:eventlist) " wiggle the mouse around within a screen cell, shouldn't trigger events call extend(args, #{cell: v:false}) call PrepareForMouseEvent(args) call extend(args, #{row: 1, col: 2, cell: v:false}) call test_gui_event('mouse', args) call feedkeys('', 'Lx!') call extend(args, #{row: 2, col: 2, cell: v:false}) call test_gui_event('mouse', args) call feedkeys('', 'Lx!') call extend(args, #{row: 2, col: 1, cell: v:false}) call test_gui_event('mouse', args) call feedkeys('', 'Lx!') call assert_equal([], g:eventlist) unlet g:eventlist unmap <MouseMove> set mousemev& endfunc " Test for 'guitablabel' and 'guitabtooltip' options func TestGuiTabLabel() call add(g:TabLabels, v:lnum + 100) let bufnrlist = tabpagebuflist(v:lnum) return bufname(bufnrlist[tabpagewinnr(v:lnum) - 1]) endfunc func TestGuiTabToolTip() call add(g:TabToolTips, v:lnum + 200) let bufnrlist = tabpagebuflist(v:lnum) return bufname(bufnrlist[tabpagewinnr(v:lnum) - 1]) endfunc func Test_gui_tablabel_tooltip() %bw! " Removing the tabline at the end of this test, reduces the window height by " one. Save and restore it after the test. let save_lines = &lines edit one set modified tabnew two set modified tabnew three set modified let g:TabLabels = [] set guitablabel=%{TestGuiTabLabel()} call test_override('starting', 1) redrawtabline call test_override('starting', 0) call assert_true(index(g:TabLabels, 101) != -1) call assert_true(index(g:TabLabels, 102) != -1) call assert_true(index(g:TabLabels, 103) != -1) set guitablabel& unlet g:TabLabels if has('gui_gtk') " Only on GTK+, the tooltip function is called even if the mouse is not " on the tabline. on Win32 and Motif, the tooltip function is called only " when the mouse pointer is over the tabline. let g:TabToolTips = [] set guitabtooltip=%{TestGuiTabToolTip()} call test_override('starting', 1) redrawtabline call test_override('starting', 0) call assert_true(index(g:TabToolTips, 201) != -1) call assert_true(index(g:TabToolTips, 202) != -1) call assert_true(index(g:TabToolTips, 203) != -1) set guitabtooltip& unlet g:TabToolTips endif %bw! let &lines = save_lines endfunc " Test for dropping files into a window in GUI func DropFilesInCmdLine() call feedkeys(":\"", 'L') let d = #{files: ['a.c', 'b.c'], row: &lines, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call feedkeys("\<CR>", 'L') endfunc func Test_gui_drop_files() CheckFeature drop_file %bw! %argdelete let d = #{files: [], row: 1, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call assert_equal([], argv()) let d = #{files: [1, 2], row: 1, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call assert_equal([], argv()) let d = #{files: ['a.c', 'b.c'], row: 1, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call assert_equal(['a.c', 'b.c'], argv()) %bw! %argdelete let d = #{files: [], row: 1, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call assert_equal([], argv()) %bw! " if the buffer in the window is modified, then the file should be opened in " a new window set modified let d = #{files: ['x.c', 'y.c'], row: 1, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call assert_equal(['x.c', 'y.c'], argv()) call assert_equal(2, winnr('$')) call assert_equal('x.c', bufname(winbufnr(1))) %bw! %argdelete " if Ctrl is pressed, then the file should be opened in a new window let d = #{files: ['s.py', 't.py'], row: 1, col: 1, modifiers: 0x10} eval 'dropfiles'->test_gui_event(d) call assert_equal(['s.py', 't.py'], argv()) call assert_equal(2, winnr('$')) call assert_equal('s.py', bufname(winbufnr(1))) %bw! %argdelete " drop the files in a non-current window belowright new let d = #{files: ['a.py', 'b.py'], row: 1, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call assert_equal(['a.py', 'b.py'], argv()) call assert_equal(2, winnr('$')) call assert_equal(1, winnr()) call assert_equal('a.py', bufname(winbufnr(1))) %bw! %argdelete " pressing shift when dropping files should change directory let save_cwd = getcwd() call mkdir('Xdropdir1', 'R') call writefile([], 'Xdropdir1/Xfile1') call writefile([], 'Xdropdir1/Xfile2') let d = #{files: ['Xdropdir1/Xfile1', 'Xdropdir1/Xfile2'], row: 1, col: 1, \ modifiers: 0x4} call test_gui_event('dropfiles', d) call assert_equal('Xdropdir1', fnamemodify(getcwd(), ':t')) call assert_equal('Xfile1', @%) call chdir(save_cwd) " pressing shift when dropping directory and files should change directory let d = #{files: ['Xdropdir1', 'Xdropdir1/Xfile2'], row: 1, col: 1, modifiers: 0x4} call test_gui_event('dropfiles', d) call assert_equal('Xdropdir1', fnamemodify(getcwd(), ':t')) call assert_equal('Xdropdir1', fnamemodify(@%, ':t')) call chdir(save_cwd) %bw! %argdelete " dropping a directory should edit it let d = #{files: ['Xdropdir1'], row: 1, col: 1, modifiers: 0} call test_gui_event('dropfiles', d) call assert_equal('Xdropdir1', @%) %bw! %argdelete " dropping only a directory name with Shift should ignore it let d = #{files: ['Xdropdir1'], row: 1, col: 1, modifiers: 0x4} call test_gui_event('dropfiles', d) call assert_equal('', @%) %bw! %argdelete " drop files in the command line. The GUI drop files adds the file names to " the low level input buffer. So need to use a cmdline map and feedkeys() " with 'Lx!' to process it in this function itself. " This sometimes fails, e.g. when using valgrind. let g:test_is_flaky = 1 cnoremap <expr> <buffer> <F4> DropFilesInCmdLine() call feedkeys(":\"\<F4>\<CR>", 'xt') call feedkeys('k', 'Lx!') call assert_equal('"a.c b.c', @:) cunmap <buffer> <F4> " Invalid arguments call assert_false(test_gui_event("dropfiles", {})) let d = #{row: 1, col: 1, modifiers: 0} call assert_false(test_gui_event("dropfiles", d)) let d = #{files: 1, row: 1, col: 1, modifiers: 0} call assert_false(test_gui_event("dropfiles", d)) let d = #{files: test_null_list(), row: 1, col: 1, modifiers: 0} call assert_false(test_gui_event("dropfiles", d)) let d = #{files: [test_null_string()], row: 1, col: 1, modifiers: 0} call assert_true(test_gui_event("dropfiles", d)) endfunc " Test for generating a GUI tabline event to select a tab page func Test_gui_tabline_event() %bw! edit Xfile1 tabedit Xfile2 tabedit Xfile3 tabfirst call assert_equal(v:true, test_gui_event('tabline', #{tabnr: 2})) call feedkeys("y", "Lx!") call assert_equal(2, tabpagenr()) call assert_equal(v:true, test_gui_event('tabline', #{tabnr: 3})) call feedkeys("y", "Lx!") call assert_equal(3, tabpagenr()) call assert_equal(v:false, 'tabline'->test_gui_event(#{tabnr: 3})) " From the cmdline window, tabline event should not be handled call feedkeys("q::let t = test_gui_event('tabline', #{tabnr: 2})\<CR>:q\<CR>", 'x!') call assert_equal(v:false, t) " Invalid arguments call assert_false(test_gui_event('tabline', {})) call assert_false(test_gui_event('tabline', #{abc: 1})) %bw! endfunc " Test for generating a GUI tabline menu event to execute an action func Test_gui_tabmenu_event() %bw! " Try to close the last tab page call test_gui_event('tabmenu', #{tabnr: 1, item: 1}) call feedkeys("y", "Lx!") edit Xfile1 tabedit Xfile2 call test_gui_event('tabmenu', #{tabnr: 1, item: 1}) call feedkeys("y", "Lx!") call assert_equal(1, tabpagenr('$')) call assert_equal('Xfile2', bufname()) eval 'tabmenu'->test_gui_event(#{tabnr: 1, item: 2}) call feedkeys("y", "Lx!") call assert_equal(2, tabpagenr('$')) " If tabnr is 0, then the current tabpage should be used. call test_gui_event('tabmenu', #{tabnr: 0, item: 2}) call feedkeys("y", "Lx!") call assert_equal(3, tabpagenr('$')) call test_gui_event('tabmenu', #{tabnr: 0, item: 1}) call feedkeys("y", "Lx!") call assert_equal(2, tabpagenr('$')) " Invalid arguments call assert_false(test_gui_event('tabmenu', {})) call assert_false(test_gui_event('tabmenu', #{tabnr: 1})) call assert_false(test_gui_event('tabmenu', #{item: 1})) call assert_false(test_gui_event('tabmenu', #{abc: 1})) %bw! endfunc " Test for find/replace text dialog event func Test_gui_findrepl() " Find/Replace dialog is supported only on GTK, Motif and MS-Windows. if !has('gui_gtk') && !has('gui_motif') && !has('gui_win32') return endif new call setline(1, ['one two one', 'Twoo One two oneo']) " Replace all instances of a string with another let args = #{find_text: 'one', repl_text: 'ONE', flags: 0x4, forward: 1} call test_gui_event('findrepl', args) call assert_equal(['ONE two ONE', 'Twoo ONE two ONEo'], getline(1, '$')) " Replace all instances of a whole string with another call cursor(1, 1) let args = #{find_text: 'two', repl_text: 'TWO', flags: 0xC, forward: 1} call test_gui_event('findrepl', args) call assert_equal(['ONE TWO ONE', 'Twoo ONE TWO ONEo'], getline(1, '$')) " Find next occurrence of a string (in a find dialog) call cursor(1, 11) let args = #{find_text: 'TWO', repl_text: '', flags: 0x11, forward: 1} call test_gui_event('findrepl', args) call assert_equal([2, 10], [line('.'), col('.')]) " Find previous occurrences of a string (in a find dialog) call cursor(1, 11) let args = #{find_text: 'TWO', repl_text: '', flags: 0x11, forward: 0} call test_gui_event('findrepl', args) call assert_equal([1, 5], [line('.'), col('.')]) " Find next occurrence of a string (in a replace dialog) call cursor(1, 1) let args = #{find_text: 'Twoo', repl_text: '', flags: 0x2, forward: 1} call test_gui_event('findrepl', args) call assert_equal([2, 1], [line('.'), col('.')]) " Replace only the next occurrence of a string (once) call cursor(1, 5) let args = #{find_text: 'TWO', repl_text: 'two', flags: 0x3, forward: 1} call test_gui_event('findrepl', args) call assert_equal(['ONE two ONE', 'Twoo ONE TWO ONEo'], getline(1, '$')) " Replace all instances of a whole string with another matching case call cursor(1, 1) let args = #{find_text: 'TWO', repl_text: 'two', flags: 0x1C, forward: 1} call test_gui_event('findrepl', args) call assert_equal(['ONE two ONE', 'Twoo ONE two ONEo'], getline(1, '$')) " Replace all instances with sub-replace specials call cursor(1, 1) let args = #{find_text: 'ONE', repl_text: '&~&', flags: 0x4, forward: 1} call test_gui_event('findrepl', args) call assert_equal(['&~& two &~&', 'Twoo &~& two &~&o'], getline(1, '$')) " Invalid arguments call assert_false(test_gui_event('findrepl', {})) let args = #{repl_text: 'a', flags: 1, forward: 1} call assert_false(test_gui_event('findrepl', args)) let args = #{find_text: 'a', flags: 1, forward: 1} call assert_false(test_gui_event('findrepl', args)) let args = #{find_text: 'a', repl_text: 'b', forward: 1} call assert_false(test_gui_event('findrepl', args)) let args = #{find_text: 'a', repl_text: 'b', flags: 1} call assert_false(test_gui_event('findrepl', args)) bw! endfunc func Test_gui_CTRL_SHIFT_V() call feedkeys(":let g:str = '\<*C-S-V>\<*C-S-I>\<*C-S-V>\<*C-S-@>'\<CR>", 'tx') call assert_equal('<C-S-I><C-S-@>', g:str) unlet g:str endfunc func Test_gui_dialog_file() " make sure the file does not exist, otherwise a dialog makes Vim hang call delete('Xdialfile') let lines =<< trim END file Xdialfile normal axxx confirm qa END call writefile(lines, 'Xlines', 'D') let prefix = '!' if has('win32') let prefix = '!start ' endif execute prefix .. GetVimCommand() .. ' -g -f --clean --gui-dialog-file Xdialog -S Xlines' call WaitForAssert({-> assert_true(filereadable('Xdialog'))}) call assert_match('Question: Save changes to "Xdialfile"?', readfile('Xdialog')->join('<NL>')) call delete('Xdialog') call delete('Xdialfile') endfunc " Test for sending low level key presses func SendKeys(keylist) for k in a:keylist call test_gui_event("key", #{event: "keydown", keycode: k}) endfor for k in reverse(a:keylist) call test_gui_event("key", #{event: "keyup", keycode: k}) endfor endfunc func Test_gui_lowlevel_keyevent() CheckMSWindows new " Test for <Ctrl-A> to <Ctrl-Z> keys for kc in range(65, 90) call SendKeys([0x11, kc]) try let ch = getcharstr() catch /^Vim:Interrupt$/ let ch = "\<c-c>" endtry call assert_equal(nr2char(kc - 64), ch) endfor " Testing more extensive windows keyboard handling " is covered in test_mswin_event.vim bw! endfunc func Test_gui_macro_csi() " Test for issue #11270 nnoremap <C-L> <Cmd>let g:triggered = 1<CR> let @q = "\x9b\xfc\x04L" norm @q call assert_equal(1, g:triggered) unlet g:triggered nunmap <C-L> " Test for issue #11057 inoremap <C-D>t bbb call setline(1, "\t") let @q = "i\x9b\xfc\x04D" " The end of :normal is like a mapping timing out norm @q call assert_equal('', getline(1)) iunmap <C-D>t endfunc func Test_gui_csi_keytrans() call assert_equal('<C-L>', keytrans("\x9b\xfc\x04L")) call assert_equal('<C-D>', keytrans("\x9b\xfc\x04D")) endfunc " vim: shiftwidth=2 sts=2 expandtab