" ============================================================================ " File: tagbar.vim " Description: List the current file's tags in a sidebar, ordered by class etc " Author: Jan Larres " Licence: Vim licence " Website: http://majutsushi.github.com/tagbar/ " Version: 1.2 " Note: This plugin was heavily inspired by the 'Taglist' plugin by " Yegappan Lakshmanan and uses a small amount of code from it. " " Original taglist copyright notice: " Permission is hereby granted to use and distribute this code, " with or without modifications, provided that this copyright " notice is copied with it. Like anything else that's free, " taglist.vim is provided *as is* and comes with no warranty of " any kind, either expressed or implied. In no event will the " copyright holder be liable for any damamges resulting from the " use of this software. " ============================================================================ if &cp || exists('g:loaded_tagbar') finish endif " Initialization {{{1 if !exists('g:tagbar_ctags_bin') if executable('ctags-exuberant') let g:tagbar_ctags_bin = 'ctags-exuberant' elseif executable('exctags') let g:tagbar_ctags_bin = 'exctags' elseif executable('ctags') let g:tagbar_ctags_bin = 'ctags' elseif executable('ctags.exe') let g:tagbar_ctags_bin = 'ctags.exe' elseif executable('tags') let g:tagbar_ctags_bin = 'tags' else echomsg 'Tagbar: Exuberant ctags not found, skipping plugin' finish endif endif let g:loaded_tagbar = 1 if !exists('g:tagbar_left') let g:tagbar_left = 0 endif if !exists('g:tagbar_width') let g:tagbar_width = 40 endif if !exists('g:tagbar_autoclose') let g:tagbar_autoclose = 0 endif if !exists('g:tagbar_autofocus') let g:tagbar_autofocus = 0 endif if !exists('g:tagbar_sort') let g:tagbar_sort = 1 endif if !exists('g:tagbar_compact') let g:tagbar_compact = 0 endif if !exists('g:tagbar_expand') let g:tagbar_expand = 0 endif let s:type_init_done = 0 let s:key_mapping_done = 0 let s:autocommands_done = 0 let s:window_expanded = 0 " s:InitTypes() {{{2 function! s:InitTypes() " Dictionary of the already processed files, indexed by file name with " complete path. " The entries are again dictionaries with the following fields: " - mtime: File modification time " - ftype: The vim file type " - tags: List of the tags that are present in the file, sorted " according to the value of 'g:tagbar_sort' " - fline: Dictionary of the tags, indexed by line number in the file " - tline: Dictionary of the tags, indexed by line number in the tagbar let s:known_files = {} let s:known_types = {} " Ant {{{3 let type_ant = {} let type_ant.ctagstype = 'ant' let type_ant.kinds = [ \ 'p:projects', \ 't:targets' \ ] let s:known_types.ant = type_ant " Asm {{{3 let type_asm = {} let type_asm.ctagstype = 'asm' let type_asm.kinds = [ \ 'm:macros', \ 't:types', \ 'd:defines', \ 'l:labels' \ ] let s:known_types.asm = type_asm " ASP {{{3 let type_aspvbs = {} let type_aspvbs.ctagstype = 'asp' let type_aspvbs.kinds = [ \ 'd:constants', \ 'c:classes', \ 'f:functions', \ 's:subroutines', \ 'v:variables' \ ] let s:known_types.aspvbs = type_aspvbs " Awk {{{3 let type_awk = {} let type_awk.ctagstype = 'awk' let type_awk.kinds = [ \ 'f:functions' \ ] let s:known_types.awk = type_awk " Basic {{{3 let type_basic = {} let type_basic.ctagstype = 'basic' let type_basic.kinds = [ \ 'c:constants', \ 'g:enumerations', \ 'f:functions', \ 'l:labels', \ 't:types', \ 'v:variables' \ ] let s:known_types.basic = type_basic " BETA {{{3 let type_beta = {} let type_beta.ctagstype = 'beta' let type_beta.kinds = [ \ 'f:fragments', \ 's:slots', \ 'v:patterns' \ ] let s:known_types.beta = type_beta " C {{{3 let type_c = {} let type_c.ctagstype = 'c' let type_c.scopes = ['enum', 'struct', 'union'] let type_c.sro = '::' let type_c.kinds = [ \ 'd:macros', \ 'p:prototypes', \ 'g:enums', \ 'e:enumerators', \ 't:typedefs', \ 's:structs', \ 'u:unions', \ 'm:members', \ 'v:variables', \ 'f:functions' \ ] let type_c.kind2scope = { \ 'g' : 'enum', \ 's' : 'struct', \ 'u' : 'union' \ } let type_c.scope2kind = { \ 'enum' : 'g', \ 'struct' : 's', \ 'union' : 'u' \ } let s:known_types.c = type_c " C++ {{{3 let type_cpp = {} let type_cpp.ctagstype = 'c++' let type_cpp.scopes = [ \ 'namespace', \ 'class', \ 'struct', \ 'enum', \ 'union' \ ] let type_cpp.sro = '::' let type_cpp.kinds = [ \ 'd:macros', \ 'p:prototypes', \ 'g:enums', \ 'e:enumerators', \ 't:typedefs', \ 'n:namespaces', \ 'c:classes', \ 's:structs', \ 'u:unions', \ 'f:functions', \ 'm:members', \ 'v:variables' \ ] let type_cpp.kind2scope = { \ 'g' : 'enum', \ 'n' : 'namespace', \ 'c' : 'class', \ 's' : 'struct', \ 'u' : 'union' \ } let type_cpp.scope2kind = { \ 'enum' : 'g', \ 'namespace' : 'n', \ 'class' : 'c', \ 'struct' : 's', \ 'union' : 'u' \ } let s:known_types.cpp = type_cpp " C# {{{3 let type_cs = {} let type_cs.ctagstype = 'c#' let type_cs.scopes = [ \ 'namespace', \ 'interface', \ 'class', \ 'struct', \ 'enum' \ ] let type_cs.sro = '.' let type_cs.kinds = [ \ 'd:macros', \ 'f:fields', \ 'g:enums', \ 'e:enumerators', \ 't:typedefs', \ 'n:namespaces', \ 'i:interfaces', \ 'c:classes', \ 's:structs', \ 'E:events', \ 'm:methods', \ 'p:properties' \ ] let type_cs.kind2scope = { \ 'n' : 'namespace', \ 'i' : 'interface', \ 'c' : 'class', \ 's' : 'struct', \ 'g' : 'enum' \ } let type_cs.scope2kind = { \ 'namespace' : 'n', \ 'interface' : 'i', \ 'class' : 'c', \ 'struct' : 's', \ 'enum' : 'g' \ } let s:known_types.cs = type_cs " COBOL {{{3 let type_cobol = {} let type_cobol.ctagstype = 'cobol' let type_cobol.kinds = [ \ 'd:data items', \ 'f:file descriptions', \ 'g:group items', \ 'p:paragraphs', \ 'P:program ids', \ 's:sections' \ ] let s:known_types.cobol = type_cobol " DOS Batch {{{3 let type_dosbatch = {} let type_dosbatch.ctagstype = 'dosbatch' let type_dosbatch.kinds = [ \ 'l:labels', \ 'v:variables' \ ] let s:known_types.dosbatch = type_dosbatch " Eiffel {{{3 let type_eiffel = {} let type_eiffel.ctagstype = 'eiffel' let type_eiffel.scopes = ['class', 'feature'] let type_eiffel.sro = '.' " Not sure, is nesting even possible? let type_eiffel.kinds = [ \ 'c:classes', \ 'f:features' \ ] let type_eiffel.kind2scope = { \ 'c' : 'class', \ 'f' : 'feature' \ } let type_eiffel.scope2kind = { \ 'class' : 'c', \ 'feature' : 'f' \ } let s:known_types.eiffel = type_eiffel " Erlang {{{3 let type_erlang = {} let type_erlang.ctagstype = 'erlang' let type_erlang.scopes = ['module'] let type_erlang.sro = '.' " Not sure, is nesting even possible? let type_erlang.kinds = [ \ 'm:modules', \ 'd:macro definitions', \ 'f:functions', \ 'r:record definitions' \ ] let type_erlang.kind2scope = { \ 'm' : 'module' \ } let type_erlang.scope2kind = { \ 'module' : 'm' \ } let s:known_types.erlang = type_erlang " Flex {{{3 " Vim doesn't support Flex out of the box, this is based on rough " guesses and probably requires " http://www.vim.org/scripts/script.php?script_id=2909 " Improvements welcome! let type_mxml = {} let type_mxml.ctagstype = 'flex' let type_mxml.scopes = ['class'] let type_mxml.sro = '.' let type_mxml.kinds = [ \ 'v:global variables', \ 'c:classes', \ 'm:methods', \ 'p:properties', \ 'f:functions', \ 'x:mxtags' \ ] let type_mxml.kind2scope = { \ 'c' : 'class' \ } let type_mxml.scope2kind = { \ 'class' : 'c' \ } let s:known_types.mxml = type_mxml " Fortran {{{3 let type_fortran = {} let type_fortran.ctagstype = 'fortran' let type_fortran.scopes = ['module', 'program', 'function', 'subroutine'] let type_fortran.sro = '.' " Not sure, is nesting even possible? let type_fortran.kinds = [ \ 'm:modules', \ 'p:programs', \ 'k:components', \ 't:derived types and structures', \ 'c:common blocks', \ 'b:block data', \ 'e:entry points', \ 'f:functions', \ 's:subroutines', \ 'l:labels', \ 'n:namelists', \ 'v:variables' \ ] let type_fortran.kind2scope = { \ 'm' : 'module', \ 'p' : 'program', \ 'f' : 'function', \ 's' : 'subroutine' \ } let type_fortran.scope2kind = { \ 'module' : 'm', \ 'program' : 'p', \ 'function' : 'f', \ 'subroutine' : 's' \ } let s:known_types.fortran = type_fortran " HTML {{{3 let type_html = {} let type_html.ctagstype = 'html' let type_html.kinds = [ \ 'f:JavaScript funtions', \ 'a:named anchors' \ ] let s:known_types.html = type_html " Java {{{3 let type_java = {} let type_java.ctagstype = 'java' let type_java.scopes = ['enum', 'interface', 'class'] let type_java.sro = '.' let type_java.kinds = [ \ 'p:packages', \ 'f:fields', \ 'g:enum types', \ 'e:enum constants', \ 'i:interfaces', \ 'c:classes', \ 'm:methods' \ ] let type_java.kind2scope = { \ 'g' : 'enum', \ 'i' : 'interface', \ 'c' : 'class' \ } let type_java.scope2kind = { \ 'enum' : 'g', \ 'interface' : 'i', \ 'class' : 'c' \ } let s:known_types.java = type_java " JavaScript {{{3 " JavaScript is weird -- it does have scopes, but ctags doesn't seem to " properly generate the information for them, instead it simply uses the " complete name. So ctags has to be fixed before I can do anything here. let type_javascript = {} let type_javascript.ctagstype = 'javascript' let type_javascript.kinds = [ \ 'v:global variables', \ 'c:classes', \ 'p:properties', \ 'm:methods', \ 'f:functions' \ ] let s:known_types.javascript = type_javascript " Lisp {{{3 let type_lisp = {} let type_lisp.ctagstype = 'lisp' let type_lisp.kinds = [ \ 'f:functions' \ ] let s:known_types.lisp = type_lisp " Lua {{{3 let type_lua = {} let type_lua.ctagstype = 'lua' let type_lua.kinds = [ \ 'f:functions' \ ] let s:known_types.lua = type_lua " Make {{{3 let type_make = {} let type_make.ctagstype = 'make' let type_make.kinds = [ \ 'm:macros' \ ] let s:known_types.make = type_make " Matlab {{{3 let type_matlab = {} let type_matlab.ctagstype = 'matlab' let type_matlab.kinds = [ \ 'f:functions' \ ] let s:known_types.matlab = type_matlab " Ocaml {{{3 let type_ocaml = {} let type_ocaml.ctagstype = 'ocaml' let type_ocaml.scopes = ['Module', 'class', 'type'] let type_ocaml.sro = '.' " Not sure, is nesting even possible? let type_ocaml.kinds = [ \ 'M:modules or functors', \ 'v:global variables', \ 'c:classes', \ 'C:constructors', \ 'm:methods', \ 'e:exceptions', \ 't:type names', \ 'f:functions', \ 'r:structure fields' \ ] let type_ocaml.kind2scope = { \ 'M' : 'Module', \ 'c' : 'class', \ 't' : 'type' \ } let type_ocaml.scope2kind = { \ 'Module' : 'M', \ 'class' : 'c', \ 'type' : 't' \ } let s:known_types.ocaml = type_ocaml " Pascal {{{3 let type_pascal = {} let type_pascal.ctagstype = 'pascal' let type_pascal.kinds = [ \ 'f:functions', \ 'p:procedures' \ ] let s:known_types.pascal = type_pascal " Perl {{{3 let type_perl = {} let type_perl.ctagstype = 'perl' let type_perl.kinds = [ \ 'p:packages', \ 'c:constants', \ 'f:formats', \ 'l:labels', \ 's:subroutines' \ ] let s:known_types.perl = type_perl " PHP {{{3 let type_php = {} let type_php.ctagstype = 'php' let type_php.kinds = [ \ 'i:interfaces', \ 'c:classes', \ 'd:constant definitions', \ 'f:functions', \ 'v:variables', \ 'j:javascript functions' \ ] let s:known_types.php = type_php " Python {{{3 let type_python = {} let type_python.ctagstype = 'python' let type_python.scopes = ['class', 'function'] let type_python.sro = '.' let type_python.kinds = [ \ 'i:imports', \ 'c:classes', \ 'f:functions', \ 'm:members', \ 'v:variables' \ ] let type_python.kind2scope = { \ 'c' : 'class', \ 'f' : 'function', \ 'm' : 'function' \ } let type_python.scope2kind = { \ 'class' : 'c', \ 'function' : 'f' \ } let s:known_types.python = type_python " REXX {{{3 let type_rexx = {} let type_rexx.ctagstype = 'rexx' let type_rexx.kinds = [ \ 's:subroutines' \ ] let s:known_types.rexx = type_rexx " Ruby {{{3 let type_ruby = {} let type_ruby.ctagstype = 'ruby' let type_ruby.scopes = ['class'] let type_ruby.sro = '.' let type_ruby.kinds = [ \ 'm:modules', \ 'c:classes', \ 'f:methods', \ 'F:singleton methods' \ ] let type_ruby.kind2scope = { \ 'c' : 'class', \ 'm' : 'class' \ } let type_ruby.scope2kind = { \ 'class' : 'c' \ } let s:known_types.ruby = type_ruby " Scheme {{{3 let type_scheme = {} let type_scheme.ctagstype = 'scheme' let type_scheme.kinds = [ \ 'f:functions', \ 's:sets' \ ] let s:known_types.scheme = type_scheme " Shell script {{{3 let type_sh = {} let type_sh.ctagstype = 'sh' let type_sh.kinds = [ \ 'f:functions' \ ] let s:known_types.sh = type_sh let s:known_types.csh = type_sh let s:known_types.zsh = type_sh " SLang {{{3 let type_slang = {} let type_slang.ctagstype = 'slang' let type_slang.kinds = [ \ 'n:namespaces', \ 'f:functions' \ ] let s:known_types.slang = type_slang " SML {{{3 let type_sml = {} let type_sml.ctagstype = 'sml' let type_sml.kinds = [ \ 'e:exception declarations', \ 'f:function definitions', \ 'c:functor definitions', \ 's:signature declarations', \ 'r:structure declarations', \ 't:type definitions', \ 'v:value bindings' \ ] let s:known_types.sml = type_sml " SQL {{{3 " The SQL ctags parser seems to be buggy for me, so this just uses the " normal kinds even though scopes should be available. Improvements " welcome! let type_sql = {} let type_sql.ctagstype = 'sql' let type_sql.kinds = [ \ 'c:cursors', \ 'f:functions', \ 'F:record fields', \ 'L:block label', \ 'P:packages', \ 'p:procedures', \ 's:subtypes', \ 't:tables', \ 'T:triggers', \ 'v:variables', \ 'i:indexes', \ 'e:events', \ 'U:publications', \ 'R:services', \ 'D:domains', \ 'V:views', \ 'n:synonyms', \ 'x:MobiLink Table Scripts', \ 'y:MobiLink Conn Scripts' \ ] let s:known_types.sql = type_sql " Tcl {{{3 let type_tcl = {} let type_tcl.ctagstype = 'tcl' let type_tcl.kinds = [ \ 'c:classes', \ 'm:methods', \ 'p:procedures' \ ] let s:known_types.tcl = type_tcl " LaTeX {{{3 let type_tex = {} let type_tex.ctagstype = 'tex' let type_tex.kinds = [ \ 'p:parts', \ 'c:chapters', \ 's:sections', \ 'u:subsections', \ 'b:subsubsections', \ 'P:paragraphs', \ 'G:subparagraphs', \ ] let s:known_types.tex = type_tex " Vera {{{3 " Why are variables 'virtual'? let type_vera = {} let type_vera.ctagstype = 'vera' let type_vera.scopes = ['enum', 'class', 'virtual'] let type_vera.sro = '.' " Nesting doesn't seem to be possible let type_vera.kinds = [ \ 'd:macros', \ 'g:enums', \ 'T:typedefs', \ 'c:classes', \ 'e:enumerators', \ 'm:members', \ 'f:functions', \ 't:tasks', \ 'v:variables', \ 'p:programs' \ ] let type_vera.kind2scope = { \ 'g' : 'enum', \ 'c' : 'class', \ 'v' : 'virtual' \ } let type_vera.scope2kind = { \ 'enum' : 'g', \ 'class' : 'c', \ 'virtual' : 'v' \ } let s:known_types.vera = type_vera " Verilog {{{3 let type_verilog = {} let type_verilog.ctagstype = 'verilog' let type_verilog.kinds = [ \ 'c:constants', \ 'e:events', \ 'f:functions', \ 'm:modules', \ 'n:net data types', \ 'p:ports', \ 'r:register data types', \ 't:tasks' \ ] let s:known_types.verilog = type_verilog " VHDL {{{3 " The VHDL ctags parser unfortunately doesn't generate proper scopes let type_vhdl = {} let type_vhdl.ctagstype = 'vhdl' let type_vhdl.kinds = [ \ 'c:constants', \ 't:types', \ 'T:subtypes', \ 'r:records', \ 'e:entities', \ 'f:functions', \ 'p:procedures', \ 'P:packages' \ ] let s:known_types.vhdl = type_vhdl " Vim {{{3 let type_vim = {} let type_vim.ctagstype = 'vim' let type_vim.kinds = [ \ 'v:variables', \ 'f:functions', \ 'a:autocommand groups', \ 'c:commands', \ 'm:maps' \ ] let s:known_types.vim = type_vim " YACC {{{3 let type_yacc = {} let type_yacc.ctagstype = 'yacc' let type_yacc.kinds = [ \ 'l:labels' \ ] let s:known_types.yacc = type_yacc " }}}3 let user_defs = s:GetUserTypeDefs() for [key, value] in items(user_defs) if !has_key(s:known_types, key) || \ (has_key(value, 'replace') && value.replace) let s:known_types[key] = value else call extend(s:known_types[key], value) endif endfor " Create a dictionary of the kind order for fast " access in sorting functions for type in values(s:known_types) let i = 0 let type.kinddict = {} for kind in type.kinds let type.kinddict[kind[0]] = i let i += 1 endfor endfor let s:access_symbols = { \ 'public' : '+', \ 'protected' : '#', \ 'private' : '-' \ } let s:type_init_done = 1 endfunction " s:GetUserTypeDefs() {{{2 function! s:GetUserTypeDefs() redir => defs silent! execute 'let g:' redir END let deflist = split(defs, '\n') call map(deflist, 'substitute(v:val, ''^\S\+\zs.*'', "", "")') call filter(deflist, 'v:val =~ "^tagbar_type_"') let defdict = {} for defstr in deflist let type = substitute(defstr, '^tagbar_type_', '', '') execute 'let defdict["' . type . '"] = g:' . defstr endfor " If the user only specified one of kind2scope and scope2kind use it to " generate the other one for def in values(defdict) if has_key(def, 'kind2scope') && !has_key(def, 'scope2kind') let def.scope2kind = {} for [key, value] in items(def.kind2scope) let def.scope2kind[value] = key endfor elseif has_key(def, 'scope2kind') && !has_key(def, 'kind2scope') let def.kind2scope = {} for [key, value] in items(def.scope2kind) let def.kind2scope[value] = key endfor endif endfor return defdict endfunction " s:MapKeys() {{{2 function! s:MapKeys() nnoremap