" buffoptions.vim : Per-Buffer options/maps/menus " Michael Geddes " Push options onto a stack - this sets the new value and remembers the old values " The list is a series of "variable", "value" pairs. " 'variable' can also be of the form '[nvoic]*map ' " eg 'vmap ' " or of the form '[anvoic]*menu ' " eg 'vmenu Tools.Test' or 'vmenu 100.100 Tools.Test' " fun! PushOption( ... ) if !exists("b:optionStack") let b:optionStack="\n" endif let c=1 let sep="\n" while c < a:0 exe 'let option=a:'.c let ax='^\(i\=abbr\(ev\)\=\)\s\+' let mx='^!\=\([nvoic]*\)map\s\+' let menx='^!\=\([anvoic]*\)menu\s\+' if option =~ mx let modes=substitute(matchstr(option,mx),mx,'\1','') if option[0] == '!' let nore='nore' else let nore='' endif let option=substitute(option,mx,'','') let ma=0 while ma < strlen(modes) let rhs=maparg(option,modes[ma]) if rhs=="" let b:optionStack=modes[ma].'unmap '.option.sep.b:optionStack else let b:optionStack=modes[ma].'map '.option.' '.rhs.sep.b:optionStack endif exe 'let nrhs=a:'.(c+1) exe modes[ma].nore.'map '.option.' '.nrhs let ma=ma+1 endwhile elseif option =~ ax " At the moment we can't silently get the old abbreviation, and it will " be a rare thing for it to be needed let lhs=substitute(option,ax,'','') let b:optionStack='iuna '.lhs.sep.b:optionStack exe 'let rhs=a:'.(c+1) exe 'iabbr '.lhs.' '.rhs elseif option =~ menx " We can't silently get the old menus, which is a problem at the moment. let modes=substitute(matchstr(option,menx),menx,'\1','') if option[0] == '!' let nore='nore' else let nore='' endif let option=substitute(option,menx,'','') let ma=0 while ma < strlen(modes) " let rhs=menuarg(option,modes[ma]) " Don't have this :( " if rhs=="" let b:optionStack=modes[ma].'unmenu '.option.sep.b:optionStack " else " let b:optionStack=modes[ma].'menu '.option.' '.rhs.sep.b:optionStack " endif exe 'let nrhs=a:'.(c+1) exe modes[ma].nore.'menu '.option.' '.nrhs let ma=ma+1 endwhile else " try not to remember any of the per-buffer options if option !~ '\<\(ts\|sw\|tabstop\|shiftwidth\|softtabstop\|sts\)\>' exe 'let curval=&'.option let b:optionStack='let &'.option."='".curval."'".sep.b:optionStack endif exe 'let &'.option.'=a:'.(c+1) endif let c=c+2 endwhile endfun " Restore the options pushed onto the stack fun! RestoreOptions() if exists("b:optionStack") let mx="^\n\\=[^\n]*" while b:optionStack != '' let erm=v:errmsg let v:errmsg="" exe matchstr(b:optionStack,mx) if v:errmsg!="" echohl ErrorMsg echo 'In Line: '.matchstr(b:optionStack,mx) echohl None else let v:errmsg=erm endif let b:optionStack=substitute(b:optionStack,mx,'','') endwhile endif endfun "Effectively Create some Buffer Enter and Leave User autocommands. " Append "Enter" and "Leave" to the filetype to get the autocommand aug MRGEnterLeave au! au BufEnter * exe "do User ".&filetype."Enter" "au BufLeave * exe "do User ".&filetype."Leave" au User *Enter : "au User *Leave call RestoreOptions() au BufLeave,BufUnload * call RestoreOptions() aug END " This is a little trick to allow mappings defined for a particular file within " the file. The lines recognized are : "vimexe:"option1","value","nmap map2","value2 " where the arguments are the same as for PushOption. " "vimexe:"nmap ",":echo 'hi'" "vimexe:"nmap ",":echo 'hi ther'" "aug MyOpts "au! "au User vimEnter call GetOptionsFromFile('"') "au User vimLeave call RestoreOptions() "aug END fun! GetOptionsFromFile(com) if !exists("b:VIMEXE") let mx='^'.a:com.'vimexe:\s*\(.*\)$' let x='' let i=1 while i<10 let cur=getline(i) if cur =~ mx let x=x.'call PushOption('.substitute(getline(i),mx,'\1','').")\|" endif let i=i+1 endwhile let b:VIMEXE=x endif exe b:VIMEXE endfun " And now for an example of how to use it: " "aug specialEdit "au! "au User sgmlEnter call PushOptions("keywordprg","/bin/htmlkey") "au User cEnter call PushOptions("breakat",". )&|", "complete",".,k/usr/dict,]", "nmap ","o","amenu 10.100 Tools.Compile\\ C",":make" ) " "au User sgmlLeave,cLeave call RestoreOptions() "aug END " This allows you to source a file and have the maps (and menus?) be entered into " a per-filetype list. The file also gets sourced without the maps... so any " functions get loaded. " Usage: call ReadFileTypeMap(txt',$home.'/vim/txtmappings.vim') " This will cause the mappings for ~/vim/txtmappings.vim to be available in " file of FileType 'txt'. fun! FTExe(filetypes, line) return FileType__ExeLine('','',-1, a:filetypes, a:line) endfun com! -nargs=+ Fexe call FTExe( ) fun! FileType__ExeLine(group,filename, lineno, filetypes, line) " let mmx='^\s*[onvica]*\(map\|menu\)\>' let mapx='^\s*\([onvic]*\)map\s\+\(\S*\)\s\+\(.\{-}\)\s*$' let menx='^\s*\([onviac]*\)menu\s\+\(\(\<[0-9.]\+\>\)\s\+\)\=\(\(\\.\|[^\\ ]\+\)\+\)\s\+\(.\{-}\)\s*$' " if a:line!~mmx | continue | endif if a:line=~mapx let mapt = substitute(a:line,mapx,'\1','') let mapa = 'map '.substitute(a:line,mapx,'\2','') let mapb = substitute(a:line,mapx,'\3','') if mapt=='' | let mapt='nvo' | endif elseif a:line=~menx let mapt = substitute(a:line,menx,'\1','') let mapa = 'menu '.substitute(a:line,menx,'\2 \4','') let mapb = substitute(a:line,menx,'\6','') if mapt=='' | let mapt='nvo' | endif else let erm=v:errmsg let v:errmsg='' exe a:line if v:errmsg!="" && lineno>0 echohl ErrorMsg echo 'In line number: '.a:lineno.' of '.a:filename echohl None else let v:errmsg=erm endif return endif let entertypes=substitute(substitute(a:filetypes,'\(\<[a-z]\+\>\)[ ,]*','\1Enter,','g'),',\s*$','','') let erm=v:errmsg let v:errmsg='' if a:group !="" exe 'aug '.a:group endif exe 'au User '.entertypes." call PushOption(\"".escape(mapt.mapa,'\"')."\",\"".escape(mapb,'\"')."\")" if v:errmsg!="" echohl ErrorMsg echo 'In line number: '.a:lineno.' of '.a:filename echohl None else let v:errmsg=erm endif if a:group != "" aug END endif endfun let path_for_buffoptions=expand(':p:h') fun! ReadFileTypeMap(types, filename) let filename=expand(a:filename) if !filereadable(filename) echohl ErrorMsg echo "Can't open file ".a:filename echohl None return "NO" endif let group='FileTypeMap_'.substitute(fnamemodify(filename,':t'),'[^a-zA-Z0-9]','_','g') exe 'aug '.group au! aug END let tname=tempname() call system( "vim ".filename." -R -e -u ".g:path_for_buffoptions."/buffoptions_mac.vim -c \"call DoIt('".group."','".a:types."','".tname."')\"") let erm=v:errmsg let v:errmsg='' exe "so ".tname if v:errmsg!="" echohl ErrorMsg echo 'Error SOURCEing File: '.a:filename echohl None else let v:errmsg=erm endif " call input('Continue?'.tname.'?') if filereadable(tname) call delete(tname) endif endfun com! -complete=file -nargs=1 SOURCE call ReadFileTypeMap( "", )