From 9d85f086d9a9536fd511089c04fc2acc6b0fbe7d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Aug 2025 17:11:13 +0800 Subject: [PATCH] vim-patch:9.1.1622: Patch v9.1.1432 causes performance regressions (#35288) Problem: Patch v9.1.1432 causes performance regressions Solution: Revert "patch 9.1.1432: GTK GUI: Buffer menu does not handle unicode correctly" (Yee Cheng Chin). This reverts commit 08896dd330c6dc8324618fde482db968e6f71088. The previous change to support Unicode characters properly in the buffers menu resorted to removing all buffer menus and re-add the buffers after doing a sort, per each buffer addition. This was quite slow because if Vim is trying to load in multiple buffers at once (e.g. when loading a session) this scales in O(n^2) and Vim can freeze for dozens of seconds when adding a few hundred buffers. related: vim/vim#17405 related: vim/vim#17928 fixes: vim/vim#17897 https://github.com/vim/vim/commit/cda0d17f5937c9e09d6821da64e57d589fd3c404 Co-authored-by: Yee Cheng Chin --- runtime/menu.vim | 66 ++++++++++++++++++++++------------- test/old/testdir/test_gui.vim | 13 ------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/runtime/menu.vim b/runtime/menu.vim index 75ba52835a..662eea9403 100644 --- a/runtime/menu.vim +++ b/runtime/menu.vim @@ -2,7 +2,7 @@ " You can also use this as a start for your own set of menus. " " Maintainer: The Vim Project -" Last Change: 2025 Jun 04 +" Last Change: 2023 Aug 10 " Former Maintainer: Bram Moolenaar " Note that ":an" (short for ":anoremenu") is often used to make a menu work @@ -684,7 +684,12 @@ func s:BMAdd() if s:bmenu_count == &menuitems && s:bmenu_short == 0 call s:BMShow() else - call s:BMRedraw() + let name = expand("") + let num = expand("") + 0 " add zero to convert to a number type + if s:BMCanAdd(name, num) + call BMFilename(name, num) + let s:bmenu_count += 1 + endif endif endif endfunc @@ -726,16 +731,17 @@ func s:BMCanAdd(name, num) endfunc " Create the buffer menu (delete an existing one first). -func s:BMShow() +func s:BMShow(...) let s:bmenu_wait = 1 let s:bmenu_short = 1 let s:bmenu_count = 0 let s:bmenu_items = {} + " + " get new priority, if exists + if a:0 == 1 + let g:bmenu_priority = a:1 + endif - call s:BMRedraw() -endfunc - -func s:BMRedraw() " Remove old menu, if it exists; keep one entry to avoid a torn off menu to " disappear. Use try/catch to avoid setting v:errmsg try | unmenu &Buffers | catch | endtry @@ -755,30 +761,26 @@ func s:BMRedraw() unmenu &Buffers.Dummy " figure out how many buffers there are - let buffer_menu_items = [] let buf = 1 while buf <= bufnr('$') - let name = bufname(buf) - if s:BMCanAdd(name, buf) - call add(buffer_menu_items, [substitute(name, ".", '\L\0', ""), name, buf]) + if s:BMCanAdd(bufname(buf), buf) + let s:bmenu_count = s:bmenu_count + 1 endif let buf = buf + 1 endwhile - let s:bmenu_count = len(buffer_menu_items) - if s:bmenu_count <= &menuitems let s:bmenu_short = 0 endif " iterate through buffer list, adding each buffer to the menu: - call sort(buffer_menu_items) - - let i = 0 - for menu_item in buffer_menu_items - call s:BMFilename(menu_item[1], menu_item[2], i) - let i += 1 - endfor - + let buf = 1 + while buf <= bufnr('$') + let name = bufname(buf) + if s:BMCanAdd(name, buf) + call BMFilename(name, buf) + endif + let buf = buf + 1 + endwhile let s:bmenu_wait = 0 aug buffer_list au! @@ -787,6 +789,21 @@ func s:BMRedraw() aug END endfunc +func s:BMHash(name) + " Make name all upper case, so that chars are between 32 and 96 + let nm = substitute(a:name, ".*", '\U\0', "") + if has("ebcdic") + " HACK: Replace all non alphabetics with 'Z' + " Just to make it work for now. + let nm = substitute(nm, "[^A-Z]", 'Z', "g") + let sp = char2nr('A') - 1 + else + let sp = char2nr(' ') + endif + " convert first six chars into a number for sorting: + return (char2nr(nm[0]) - sp) * 0x800000 + (char2nr(nm[1]) - sp) * 0x20000 + (char2nr(nm[2]) - sp) * 0x1000 + (char2nr(nm[3]) - sp) * 0x80 + (char2nr(nm[4]) - sp) * 0x20 + (char2nr(nm[5]) - sp) +endfunc + func s:BMHash2(name) let nm = substitute(a:name, ".", '\L\0', "") " Not exactly right for EBCDIC... @@ -808,15 +825,16 @@ func s:BMHash2(name) endfunc " Insert a buffer name into the buffer menu. -func s:BMFilename(name, num, index) +func s:BMFilename(name, num) let munge = BMMunge(a:name, a:num) + let hash = BMHash(munge) if s:bmenu_short == 0 let s:bmenu_items[a:num] = munge - let cmd = 'an ' .. g:bmenu_priority .. '.9999.' .. a:index .. ' &Buffers.' .. munge + let cmd = 'an ' . g:bmenu_priority . '.' . hash . ' &Buffers.' . munge else let menu_name = BMHash2(munge) . munge let s:bmenu_items[a:num] = menu_name - let cmd = 'an ' .. g:bmenu_priority .. '.9999.0.' .. a:index .. ' &Buffers.' .. menu_name + let cmd = 'an ' . g:bmenu_priority . '.' . hash . '.' . hash . ' &Buffers.' . menu_name endif " set 'cpo' to include the let cpo_save = &cpo diff --git a/test/old/testdir/test_gui.vim b/test/old/testdir/test_gui.vim index fc39ac15e5..9780d22e4f 100644 --- a/test/old/testdir/test_gui.vim +++ b/test/old/testdir/test_gui.vim @@ -44,17 +44,4 @@ func Test_colorscheme() redraw! endfunc -" Test that buffer names are shown at the end in the :Buffers menu -func Test_Buffers_Menu() - doautocmd LoadBufferMenu VimEnter - - let name = '天' - exe ':badd ' .. name - let nr = bufnr('$') - - let cmd = printf(':amenu Buffers.%s\ (%d)', name, nr) - let menu = split(execute(cmd), '\n')[1] - call assert_match('^9999 '.. name, menu) -endfunc - " vim: shiftwidth=2 sts=2 expandtab