Merge pull request #37530 from zeertzjq/vim-9.1.1908

vim-patch:8.2.4738,9.0.{0874,1066,1480},9.1.{1370,1908}
This commit is contained in:
zeertzjq
2026-01-24 10:25:05 +08:00
committed by GitHub
30 changed files with 253 additions and 28 deletions

View File

@@ -195,6 +195,8 @@ EXTERN const char e_stray_closing_curly_str[]
INIT(= N_("E1278: Stray '}' without a matching '{': %s"));
EXTERN const char e_missing_close_curly_str[]
INIT(= N_("E1279: Missing '}': %s"));
EXTERN const char e_cannot_change_menus_while_listing[]
INIT(= N_("E1310: Cannot change menus while listing"));
EXTERN const char e_not_allowed_to_change_window_layout_in_this_autocmd[]
INIT(= N_("E1312: Not allowed to change the window layout in this autocmd"));

View File

@@ -48,6 +48,10 @@
#include "menu.c.generated.h"
/// When non-zero no menu must be added or cleared. Prevents the list of menus
/// changing while listing them.
static int menus_locked = 0;
/// The character for each menu mode
static char *menu_mode_chars[] = { "n", "v", "s", "o", "i", "c", "tl", "t" };
@@ -67,6 +71,17 @@ static vimmenu_T **get_root_menu(const char *const name)
return &root_menu;
}
/// If "menus_locked" is set then give an error and return true.
/// Otherwise return false.
static int is_menus_locked(void)
{
if (menus_locked > 0) {
emsg(_(e_cannot_change_menus_while_listing));
return true;
}
return false;
}
/// Do the :menu command and relatives.
/// @param eap Ex command arguments
void ex_menu(exarg_T *eap)
@@ -202,6 +217,10 @@ void ex_menu(exarg_T *eap)
}
menu_enable_recurse(*root_menu_ptr, menu_path, modes, enable);
} else if (unmenu) {
if (is_menus_locked()) {
goto theend;
}
// Delete menu(s).
if (strcmp(menu_path, "*") == 0) { // meaning: remove all menus
menu_path = "";
@@ -221,6 +240,10 @@ void ex_menu(exarg_T *eap)
// Careful: remove_menu() changes menu_path
remove_menu(root_menu_ptr, menu_path, modes, false);
} else {
if (is_menus_locked()) {
goto theend;
}
// Add menu(s).
// Replace special key codes.
if (STRICMP(map_to, "<nop>") == 0) { // "<Nop>" means nothing
@@ -729,12 +752,14 @@ bool menu_get(char *const path_name, int modes, list_T *list)
/// Find menu matching `name` and `modes`. Does not handle empty `name`.
///
/// @param menu top menu to start looking from
/// @param name path towards the menu
/// @param menu top menu to start looking from
/// @param path_name path towards the menu
/// @return found menu or NULL
static vimmenu_T *find_menu(vimmenu_T *menu, char *name, int modes)
static vimmenu_T *find_menu(vimmenu_T *menu, const char *path_name, int modes)
{
assert(*name);
assert(*path_name);
char *const saved_name = xstrdup(path_name);
char *name = saved_name;
while (*name) {
// find the end of one dot-separated name and put a NUL at the dot
@@ -744,12 +769,14 @@ static vimmenu_T *find_menu(vimmenu_T *menu, char *name, int modes)
// Found menu
if (*p != NUL && menu->children == NULL) {
emsg(_(e_notsubmenu));
return NULL;
menu = NULL;
goto theend;
} else if ((menu->modes & modes) == 0x0) {
emsg(_(e_menu_only_exists_in_another_mode));
return NULL;
menu = NULL;
goto theend;
} else if (*p == NUL) { // found a full match
return menu;
goto theend;
}
break;
}
@@ -758,7 +785,7 @@ static vimmenu_T *find_menu(vimmenu_T *menu, char *name, int modes)
if (menu == NULL) {
semsg(_(e_nomenu), name);
return NULL;
break;
}
// Found a match, search the sub-menu.
name = p;
@@ -766,7 +793,9 @@ static vimmenu_T *find_menu(vimmenu_T *menu, char *name, int modes)
menu = menu->children;
}
abort();
theend:
xfree(saved_name);
return menu;
}
/// Show the mapping associated with a menu item or hierarchy in a sub-menu.
@@ -781,10 +810,14 @@ static int show_menus(char *const path_name, int modes)
}
}
// Now we have found the matching menu, and we list the mappings.
// make sure the list of menus doesn't change while listing them
menus_locked++;
// list the matching menu mappings
msg_puts_title(_("\n--- Menus ---"));
show_menus_recursive(menu, modes, 0);
menus_locked--;
return OK;
}

View File

@@ -326,6 +326,37 @@ describe('cmdline', function()
]])
end)
-- oldtest: Test_wildmenu_with_pum_foldexpr()
it('pum when using &foldtext', function()
local screen = Screen.new(60, 10)
exec([[
call setline(1, ['folded one', 'folded two', 'some more text'])
func MyFoldText()
return 'foo'
endfunc
set foldtext=MyFoldText() wildoptions=pum
normal ggzfj
]])
feed(':set<Tab>')
screen:expect([[
{13:foo·························································}|
some more text |
{1:~ }|*3
{12: set }{1: }|
{4: setfiletype }{1: }|
{4: setglobal }{1: }|
{4: setlocal }{1: }|
:set^ |
]])
feed('<Esc>')
screen:expect([[
{13:^foo·························································}|
some more text |
{1:~ }|*7
|
]])
end)
-- oldtest: Test_rulerformat_position()
it("ruler has correct position with 'rulerformat' set", function()
local screen = Screen.new(20, 3)

View File

@@ -124,13 +124,39 @@ func CheckNotMacM1()
endif
endfunc
func SetupWindowSizeToForVisualDumps()
" The dumps used as reference in these tests were created with a terminal
" width of 75 columns. The vim window that uses the remainder of the GUI
" window width must be at least 3 columns. In theory this means we need the
" GUI shell to provide 78+ columns. However the GTK3 resize logic is flaky,
" sometimes resulting in X11 Configure events that are narrower than
" expected by a number of pixels equal to 2 column widths. Therefore
" setting 80 columns ensures that the GUI shell can still provide 78+
" columns. This is very likely papering over a GTK3 resize bug but one that
" has existed for a very long time. Establishing this workaround is meant to
" get the GTK3 code working under CI so that we can focus on removing this
" over the long term.
if &columns != 80
set columns=80
endif
" Without resetting lines, some GTK3 resize events can carry over between
" tests, which invalidate assumptions in the scrollbar offset calculations.
if &lines != 25
set lines=25
endif
endfunc
" Command to check that making screendumps is supported.
" Caller must source screendump.vim
command CheckScreendump call CheckScreendump()
func CheckScreendump()
let g:check_screendump_called = v:true
if !CanRunVimInTerminal()
throw 'Skipped: cannot make screendumps'
endif
if has('gui_running')
call SetupWindowSizeToForVisualDumps()
endif
endfunc
" Command to check that we can Run Vim in a terminal window

View File

@@ -643,6 +643,8 @@ for g:testfunc in sort(s:tests)
" A test can set g:test_is_flaky to retry running the test.
let g:test_is_flaky = 0
let g:check_screendump_called = v:false
" A test can set g:max_run_nr to change the max retry count.
let g:max_run_nr = 5
if has('mac')

View File

@@ -580,6 +580,7 @@ func Test_WinScrolled_close_curwin()
endfunc
func Test_WinScrolled_once_only()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -609,6 +610,7 @@ endfunc
" Check that WinScrolled is not triggered immediately when defined and there
" are split windows.
func Test_WinScrolled_not_when_defined()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -3015,6 +3017,7 @@ endfunc
func Test_autocmd_nested_switch_window()
" run this in a separate Vim so that SafeState works
CheckRunVimInTerminal
CheckScreendump
let lines =<< trim END
vim9script

View File

@@ -2849,6 +2849,7 @@ endfunc
" Test for using a popup menu for the command line completion matches
" (wildoptions=pum)
func Test_wildmenu_pum()
CheckScreendump
CheckRunVimInTerminal
let commands =<< trim [CODE]
@@ -3201,10 +3202,35 @@ func Test_wildmenumode_with_pum()
cunmap <F2>
endfunc
func Test_wildmenu_with_pum_foldexpr()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
call setline(1, ['folded one', 'folded two', 'some more text'])
func MyFoldText()
return 'foo'
endfunc
set foldtext=MyFoldText() wildoptions=pum
normal ggzfj
END
call writefile(lines, 'Xpumfold')
let buf = RunVimInTerminal('-S Xpumfold', #{rows: 10})
call term_sendkeys(buf, ":set\<Tab>")
call VerifyScreenDump(buf, 'Test_wildmenu_with_pum_foldexpr_1', {})
call term_sendkeys(buf, "\<Esc>")
call VerifyScreenDump(buf, 'Test_wildmenu_with_pum_foldexpr_2', {})
call StopVimInTerminal(buf)
call delete('Xpumfold')
endfunc
" Test for opening the cmdline completion popup menu from the terminal window.
" The popup menu should be positioned correctly over the status line of the
" bottom-most window.
func Test_wildmenu_pum_from_terminal()
CheckScreendump
CheckRunVimInTerminal
let python = PythonProg()
call CheckPython(python)
@@ -3225,6 +3251,7 @@ func Test_wildmenu_pum_from_terminal()
endfunc
func Test_wildmenu_pum_odd_wildchar()
CheckScreendump
CheckRunVimInTerminal
" Test odd wildchar interactions with pum. Make sure they behave properly

View File

@@ -563,6 +563,8 @@ endfunc
" Test that cursor is drawn at the correct column when it is after end of the
" line with 'virtualedit' and concealing.
func Run_test_conceal_virtualedit_after_eol(wrap)
CheckScreendump
let code =<< trim eval [CODE]
let &wrap = {a:wrap}
call setline(1, 'abcdefgh|hidden|ijklmnpop')
@@ -595,6 +597,8 @@ endfunc
" Same as Run_test_conceal_virtualedit_after_eol(), but with 'rightleft'.
func Run_test_conceal_virtualedit_after_eol_rightleft(wrap)
CheckScreendump
let code =<< trim eval [CODE]
let &wrap = {a:wrap}
call setline(1, 'abcdefgh|hidden|ijklmnpop')
@@ -628,6 +632,8 @@ endfunc
" Test that cursor position is correct when double-width chars are concealed.
func Run_test_conceal_double_width(wrap)
CheckScreendump
let code =<< trim eval [CODE]
let &wrap = {a:wrap}
call setline(1, ['aaaaa口=口bbbbb口=口ccccc', 'foobar'])

View File

@@ -7,7 +7,12 @@ CheckScreendump
" Run the command in terminal and wait for it to complete via notification
func s:RunCommandAndWait(buf, cmd)
call term_sendkeys(a:buf, a:cmd .. "; printf '" .. TermNotifyParentCmd(v:false) .. "'\<cr>")
call WaitForChildNotification()
if ValgrindOrAsan()
" test times out on ASAN CI builds
call WaitForChildNotification(10000)
else
call WaitForChildNotification()
endif
endfunc
func Test_crash1()
@@ -241,6 +246,7 @@ func Test_crash1_3()
endfunc
func Test_crash2()
CheckScreendump
" The following used to crash Vim
let opts = #{wait_for_ruler: 0, rows: 20}
let args = ' -u NONE -i NONE -n -e -s -S '

View File

@@ -90,6 +90,10 @@ func Test_curswant_with_cursorline()
endfunc
func Test_screenpos()
if has('gui_running')
set lines=25
set columns=78
endif
rightbelow new
rightbelow 20vsplit
call setline(1, ["\tsome text", "long wrapping line here", "next line"])

View File

@@ -111,6 +111,7 @@ endfunc
" This should no longer trigger ml_get errors
func Test_delete_ml_get_errors()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
set noshowcmd noruler scrolloff=0

View File

@@ -951,6 +951,8 @@ endfunc
" Verify a screendump with both the internal and external diff.
func VerifyBoth(buf, dumpfile, extra)
CheckScreendump
" trailing : for leaving the cursor on the command line
for cmd in [":set diffopt=filler" . a:extra . "\<CR>:", ":set diffopt+=internal\<CR>:"]
call term_sendkeys(a:buf, cmd)
@@ -970,6 +972,8 @@ endfunc
" Verify a screendump with the internal diff only.
func VerifyInternal(buf, dumpfile, extra)
CheckScreendump
call term_sendkeys(a:buf, ":diffupdate!\<CR>")
" trailing : for leaving the cursor on the command line
call term_sendkeys(a:buf, ":set diffopt=internal,filler" . a:extra . "\<CR>:")

View File

@@ -519,6 +519,8 @@ func Test_display_linebreak_breakat()
endfunc
func Run_Test_display_lastline(euro)
CheckScreendump
let lines =<< trim END
call setline(1, ['aaa', 'b'->repeat(200)])
set display=truncate

View File

@@ -2057,6 +2057,7 @@ endfunc
" Test for positioning cursor after CTRL-R expression failed
func Test_edit_ctrl_r_failed()
CheckScreendump
CheckRunVimInTerminal
let buf = RunVimInTerminal('', #{rows: 6, cols: 60})

View File

@@ -847,18 +847,6 @@ func Test_mode()
execute "normal! gR\<C-o>g@l\<Esc>"
call assert_equal('n-niV', g:current_modes)
" Test statusline updates for overstrike mode
if CanRunVimInTerminal()
let buf = RunVimInTerminal('', {'rows': 12})
call term_sendkeys(buf, ":set laststatus=2 statusline=%!mode(1)\<CR>")
call term_sendkeys(buf, ":")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_mode_1', {})
call term_sendkeys(buf, "\<Insert>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_mode_2', {})
call StopVimInTerminal(buf)
endif
if has('terminal')
term
@@ -876,6 +864,22 @@ func Test_mode()
delfunction OperatorFunc
endfunc
" Test for the mode() function using Screendump feature
func Test_mode_screendump()
CheckScreendump
" Test statusline updates for overstrike mode
let buf = RunVimInTerminal('', {'rows': 12})
call term_sendkeys(buf, ":set laststatus=2 statusline=%!mode(1)\<CR>")
call term_sendkeys(buf, ":")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_mode_1', {})
call term_sendkeys(buf, "\<Insert>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_mode_2', {})
call StopVimInTerminal(buf)
endfunc
" Test for append()
func Test_append()
enew!
@@ -914,7 +918,7 @@ func Test_setline()
call setline(3, v:_null_list)
call setline(2, ["baz"])
call assert_equal(['bar', 'baz'], getline(1, '$'))
close!
bw!
endfunc
func Test_getbufvar()

View File

@@ -68,6 +68,7 @@ func Test_hlsearch_eol_highlight()
endfunc
func Test_hlsearch_Ctrl_R()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -86,6 +87,7 @@ func Test_hlsearch_Ctrl_R()
endfunc
func Test_hlsearch_clipboard()
CheckScreendump
CheckRunVimInTerminal
CheckFeature clipboard_working

View File

@@ -344,6 +344,7 @@ func Test_matchdelete_error()
endfunc
func Test_matchclear_other_window()
CheckScreendump
CheckRunVimInTerminal
let buf = OtherWindowCommon()
call term_sendkeys(buf, ":call clearmatches(winid)\<CR>")
@@ -354,6 +355,7 @@ func Test_matchclear_other_window()
endfunc
func Test_matchadd_other_window()
CheckScreendump
CheckRunVimInTerminal
let buf = OtherWindowCommon()
call term_sendkeys(buf, ":call matchadd('Search', 'Hello', 1, -1, #{window: winid})\<CR>")
@@ -365,6 +367,7 @@ func Test_matchadd_other_window()
endfunc
func Test_match_in_linebreak()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -372,15 +375,15 @@ func Test_match_in_linebreak()
call printf('%s]%s', repeat('x', 50), repeat('x', 70))->setline(1)
call matchaddpos('ErrorMsg', [[1, 51]])
END
call writefile(lines, 'XscriptMatchLinebreak')
call writefile(lines, 'XscriptMatchLinebreak', 'D')
let buf = RunVimInTerminal('-S XscriptMatchLinebreak', #{rows: 10})
call VerifyScreenDump(buf, 'Test_match_linebreak', {})
call StopVimInTerminal(buf)
call delete('XscriptMatchLinebreak')
endfunc
func Test_match_with_incsearch()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -388,7 +391,7 @@ func Test_match_with_incsearch()
call setline(1, range(20))
call matchaddpos('ErrorMsg', [3])
END
call writefile(lines, 'XmatchWithIncsearch')
call writefile(lines, 'XmatchWithIncsearch', 'D')
let buf = RunVimInTerminal('-S XmatchWithIncsearch', #{rows: 6})
call VerifyScreenDump(buf, 'Test_match_with_incsearch_1', {})
@@ -397,7 +400,6 @@ func Test_match_with_incsearch()
call term_sendkeys(buf, "\<CR>")
call StopVimInTerminal(buf)
call delete('XmatchWithIncsearch')
endfunc
" Test for deleting matches outside of the screen redraw top/bottom lines
@@ -421,6 +423,7 @@ func Test_matchdelete_redraw()
endfunc
func Test_match_tab_with_linebreak()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END

View File

@@ -3,6 +3,8 @@
source check.vim
CheckFeature menu
source screendump.vim
func Test_load_menu()
try
source $VIMRUNTIME/menu.vim
@@ -612,4 +614,50 @@ func Test_only_modifier()
tunmenu a.b
endfunc
func Test_unmenu_while_listing_menus()
CheckRunVimInTerminal
let lines =<< trim END
set nocompatible
unmenu *
for i in range(1, 999)
exe 'menu ' .. 'foo.' .. i .. ' bar'
endfor
au CmdlineLeave : call timer_start(0, {-> execute('unmenu *')})
END
call writefile(lines, 'Xmenuclear', 'D')
let buf = RunVimInTerminal('-S Xmenuclear', {'rows': 10})
" this was using freed memory
call term_sendkeys(buf, ":menu\<CR>")
call TermWait(buf, 50)
call term_sendkeys(buf, "G")
call TermWait(buf, 50)
call term_sendkeys(buf, "\<CR>")
call StopVimInTerminal(buf)
endfunc
" Test for opening a menu drawn in the cmdline area
func Test_popupmenu_cmdline()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
set mousemodel=popup
menu PopUp.Test1 :<CR>
menu PopUp.Test2 :<CR>
menu PopUp.Test3 :<CR>
call setline(1, repeat(['abcde'], 5))
END
call writefile(lines, 'Xpopupcmdline', 'D')
let buf = RunVimInTerminal('-S Xpopupcmdline', {'rows': 4})
" cmdline area should be cleared when popupmenu that covered it is closed
call term_sendkeys(buf, "\<RightMouse>\<RightRelease>\<Esc>")
call VerifyScreenDump(buf, 'Test_popupmenu_cmdline_1', {})
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -400,6 +400,7 @@ func Test_message_more_scrollback()
endfunc
func Test_message_not_cleared_after_mode()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -435,6 +436,7 @@ func Test_message_not_cleared_after_mode()
endfunc
func Test_mode_cleared_after_silent_message()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -459,6 +461,7 @@ endfunc
" Test verbose message before echo command
func Test_echo_verbose_system()
CheckScreendump
CheckRunVimInTerminal
CheckUnix " needs the "seq" command
CheckNotMac " the macos TMPDIR is too long for snapshot testing

View File

@@ -47,6 +47,7 @@ func Test_move()
endfunc
func Test_move_undo()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END

View File

@@ -248,6 +248,7 @@ func Test_put_visual_block_mode()
bwipe!
set ve=
endfunc
func Test_put_other_window()
CheckScreendump
CheckRunVimInTerminal
@@ -267,6 +268,7 @@ func Test_put_other_window()
call StopVimInTerminal(buf)
endfunc
func Test_put_in_last_displayed_line()
CheckScreendump
CheckRunVimInTerminal

View File

@@ -886,6 +886,7 @@ func Test_incsearch_cmdline_modifier()
endfunc
func Test_incsearch_scrolling()
CheckScreendump
CheckRunVimInTerminal
call assert_equal(0, &scrolloff)
call writefile([

View File

@@ -1803,6 +1803,7 @@ endfunc
" Test for correct cursor position after the sign column appears or disappears.
func Test_sign_cursor_position()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END

View File

@@ -835,6 +835,7 @@ func Test_issue_3969()
endfunc
func Test_start_with_tabs()
CheckScreendump
CheckRunVimInTerminal
let buf = RunVimInTerminal('-p a b c', {})

View File

@@ -16,6 +16,10 @@ func TearDown()
endfunc
func s:get_statusline()
if has('gui_running')
redraw!
sleep 1m
endif
return ScreenLines(&lines - 1, &columns)[0]
endfunc

View File

@@ -728,6 +728,7 @@ func Test_sub_cmd_9()
endfunc
func Test_sub_highlight_zero_match()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END

View File

@@ -632,6 +632,7 @@ endfunc
" Check highlighting for a small piece of C code with a screen dump.
func Test_syntax_c()
CheckScreendump
CheckRunVimInTerminal
call writefile([
\ '/* comment line at the top */',

View File

@@ -688,6 +688,7 @@ func Test_tabs()
endfunc
func Test_tabpage_cmdheight()
CheckScreendump
CheckRunVimInTerminal
call writefile([
\ 'set laststatus=2',

View File

@@ -847,6 +847,7 @@ func Test_undo_mark()
endfunc
func Test_undo_after_write()
CheckScreendump
" use a terminal to make undo work like when text is typed
CheckRunVimInTerminal

View File

@@ -294,6 +294,7 @@ func Test_getcellwidths()
endfunc
func Test_setcellwidths_dump()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -311,6 +312,7 @@ endfunc
" Test setcellwidths() on characters that are not targets of 'ambiwidth'.
func Test_setcellwidths_with_non_ambiwidth_character_dump()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END
@@ -333,6 +335,7 @@ endfunc
" For some reason this test causes Test_customlist_completion() to fail on CI,
" so run it as the last test.
func Test_zz_ambiwidth_hl_dump()
CheckScreendump
CheckRunVimInTerminal
let lines =<< trim END