summaryrefslogtreecommitdiffstats
path: root/runtime/menu.vim
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-03-19 18:46:57 +0100
committerBram Moolenaar <Bram@vim.org>2020-03-19 18:46:57 +0100
commit5e94a29ebbde10dd973d58f1adba9a2fc83877d1 (patch)
tree66b87e6f87e558d31f2313791895a428fe9dead3 /runtime/menu.vim
parent37f471df6ee422beb4d08ee4ccda35f8279e3bb7 (diff)
patch 8.2.0413: buffer menu does not handle special buffers properlyv8.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.
Diffstat (limited to 'runtime/menu.vim')
-rw-r--r--runtime/menu.vim115
1 files changed, 70 insertions, 45 deletions
diff --git a/runtime/menu.vim b/runtime/menu.vim
index f01ca7719b..b17e8ea884 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 <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<Tab>:%!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 <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
-func! s:BMRemove()
+" invoked from a BufDelete or BufFilePre autocommand
+func s:BMRemove()
if s:bmenu_wait == 0
- let name = expand("<afile>")
- if isdirectory(name)
- return
+ 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
- let munge = <SID>BMMunge(name, expand("<abuf>"))
+ endif
+endfunc
- 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
+" 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 <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.Select\ &All <C-U>call <SID>SelectAll()<
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