To: vim_dev@googlegroups.com Subject: Patch 8.2.0413 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0413 Problem: Buffer menu does not handle special buffers properly. Solution: Keep a dictionary with buffer names to reliably keep track of entries. Also trigger BufFilePre and BufFilePost for command-line and terminal buffers when the name changes. Files: src/testdir/test_alot.vim, src/testdir/Make_all.mak, runtime/menu.vim, src/ex_getln.c, src/terminal.c, src/testdir/test_menu.vim *** ../vim-8.2.0412/src/testdir/test_alot.vim 2020-01-28 21:53:24.039964573 +0100 --- src/testdir/test_alot.vim 2020-03-19 17:45:57.938251215 +0100 *************** *** 19,25 **** source test_global.vim source test_jumps.vim source test_lispwords.vim - source test_menu.vim source test_move.vim source test_put.vim source test_recover.vim --- 19,24 ---- *** ../vim-8.2.0412/src/testdir/Make_all.mak 2020-03-06 20:35:46.120669845 +0100 --- src/testdir/Make_all.mak 2020-03-19 17:46:29.514127093 +0100 *************** *** 175,183 **** test_matchadd_conceal \ test_matchadd_conceal_utf8 \ test_memory_usage \ - test_method \ test_menu \ test_messages \ test_mksession \ test_mksession_utf8 \ test_modeline \ --- 175,183 ---- test_matchadd_conceal \ test_matchadd_conceal_utf8 \ test_memory_usage \ test_menu \ test_messages \ + test_method \ test_mksession \ test_mksession_utf8 \ test_modeline \ *************** *** 402,407 **** --- 402,408 ---- test_matchadd_conceal.res \ test_matchadd_conceal_utf8.res \ test_memory_usage.res \ + test_menu.res \ test_messages.res \ test_method.res \ test_mksession.res \ *** ../vim-8.2.0412/runtime/menu.vim 2019-12-10 22:06:33.000000000 +0100 --- runtime/menu.vim 2020-03-19 18:17:55.920722422 +0100 *************** *** 2,8 **** " You can also use this as a start for your own set of menus. " " Maintainer: Bram Moolenaar ! " Last Change: 2019 Dec 10 " Note that ":an" (short for ":anoremenu") is often used to make a menu work " in all modes and avoid side effects from mappings defined by the user. --- 2,8 ---- " You can also use this as a start for your own set of menus. " " Maintainer: Bram Moolenaar ! " Last Change: 2020 Mar 19 " Note that ":an" (short for ":anoremenu") is often used to make a menu work " in all modes and avoid side effects from mappings defined by the user. *************** *** 139,149 **** an 10.610 &File.Sa&ve-Exit:wqa :confirm wqa an 10.620 &File.E&xit:qa :confirm qa ! func! SelectAll() exe "norm! gg" . (&slm == "" ? "VG" : "gH\G") endfunc ! func! s:FnameEscape(fname) if exists('*fnameescape') return fnameescape(a:fname) endif --- 139,149 ---- an 10.610 &File.Sa&ve-Exit:wqa :confirm wqa an 10.620 &File.E&xit:qa :confirm qa ! func s:SelectAll() exe "norm! gg" . (&slm == "" ? "VG" : "gH\G") endfunc ! func s:FnameEscape(fname) if exists('*fnameescape') return fnameescape(a:fname) endif *************** *** 356,362 **** let s:did_setup_color_schemes = 0 " Setup the Edit.Color Scheme submenu ! func! s:SetupColorSchemes() abort if s:did_setup_color_schemes return endif --- 356,362 ---- let s:did_setup_color_schemes = 0 " Setup the Edit.Color Scheme submenu ! func s:SetupColorSchemes() abort if s:did_setup_color_schemes return endif *************** *** 388,394 **** if has("keymap") let s:did_setup_keymaps = 0 ! func! s:SetupKeymaps() abort if s:did_setup_keymaps return endif --- 388,394 ---- if has("keymap") let s:did_setup_keymaps = 0 ! func s:SetupKeymaps() abort if s:did_setup_keymaps return endif *************** *** 454,460 **** an 40.335.270 &Tools.&Spelling.&Find\ More\ Languages :call SpellLang() let s:undo_spellang = ['aun &Tools.&Spelling.&Find\ More\ Languages'] ! func! s:SpellLang() for cmd in s:undo_spellang exe "silent! " . cmd endfor --- 454,460 ---- an 40.335.270 &Tools.&Spelling.&Find\ More\ Languages :call SpellLang() let s:undo_spellang = ['aun &Tools.&Spelling.&Find\ More\ Languages'] ! func s:SpellLang() for cmd in s:undo_spellang exe "silent! " . cmd endfor *************** *** 566,572 **** " Use a function to do the conversion, so that it also works with 'insertmode' " set. ! func! s:XxdConv() let mod = &mod if has("vms") %!mc vim:xxd --- 566,572 ---- " Use a function to do the conversion, so that it also works with 'insertmode' " set. ! func s:XxdConv() let mod = &mod if has("vms") %!mc vim:xxd *************** *** 580,586 **** let &mod = mod endfun ! func! s:XxdBack() let mod = &mod if has("vms") %!mc vim:xxd -r --- 580,586 ---- let &mod = mod endfun ! func s:XxdBack() let mod = &mod if has("vms") %!mc vim:xxd -r *************** *** 593,599 **** let &mod = mod endfun ! func! s:XxdFind() if !exists("g:xxdprogram") " On the PC xxd may not be in the path but in the install directory if has("win32") && !executable("xxd") --- 593,599 ---- let &mod = mod endfun ! func s:XxdFind() if !exists("g:xxdprogram") " On the PC xxd may not be in the path but in the install directory if has("win32") && !executable("xxd") *************** *** 610,616 **** let s:did_setup_compilers = 0 " Setup the Tools.Compiler submenu ! func! s:SetupCompilers() abort if s:did_setup_compilers return endif --- 610,616 ---- let s:did_setup_compilers = 0 " Setup the Tools.Compiler submenu ! func s:SetupCompilers() abort if s:did_setup_compilers return endif *************** *** 634,640 **** " Load ColorScheme, Compiler Setting and Keymap menus when idle. if !exists("do_no_lazyload_menus") ! func! s:SetupLazyloadMenus() call s:SetupColorSchemes() call s:SetupCompilers() if has("keymap") --- 634,640 ---- " Load ColorScheme, Compiler Setting and Keymap menus when idle. if !exists("do_no_lazyload_menus") ! func s:SetupLazyloadMenus() call s:SetupColorSchemes() call s:SetupCompilers() if has("keymap") *************** *** 656,706 **** " startup faster. let s:bmenu_wait = 1 if !exists("bmenu_priority") let bmenu_priority = 60 endif ! func! s:BMAdd() if s:bmenu_wait == 0 " when adding too many buffers, redraw in short format if s:bmenu_count == &menuitems && s:bmenu_short == 0 call s:BMShow() else ! call BMFilename(expand(""), expand("")) ! let s:bmenu_count = s:bmenu_count + 1 endif endif endfunc ! func! s:BMRemove() if s:bmenu_wait == 0 ! let name = expand("") ! if isdirectory(name) ! return endif ! let munge = BMMunge(name, expand("")) ! if s:bmenu_short == 0 ! exe 'silent! aun &Buffers.' . munge ! else ! exe 'silent! aun &Buffers.' . BMHash2(munge) . munge ! endif ! let s:bmenu_count = s:bmenu_count - 1 endif endfunc " Create the buffer menu (delete an existing one first). ! func! s:BMShow(...) let s:bmenu_wait = 1 let s:bmenu_short = 1 let s:bmenu_count = 0 " " get new priority, if exists if a:0 == 1 let g:bmenu_priority = a:1 endif ! " Remove old menu, if 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 exe 'noremenu ' . g:bmenu_priority . ".1 &Buffers.Dummy l" --- 656,730 ---- " startup faster. let s:bmenu_wait = 1 + " Dictionary of buffer number to name. This helps prevent problems where a + " buffer as renamed and we didn't keep track of that. + let s:bmenu_items = {} + if !exists("bmenu_priority") let bmenu_priority = 60 endif ! " invoked from a BufCreate or BufFilePost autocommand ! func s:BMAdd() if s:bmenu_wait == 0 " when adding too many buffers, redraw in short format if s:bmenu_count == &menuitems && s:bmenu_short == 0 call s:BMShow() else ! let name = expand("") ! let num = expand("") ! if s:BMCanAdd(name, num) ! call BMFilename(name, num) ! let s:bmenu_count += 1 ! endif endif endif endfunc ! " invoked from a BufDelete or BufFilePre autocommand ! func s:BMRemove() if s:bmenu_wait == 0 ! let bufnum = expand("") ! if s:bmenu_items->has_key(bufnum) ! let menu_name = s:bmenu_items[bufnum] ! exe 'silent! aun &Buffers.' . menu_name ! let s:bmenu_count = s:bmenu_count - 1 ! unlet s:bmenu_items[bufnum] endif ! endif ! endfunc ! " Return non-zero if buffer with number "name" / "num" is useful to add in the ! " buffer menu. ! func s:BMCanAdd(name, num) ! " no directory or unlisted buffer ! if isdirectory(a:name) || !buflisted(a:num) ! return 0 ! endif ! ! " no special buffer, such as terminal or popup ! let buftype = getbufvar(a:num, '&buftype') ! if buftype != '' && buftype != 'nofile' && buftype != 'nowrite' ! return 0 endif + + " only existing buffers + return bufexists(a:num) endfunc " Create the buffer menu (delete an existing one first). ! 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 ! " 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 exe 'noremenu ' . g:bmenu_priority . ".1 &Buffers.Dummy l" *************** *** 721,727 **** " figure out how many buffers there are let buf = 1 while buf <= bufnr('$') ! if bufexists(buf) && !isdirectory(bufname(buf)) && buflisted(buf) let s:bmenu_count = s:bmenu_count + 1 endif let buf = buf + 1 --- 745,751 ---- " figure out how many buffers there are let buf = 1 while buf <= bufnr('$') ! if s:BMCanAdd(bufname(buf), buf) let s:bmenu_count = s:bmenu_count + 1 endif let buf = buf + 1 *************** *** 733,740 **** " iterate through buffer list, adding each buffer to the menu: let buf = 1 while buf <= bufnr('$') ! if bufexists(buf) && !isdirectory(bufname(buf)) && buflisted(buf) ! call BMFilename(bufname(buf), buf) endif let buf = buf + 1 endwhile --- 757,765 ---- " iterate through buffer list, adding each buffer to the menu: 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 *************** *** 746,752 **** 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") --- 771,777 ---- 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") *************** *** 761,767 **** 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... if nm[0] < 'a' || nm[0] > 'z' --- 786,792 ---- 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... if nm[0] < 'a' || nm[0] > 'z' *************** *** 781,802 **** endif endfunc ! " insert a buffer name into the buffer menu: ! func! s:BMFilename(name, num) ! if isdirectory(a:name) ! return ! endif let munge = BMMunge(a:name, a:num) let hash = BMHash(munge) if s:bmenu_short == 0 ! let name = 'an ' . g:bmenu_priority . '.' . hash . ' &Buffers.' . munge else ! let name = 'an ' . g:bmenu_priority . '.' . hash . '.' . hash . ' &Buffers.' . BMHash2(munge) . munge endif " set 'cpo' to include the let cpo_save = &cpo set cpo&vim ! exe name . ' :confirm b' . a:num . '' let &cpo = cpo_save endfunc --- 806,827 ---- endif endfunc ! " Insert a buffer name into the buffer menu. ! 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 . '.' . hash . ' &Buffers.' . munge else ! let menu_name = BMHash2(munge) . munge ! let s:bmenu_items[a:num] = menu_name ! let cmd = 'an ' . g:bmenu_priority . '.' . hash . '.' . hash . ' &Buffers.' . menu_name endif " set 'cpo' to include the let cpo_save = &cpo set cpo&vim ! exe cmd . ' :confirm b' . a:num . '' let &cpo = cpo_save endfunc *************** *** 804,810 **** if !exists("g:bmenu_max_pathlen") let g:bmenu_max_pathlen = 35 endif ! func! s:BMTruncName(fname) let name = a:fname if g:bmenu_max_pathlen < 5 let name = "" --- 829,835 ---- if !exists("g:bmenu_max_pathlen") let g:bmenu_max_pathlen = 35 endif ! func s:BMTruncName(fname) let name = a:fname if g:bmenu_max_pathlen < 5 let name = "" *************** *** 824,830 **** return name endfunc ! func! s:BMMunge(fname, bnum) let name = a:fname if name == '' if !exists("g:menutrans_no_file") --- 849,855 ---- return name endfunc ! func s:BMMunge(fname, bnum) let name = a:fname if name == '' if !exists("g:menutrans_no_file") *************** *** 941,947 **** if has("spell") " Spell suggestions in the popup menu. Note that this will slow down the " appearance of the menu! ! func! SpellPopup() if exists("s:changeitem") && s:changeitem != '' call SpellDel() endif --- 966,972 ---- if has("spell") " Spell suggestions in the popup menu. Note that this will slow down the " appearance of the menu! ! func s:SpellPopup() if exists("s:changeitem") && s:changeitem != '' call SpellDel() endif *************** *** 997,1003 **** call cursor(0, curcol) " put the cursor back where it was endfunc ! func! SpellReplace(n) let l = getline('.') " Move the cursor to the start of the word. call spellbadword() --- 1022,1028 ---- call cursor(0, curcol) " put the cursor back where it was endfunc ! func s:SpellReplace(n) let l = getline('.') " Move the cursor to the start of the word. call spellbadword() *************** *** 1005,1011 **** \ . strpart(l, col('.') + len(s:fromword) - 1)) endfunc ! func! SpellDel() exe "aunmenu PopUp." . s:changeitem exe "aunmenu PopUp." . s:additem exe "aunmenu PopUp." . s:ignoreitem --- 1030,1036 ---- \ . strpart(l, col('.') + len(s:fromword) - 1)) endfunc ! func s:SpellDel() exe "aunmenu PopUp." . s:changeitem exe "aunmenu PopUp." . s:additem exe "aunmenu PopUp." . s:ignoreitem *** ../vim-8.2.0412/src/ex_getln.c 2020-03-18 15:23:10.979695103 +0100 --- src/ex_getln.c 2020-03-19 17:51:08.053044242 +0100 *************** *** 4195,4201 **** --- 4195,4203 ---- // Create the command-line buffer empty. (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL); + apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf); (void)setfname(curbuf, (char_u *)"[Command Line]", NULL, TRUE); + apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf); set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL); curbuf->b_p_ma = TRUE; #ifdef FEAT_FOLDING *** ../vim-8.2.0412/src/terminal.c 2020-03-11 19:29:57.853088812 +0100 --- src/terminal.c 2020-03-19 17:51:08.053044242 +0100 *************** *** 523,528 **** --- 523,530 ---- term->tl_next = first_term; first_term = term; + apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf); + if (opt->jo_term_name != NULL) curbuf->b_ffname = vim_strsave(opt->jo_term_name); else if (argv != NULL) *************** *** 571,576 **** --- 573,580 ---- curbuf->b_sfname = vim_strsave(curbuf->b_ffname); curbuf->b_fname = curbuf->b_ffname; + apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf); + if (opt->jo_term_opencmd != NULL) term->tl_opencmd = vim_strsave(opt->jo_term_opencmd); *** ../vim-8.2.0412/src/testdir/test_menu.vim 2020-03-15 16:12:16.552208654 +0100 --- src/testdir/test_menu.vim 2020-03-19 18:45:21.857156136 +0100 *************** *** 19,24 **** --- 19,59 ---- call assert_equal('', v:errmsg) endfunc + func Test_buffer_menu_special_buffers() + " Load in runtime menus + try + source $VIMRUNTIME/menu.vim + catch + call assert_report('error while loading menus: ' . v:exception) + endtry + + let v:errmsg = '' + doautocmd LoadBufferMenu VimEnter + call assert_equal('', v:errmsg) + + let orig_buffer_menus = execute("nmenu Buffers") + + " Make a new command-line window, test that it does not create a new buffer + " menu. + call feedkeys("q::let cmdline_buffer_menus=execute('nmenu Buffers')\:q\", 'ntx') + call assert_equal(len(split(orig_buffer_menus, "\n")), len(split(cmdline_buffer_menus, "\n"))) + call assert_equal(orig_buffer_menus, execute("nmenu Buffers")) + + if has('terminal') + " Open a terminal window and test that it does not create a buffer menu + " item. + terminal + let term_buffer_menus = execute('nmenu Buffers') + call assert_equal(len(split(orig_buffer_menus, "\n")), len(split(term_buffer_menus, "\n"))) + bwipe! + call assert_equal(orig_buffer_menus, execute("nmenu Buffers")) + endif + + " Remove menus to clean up + source $VIMRUNTIME/delmenu.vim + call assert_equal('', v:errmsg) + endfunc + func Test_translate_menu() if !has('multi_lang') return *************** *** 121,126 **** --- 156,162 ---- " Test for menu item completion in command line func Test_menu_expand() " Create the menu itmes for test + menu Dummy.Nothing lll for i in range(1, 4) let m = 'menu Xmenu.A' .. i .. '.A' .. i for j in range(1, 4) *************** *** 146,152 **** " Test for to go up a menu call feedkeys(":emenu Xmenu.A\\\\\" .. \ "\\\"\", 'xt') ! call assert_equal('"emenu Buffers. Xmenu.', @:) " Test for expanding only submenus call feedkeys(":popup Xmenu.\\\"\", 'xt') --- 182,188 ---- " Test for to go up a menu call feedkeys(":emenu Xmenu.A\\\\\" .. \ "\\\"\", 'xt') ! call assert_equal('"emenu Dummy. Xmenu.', @:) " Test for expanding only submenus call feedkeys(":popup Xmenu.\\\"\", 'xt') *************** *** 166,171 **** --- 202,208 ---- set wildmenu& unmenu Xmenu + unmenu Dummy " Test for expanding popup menus with some hidden items menu Xmenu.foo.A1 a1 *************** *** 175,181 **** call feedkeys(":popup Xmenu.\\\"\", 'xt') call assert_equal('"popup Xmenu.foo', @:) unmenu Xmenu - endfunc " Test for the menu_info() function --- 212,217 ---- *** ../vim-8.2.0412/src/version.c 2020-03-19 17:13:36.646135855 +0100 --- src/version.c 2020-03-19 18:45:49.712997574 +0100 *************** *** 740,741 **** --- 740,743 ---- { /* Add new patch number below this line */ + /**/ + 413, /**/ -- "My particular problem is with registry entries, which seem to just accumulate like plastic coffee cups..." -- Paul Moore /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///