Mercurial > vim
changeset 19713:8514e8b7e661 v8.2.0413
patch 8.2.0413: buffer menu does not handle special buffers properly
Commit: https://github.com/vim/vim/commit/5e94a29ebbde10dd973d58f1adba9a2fc83877d1
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Mar 19 18:46:57 2020 +0100
patch 8.2.0413: buffer menu does not handle special buffers properly
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.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 19 Mar 2020 19:00:04 +0100 |
parents | 714875349336 |
children | 0e0ef0f4009f |
files | runtime/menu.vim src/ex_getln.c src/terminal.c src/testdir/Make_all.mak src/testdir/test_alot.vim src/testdir/test_menu.vim src/version.c |
diffstat | 7 files changed, 120 insertions(+), 51 deletions(-) [+] |
line wrap: on
line diff
--- 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: Bram Moolenaar <Bram@vim.org> -" Last Change: 2019 Dec 10 +" 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,11 +139,11 @@ an 10.600 &File.-SEP4- <Nop> an 10.610 &File.Sa&ve-Exit<Tab>:wqa :confirm wqa<CR> an 10.620 &File.E&xit<Tab>:qa :confirm qa<CR> -func! <SID>SelectAll() +func s:SelectAll() exe "norm! gg" . (&slm == "" ? "VG" : "gH\<C-O>G") endfunc -func! s:FnameEscape(fname) +func s:FnameEscape(fname) if exists('*fnameescape') return fnameescape(a:fname) endif @@ -356,7 +356,7 @@ endfun let s:did_setup_color_schemes = 0 " Setup the Edit.Color Scheme submenu -func! s:SetupColorSchemes() abort +func s:SetupColorSchemes() abort if s:did_setup_color_schemes return endif @@ -388,7 +388,7 @@ endif if has("keymap") let s:did_setup_keymaps = 0 - func! s:SetupKeymaps() abort + func s:SetupKeymaps() abort if s:did_setup_keymaps return endif @@ -454,7 +454,7 @@ if has("spell") an <silent> 40.335.270 &Tools.&Spelling.&Find\ More\ Languages :call <SID>SpellLang()<CR> let s:undo_spellang = ['aun &Tools.&Spelling.&Find\ More\ Languages'] - func! s:SpellLang() + func s:SpellLang() for cmd in s:undo_spellang exe "silent! " . cmd endfor @@ -566,7 +566,7 @@ an <silent> 40.540 &Tools.Conve&rt\ Back " Use a function to do the conversion, so that it also works with 'insertmode' " set. -func! s:XxdConv() +func s:XxdConv() let mod = &mod if has("vms") %!mc vim:xxd @@ -580,7 +580,7 @@ func! s:XxdConv() let &mod = mod endfun -func! s:XxdBack() +func s:XxdBack() let mod = &mod if has("vms") %!mc vim:xxd -r @@ -593,7 +593,7 @@ func! s:XxdBack() let &mod = mod endfun -func! s:XxdFind() +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,7 +610,7 @@ endfun let s:did_setup_compilers = 0 " Setup the Tools.Compiler submenu -func! s:SetupCompilers() abort +func s:SetupCompilers() abort if s:did_setup_compilers return endif @@ -634,7 +634,7 @@ endif " Load ColorScheme, Compiler Setting and Keymap menus when idle. if !exists("do_no_lazyload_menus") - func! s:SetupLazyloadMenus() + func s:SetupLazyloadMenus() call s:SetupColorSchemes() call s:SetupCompilers() if has("keymap") @@ -656,51 +656,75 @@ if !exists("no_buffers_menu") " 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 -func! s:BMAdd() +" 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 - call <SID>BMFilename(expand("<afile>"), expand("<abuf>")) - let s:bmenu_count = s:bmenu_count + 1 + let name = expand("<afile>") + let num = expand("<abuf>") + if s:BMCanAdd(name, num) + call <SID>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("<abuf>") + 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 -func! s:BMRemove() - if s:bmenu_wait == 0 - let name = expand("<afile>") - if isdirectory(name) - return - endif - let munge = <SID>BMMunge(name, expand("<abuf>")) +" 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 - if s:bmenu_short == 0 - exe 'silent! aun &Buffers.' . munge - else - exe 'silent! aun &Buffers.' . <SID>BMHash2(munge) . munge - endif - let s:bmenu_count = s:bmenu_count - 1 + " 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(...) +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 exists; keep one entry to avoid a torn off menu to + " 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,7 +745,7 @@ func! s:BMShow(...) " figure out how many buffers there are let buf = 1 while buf <= bufnr('$') - if bufexists(buf) && !isdirectory(bufname(buf)) && buflisted(buf) + if s:BMCanAdd(bufname(buf), buf) let s:bmenu_count = s:bmenu_count + 1 endif let buf = buf + 1 @@ -733,8 +757,9 @@ func! s:BMShow(...) " 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 <SID>BMFilename(bufname(buf), buf) + let name = bufname(buf) + if s:BMCanAdd(name, buf) + call <SID>BMFilename(name, buf) endif let buf = buf + 1 endwhile @@ -746,7 +771,7 @@ func! s:BMShow(...) aug END endfunc -func! s:BMHash(name) +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,7 +786,7 @@ func! s:BMHash(name) 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) +func s:BMHash2(name) let nm = substitute(a:name, ".", '\L\0', "") " Not exactly right for EBCDIC... if nm[0] < 'a' || nm[0] > 'z' @@ -781,22 +806,22 @@ func! s:BMHash2(name) endif endfunc -" insert a buffer name into the buffer menu: -func! s:BMFilename(name, num) - if isdirectory(a:name) - return - endif +" Insert a buffer name into the buffer menu. +func s:BMFilename(name, num) let munge = <SID>BMMunge(a:name, a:num) let hash = <SID>BMHash(munge) if s:bmenu_short == 0 - let name = 'an ' . g:bmenu_priority . '.' . hash . ' &Buffers.' . munge + let s:bmenu_items[a:num] = munge + let cmd = 'an ' . g:bmenu_priority . '.' . hash . ' &Buffers.' . munge else - let name = 'an ' . g:bmenu_priority . '.' . hash . '.' . hash . ' &Buffers.' . <SID>BMHash2(munge) . munge + let menu_name = <SID>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 <CR> let cpo_save = &cpo set cpo&vim - exe name . ' :confirm b' . a:num . '<CR>' + exe cmd . ' :confirm b' . a:num . '<CR>' let &cpo = cpo_save endfunc @@ -804,7 +829,7 @@ endfunc if !exists("g:bmenu_max_pathlen") let g:bmenu_max_pathlen = 35 endif -func! s:BMTruncName(fname) +func s:BMTruncName(fname) let name = a:fname if g:bmenu_max_pathlen < 5 let name = "" @@ -824,7 +849,7 @@ func! s:BMTruncName(fname) return name endfunc -func! s:BMMunge(fname, bnum) +func s:BMMunge(fname, bnum) let name = a:fname if name == '' if !exists("g:menutrans_no_file") @@ -941,7 +966,7 @@ cnoremenu <script> <silent> 1.100 PopUp. if has("spell") " Spell suggestions in the popup menu. Note that this will slow down the " appearance of the menu! - func! <SID>SpellPopup() + func s:SpellPopup() if exists("s:changeitem") && s:changeitem != '' call <SID>SpellDel() endif @@ -997,7 +1022,7 @@ if has("spell") call cursor(0, curcol) " put the cursor back where it was endfunc - func! <SID>SpellReplace(n) + func s:SpellReplace(n) let l = getline('.') " Move the cursor to the start of the word. call spellbadword() @@ -1005,7 +1030,7 @@ if has("spell") \ . strpart(l, col('.') + len(s:fromword) - 1)) endfunc - func! <SID>SpellDel() + func s:SpellDel() exe "aunmenu PopUp." . s:changeitem exe "aunmenu PopUp." . s:additem exe "aunmenu PopUp." . s:ignoreitem
--- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -4195,7 +4195,9 @@ open_cmdwin(void) // 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
--- a/src/terminal.c +++ b/src/terminal.c @@ -523,6 +523,8 @@ term_start( 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,6 +573,8 @@ term_start( 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);
--- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -175,9 +175,9 @@ NEW_TESTS = \ test_matchadd_conceal \ test_matchadd_conceal_utf8 \ test_memory_usage \ - test_method \ test_menu \ test_messages \ + test_method \ test_mksession \ test_mksession_utf8 \ test_modeline \ @@ -402,6 +402,7 @@ NEW_TESTS_RES = \ 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 \
--- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -19,7 +19,6 @@ source test_glob2regpat.vim 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
--- a/src/testdir/test_menu.vim +++ b/src/testdir/test_menu.vim @@ -19,6 +19,41 @@ func Test_load_menu() 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')\<CR>:q\<CR>", '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,6 +156,7 @@ endfunc " 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,7 +182,7 @@ func Test_menu_expand() " Test for <Up> to go up a menu call feedkeys(":emenu Xmenu.A\<Tab>\<Down>\<Up>\<Up>\<Up>" .. \ "\<C-A>\<C-B>\"\<CR>", 'xt') - call assert_equal('"emenu Buffers. Xmenu.', @:) + call assert_equal('"emenu Dummy. Xmenu.', @:) " Test for expanding only submenus call feedkeys(":popup Xmenu.\<C-A>\<C-B>\"\<CR>", 'xt') @@ -166,6 +202,7 @@ func Test_menu_expand() set wildmenu& unmenu Xmenu + unmenu Dummy " Test for expanding popup menus with some hidden items menu Xmenu.foo.A1 a1 @@ -175,7 +212,6 @@ func Test_menu_expand() call feedkeys(":popup Xmenu.\<C-A>\<C-B>\"\<CR>", 'xt') call assert_equal('"popup Xmenu.foo', @:) unmenu Xmenu - endfunc " Test for the menu_info() function