" Buffer Menus - Add menus to the current buffer only. " Author: Michael Geddes " Version: 1.9 " " Contributions by Luc Hermitte " Usage - " :Bmenu[!] [""] [""|""] [] [] " Add menus to different modes for the current buffer. (Bang is used to " specify 'noremenu') " :B[ivacn]menu[!][""] [""|""] [] " Add menu for one mode (or 'a' for all modes) for the current buffer. " (Bang is used to specify 'noremenu') " ":B[ivacn]noremenu [""] [""|""] [] [] " Adds a 'norecursive' menu. " " The above commands accept '' as a flag to do a silent mapping. " They also allow (providing you have done the "exe FindBufferSID()" " at the beginning of the script), and will expand and " in menu names. " " :Bunmenuall " Remove all menus for the current buffer " " BufferOneShot( ) " Use this to make sure Bmenus only get added ONCE per buffer. " eg: " if BufferOneShot('MyProgram') " Bmenu 10.20 Test.Test iHello " endif " A buffer local-variable called b:buffer_oneshot_MyProgram will be " created (just in case you want to unlet it when testing). " " exe FindBufferSID() " :exe the result of this function when using in menu commands so that the correct " function gets called. " " TODO: " * Add a 'Bunmenu' for one menu. " * If the same menu is added twice to the same mode, update the first entry rather than just " adding it twice (there _will_ be an error on leaving the buffer if this " happens, as there will be two unmenus for the same mode). " Examples - " Bmenu ni 10.30 Test.It Test " Bimenu 10.40 Test.More Hello " Bamenu Test.Ignore :set ic com! -nargs=+ -bang -complete=menu Bmenu call DoBufferMenu(, ) com! -nargs=+ -bang -complete=menu Bimenu call DoBufferMenu(, 'i', ) com! -nargs=+ -bang -complete=menu Bvmenu call DoBufferMenu(, 'v', ) com! -nargs=+ -bang -complete=menu Bamenu call DoBufferMenu(, 'a', ) com! -nargs=+ -bang -complete=menu Bcmenu call DoBufferMenu(, 'c', ) com! -nargs=+ -bang -complete=menu Bnmenu call DoBufferMenu(, 'n', ) com! -nargs=0 Bunmenuall call ClearBufferMenus() com! -nargs=+ -complete=menu Bnoremenu \ call DoBufferMenu('!', ) com! -nargs=+ -complete=menu Binoremenu \ call DoBufferMenu('!', 'i', ) com! -nargs=+ -complete=menu Bvnoremenu \ call DoBufferMenu('!', 'v', ) com! -nargs=+ -complete=menu Banoremenu \ call DoBufferMenu('!', 'a', ) com! -nargs=+ -complete=menu Bcnoremenu \ call DoBufferMenu('!', 'c', ) com! -nargs=+ -complete=menu Bnnoremenu \ call DoBufferMenu('!', 'n', ) " s:ClearBufferMenus " Clear out all the menus fun! s:ClearBufferMenus() call s:RestoreMenus() let b:bufferMenuStack="" let b:bufferUnmenuStack="" endfun " Works out what arguments were passed to the command. " Use ! for 'noremenu' fun! s:DoBufferMenu( bang, ...) let n=1 let modes='' if a:{n} =~ '^[anvoic]*$' let modes=a:{n} let n=n+1 endif let silent = '' let useenable= exists('g:buffermenu_use_disable') && g:buffermenu_use_disable while 1 if a:{n} ==? '' let silent = '' let n = n + 1 elseif a:{n} ==? '' let useenable=0 elseif a:{n} ==? '' let useenable=1 else break endif endwhile let menunumber='' if a:{n} =~ '^\s*[0-9]\+\>\(\.[0-9]\+\)*' let menunumber=a:{n}.' ' let n=n+1 endif if a:0 >= (n+1) let menuname=escape(a:{n},' ') let menucmd=a:{n+1} let n=n+2 while n <= a:0 let menucmd=menucmd.' '.a:{n} let n=n+1 endwhile call s:BufferMenu( a:bang=='!', useenable, modes, silent.menunumber.menuname, menucmd ) else let cmd='('.modes.')menu'.a:bang.' '.menunumber.' ^^ ' let x=n while x<= a:0 let cmd=cmd.' {'.escape(a:{x},' ').'}' let x=x+1 endwhile echoerr 'Invalid arguments: '.cmd endif endfun " s:BufferMenu - Do the work of adding the menu to the buffer. " dontremap - use noremenu " useenable - use menu disable instead of unmenu " modes - list of modes " menuname - name of menu (including priority) " mapping - command to map menu to fun! s:BufferMenu( dontremap, useenable, modes, menuname, mapping ) let sep="\n" if !exists("b:bufferUnmenuStack") let b:bufferUnmenuStack=sep endif if !exists("b:bufferMenuStack") let b:bufferMenuStack=sep endif " We can't silently get the old menus, which is a problem at the moment. let noRe = a:dontremap ? 'nore' : '' let mll=escape(exists('maplocalleader')?maplocalleader : "\\","\\|") let ml=escape(exists('mapleader')?mapleader : "\\","\\|") let menuname=substitute(a:menuname, '\c',escape(mll,"\\") , 'g') let menuname=substitute(menuname, '\c',escape(ml,"\\") , 'g') if exists('b:bmenu_sid_t') let mapping=substitute(a:mapping, '\c',b:bmenu_sid_t, 'g') else if match(a:mapping, '\c') >= 0 echoerr 'You must have "exe FindBufferSID()" before adding buffer menus with !' return endif let mapping=a:mapping endif " Get the modes - if nothing, use the default. let ma=0 let modes=a:modes if modes=='' let modes=' ' " Execute a 'menu' command without prefix endif " Execute while ma < strlen(modes) let cmd=(modes[ma]).noRe. 'menu '.menuname.' '.mapping let erm=v:errmsg let v:errmsg="" exe cmd if v:errmsg!="" echoerr 'In command: '.cmd break else let stripname=substitute(menuname,'^\s*[0-9][0-9.]*','','') if a:useenable let cmd=(modes[ma]).'menu enable '.stripname let undocmd=(modes[ma]).'menu disable '.stripname else let undocmd=(modes[ma]).'unmenu '.stripname endif let v:errmsg=erm let b:bufferUnmenuStack=undocmd.sep.b:bufferUnmenuStack let b:bufferMenuStack=b:bufferMenuStack.cmd.sep endif let ma=ma+1 endwhile endfun " Execute '\n' separated items in such a way that errors can be reported with " the command executed. fun! s:CallStack(stack,stackname) let mx="^\n\\=[^\n]*" let here=0 let last=strlen(a:stack) while here < last let back=matchend(a:stack,mx,here) if back<0 | return | endif let cmd=strpart(a:stack,here, back-here) let erm=v:errmsg let v:errmsg="" exe cmd if v:errmsg!="" echoerr 'Error processing stack "'.a:stackname.'" command: '.cmd else let v:errmsg=erm endif let here=back endwhile endfun " Restore the menus for the buffer fun! s:RestoreMenus() if exists("b:bufferUnmenuStack") && exists('b:buffer_did_menu_stack') unlet b:buffer_did_menu_stack call s:CallStack(b:bufferUnmenuStack, 'Buffer Unmenu') endif endfun " Remove the menus for the buffer fun! s:BufferMenus() if exists("b:bufferMenuStack") let b:buffer_did_menu_stack=1 call s:CallStack(b:bufferMenuStack, 'Buffer Menu') endif endfun fun! BufferOneShot(desc) if exists('b:buffer_oneshot_'.a:desc) return 0 endif let b:buffer_oneshot_{a:desc}=1 return 1 endfun aug MRGBufferMenuEnter au! au BufEnter * call BufferMenus() au BufLeave,BufUnload * call RestoreMenus() aug END " Execute the result of this to make sure that works when creating menus " Example: " exe FindBufferSID() fun! FindBufferSID() return 'imap zzzzzzz |let t_z=@z|redir @z|silent imap zzzzzzz |let b:bmenu_sid_t=matchstr(@z,"\\d\\+_$")|let @z=t_z|unlet t_z|iunmap zzzzzzz' endfun " vim600: set ts=4 sw=4 noet fdm=indent: