1
0
mirror of https://github.com/gryf/tagbar.git synced 2025-12-17 11:30:28 +01:00

Allow project-specific type config

This commit is contained in:
Jan Larres
2013-04-23 18:07:29 +12:00
parent 1c605bd958
commit acca348959
2 changed files with 96 additions and 67 deletions

View File

@@ -819,47 +819,13 @@ function! s:LoadUserTypeDefs(...) abort
let defdict = tagbar#getusertypes()
endif
" Transform the 'kind' definitions into dictionary format
for def in values(defdict)
if has_key(def, 'kinds')
let kinds = def.kinds
let def.kinds = []
for kind in kinds
let kindlist = split(kind, ':')
let kinddict = {'short' : kindlist[0], 'long' : kindlist[1]}
if len(kindlist) == 4
let kinddict.fold = kindlist[2]
let kinddict.stl = kindlist[3]
elseif len(kindlist) == 3
let kinddict.fold = kindlist[2]
let kinddict.stl = 1
else
let kinddict.fold = 0
let kinddict.stl = 1
endif
call add(def.kinds, kinddict)
endfor
endif
" If the user only specified one of kind2scope and scope2kind use it
" to generate the other one
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
let transformed = {}
for [type, def] in items(defdict)
let transformed[type] = s:TransformUserTypeDef(def)
endfor
unlet! key value
for [key, value] in items(defdict)
if !has_key(s:known_types, key) ||
\ (has_key(value, 'replace') && value.replace)
for [key, value] in items(transformed)
if !has_key(s:known_types, key) || get(value, 'replace', 0)
let s:known_types[key] = s:TypeInfo.New(value)
else
call extend(s:known_types[key], value)
@@ -871,7 +837,42 @@ function! s:LoadUserTypeDefs(...) abort
endif
endfunction
" s:TransformUserTypeDef() {{{2
" Transform the user definitions into the internal format
function! s:TransformUserTypeDef(def) abort
let newdef = copy(a:def)
if has_key(a:def, 'kinds')
let newdef.kinds = []
let kinds = a:def.kinds
for kind in kinds
let kindlist = split(kind, ':')
let kinddict = {'short' : kindlist[0], 'long' : kindlist[1]}
let kinddict.fold = get(kindlist, 2, 0)
let kinddict.stl = get(kindlist, 3, 1)
call add(newdef.kinds, kinddict)
endfor
endif
" If the user only specified one of kind2scope and scope2kind then use it
" to generate the respective other
if has_key(a:def, 'kind2scope') && !has_key(a:def, 'scope2kind')
let newdef.scope2kind = {}
for [key, value] in items(a:def.kind2scope)
let newdef.scope2kind[value] = key
endfor
elseif has_key(a:def, 'scope2kind') && !has_key(a:def, 'kind2scope')
let newdef.kind2scope = {}
for [key, value] in items(a:def.scope2kind)
let newdef.kind2scope[value] = key
endfor
endif
return newdef
endfunction
" s:CreateTypeKinddict() {{{2
" TODO: make instance method
function! s:CreateTypeKinddict(type) abort
" Create a dictionary of the kind order for fast access in sorting
" functions
@@ -968,7 +969,7 @@ function! s:CreateAutocommands() abort
autocmd BufEnter __Tagbar__ nested call s:QuitIfOnlyWindow()
autocmd CursorHold __Tagbar__ call s:ShowPrototype(1)
autocmd BufReadPost,BufWritePost * call
autocmd BufWritePost * call
\ s:AutoUpdate(fnamemodify(expand('<afile>'), ':p'), 1)
autocmd BufEnter,CursorHold,FileType * call
\ s:AutoUpdate(fnamemodify(expand('<afile>'), ':p'), 0)
@@ -1507,7 +1508,7 @@ endfunction
let s:FileInfo = {}
" s:FileInfo.New() {{{3
function! s:FileInfo.New(fname, ftype) abort dict
function! s:FileInfo.New(fname, ftype, typeinfo) abort dict
let newobj = copy(self)
" The complete file path
@@ -1533,10 +1534,9 @@ function! s:FileInfo.New(fname, ftype) abort dict
" Dictionary of the folding state of 'kind's, indexed by short name
let newobj.kindfolds = {}
let typeinfo = s:known_types[a:ftype]
let newobj.typeinfo = typeinfo
let newobj.typeinfo = a:typeinfo
" copy the default fold state from the type info
for kind in typeinfo.kinds
for kind in a:typeinfo.kinds
let newobj.kindfolds[kind.short] =
\ g:tagbar_foldlevel == 0 ? 1 : kind.fold
endfor
@@ -1544,7 +1544,7 @@ function! s:FileInfo.New(fname, ftype) abort dict
" Dictionary of dictionaries of the folding state of individual tags,
" indexed by kind and full path
let newobj.tagfolds = {}
for kind in typeinfo.kinds
for kind in a:typeinfo.kinds
let newobj.tagfolds[kind.short] = {}
endfor
@@ -1566,8 +1566,7 @@ function! s:FileInfo.reset() abort dict
let self._tagfolds_old = self.tagfolds
let self.tagfolds = {}
let typeinfo = s:known_types[self.ftype]
for kind in typeinfo.kinds
for kind in self.typeinfo.kinds
let self.tagfolds[kind.short] = {}
endfor
endfunction
@@ -1905,13 +1904,22 @@ function! s:ProcessFile(fname, ftype) abort
return
endif
let typeinfo = s:known_types[a:ftype]
" If the file has only been updated preserve the fold states, otherwise
" create a new entry
if s:known_files.has(a:fname) && !empty(s:known_files.get(a:fname))
let fileinfo = s:known_files.get(a:fname)
let typeinfo = fileinfo.typeinfo
call fileinfo.reset()
else
let fileinfo = s:FileInfo.New(a:fname, a:ftype)
silent! execute 'doautocmd <nomodeline> TagbarProjects User ' . a:fname
if exists('b:tagbar_type')
let typeinfo = extend(copy(typeinfo),
\ s:TransformUserTypeDef(b:tagbar_type))
call s:CreateTypeKinddict(typeinfo)
endif
let fileinfo = s:FileInfo.New(a:fname, a:ftype, typeinfo)
endif
" Use a temporary files for ctags processing instead of the original one.
@@ -1926,7 +1934,7 @@ function! s:ProcessFile(fname, ftype) abort
call writefile(getbufline(fileinfo.bufnr, 1, '$'), tempfile)
let fileinfo.mtime = getftime(tempfile)
let ctags_output = s:ExecuteCtagsOnFile(tempfile, a:fname, a:ftype)
let ctags_output = s:ExecuteCtagsOnFile(tempfile, a:fname, typeinfo)
call delete(tempfile)
@@ -1940,12 +1948,11 @@ function! s:ProcessFile(fname, ftype) abort
call s:LogDebugMessage('Ctags output empty')
" No need to go through the tag processing if there are no tags, and
" preserving the old fold state isn't necessary either
call s:known_files.put(s:FileInfo.New(a:fname, a:ftype), a:fname)
call s:known_files.put(s:FileInfo.New(a:fname, a:ftype,
\ s:known_types[a:ftype]), a:fname)
return
endif
let typeinfo = fileinfo.typeinfo
call s:LogDebugMessage('Filetype tag kinds: ' .
\ string(keys(typeinfo.kinddict)))
@@ -2025,17 +2032,15 @@ function! s:ProcessFile(fname, ftype) abort
endfunction
" s:ExecuteCtagsOnFile() {{{2
function! s:ExecuteCtagsOnFile(fname, realfname, ftype) abort
function! s:ExecuteCtagsOnFile(fname, realfname, typeinfo) abort
call s:LogDebugMessage('ExecuteCtagsOnFile called [' . a:fname . ']')
let typeinfo = s:known_types[a:ftype]
if has_key(typeinfo, 'ctagsargs') && type(typeinfo.ctagsargs)==type(' ')
"if ctagsargs is a string, prepend and append space seperators
let ctags_args = ' ' . typeinfo.ctagsargs . ' '
elseif has_key(typeinfo, 'ctagsargs') && type(typeinfo.ctagsargs)==type([])
let ctags_args = typeinfo.ctagsargs
"otherwise ctagsargs is not defined or not defined as a valid type
if has_key(a:typeinfo, 'ctagsargs') && type(a:typeinfo.ctagsargs) == type('')
" if ctagsargs is a string, prepend and append space separators
let ctags_args = ' ' . a:typeinfo.ctagsargs . ' '
elseif has_key(a:typeinfo, 'ctagsargs') && type(a:typeinfo.ctagsargs) == type([])
let ctags_args = a:typeinfo.ctagsargs
" otherwise ctagsargs is not defined or not defined as a valid type
else
"Prefer constructing ctags_args as a list rather than a string
"See s:EscapeCtagsCmd() - It's a best practice to shellescape()
@@ -2053,14 +2058,14 @@ function! s:ExecuteCtagsOnFile(fname, realfname, ftype) abort
\ ]
" Include extra type definitions
if has_key(typeinfo, 'deffile')
let ctags_args += ['--options=' . typeinfo.deffile]
if has_key(a:typeinfo, 'deffile')
let ctags_args += ['--options=' . a:typeinfo.deffile]
endif
let ctags_type = typeinfo.ctagstype
let ctags_type = a:typeinfo.ctagstype
let ctags_kinds = ''
for kind in typeinfo.kinds
for kind in a:typeinfo.kinds
let ctags_kinds .= kind.short
endfor
@@ -2068,11 +2073,11 @@ function! s:ExecuteCtagsOnFile(fname, realfname, ftype) abort
let ctags_args += ['--' . ctags_type . '-kinds=' . ctags_kinds]
endif
if has_key(typeinfo, 'ctagsbin')
if has_key(a:typeinfo, 'ctagsbin')
" reset 'wildignore' temporarily in case *.exe is included in it
let wildignore_save = &wildignore
set wildignore&
let ctags_bin = expand(typeinfo.ctagsbin)
let ctags_bin = expand(a:typeinfo.ctagsbin)
let &wildignore = wildignore_save
else
let ctags_bin = g:tagbar_ctags_bin

View File

@@ -980,6 +980,30 @@ LaTeX parser that works better than the example configuration presented here.
So if you are using a development build newer than that or a stable version
newer than 5.8 you should use the built-in support instead of this example.
Project-specific configuration~
In addition to the normal global configuration it is also possible to have
project-specific settings. This is mostly useful for additional ctags options,
like for example macros to ignore. Or maybe you want to do things like folding
certain tag kinds in some projects.
In order to use this feature you need to create User |autocommand|s in an
augroup called "TagbarProjects" and have it create a buffer-local variable
called "b:tagbar_type". This variable has to hold a type definition just like
the normal ones described in this chapter. This definition will then be
applied only to the files matched by the autocommand.
Note that there can be multiple definitions of the augroup with their own
autocommands (for example in separate project directories); they will get
merged automatically by Vim.
Example:
>
augroup TagbarProjects
autocmd User ~/myproject/*.c let b:tagbar_type = {'deffile' : '~/myproject/ctags.cnf'}
augroup END
<
Writing your own tag-generating program~
If you want to write your own program for generating tags then here are some
imporant tips to get it to integrate well with Tagbar: