To: vim_dev@googlegroups.com Subject: Patch 8.2.4259 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4259 Problem: Number of test functions for GUI events is growing. Solution: Use one function with a dictionary. (Yegappan Lakshmanan, closes #9660) Files: runtime/doc/builtin.txt, runtime/doc/testing.txt, runtime/doc/usr_41.txt, src/evalfunc.c, src/proto/testing.pro, src/testdir/test_gui.vim, src/testdir/test_vim9_builtin.vim, src/testing.c *** ../vim-8.2.4258/runtime/doc/builtin.txt 2022-01-29 13:06:19.336028749 +0000 --- runtime/doc/builtin.txt 2022-01-30 12:28:31.920244465 +0000 *************** *** 642,654 **** test_garbagecollect_now() none free memory right now for testing test_garbagecollect_soon() none free memory soon for testing test_getvalue({string}) any get value of an internal variable ! test_gui_drop_files({list}, {row}, {col}, {mods}) ! none drop a list of files in a window ! test_gui_mouse_event({button}, {row}, {col}, {repeated}, {mods}) ! none add a mouse event to the input buffer ! test_gui_tabline_event({tabnr}) Bool add a tabline event to the input buffer ! test_gui_tabmenu_event({tabnr}, {event}) ! none add a tabmenu event to the input buffer test_ignore_error({expr}) none ignore a specific error test_null_blob() Blob null value for testing test_null_channel() Channel null value for testing --- 642,648 ---- test_garbagecollect_now() none free memory right now for testing test_garbagecollect_soon() none free memory soon for testing test_getvalue({string}) any get value of an internal variable ! test_gui_event({event}, {args}) bool generate a GUI event for testing test_ignore_error({expr}) none ignore a specific error test_null_blob() Blob null value for testing test_null_channel() Channel null value for testing *** ../vim-8.2.4258/runtime/doc/testing.txt 2022-01-27 13:16:54.328078845 +0000 --- runtime/doc/testing.txt 2022-01-30 12:28:31.920244465 +0000 *************** *** 79,141 **** Can also be used as a |method|: > GetName()->test_getvalue() < ! *test_gui_drop_files()* ! test_gui_drop_files({list}, {row}, {col}, {mods}) ! Drop one or more files in {list} in the window at {row}, {col}. ! This function only works when the GUI is running. ! ! The supported values for {mods} are: ! 0x4 Shift ! 0x8 Alt ! 0x10 Ctrl ! The files are added to the argument list and the first file in ! {list} is edited in the window. See |drag-n-drop| for more ! information. ! ! *test_gui_mouse_event()* ! test_gui_mouse_event({button}, {row}, {col}, {multiclick}, {modifiers}) ! Inject a mouse button click event. This function only works ! when the GUI is running. ! The supported values for {button} are: ! 0 right mouse button ! 1 middle mouse button ! 2 left mouse button ! 3 mouse button release ! 4 scroll wheel down ! 5 scroll wheel up ! 6 scroll wheel left ! 7 scroll wheel right ! {row} and {col} specify the location of the mouse click. The ! first row of the Vim window is 1 and the last row is 'lines'. ! The maximum value of {col} is 'columns'. ! To inject a multiclick event, set {multiclick} to 1. ! The supported values for {modifiers} are: ! 4 shift is pressed ! 8 alt is pressed ! 16 ctrl is pressed ! After injecting the mouse event you probably should call ! |feedkeys()| to have them processed, e.g.: > ! call feedkeys("y", 'Lx!') ! *test_gui_tabline_event()* ! test_gui_tabline_event({tabnr}) ! Add an event that simulates a click on the tabline to select ! tabpage {tabnr} to the input buffer. ! Returns TRUE if the event is successfully added, FALSE if ! already in the tabpage {tabnr} or the cmdline window is open. ! After injecting the event you probably should call ! |feedkeys()| to have them processed, e.g.: > ! call feedkeys("y", 'Lx!') ! ! *test_gui_tabmenu_event()* ! test_gui_tabmenu_event({tabnr}, {event}) ! Add an event that simulates selecting a tabline menu entry for ! tabpage {tabnr} to the input buffer. {event} is 1 for the ! first menu entry, 2 for the second entry and so on. ! After injecting the event you probably should call |feedkeys()| to have them processed, e.g.: > call feedkeys("y", 'Lx!') test_ignore_error({expr}) *test_ignore_error()* Ignore any error containing {expr}. A normal message is given instead. --- 82,159 ---- Can also be used as a |method|: > GetName()->test_getvalue() < ! *test_gui_event()* ! test_gui_event({event}, {args}) ! Generate a GUI {event} with arguments {args} for testing Vim ! functionality. ! ! {event} is a String and the supported values are: ! "dropfiles" drop one or more files in a window. ! "mouse" mouse button click event. ! "tabline" select a tab page by mouse click. ! "tabmenu" select a tabline menu entry. ! ! {args} is a Dict and contains the arguments for the event. ! ! "dropfiles": ! Drop one or more files in a specified window. The supported ! items in {args} are: ! files: List of file names ! row: window row number ! col: window column number ! modifiers: key modifiers. The supported values are: ! 0x4 Shift ! 0x8 Alt ! 0x10 Ctrl ! The files are added to the |argument-list| and the first ! file in {files} is edited in the window. See |drag-n-drop| ! for more information. This function only works when the GUI ! is running and the |drop_file| feature is present. ! ! "mouse": ! Inject a mouse button click event. This function only works ! when the GUI is running. The supported items in {args} are: ! button: mouse button. The supported values are: ! 0 right mouse button ! 1 middle mouse button ! 2 left mouse button ! 3 mouse button release ! 4 scroll wheel down ! 5 scroll wheel up ! 6 scroll wheel left ! 7 scroll wheel right ! row: mouse click row number. The first row of the ! Vim window is 1 and the last row is 'lines'. ! col: mouse click column number. The maximum value ! of {col} is 'columns'. ! multiclick: set to 1 to inject a multiclick mouse event. ! modifiers: key modifiers. The supported values are: ! 4 shift is pressed ! 8 alt is pressed ! 16 ctrl is pressed ! ! "tabline": ! Inject a mouse click event on the tabline to select a ! tabpage. The supported items in {args} are: ! tabnr: tab page number ! ! "tabmenu": ! Inject an event to select a tabline menu entry. The ! supported items in {args} are: ! tabnr: tab page number ! item: tab page menu item number. 1 for the first ! menu item, 2 for the second item and so on. ! After injecting the GUI events you probably should call |feedkeys()| to have them processed, e.g.: > call feedkeys("y", 'Lx!') + < + Returns TRUE if the event is successfully added, FALSE if + there is a failure. + Can also be used as a |method|: > + GetEvent()->test_gui_event({args}) + < test_ignore_error({expr}) *test_ignore_error()* Ignore any error containing {expr}. A normal message is given instead. *************** *** 149,154 **** --- 167,173 ---- Can also be used as a |method|: > GetErrorText()->test_ignore_error() + test_null_blob() *test_null_blob()* Return a |Blob| that is null. Only useful for testing. *** ../vim-8.2.4258/runtime/doc/usr_41.txt 2022-01-29 13:06:19.336028749 +0000 --- runtime/doc/usr_41.txt 2022-01-30 12:28:31.920244465 +0000 *************** *** 1026,1035 **** test_garbagecollect_now() free memory right now test_garbagecollect_soon() set a flag to free memory soon test_getvalue() get value of an internal variable ! test_gui_drop_files() drop file(s) in a window ! test_gui_mouse_event() add a GUI mouse event to the input buffer ! test_gui_tabline_event() add a GUI tabline event to the input buffer ! test_gui_tabmenu_event() add a GUI tabmenu event to the input buffer test_ignore_error() ignore a specific error message test_null_blob() return a null Blob test_null_channel() return a null Channel --- 1117,1123 ---- test_garbagecollect_now() free memory right now test_garbagecollect_soon() set a flag to free memory soon test_getvalue() get value of an internal variable ! test_gui_event() generate a GUI event for testing test_ignore_error() ignore a specific error message test_null_blob() return a null Blob test_null_channel() return a null Channel *** ../vim-8.2.4258/src/evalfunc.c 2022-01-29 21:45:30.473921671 +0000 --- src/evalfunc.c 2022-01-30 12:28:31.924244406 +0000 *************** *** 937,947 **** static argcheck_T arg3_string_string_bool[] = {arg_string, arg_string, arg_bool}; static argcheck_T arg3_string_string_dict[] = {arg_string, arg_string, arg_dict_any}; static argcheck_T arg3_string_string_number[] = {arg_string, arg_string, arg_number}; - static argcheck_T arg4_list_number_number_number[] = {arg_list_string, arg_number, arg_number, arg_number}; static argcheck_T arg4_number_number_string_any[] = {arg_number, arg_number, arg_string, NULL}; static argcheck_T arg4_string_string_any_string[] = {arg_string, arg_string, NULL, arg_string}; static argcheck_T arg4_string_string_number_string[] = {arg_string, arg_string, arg_number, arg_string}; - static argcheck_T arg5_number[] = {arg_number, arg_number, arg_number, arg_number, arg_number}; /* Function specific argument types (not covered by the above) */ static argcheck_T arg15_assert_fails[] = {arg_string_or_nr, arg_string_or_list_any, NULL, arg_number, arg_string}; static argcheck_T arg34_assert_inrange[] = {arg_float_or_nr, arg_float_or_nr, arg_float_or_nr, arg_string}; --- 937,945 ---- *************** *** 2337,2350 **** ret_void, f_test_garbagecollect_soon}, {"test_getvalue", 1, 1, FEARG_1, arg1_string, ret_number, f_test_getvalue}, ! {"test_gui_drop_files", 4, 4, 0, arg4_list_number_number_number, ! ret_void, f_test_gui_drop_files}, ! {"test_gui_mouse_event", 5, 5, 0, arg5_number, ! ret_void, f_test_gui_mouse_event}, ! {"test_gui_tabline_event", 1, 1, 0, arg1_number, ! ret_bool, f_test_gui_tabline_event}, ! {"test_gui_tabmenu_event", 2, 2, 0, arg2_number, ! ret_void, f_test_gui_tabmenu_event}, {"test_ignore_error", 1, 1, FEARG_1, arg1_string, ret_void, f_test_ignore_error}, {"test_null_blob", 0, 0, 0, NULL, --- 2335,2342 ---- ret_void, f_test_garbagecollect_soon}, {"test_getvalue", 1, 1, FEARG_1, arg1_string, ret_number, f_test_getvalue}, ! {"test_gui_event", 2, 2, FEARG_1, arg2_string_dict, ! ret_bool, f_test_gui_event}, {"test_ignore_error", 1, 1, FEARG_1, arg1_string, ret_void, f_test_ignore_error}, {"test_null_blob", 0, 0, 0, NULL, *** ../vim-8.2.4258/src/proto/testing.pro 2022-01-27 13:16:54.328078845 +0000 --- src/proto/testing.pro 2022-01-30 12:28:31.924244406 +0000 *************** *** 34,42 **** void f_test_void(typval_T *argvars, typval_T *rettv); void f_test_scrollbar(typval_T *argvars, typval_T *rettv); void f_test_setmouse(typval_T *argvars, typval_T *rettv); ! void f_test_gui_mouse_event(typval_T *argvars, typval_T *rettv); ! void f_test_gui_tabline_event(typval_T *argvars, typval_T *rettv); ! void f_test_gui_tabmenu_event(typval_T *argvars, typval_T *rettv); void f_test_settime(typval_T *argvars, typval_T *rettv); - void f_test_gui_drop_files(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ --- 34,39 ---- void f_test_void(typval_T *argvars, typval_T *rettv); void f_test_scrollbar(typval_T *argvars, typval_T *rettv); void f_test_setmouse(typval_T *argvars, typval_T *rettv); ! void f_test_gui_event(typval_T *argvars, typval_T *rettv); void f_test_settime(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ *** ../vim-8.2.4258/src/testdir/test_gui.vim 2022-01-27 13:16:54.332078790 +0000 --- src/testdir/test_gui.vim 2022-01-30 12:28:31.924244406 +0000 *************** *** 897,929 **** " place the cursor using left click in normal mode call cursor(1, 1) ! call test_gui_mouse_event(0, 2, 4, 0, 0) ! call test_gui_mouse_event(3, 2, 4, 0, 0) call feedkeys("\", 'Lx!') call assert_equal([0, 2, 4, 0], getpos('.')) " select and yank a word let @" = '' ! call test_gui_mouse_event(0, 1, 9, 0, 0) ! call test_gui_mouse_event(0, 1, 9, 1, 0) ! call test_gui_mouse_event(3, 1, 9, 0, 0) call feedkeys("y", 'Lx!') call assert_equal('three', @") " create visual selection using right click let @" = '' ! call test_gui_mouse_event(0, 2, 6, 0, 0) ! call test_gui_mouse_event(3, 2, 6, 0, 0) ! call test_gui_mouse_event(2, 2, 13, 0, 0) ! call test_gui_mouse_event(3, 2, 13, 0, 0) call feedkeys("y", 'Lx!') call assert_equal('five six', @") " paste using middle mouse button let @* = 'abc ' call feedkeys('""', 'Lx!') ! call test_gui_mouse_event(1, 1, 9, 0, 0) ! call test_gui_mouse_event(3, 1, 9, 0, 0) call feedkeys("\", 'Lx!') call assert_equal(['one two abc three', 'four five six'], getline(1, '$')) --- 897,941 ---- " place the cursor using left click in normal mode call cursor(1, 1) ! 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("\", '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("\", 'Lx!') call assert_equal(['one two abc three', 'four five six'], getline(1, '$')) *************** *** 931,947 **** let @" = '' call cursor(1, 1) call feedkeys('v', 'Lx!') ! call test_gui_mouse_event(2, 1, 17, 0, 0) ! call test_gui_mouse_event(3, 1, 17, 0, 0) call feedkeys("y", 'Lx!') call assert_equal('one two abc three', @") " extend visual selection using mouse drag let @" = '' call cursor(1, 1) ! call test_gui_mouse_event(0, 2, 1, 0, 0) ! call test_gui_mouse_event(0x43, 2, 9, 0, 0) ! call test_gui_mouse_event(0x3, 2, 9, 0, 0) call feedkeys("y", 'Lx!') call assert_equal('four five', @") --- 943,964 ---- 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', @") *************** *** 949,981 **** let @" = '' call cursor(1, 1) redraw! ! call test_gui_mouse_event(0, 1, 4, 0, 0) ! call test_gui_mouse_event(0x700, 1, 9, 0, 0) ! call test_gui_mouse_event(0x700, 1, 13, 0, 0) ! call test_gui_mouse_event(0x3, 1, 13, 0, 0) call feedkeys("y", 'Lx!') call assert_equal(' two abc t', @") " Using mouse in insert mode call cursor(1, 1) call feedkeys('i', 't') ! call test_gui_mouse_event(0, 2, 11, 0, 0) ! call test_gui_mouse_event(3, 2, 11, 0, 0) call feedkeys("po\", 'Lx!') call assert_equal(['one two abc three', 'four five posix'], getline(1, '$')) %d _ call setline(1, range(1, 100)) " scroll up ! call test_gui_mouse_event(0x200, 2, 1, 0, 0) ! call test_gui_mouse_event(0x200, 2, 1, 0, 0) ! call test_gui_mouse_event(0x200, 2, 1, 0, 0) call feedkeys("H", 'Lx!') call assert_equal(10, line('.')) " scroll down ! call test_gui_mouse_event(0x100, 2, 1, 0, 0) ! call test_gui_mouse_event(0x100, 2, 1, 0, 0) call feedkeys("H", 'Lx!') call assert_equal(4, line('.')) --- 966,1007 ---- 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\", 'Lx!') call assert_equal(['one two abc three', 'four five posix'], getline(1, '$')) %d _ 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('.')) *************** *** 983,997 **** set nowrap call setline(1, range(10)->join('')->repeat(10)) " scroll left ! call test_gui_mouse_event(0x500, 1, 5, 0, 0) ! call test_gui_mouse_event(0x500, 1, 10, 0, 0) ! call test_gui_mouse_event(0x500, 1, 15, 0, 0) call feedkeys('g0', 'Lx!') call assert_equal(19, col('.')) " scroll right ! call test_gui_mouse_event(0x600, 1, 15, 0, 0) ! call test_gui_mouse_event(0x600, 1, 10, 0, 0) call feedkeys('g0', 'Lx!') call assert_equal(7, col('.')) set wrap& --- 1009,1028 ---- 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& *************** *** 1021,1055 **** " 0x300- X2) for button in [0, 1, 2, 0x300, 0x400] " Single click ! call test_gui_mouse_event(button, 2, 5, 0, 0) ! call test_gui_mouse_event(3, 2, 5, 0, 0) " Double/Triple click is supported by only the Left/Middle/Right mouse " buttons if button <= 2 " Double Click ! call test_gui_mouse_event(button, 2, 5, 0, 0) ! call test_gui_mouse_event(button, 2, 5, 1, 0) ! call test_gui_mouse_event(3, 2, 5, 0, 0) " Triple Click ! call test_gui_mouse_event(button, 2, 5, 0, 0) ! call test_gui_mouse_event(button, 2, 5, 1, 0) ! call test_gui_mouse_event(button, 2, 5, 1, 0) ! call test_gui_mouse_event(3, 2, 5, 0, 0) endif " Shift click ! call test_gui_mouse_event(button, 3, 7, 0, 4) ! call test_gui_mouse_event(3, 3, 7, 0, 4) " Alt click ! call test_gui_mouse_event(button, 3, 7, 0, 8) ! call test_gui_mouse_event(3, 3, 7, 0, 8) " Ctrl click ! call test_gui_mouse_event(button, 3, 7, 0, 16) ! call test_gui_mouse_event(3, 3, 7, 0, 16) call feedkeys("\", 'Lx!') endfor --- 1052,1104 ---- " 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("\", 'Lx!') endfor *************** *** 1079,1087 **** redraw! " Double click should select the word and copy it to clipboard let @* = '' ! call test_gui_mouse_event(0, 2, 11, 0, 0) ! call test_gui_mouse_event(0, 2, 11, 1, 0) ! call test_gui_mouse_event(3, 2, 11, 0, 0) call feedkeys("\", 'Lx!') call assert_equal([0, 1, 1, 0], getpos('.')) call assert_equal('sixteen', @*) --- 1128,1140 ---- 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("\", 'Lx!') call assert_equal([0, 1, 1, 0], getpos('.')) call assert_equal('sixteen', @*) *************** *** 1089,1116 **** call cursor(1, 6) redraw! let @* = '' ! call test_gui_mouse_event(2, 1, 11, 0, 0) ! call test_gui_mouse_event(3, 1, 11, 0, 0) call feedkeys("\", '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! ! call test_gui_mouse_event(1, 1, 11, 0, 0) ! call test_gui_mouse_event(3, 1, 11, 0, 0) call feedkeys("\", 'Lx!') call assert_equal([0, 2, 7, 0], getpos('.')) call assert_equal('wo thrfour five sixteen', getline(2)) set mouse& let &guioptions = save_guioptions ! " Test invalid parameters for test_gui_mouse_event() ! call assert_fails('call test_gui_mouse_event("", 1, 2, 3, 4)', 'E1210:') ! call assert_fails('call test_gui_mouse_event(0, "", 2, 3, 4)', 'E1210:') ! call assert_fails('call test_gui_mouse_event(0, 1, "", 3, 4)', 'E1210:') ! call assert_fails('call test_gui_mouse_event(0, 1, 2, "", 4)', 'E1210:') ! call assert_fails('call test_gui_mouse_event(0, 1, 2, 3, "")', 'E1210:') bw! call test_override('no_query_mouse', 0) --- 1142,1185 ---- 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("\", '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("\", 'Lx!') call assert_equal([0, 2, 7, 0], getpos('.')) call assert_equal('wo thrfour five sixteen', getline(2)) set mouse& let &guioptions = save_guioptions ! " Test invalid parameters for test_gui_event() ! 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) *************** *** 1178,1220 **** CheckFeature drop_file call feedkeys(":\"", 'L') ! call test_gui_drop_files(['a.c', 'b.c'], &lines, 1, 0) call feedkeys("\", 'L') endfunc func Test_gui_drop_files() CheckFeature drop_file ! call assert_fails('call test_gui_drop_files(1, 1, 1, 0)', 'E1211:') ! call assert_fails('call test_gui_drop_files(["x"], "", 1, 0)', 'E1210:') ! call assert_fails('call test_gui_drop_files(["x"], 1, "", 0)', 'E1210:') ! call assert_fails('call test_gui_drop_files(["x"], 1, 1, "")', 'E1210:') %bw! %argdelete ! call test_gui_drop_files([], 1, 1, 0) call assert_equal([], argv()) ! call test_gui_drop_files([1, 2], 1, 1, 0) call assert_equal([], argv()) ! call test_gui_drop_files(['a.c', 'b.c'], 1, 1, 0) call assert_equal(['a.c', 'b.c'], argv()) %bw! %argdelete ! call test_gui_drop_files([], 1, 1, 0) 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 ! call test_gui_drop_files(['x.c', 'y.c'], 1, 1, 0) 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 ! call test_gui_drop_files(['s.py', 't.py'], 1, 1, 0x10) call assert_equal(['s.py', 't.py'], argv()) call assert_equal(2, winnr('$')) call assert_equal('s.py', bufname(winbufnr(1))) --- 1247,1295 ---- CheckFeature drop_file call feedkeys(":\"", 'L') ! let d = #{files: ['a.c', 'b.c'], row: &lines, col: 1, modifiers: 0} ! call test_gui_event('dropfiles', d) call feedkeys("\", 'L') endfunc func Test_gui_drop_files() CheckFeature drop_file ! call assert_false(test_gui_event("dropfiles", {})) ! let d = #{row: 1, col: 1, modifiers: 0} ! call assert_false(test_gui_event("dropfiles", d)) %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))) *************** *** 1222,1228 **** %argdelete " drop the files in a non-current window belowright new ! call test_gui_drop_files(['a.py', 'b.py'], 1, 1, 0) call assert_equal(['a.py', 'b.py'], argv()) call assert_equal(2, winnr('$')) call assert_equal(1, winnr()) --- 1297,1304 ---- %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()) *************** *** 1234,1257 **** call mkdir('Xdir1') call writefile([], 'Xdir1/Xfile1') call writefile([], 'Xdir1/Xfile2') ! call test_gui_drop_files(['Xdir1/Xfile1', 'Xdir1/Xfile2'], 1, 1, 0x4) call assert_equal('Xdir1', fnamemodify(getcwd(), ':t')) call assert_equal('Xfile1', @%) call chdir(save_cwd) " pressing shift when dropping directory and files should change directory ! call test_gui_drop_files(['Xdir1', 'Xdir1/Xfile2'], 1, 1, 0x4) call assert_equal('Xdir1', fnamemodify(getcwd(), ':t')) call assert_equal('Xdir1', fnamemodify(@%, ':t')) call chdir(save_cwd) %bw! %argdelete " dropping a directory should edit it ! call test_gui_drop_files(['Xdir1'], 1, 1, 0) call assert_equal('Xdir1', @%) %bw! %argdelete " dropping only a directory name with Shift should ignore it ! call test_gui_drop_files(['Xdir1'], 1, 1, 0x4) call assert_equal('', @%) %bw! %argdelete --- 1310,1338 ---- call mkdir('Xdir1') call writefile([], 'Xdir1/Xfile1') call writefile([], 'Xdir1/Xfile2') ! let d = #{files: ['Xdir1/Xfile1', 'Xdir1/Xfile2'], row: 1, col: 1, ! \ modifiers: 0x4} ! call test_gui_event('dropfiles', d) call assert_equal('Xdir1', fnamemodify(getcwd(), ':t')) call assert_equal('Xfile1', @%) call chdir(save_cwd) " pressing shift when dropping directory and files should change directory ! let d = #{files: ['Xdir1', 'Xdir1/Xfile2'], row: 1, col: 1, modifiers: 0x4} ! call test_gui_event('dropfiles', d) call assert_equal('Xdir1', fnamemodify(getcwd(), ':t')) call assert_equal('Xdir1', fnamemodify(@%, ':t')) call chdir(save_cwd) %bw! %argdelete " dropping a directory should edit it ! let d = #{files: ['Xdir1'], row: 1, col: 1, modifiers: 0} ! call test_gui_event('dropfiles', d) call assert_equal('Xdir1', @%) %bw! %argdelete " dropping only a directory name with Shift should ignore it ! let d = #{files: ['Xdir1'], row: 1, col: 1, modifiers: 0x4} ! call test_gui_event('dropfiles', d) call assert_equal('', @%) %bw! %argdelete *************** *** 1274,1289 **** tabedit Xfile3 tabfirst ! call assert_equal(v:true, test_gui_tabline_event(2)) call feedkeys("y", "Lx!") call assert_equal(2, tabpagenr()) ! call assert_equal(v:true, test_gui_tabline_event(3)) call feedkeys("y", "Lx!") call assert_equal(3, tabpagenr()) ! call assert_equal(v:false, test_gui_tabline_event(3)) " From the cmdline window, tabline event should not be handled ! call feedkeys("q::let t = test_gui_tabline_event(2)\:q\", 'x!') call assert_equal(v:false, t) %bw! --- 1355,1370 ---- 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})\:q\", 'x!') call assert_equal(v:false, t) %bw! *************** *** 1294,1318 **** %bw! " Try to close the last tab page ! call test_gui_tabmenu_event(1, 1) call feedkeys("y", "Lx!") edit Xfile1 tabedit Xfile2 ! call test_gui_tabmenu_event(1, 1) call feedkeys("y", "Lx!") call assert_equal(1, tabpagenr('$')) call assert_equal('Xfile2', bufname()) ! call test_gui_tabmenu_event(1, 2) call feedkeys("y", "Lx!") call assert_equal(2, tabpagenr('$')) " If tabnr is 0, then the current tabpage should be used. ! call test_gui_tabmenu_event(0, 2) call feedkeys("y", "Lx!") call assert_equal(3, tabpagenr('$')) ! call test_gui_tabmenu_event(0, 1) call feedkeys("y", "Lx!") call assert_equal(2, tabpagenr('$')) --- 1375,1399 ---- %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('$')) *** ../vim-8.2.4258/src/testdir/test_vim9_builtin.vim 2022-01-29 21:45:30.477921609 +0000 --- src/testdir/test_vim9_builtin.vim 2022-01-30 12:28:31.924244406 +0000 *************** *** 4069,4089 **** v9.CheckDefAndScriptFailure(['test_getvalue(1.1)'], ['E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1']) enddef ! def Test_test_gui_drop_files() CheckGui ! v9.CheckDefAndScriptFailure(['test_gui_drop_files("a", 1, 1, 0)'], ['E1013: Argument 1: type mismatch, expected list but got string', 'E1211: List required for argument 1']) ! v9.CheckDefAndScriptFailure(['test_gui_drop_files(["x"], "", 1, 0)'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) ! v9.CheckDefAndScriptFailure(['test_gui_drop_files(["x"], 1, "", 0)'], ['E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3']) ! v9.CheckDefAndScriptFailure(['test_gui_drop_files(["x"], 1, 1, "")'], ['E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4']) ! enddef ! ! def Test_test_gui_mouse_event() ! CheckGui ! v9.CheckDefAndScriptFailure(['test_gui_mouse_event(1.1, 1, 1, 1, 1)'], ['E1013: Argument 1: type mismatch, expected number but got float', 'E1210: Number required for argument 1']) ! v9.CheckDefAndScriptFailure(['test_gui_mouse_event(1, "1", 1, 1, 1)'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) ! v9.CheckDefAndScriptFailure(['test_gui_mouse_event(1, 1, "1", 1, 1)'], ['E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3']) ! v9.CheckDefAndScriptFailure(['test_gui_mouse_event(1, 1, 1, "1", 1)'], ['E1013: Argument 4: type mismatch, expected number but got string', 'E1210: Number required for argument 4']) ! v9.CheckDefAndScriptFailure(['test_gui_mouse_event(1, 1, 1, 1, "1")'], ['E1013: Argument 5: type mismatch, expected number but got string', 'E1210: Number required for argument 5']) enddef def Test_test_ignore_error() --- 4069,4078 ---- v9.CheckDefAndScriptFailure(['test_getvalue(1.1)'], ['E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1']) enddef ! def Test_test_gui_event() CheckGui ! v9.CheckDefAndScriptFailure(['test_gui_event([], {})'], ['E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1']) ! v9.CheckDefAndScriptFailure(['test_gui_event("abc", 1)'], ['E1013: Argument 2: type mismatch, expected dict but got number', 'E1206: Dictionary required for argument 2']) enddef def Test_test_ignore_error() *** ../vim-8.2.4258/src/testing.c 2022-01-28 14:39:54.317663768 +0000 --- src/testing.c 2022-01-30 12:28:31.924244406 +0000 *************** *** 1315,1392 **** mouse_col = (time_t)tv_get_number(&argvars[1]) - 1; } - void - f_test_gui_mouse_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED) - { # ifdef FEAT_GUI ! int button; ! int row; ! int col; ! int repeated_click; ! int_u mods; ! ! if (check_for_number_arg(argvars, 0) == FAIL ! || check_for_number_arg(argvars, 1) == FAIL ! || check_for_number_arg(argvars, 2) == FAIL ! || check_for_number_arg(argvars, 3) == FAIL ! || check_for_number_arg(argvars, 4) == FAIL) ! return; ! ! button = tv_get_number(&argvars[0]); ! row = tv_get_number(&argvars[1]); ! col = tv_get_number(&argvars[2]); ! repeated_click = tv_get_number(&argvars[3]); ! mods = tv_get_number(&argvars[4]); ! ! gui_send_mouse_event(button, TEXT_X(col - 1), TEXT_Y(row - 1), repeated_click, mods); ! # endif ! } ! ! void ! f_test_gui_tabline_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED) ! { ! # ifdef FEAT_GUI_TABLINE ! int tabnr; ! ! if (check_for_number_arg(argvars, 0) == FAIL) ! return; ! ! tabnr = tv_get_number(&argvars[0]); ! ! rettv->v_type = VAR_BOOL; ! rettv->vval.v_number = send_tabline_event(tabnr); ! # endif ! } ! ! void ! f_test_gui_tabmenu_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED) ! { ! # ifdef FEAT_GUI_TABLINE ! int tabnr; ! int event; ! ! if (check_for_number_arg(argvars, 0) == FAIL ! || check_for_number_arg(argvars, 1) == FAIL) ! return; ! ! tabnr = tv_get_number(&argvars[0]); ! event = tv_get_number(&argvars[1]); ! ! send_tabline_menu_event(tabnr, event); ! # endif ! } ! ! void ! f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) ! { ! if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) ! return; ! ! time_for_testing = (time_t)tv_get_number(&argvars[0]); ! } ! ! void ! f_test_gui_drop_files(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #if defined(HAVE_DROP_FILE) int row; --- 1315,1323 ---- mouse_col = (time_t)tv_get_number(&argvars[1]) - 1; } # ifdef FEAT_GUI ! static int ! test_gui_drop_files(dict_T *args UNUSED) { #if defined(HAVE_DROP_FILE) int row; *************** *** 1394,1419 **** int_u mods; char_u **fnames; int count = 0; list_T *l; listitem_T *li; ! if (check_for_list_arg(argvars, 0) == FAIL ! || check_for_number_arg(argvars, 1) == FAIL ! || check_for_number_arg(argvars, 2) == FAIL ! || check_for_number_arg(argvars, 3) == FAIL) ! return; ! ! row = tv_get_number(&argvars[1]); ! col = tv_get_number(&argvars[2]); ! mods = tv_get_number(&argvars[3]); ! l = argvars[0].vval.v_list; if (list_len(l) == 0) ! return; fnames = ALLOC_MULT(char_u *, list_len(l)); if (fnames == NULL) ! return; FOR_ALL_LIST_ITEMS(l, li) { --- 1325,1353 ---- int_u mods; char_u **fnames; int count = 0; + typval_T t; list_T *l; listitem_T *li; ! if (dict_find(args, (char_u *)"files", -1) == NULL ! || dict_find(args, (char_u *)"row", -1) == NULL ! || dict_find(args, (char_u *)"col", -1) == NULL ! || dict_find(args, (char_u *)"modifiers", -1) == NULL) ! return FALSE; ! ! if (dict_get_tv(args, (char_u *)"files", &t) == FAIL) ! return FALSE; ! row = (int)dict_get_number(args, (char_u *)"row"); ! col = (int)dict_get_number(args, (char_u *)"col"); ! mods = (int)dict_get_number(args, (char_u *)"modifiers"); ! l = t.vval.v_list; if (list_len(l) == 0) ! return FALSE; fnames = ALLOC_MULT(char_u *, list_len(l)); if (fnames == NULL) ! return FALSE; FOR_ALL_LIST_ITEMS(l, li) { *************** *** 1427,1433 **** while (--count >= 0) vim_free(fnames[count]); vim_free(fnames); ! return; } count++; } --- 1361,1367 ---- while (--count >= 0) vim_free(fnames[count]); vim_free(fnames); ! return FALSE; } count++; } *************** *** 1437,1442 **** --- 1371,1482 ---- else vim_free(fnames); # endif + + return TRUE; + } + + static int + test_gui_mouse_event(dict_T *args UNUSED) + { + int button; + int row; + int col; + int repeated_click; + int_u mods; + + if (dict_find(args, (char_u *)"button", -1) == NULL + || dict_find(args, (char_u *)"row", -1) == NULL + || dict_find(args, (char_u *)"col", -1) == NULL + || dict_find(args, (char_u *)"multiclick", -1) == NULL + || dict_find(args, (char_u *)"modifiers", -1) == NULL) + return FALSE; + + button = (int)dict_get_number(args, (char_u *)"button"); + row = (int)dict_get_number(args, (char_u *)"row"); + col = (int)dict_get_number(args, (char_u *)"col"); + repeated_click = (int)dict_get_number(args, (char_u *)"multiclick"); + mods = (int)dict_get_number(args, (char_u *)"modifiers"); + + gui_send_mouse_event(button, TEXT_X(col - 1), TEXT_Y(row - 1), + repeated_click, mods); + return TRUE; + } + + static int + test_gui_tabline_event(dict_T *args UNUSED) + { + # ifdef FEAT_GUI_TABLINE + int tabnr; + + if (dict_find(args, (char_u *)"tabnr", -1) == NULL) + return FALSE; + + tabnr = (int)dict_get_number(args, (char_u *)"tabnr"); + + return send_tabline_event(tabnr); + # else + return FALSE; + # endif + } + + static int + test_gui_tabmenu_event(dict_T *args UNUSED) + { + # ifdef FEAT_GUI_TABLINE + int tabnr; + int item; + + if (dict_find(args, (char_u *)"tabnr", -1) == NULL + || dict_find(args, (char_u *)"item", -1) == NULL) + return FALSE; + + tabnr = (int)dict_get_number(args, (char_u *)"tabnr"); + item = (int)dict_get_number(args, (char_u *)"item"); + + send_tabline_menu_event(tabnr, item); + # endif + return TRUE; + } + # endif + + void + f_test_gui_event(typval_T *argvars UNUSED, typval_T *rettv UNUSED) + { + # ifdef FEAT_GUI + char_u *event; + + rettv->v_type = VAR_BOOL; + rettv->vval.v_number = FALSE; + + if (check_for_string_arg(argvars, 0) == FAIL + || check_for_dict_arg(argvars, 1) == FAIL + || argvars[1].vval.v_dict == NULL) + return; + + event = tv_get_string(&argvars[0]); + if (STRCMP(event, "dropfiles") == 0) + rettv->vval.v_number = test_gui_drop_files(argvars[1].vval.v_dict); + else if (STRCMP(event, "mouse") == 0) + rettv->vval.v_number = test_gui_mouse_event(argvars[1].vval.v_dict); + else if (STRCMP(event, "tabline") == 0) + rettv->vval.v_number = test_gui_tabline_event(argvars[1].vval.v_dict); + else if (STRCMP(event, "tabmenu") == 0) + rettv->vval.v_number = test_gui_tabmenu_event(argvars[1].vval.v_dict); + else + { + semsg(_(e_invalid_argument_str), event); + return; + } + # endif + } + + void + f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) + { + if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) + return; + + time_for_testing = (time_t)tv_get_number(&argvars[0]); } #endif // defined(FEAT_EVAL) *** ../vim-8.2.4258/src/version.c 2022-01-30 12:10:14.871460295 +0000 --- src/version.c 2022-01-30 12:32:59.704341451 +0000 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4259, /**/ -- Bad programs can be written in any language. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///