diff --git a/runtime/menu.vim b/runtime/menu.vim index e20720dbd2..706e3072d7 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: Bram Moolenaar -" 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- an 10.610 &File.Sa&ve-Exit:wqa :confirm wqa an 10.620 &File.E&xit:qa :confirm qa -func! SelectAll() +func s:SelectAll() exe "norm! gg" . (&slm == "" ? "VG" : "gH\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 40.335.270 &Tools.&Spelling.&Find\ More\ Languages :call SpellLang() let s:undo_spelllang = ['aun &Tools.&Spelling.&Find\ More\ Languages'] - func! s:SpellLang() + func s:SpellLang() for cmd in s:undo_spelllang exe "silent! " . cmd endfor @@ -566,7 +566,7 @@ an 40.540 &Tools.Conve&rt\ Back:%!xxd\ -r " 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 BMFilename(expand(""), expand("")) - let s:bmenu_count = s:bmenu_count + 1 + let name = expand("") + let num = expand("") + if s:BMCanAdd(name, num) + call BMFilename(name, num) + let s:bmenu_count += 1 + endif endif endif endfunc -func! s:BMRemove() +" invoked from a BufDelete or BufFilePre autocommand +func s:BMRemove() if s:bmenu_wait == 0 - let name = expand("") - if isdirectory(name) - return + 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 - 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 +" 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(...) +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 BMFilename(bufname(buf), buf) + let name = bufname(buf) + if s:BMCanAdd(name, buf) + call 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 = BMMunge(a:name, a:num) let hash = 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.' . BMHash2(munge) . munge + 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 name . ' :confirm b' . a:num . '' + exe cmd . ' :confirm b' . a:num . '' 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