Skip to content
Browse files

[vim] tagbar update

  • Loading branch information...
1 parent 1490b99 commit c1ab82089793333e588c8f766d21fa810db395c3 @guns committed
View
3 etc/vim/bundle/tagbar/README.md
@@ -5,6 +5,9 @@ It provides a sidebar that displays the ctags-generated tags of the current file
Check out the homepage at http://majutsushi.github.com/tagbar/ for more information.
+# Support for additional filetypes
+
+For filetypes that are not supported by Exuberant Ctags check out [the wiki](https://github.com/majutsushi/tagbar/wiki) to see whether other projects offer support for them and how to use them. Please add any other projects/configurations that you find or create yourself so that others can benefit from them, too.
# Important: If the file structure is displayed wrong
View
675 etc/vim/bundle/tagbar/autoload/tagbar.vim
@@ -43,9 +43,10 @@ unlet s:ftype_out
let s:icon_closed = g:tagbar_iconchars[0]
let s:icon_open = g:tagbar_iconchars[1]
-let s:type_init_done = 0
-let s:autocommands_done = 0
-let s:autocommands_enabled = 0
+let s:type_init_done = 0
+let s:autocommands_done = 0
+let s:statusline_in_use = 0
+
" 0: not checked yet; 1: checked and found; 2: checked and not found
let s:checked_ctags = 0
let s:checked_ctags_types = 0
@@ -53,6 +54,7 @@ let s:ctags_types = {}
let s:new_window = 1
let s:is_maximized = 0
+let s:winrestcmd = ''
let s:short_help = 1
let s:nearby_disabled = 0
@@ -800,8 +802,8 @@ function! s:InitTypes() abort
call s:LoadUserTypeDefs()
- for type in values(s:known_types)
- call s:CreateTypeKinddict(type)
+ for typeinfo in values(s:known_types)
+ call typeinfo.createKinddict()
endfor
let s:type_init_done = 1
@@ -822,47 +824,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)
@@ -870,19 +838,42 @@ function! s:LoadUserTypeDefs(...) abort
endfor
if a:0 > 0
- call s:CreateTypeKinddict(s:known_types[type])
+ call s:known_types[type].createKinddict()
endif
endfunction
-" s:CreateTypeKinddict() {{{2
-function! s:CreateTypeKinddict(type) abort
- " Create a dictionary of the kind order for fast access in sorting
- " functions
- let i = 0
- for kind in a:type.kinds
- let a:type.kinddict[kind.short] = i
- let i += 1
- endfor
+" 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:RestoreSession() {{{2
@@ -931,35 +922,38 @@ function! s:MapKeys() abort
inoremap <script> <silent> <buffer> <LeftRelease>
\ <LeftRelease><C-o>:call <SID>CheckMouseClick()<CR>
- nnoremap <script> <silent> <buffer> <CR> :call <SID>JumpToTag(0)<CR>
- nnoremap <script> <silent> <buffer> p :call <SID>JumpToTag(1)<CR>
- nnoremap <script> <silent> <buffer> <Space> :call <SID>ShowPrototype(0)<CR>
-
- nnoremap <script> <silent> <buffer> + :call <SID>OpenFold()<CR>
- nnoremap <script> <silent> <buffer> <kPlus> :call <SID>OpenFold()<CR>
- nnoremap <script> <silent> <buffer> zo :call <SID>OpenFold()<CR>
- nnoremap <script> <silent> <buffer> - :call <SID>CloseFold()<CR>
- nnoremap <script> <silent> <buffer> <kMinus> :call <SID>CloseFold()<CR>
- nnoremap <script> <silent> <buffer> zc :call <SID>CloseFold()<CR>
- nnoremap <script> <silent> <buffer> o :call <SID>ToggleFold()<CR>
- nnoremap <script> <silent> <buffer> za :call <SID>ToggleFold()<CR>
-
- nnoremap <script> <silent> <buffer> * :call <SID>SetFoldLevel(99, 1)<CR>
- nnoremap <script> <silent> <buffer> <kMultiply>
- \ :call <SID>SetFoldLevel(99, 1)<CR>
- nnoremap <script> <silent> <buffer> zR :call <SID>SetFoldLevel(99, 1)<CR>
- nnoremap <script> <silent> <buffer> = :call <SID>SetFoldLevel(0, 1)<CR>
- nnoremap <script> <silent> <buffer> zM :call <SID>SetFoldLevel(0, 1)<CR>
-
- nnoremap <script> <silent> <buffer> <C-N>
- \ :call <SID>GotoNextToplevelTag(1)<CR>
- nnoremap <script> <silent> <buffer> <C-P>
- \ :call <SID>GotoNextToplevelTag(-1)<CR>
-
- nnoremap <script> <silent> <buffer> s :call <SID>ToggleSort()<CR>
- nnoremap <script> <silent> <buffer> x :call <SID>ZoomWindow()<CR>
- nnoremap <script> <silent> <buffer> q :call <SID>CloseWindow()<CR>
- nnoremap <script> <silent> <buffer> h :call <SID>ToggleHelp()<CR>
+ let maps = [
+ \ ['jump', 'JumpToTag(0)'],
+ \ ['preview', 'JumpToTag(1)'],
+ \ ['nexttag', 'GotoNextToplevelTag(1)'],
+ \ ['prevtag', 'GotoNextToplevelTag(-1)'],
+ \ ['showproto', 'ShowPrototype(0)'],
+ \
+ \ ['openfold', 'OpenFold()'],
+ \ ['closefold', 'CloseFold()'],
+ \ ['togglefold', 'ToggleFold()'],
+ \ ['openallfolds', 'SetFoldLevel(99, 1)'],
+ \ ['closeallfolds', 'SetFoldLevel(0, 1)'],
+ \
+ \ ['togglesort', 'ToggleSort()'],
+ \ ['zoomwin', 'ZoomWindow()'],
+ \ ['close', 'CloseWindow()'],
+ \ ['help', 'ToggleHelp()'],
+ \ ]
+
+ for [map, func] in maps
+ let def = get(g:, 'tagbar_map_' . map)
+ if type(def) == type("")
+ let keys = [def]
+ else
+ let keys = def
+ endif
+ for key in keys
+ execute 'nnoremap <script> <silent> <buffer> ' . key .
+ \ ' :call <SID>' . func . '<CR>'
+ endfor
+ unlet def
+ endfor
endfunction
" s:CreateAutocommands() {{{2
@@ -969,6 +963,8 @@ function! s:CreateAutocommands() abort
augroup TagbarAutoCmds
autocmd!
autocmd BufEnter __Tagbar__ nested call s:QuitIfOnlyWindow()
+ autocmd WinEnter __Tagbar__ call s:SetStatusLine('current')
+ autocmd WinLeave __Tagbar__ call s:SetStatusLine('noncurrent')
autocmd BufReadPost,BufWritePost * call
\ s:AutoUpdate(fnamemodify(expand('<afile>'), ':p'), 1)
@@ -981,15 +977,14 @@ function! s:CreateAutocommands() abort
augroup END
let s:autocommands_done = 1
- let s:autocommands_enabled = 1
endfunction
" s:PauseAutocommands() {{{2
-" Toggle autocommands
+" Toggle autocommands
function! s:PauseAutocommands() abort
- if s:autocommands_enabled == 1
+ if s:autocommands_done
autocmd! TagbarAutoCmds
- let s:autocommands_enabled = 0
+ let s:autocommands_done = 0
else
call s:CreateAutocommands()
call s:AutoUpdate(fnamemodify(expand('%'), ':p'), 0)
@@ -1020,12 +1015,11 @@ function! s:CheckForExCtags(silent) abort
endif
endfor
if !exists('g:tagbar_ctags_bin')
- if !a:silent
- echoerr 'Tagbar: Exuberant ctags not found!'
- echomsg 'Please download Exuberant Ctags from ctags.sourceforge.net'
- \ 'and install it in a directory in your $PATH'
- \ 'or set g:tagbar_ctags_bin.'
- endif
+ let errmsg = 'Tagbar: Exuberant ctags not found!'
+ let infomsg = 'Please download Exuberant Ctags from' .
+ \ ' ctags.sourceforge.net and install it in a' .
+ \ ' directory in your $PATH or set g:tagbar_ctags_bin.'
+ call s:CtagsErrMsg(errmsg, infomsg, a:silent)
let s:checked_ctags = 2
return 0
endif
@@ -1039,11 +1033,10 @@ function! s:CheckForExCtags(silent) abort
let &wildignore = wildignore_save
if !executable(g:tagbar_ctags_bin)
- if !a:silent
- echoerr "Tagbar: Exuberant ctags not found at " .
- \ "'" . g:tagbar_ctags_bin . "'!"
- echomsg 'Please check your g:tagbar_ctags_bin setting.'
- endif
+ let errmsg = "Tagbar: Exuberant ctags not found at " .
+ \ "'" . g:tagbar_ctags_bin . "'!"
+ let infomsg = 'Please check your g:tagbar_ctags_bin setting.'
+ call s:CtagsErrMsg(errmsg, infomsg, a:silent)
let s:checked_ctags = 2
return 0
endif
@@ -1058,35 +1051,19 @@ function! s:CheckForExCtags(silent) abort
let ctags_output = s:ExecuteCtags(ctags_cmd)
if v:shell_error || ctags_output !~# 'Exuberant Ctags'
- if !a:silent
- echoerr 'Tagbar: Ctags doesn''t seem to be Exuberant Ctags!'
- echomsg 'GNU ctags will NOT WORK.'
- \ 'Please download Exuberant Ctags from ctags.sourceforge.net'
- \ 'and install it in a directory in your $PATH'
- \ 'or set g:tagbar_ctags_bin.'
- echomsg 'Executed command: "' . ctags_cmd . '"'
- if !empty(ctags_output)
- echomsg 'Command output:'
- for line in split(ctags_output, '\n')
- echomsg line
- endfor
- endif
- endif
+ let errmsg = 'Tagbar: Ctags doesn''t seem to be Exuberant Ctags!'
+ let infomsg = 'GNU ctags will NOT WORK.' .
+ \ ' Please download Exuberant Ctags from ctags.sourceforge.net' .
+ \ ' and install it in a directory in your $PATH' .
+ \ ' or set g:tagbar_ctags_bin.'
+ call s:CtagsErrMsg(errmsg, infomsg, a:silent, ctags_cmd, ctags_output)
let s:checked_ctags = 2
return 0
elseif !s:CheckExCtagsVersion(ctags_output)
- if !a:silent
- echoerr 'Tagbar: Exuberant Ctags is too old!'
- echomsg 'You need at least version 5.5 for Tagbar to work.'
- \ 'Please download a newer version from ctags.sourceforge.net.'
- echomsg 'Executed command: "' . ctags_cmd . '"'
- if !empty(ctags_output)
- echomsg 'Command output:'
- for line in split(ctags_output, '\n')
- echomsg line
- endfor
- endif
- endif
+ let errmsg = 'Tagbar: Exuberant Ctags is too old!'
+ let infomsg = 'You need at least version 5.5 for Tagbar to work.' .
+ \ ' Please download a newer version from ctags.sourceforge.net.'
+ call s:CtagsErrMsg(errmsg, infomsg, a:silent, ctags_cmd, ctags_output)
let s:checked_ctags = 2
return 0
else
@@ -1095,11 +1072,44 @@ function! s:CheckForExCtags(silent) abort
endif
endfunction
+" s:CtagsErrMsg() {{{2
+function! s:CtagsErrMsg(errmsg, infomsg, silent, ...) abort
+ call s:LogDebugMessage(a:errmsg)
+ let ctags_cmd = a:0 > 0 ? a:1 : ''
+ let ctags_output = a:0 > 0 ? a:2 : ''
+
+ if ctags_output != ''
+ call s:LogDebugMessage("Command output:\n" . ctags_output)
+ endif
+
+ if !a:silent
+ echoerr a:errmsg
+ echomsg a:infomsg
+
+ if ctags_cmd == ''
+ return
+ endif
+
+ echomsg 'Executed command: "' . ctags_cmd . '"'
+ if ctags_output != ''
+ echomsg 'Command output:'
+ for line in split(ctags_output, '\n')
+ echomsg line
+ endfor
+ else
+ echomsg 'Command output is empty.'
+ endif
+ endif
+endfunction
+
+
" s:CheckExCtagsVersion() {{{2
function! s:CheckExCtagsVersion(output) abort
call s:LogDebugMessage('Checking Exuberant Ctags version')
if a:output =~ 'Exuberant Ctags Development'
+ call s:LogDebugMessage("Found development version, " .
+ \ "assuming compatibility")
return 1
endif
@@ -1107,6 +1117,9 @@ function! s:CheckExCtagsVersion(output) abort
let major = matchlist[1]
let minor = matchlist[2]
+ call s:LogDebugMessage("Ctags version: " .
+ \ "major='" . major . "', minor='" . minor . "'")
+
return major >= 6 || (major == 5 && minor >= 5)
endfunction
@@ -1505,11 +1518,21 @@ function! s:TypeInfo.getKind(kind) abort dict
return self.kinds[idx]
endfunction
+" s:TypeInfo.createKinddict() {{{3
+" Create a dictionary of the kind order for fast access in sorting functions
+function! s:TypeInfo.createKinddict() abort dict
+ let i = 0
+ for kind in self.kinds
+ let self.kinddict[kind.short] = i
+ let i += 1
+ endfor
+endfunction
+
" File info {{{2
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
@@ -1535,10 +1558,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
@@ -1546,7 +1568,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
@@ -1568,8 +1590,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
@@ -1583,13 +1604,7 @@ endfunction
" s:FileInfo.sortTags() {{{3
function! s:FileInfo.sortTags() abort dict
- if has_key(s:compare_typeinfo, 'sort')
- if s:compare_typeinfo.sort
- call s:SortTags(self.tags, 's:CompareByKind')
- else
- call s:SortTags(self.tags, 's:CompareByLine')
- endif
- elseif g:tagbar_sort
+ if get(s:compare_typeinfo, 'sort', g:tagbar_sort)
call s:SortTags(self.tags, 's:CompareByKind')
else
call s:SortTags(self.tags, 's:CompareByLine')
@@ -1683,7 +1698,7 @@ function! s:OpenWindow(flags) abort
if tagbarwinnr != -1
if winnr() != tagbarwinnr && jump
call s:winexec(tagbarwinnr . 'wincmd w')
- call s:HighlightTag(1, 1, curline)
+ call s:HighlightTag(g:tagbar_autoshowtag != 2, 1, curline)
endif
call s:LogDebugMessage("OpenWindow finished, Tagbar already open")
return
@@ -1698,7 +1713,8 @@ function! s:OpenWindow(flags) abort
" Expand the Vim window to accomodate for the Tagbar window if requested
" and save the window positions to be able to restore them later.
- if g:tagbar_expand && !s:window_expanded && has('gui_running')
+ if g:tagbar_expand >= 1 && !s:window_expanded &&
+ \ (has('gui_running') || g:tagbar_expand == 2)
let s:window_pos.pre.x = getwinposx()
let s:window_pos.pre.y = getwinposy()
let &columns += g:tagbar_width + 1
@@ -1707,14 +1723,9 @@ function! s:OpenWindow(flags) abort
let s:window_expanded = 1
endif
- let eventignore_save = &eventignore
- set eventignore=all
-
let openpos = g:tagbar_left ? 'topleft vertical ' : 'botright vertical '
exe 'silent keepalt ' . openpos . g:tagbar_width . 'split ' . '__Tagbar__'
- let &eventignore = eventignore_save
-
call s:InitWindow(autoclose)
" If the current file exists, but is empty, it means that it had a
@@ -1726,7 +1737,7 @@ function! s:OpenWindow(flags) abort
endif
call s:AutoUpdate(curfile, 0)
- call s:HighlightTag(1, 1, curline)
+ call s:HighlightTag(g:tagbar_autoshowtag != 2, 1, curline)
if !(g:tagbar_autoclose || autofocus || g:tagbar_autofocus)
call s:winexec('wincmd p')
@@ -1748,14 +1759,25 @@ function! s:InitWindow(autoclose) abort
setlocal nobuflisted
setlocal nomodifiable
setlocal nolist
- setlocal nonumber
setlocal nowrap
setlocal winfixwidth
setlocal textwidth=0
setlocal nospell
- if exists('+relativenumber')
- setlocal norelativenumber
+ if g:tagbar_show_linenumbers == 0
+ setlocal nonumber
+ if exists('+relativenumber')
+ setlocal norelativenumber
+ endif
+ elseif g:tagbar_show_linenumbers == 1
+ setlocal number
+ elseif g:tagbar_show_linenumbers == 2
+ setlocal relativenumber
+ else
+ set number<
+ if exists('+relativenumber')
+ set relativenumber<
+ endif
endif
setlocal nofoldenable
@@ -1766,12 +1788,7 @@ function! s:InitWindow(autoclose) abort
setlocal foldmethod&
setlocal foldexpr&
- " Earlier versions have a bug in local, evaluated statuslines
- if v:version > 701 || (v:version == 701 && has('patch097'))
- setlocal statusline=%!TagbarGenerateStatusline()
- else
- setlocal statusline=Tagbar
- endif
+ call s:SetStatusLine('current')
let s:new_window = 1
@@ -1855,16 +1872,22 @@ function! s:CloseWindow() abort
if index(tablist, tagbarbufnr) == -1
let &columns -= g:tagbar_width + 1
let s:window_expanded = 0
- " Only restore window position if it hasn't been moved manually
- " after the expanding
- if getwinposx() == s:window_pos.post.x &&
+ " Only restore window position if it is available and if the
+ " window hasn't been moved manually after the expanding
+ if getwinposx() != -1 &&
+ \ getwinposx() == s:window_pos.post.x &&
\ getwinposy() == s:window_pos.post.y
execute 'winpos ' . s:window_pos.pre.x .
\ ' ' . s:window_pos.pre.y
- endif
+ endif
endif
endif
+ if s:autocommands_done && !s:statusline_in_use
+ autocmd! TagbarAutoCmds
+ let s:autocommands_done = 0
+ endif
+
call s:LogDebugMessage('CloseWindow finished')
endfunction
@@ -1872,8 +1895,10 @@ endfunction
function! s:ZoomWindow() abort
if s:is_maximized
execute 'vert resize ' . g:tagbar_width
+ execute s:winrestcmd
let s:is_maximized = 0
else
+ let s:winrestcmd = winrestcmd()
vert resize
let s:is_maximized = 1
endif
@@ -1907,13 +1932,24 @@ 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)
+ if exists('#TagbarProjects#User')
+ execute 'doautocmd <nomodeline> TagbarProjects User ' . a:fname
+ if exists('b:tagbar_type')
+ let typeinfo = extend(copy(typeinfo),
+ \ s:TransformUserTypeDef(b:tagbar_type))
+ call typeinfo.createKinddict()
+ endif
+ endif
+ let fileinfo = s:FileInfo.New(a:fname, a:ftype, typeinfo)
endif
" Use a temporary files for ctags processing instead of the original one.
@@ -1928,7 +1964,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)
@@ -1942,12 +1978,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)))
@@ -1980,7 +2015,7 @@ function! s:ProcessFile(fname, ftype) abort
call filter(fileinfo.tags, '!(' . is_scoped . ')')
call s:AddScopedTags(scopedtags, processedtags, {}, 0,
- \ typeinfo, fileinfo)
+ \ typeinfo, fileinfo, line('$'))
if !empty(scopedtags)
echoerr 'Tagbar: ''scopedtags'' not empty after processing,'
@@ -2027,42 +2062,52 @@ 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')
- let ctags_args = ' ' . typeinfo.ctagsargs . ' '
+ 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
- let ctags_args = ' -f - '
- let ctags_args .= ' --format=2 '
- let ctags_args .= ' --excmd=pattern '
- let ctags_args .= ' --fields=nksSa '
- let ctags_args .= ' --extra= '
- let ctags_args .= ' --sort=yes '
+ "Prefer constructing ctags_args as a list rather than a string
+ "See s:EscapeCtagsCmd() - It's a best practice to shellescape()
+ "each arg separately because in special cases where space is
+ "intended to be in an argument, spaces in a single ctag_args
+ "string would be ambiguous. Is the space an argument separator
+ "or to be included in the argument
+ let ctags_args = [ '-f',
+ \ '-',
+ \ '--format=2',
+ \ '--excmd=pattern',
+ \ '--fields=nksSa',
+ \ '--extra=',
+ \ '--sort=yes'
+ \ ]
" 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=' . expand(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
- let ctags_args .= ' --language-force=' . ctags_type .
- \ ' --' . ctags_type . '-kinds=' . ctags_kinds . ' '
+ let ctags_args += ['--language-force=' . ctags_type]
+ 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
@@ -2135,12 +2180,16 @@ function! s:ParseTagline(part1, part2, typeinfo, fileinfo) abort
" Remove all tabs that may illegally be in the value
let val = substitute(strpart(field, delimit + 1), '\t', '', 'g')
if len(val) > 0
- let taginfo.fields[key] = val
+ if key == 'line' || key == 'column'
+ let taginfo.fields[key] = str2nr(val)
+ else
+ let taginfo.fields[key] = val
+ endif
endif
endfor
" Needed for jsctags
if has_key(taginfo.fields, 'lineno')
- let taginfo.fields.line = taginfo.fields.lineno
+ let taginfo.fields.line = str2nr(taginfo.fields.lineno)
endif
" Make some information easier accessible
@@ -2185,7 +2234,7 @@ endfunction
" Tagbar. Properly parsing them is quite tricky, so try not to think about it
" too much.
function! s:AddScopedTags(tags, processedtags, parent, depth,
- \ typeinfo, fileinfo) abort
+ \ typeinfo, fileinfo, maxline) abort
if !empty(a:parent)
let curpath = a:parent.fullpath
let pscope = a:typeinfo.kind2scope[a:parent.fields.kind]
@@ -2203,7 +2252,9 @@ function! s:AddScopedTags(tags, processedtags, parent, depth,
let is_cur_tag .= ' &&
\ (v:val.path ==# curpath ||
\ match(v:val.path, ''\V\^\C'' . curpath . a:typeinfo.sro) == 0) &&
- \ (v:val.path ==# curpath ? (v:val.scope ==# pscope) : 1)'
+ \ (v:val.path ==# curpath ? (v:val.scope ==# pscope) : 1) &&
+ \ v:val.fields.line >= a:parent.fields.line &&
+ \ v:val.fields.line <= a:maxline'
endif
let curtags = filter(copy(a:tags), is_cur_tag)
@@ -2241,8 +2292,23 @@ function! s:AddScopedTags(tags, processedtags, parent, depth,
let tag.children = []
endif
+ " Check for tags with the exact same name that may be created
+ " alternatively in a conditional (Issue #139). The only way to
+ " distinguish between them is by line number.
+ let twins = filter(copy(realtags),
+ \ "v:val.fullpath ==# '" .
+ \ substitute(tag.fullpath, "'", "''", 'g') . "'" .
+ \ " && v:val.fields.line != " . tag.fields.line)
+ let maxline = line('$')
+ for twin in twins
+ if twin.fields.line <= maxline &&
+ \ twin.fields.line > tag.fields.line
+ let maxline = twin.fields.line - 1
+ endif
+ endfor
+
call s:AddScopedTags(a:tags, tag.children, tag, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
+ \ a:typeinfo, a:fileinfo, maxline)
endfor
call extend(a:processedtags, realtags)
@@ -2268,7 +2334,7 @@ function! s:AddScopedTags(tags, processedtags, parent, depth,
if !empty(grandchildren)
call s:AddScopedTags(a:tags, a:processedtags, a:parent, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
+ \ a:typeinfo, a:fileinfo, a:maxline)
endif
endfunction
@@ -2307,15 +2373,16 @@ function! s:ProcessPseudoChildren(tags, tag, depth, typeinfo, fileinfo) abort
endif
call s:AddScopedTags(a:tags, childtag.children, childtag, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
+ \ a:typeinfo, a:fileinfo, line('$'))
endfor
- let is_grandchild = 'v:val.depth > a:depth &&
- \ match(v:val.path, ''^\C'' . a:tag.fullpath) == 0'
+ let is_grandchild = 'v:val.depth > a:depth && ' .
+ \ 'match(v:val.path,' .
+ \ '''^\C'' . substitute(a:tag.fullpath, "''", "''''", "g")) == 0'
let grandchildren = filter(copy(a:tags), is_grandchild)
if !empty(grandchildren)
call s:AddScopedTags(a:tags, a:tag.children, a:tag, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
+ \ a:typeinfo, a:fileinfo, line('$'))
endif
endfunction
@@ -2426,6 +2493,7 @@ function! s:ToggleSort() abort
call fileinfo.sortTags()
call s:RenderContent()
+ call s:SetStatusLine('current')
execute curline
endfunction
@@ -2486,8 +2554,17 @@ function! s:RenderContent(...) abort
let typeinfo = fileinfo.typeinfo
- " Print tags
- call s:PrintKinds(typeinfo, fileinfo)
+ if !empty(fileinfo.tags)
+ " Print tags
+ call s:PrintKinds(typeinfo, fileinfo)
+ else
+ call s:LogDebugMessage('No tags found, skipping printing.')
+ if g:tagbar_compact && s:short_help
+ silent 0put ='\" No tags found.'
+ else
+ silent put ='\" No tags found.'
+ endif
+ endif
" Delete empty lines at the end of the buffer
for linenr in range(line('$'), 1, -1)
@@ -2690,28 +2767,36 @@ function! s:PrintHelp() abort
silent 0put ='\" Tagbar keybindings'
silent put ='\"'
silent put ='\" --------- General ---------'
- silent put ='\" <Enter> : Jump to tag definition'
- silent put ='\" p : As above, but stay in'
- silent put ='\" Tagbar window'
- silent put ='\" <C-N> : Go to next top-level tag'
- silent put ='\" <C-P> : Go to previous top-level tag'
- silent put ='\" <Space> : Display tag prototype'
+ silent put ='\" ' . s:get_map_str('jump') . ': Jump to tag definition'
+ silent put ='\" ' . s:get_map_str('preview') . ': As above, but stay in'
+ silent put ='\" Tagbar window'
+ silent put ='\" ' . s:get_map_str('nexttag') . ': Go to next top-level tag'
+ silent put ='\" ' . s:get_map_str('prevtag') . ': Go to previous top-level tag'
+ silent put ='\" ' . s:get_map_str('showproto') . ': Display tag prototype'
silent put ='\"'
silent put ='\" ---------- Folds ----------'
- silent put ='\" +, zo : Open fold'
- silent put ='\" -, zc : Close fold'
- silent put ='\" o, za : Toggle fold'
- silent put ='\" *, zR : Open all folds'
- silent put ='\" =, zM : Close all folds'
+ silent put ='\" ' . s:get_map_str('openfold') . ': Open fold'
+ silent put ='\" ' . s:get_map_str('closefold') . ': Close fold'
+ silent put ='\" ' . s:get_map_str('togglefold') . ': Toggle fold'
+ silent put ='\" ' . s:get_map_str('openallfolds') . ': Open all folds'
+ silent put ='\" ' . s:get_map_str('closeallfolds') . ': Close all folds'
silent put ='\"'
silent put ='\" ---------- Misc -----------'
- silent put ='\" s : Toggle sort'
- silent put ='\" x : Zoom window in/out'
- silent put ='\" q : Close window'
- silent put ='\" <F1> : Remove help'
+ silent put ='\" ' . s:get_map_str('togglesort') . ': Toggle sort'
+ silent put ='\" ' . s:get_map_str('zoomwin') . ': Zoom window in/out'
+ silent put ='\" ' . s:get_map_str('close') . ': Close window'
+ silent put ='\" ' . s:get_map_str('help') . ': Toggle help'
silent put _
endif
endfunction
+function! s:get_map_str(map) abort
+ let def = get(g:, 'tagbar_map_' . a:map)
+ if type(def) == type("")
+ return def
+ else
+ return join(def, ', ')
+ endif
+endfunction
" s:RenderKeepView() {{{2
" The gist of this function was taken from NERDTree by Martin Grenfell.
@@ -2780,7 +2865,7 @@ function! s:HighlightTag(openfolds, ...) abort
return
endif
- if g:tagbar_autoshowtag || a:openfolds
+ if g:tagbar_autoshowtag == 1 || a:openfolds
call s:OpenParents(tag)
endif
@@ -2861,11 +2946,10 @@ function! s:JumpToTag(stay_in_tagbar) abort
.foldopen
endif
- redraw
-
if a:stay_in_tagbar
call s:HighlightTag(0)
call s:winexec(tagbarwinnr . 'wincmd w')
+ redraw
elseif g:tagbar_autoclose || autoclose
call s:CloseWindow()
else
@@ -3197,32 +3281,79 @@ endfunction
" Assemble the ctags command line in a way that all problematic characters are
" properly escaped and converted to the system's encoding
" Optional third parameter is a file name to run ctags on
+" Note: The second parameter (a:args) can be a list of args or
+" a single string of the args.
+" When a:args is a list, each argument in the list will be escaped for the
+" current &shell type.
+" When a:args is a string, all arguments should be escaped appropriately
+" (if required). In most use cases no escaping is required so a string
+" is acceptable. But in cases where arguments may need to be escaped
+" differently for each &shell type, then pass a list of arguments.
function! s:EscapeCtagsCmd(ctags_bin, args, ...) abort
call s:LogDebugMessage('EscapeCtagsCmd called')
call s:LogDebugMessage('ctags_bin: ' . a:ctags_bin)
- call s:LogDebugMessage('ctags_args: ' . a:args)
+ if type(a:args)==type('')
+ call s:LogDebugMessage('ctags_args (is a string): ' . a:args)
+ elseif type(a:args)==type([])
+ call s:LogDebugMessage('ctags_args (is a list): ' . string(a:args))
+ endif
if exists('+shellslash')
let shellslash_save = &shellslash
set noshellslash
endif
- if a:0 == 1
- let fname = shellescape(a:1)
+ "Set up 0th argument of ctags_cmd
+ "a:ctags_bin may have special characters that require escaping.
+ if &shell =~ 'cmd\.exe$' && a:ctags_bin !~ '\s'
+ "For windows cmd.exe, escaping the 0th argument can cause
+ "problems if it references a batch file and the batch file uses %~dp0.
+ "So for windows cmd.exe, only escape the 0th argument iff necessary.
+ "Only known necessary case is when ctags_bin executable filename has
+ "whitespace character(s).
+
+ " Example: If 0th argument is wrapped in double quotes AND it is not
+ " an absolute path to ctags_bin, but rather an executable in %PATH%,
+ " then %~dp0 resolves to the current working directory rather than
+ " the batch file's directory. Batch files like this generally exepect
+ " and depend on %~dp0 to resolve the batch file's directory.
+ " Note: Documentation such as `help cmd.exe` and
+ " http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true
+ " suggest other special characters that require escaping for command
+ " line completion. But tagbar.vim does not use the command line
+ " completion feature of cmd.exe and testing shows that the only special
+ " character that needs to be escaped for tagbar.vim is <space> for
+ " windows cmd.exe.
+ let ctags_cmd = a:ctags_bin
else
- let fname = ''
+ let ctags_cmd = shellescape(a:ctags_bin)
+ endif
+
+ "Add additional arguments to ctags_cmd
+ if type(a:args)==type('')
+ "When a:args is a string, append the arguments
+ "Note: In this case, do not attempt to shell escape a:args string.
+ "This function expects the string to already be escaped properly for
+ "the shell type. Why not escape? Because it could be ambiguous about
+ "whether a space is an argument separator or included in the argument.
+ "Since escaping rules vary from shell to shell, it is better to pass a
+ "list of arguments to a:args. With a list, each argument is clearly
+ "separated, so shellescape() can calculate the appropriate escaping
+ "for each argument for the current &shell.
+ let ctags_cmd .= ' ' . a:args
+ elseif type(a:args)==type([])
+ "When a:args is a list, shellescape() each argument and append ctags_cmd
+ "Note: It's a better practice to shellescape() each argument separately so that
+ "spaces used as a separator between arguments can be distinguished with
+ "spaces used inside a single argument.
+ for arg in a:args
+ let ctags_cmd .= ' ' . shellescape(arg)
+ endfor
endif
- let ctags_cmd = shellescape(a:ctags_bin) . ' ' . a:args . ' ' . fname
-
- " Stupid cmd.exe quoting
- if &shell =~ 'cmd\.exe'
- let reserved_chars = '&()@^'
- " not allowed in filenames, but escape anyway just in case
- let reserved_chars .= '<>|'
- let pattern = join(split(reserved_chars, '\zs'), '\|')
- let ctags_cmd = substitute(ctags_cmd, '\V\(' . pattern . '\)',
- \ '^\0', 'g')
+ "if a filename was specified, add filename as final argument to ctags_cmd.
+ if a:0 == 1
+ let ctags_cmd .= ' ' . shellescape(a:1)
endif
if exists('+shellslash')
@@ -3269,7 +3400,13 @@ function! s:ExecuteCtags(ctags_cmd) abort
set shellcmdflag=/s\ /c
endif
- let ctags_output = system(a:ctags_cmd)
+ if s:debug
+ silent 5verbose let ctags_output = system(a:ctags_cmd)
+ call s:LogDebugMessage(v:statusmsg)
+ redraw!
+ else
+ let ctags_output = system(a:ctags_cmd)
+ endif
if &shell =~ 'cmd\.exe'
let &shellxquote = shellxquote_save
@@ -3418,6 +3555,43 @@ function! s:IsValidFile(fname, ftype) abort
return 1
endfunction
+" s:SetStatusLine() {{{2
+function! s:SetStatusLine(current)
+ " Make sure we're actually in the Tagbar window
+ let tagbarwinnr = bufwinnr('__Tagbar__')
+ if tagbarwinnr == -1
+ return
+ endif
+ if tagbarwinnr != winnr()
+ let in_tagbar = 0
+ call s:winexec(tagbarwinnr . 'wincmd w')
+ else
+ let in_tagbar = 1
+ endif
+ let current = a:current == 'current'
+
+ let sort = g:tagbar_sort ? 'Name' : 'Order'
+
+ if !empty(s:known_files.getCurrent())
+ let fname = fnamemodify(s:known_files.getCurrent().fpath, ':t')
+ else
+ let fname = ''
+ endif
+
+ if exists('g:tagbar_status_func')
+ let args = [current, sort, fname]
+ let &l:statusline = call(g:tagbar_status_func, args)
+ else
+ let colour = current ? '%#StatusLine#' : '%#StatusLineNC#'
+ let text = colour . '[' . sort . '] ' . fname
+ let &l:statusline = text
+ endif
+
+ if !in_tagbar
+ call s:winexec('wincmd p')
+ endif
+endfunction
+
" s:QuitIfOnlyWindow() {{{2
function! s:QuitIfOnlyWindow() abort
" Check if there is more than one window
@@ -3471,14 +3645,16 @@ endfunction
" s:winexec() {{{2
function! s:winexec(cmd) abort
- call s:LogDebugMessage("Executing without autocommands: " . a:cmd)
+ " Commented out for now to see if it works without.
- let eventignore_save = &eventignore
- set eventignore=BufEnter
+ " call s:LogDebugMessage("Executing without autocommands: " . a:cmd)
+
+ " let eventignore_save = &eventignore
+ " set eventignore=all
execute a:cmd
- let &eventignore = eventignore_save
+ " let &eventignore = eventignore_save
endfunction
" TagbarBalloonExpr() {{{2
@@ -3492,22 +3668,6 @@ function! TagbarBalloonExpr() abort
return taginfo.getPrototype(0)
endfunction
-" TagbarGenerateStatusline() {{{2
-function! TagbarGenerateStatusline() abort
- if g:tagbar_sort
- let text = '[Name]'
- else
- let text = '[Order]'
- endif
-
- if !empty(s:known_files.getCurrent())
- let filename = fnamemodify(s:known_files.getCurrent().fpath, ':t')
- let text .= ' ' . filename
- endif
-
- return text
-endfunction
-
" Debugging {{{1
" s:StartDebug() {{{2
function! s:StartDebug(filename) abort
@@ -3591,7 +3751,7 @@ function! tagbar#RestoreSession() abort
endfunction
function! tagbar#PauseAutocommands() abort
- call s:PauseAutocommands()
+ call s:PauseAutocommands()
endfunction
" }}}2
@@ -3637,6 +3797,10 @@ endfunction
" tagbar#currenttag() {{{2
function! tagbar#currenttag(fmt, default, ...) abort
+ " Indicate that the statusline functionality is being used. This prevents
+ " the CloseWindow() function from removing the autocommands.
+ let s:statusline_in_use = 1
+
if a:0 > 0
" also test for non-zero value for backwards compatibility
let longsig = a:1 =~# 's' || (type(a:1) == type(0) && a:1 != 0)
@@ -3665,6 +3829,17 @@ function! tagbar#currenttag(fmt, default, ...) abort
endif
endfunction
+" tagbar#currentfile() {{{2
+function! tagbar#currentfile() abort
+ let filename = ''
+
+ if !empty(s:known_files.getCurrent())
+ let filename = fnamemodify(s:known_files.getCurrent().fpath, ':t')
+ endif
+
+ return filename
+endfunction
+
" tagbar#gettypeconfig() {{{2
function! tagbar#gettypeconfig(type) abort
if !s:Init(1)
View
143 etc/vim/bundle/tagbar/doc/tagbar.txt
@@ -261,14 +261,15 @@ COMMANDS *tagbar-commands*
Close the Tagbar window if it is open.
:TagbarToggle *:TagbarToggle*
- Open the Tagbar window if it is closed or close it if it is open.
+:Tagbar
+ Open the Tagbar window if it is closed, or close it if it is open.
:TagbarOpenAutoClose *:TagbarOpenAutoClose*
Open the Tagbar window, jump to it and close it on tag selection. This is
an alias for ":TagbarOpen fjc".
:TagbarTogglePause *:TagbarTogglePause*
- Freezes/Unfreezes the Tagbar window. Stops the contents of the window
+ Freezes/Unfreezes the Tagbar window. Stops the contents of the window
from changing when a different source file is selected.
:TagbarSetFoldlevel[!] {number} *:TagbarSetFoldlevel*
@@ -298,6 +299,8 @@ COMMANDS *tagbar-commands*
Start debug mode. This will write debug messages to file [logfile] while
using Tagbar. If no argument is given "tagbardebug.log" in the current
directory is used. Note: an existing file will be overwritten!
+ Note also that it is usually necessary to call this command before loading
+ a file that creates problems in order to get all of the needed data.
:TagbarDebugEnd *:TagbarDebugEnd*
End debug mode, debug messages will no longer be written to the logfile.
@@ -308,27 +311,51 @@ KEY MAPPINGS *tagbar-keys*
The following mappings are valid in the Tagbar window:
<F1> Display key mapping help.
+ Map option: tagbar_map_help
<CR>/<Enter> Jump to the tag under the cursor. Doesn't work for pseudo-tags
or generic headers.
+ Map option: tagbar_map_jump
p Jump to the tag under the cursor, but stay in the Tagbar window.
+ Map option: tagbar_map_preview
<LeftMouse> When on a fold icon, open or close the fold depending on the
current state.
<2-LeftMouse> Same as <CR>. See |g:tagbar_singleclick| if you want to use a
single- instead of a double-click.
+<C-N> Go to the next top-level tag.
+ Map option: tagbar_map_nexttag
+<C-P> Go to the previous top-level tag.
+ Map option: tagbar_map_prevtag
<Space> Display the prototype of the current tag (i.e. the line defining
it) in the command line.
+ Map option: tagbar_map_showproto
+/zo Open the fold under the cursor.
+ Map option: tagbar_map_openfold
-/zc Close the fold under the cursor or the current one if there is
no fold under the cursor.
+ Map option: tagbar_map_closefold
o/za Toggle the fold under the cursor or the current one if there is
no fold under the cursor.
+ Map option: tagbar_map_togglefold
*/zR Open all folds by setting foldlevel to 99.
+ Map option: tagbar_map_openallfolds
=/zM Close all folds by setting foldlevel to 0.
-<C-N> Go to the next top-level tag.
-<C-P> Go to the previous top-level tag.
+ Map option: tagbar_map_closeallfolds
s Toggle sort order between name and file order.
+ Map option: tagbar_map_togglesort
x Toggle zooming the window.
+ Map option: tagbar_map_zoomwin
q Close the Tagbar window.
+ Map option: tagbar_map_close
+
+These mappings can be redefined with the given map options. The argument can
+be either a string or a |List| of strings. In the latter case the
+functionality will be assigned to all of the keys in the list. For example, if
+you want to remap the sort toggling functionality to "r":
+>
+ let g:tagbar_map_togglesort = "r"
+<
+See |key-notation| for how to write special keys like <Space> or the keypad
+keys.
==============================================================================
5. Configuration *tagbar-configuration*
@@ -443,12 +470,31 @@ Example:
let g:tagbar_show_visibility = 0
<
+ *g:tagbar_show_linenumbers*
+g:tagbar_show_linenumbers~
+Default: 0
+
+Whether line numbers should be shown in the Tagbar window.
+
+Possible values are:
+ 0: Don't show any line numbers.
+ 1: Show absolute line numbers.
+ 2: Show relative line numbers.
+ -1: Use the global line number settings.
+
+Example:
+>
+ let g:tagbar_show_linenumbers = 2
+<
+
*g:tagbar_expand*
g:tagbar_expand~
Default: 0
-If this option is set the Vim window will be expanded by the width of the
-Tagbar window if using a GUI version of Vim.
+If this option is set to 1 the Vim window will be expanded by the width of the
+Tagbar window if using a GUI version of Vim. Setting it to 2 will also try
+expanding a terminal, but note that this is not supported by all terminals.
+See also |xterm-resize|.
Example:
>
@@ -492,7 +538,7 @@ Examples (don't worry if some of the characters aren't displayed correctly,
just choose other characters in that case):
>
let g:tagbar_iconchars = ['▶', '▼'] (default on Linux and Mac OS X)
- let g:tagbar_iconchars = ['', '']
+ let g:tagbar_iconchars = ['', '']
let g:tagbar_iconchars = ['▷', '◢']
let g:tagbar_iconchars = ['+', '-'] (default on Windows)
<
@@ -501,11 +547,14 @@ just choose other characters in that case):
g:tagbar_autoshowtag~
Default: 0
-If this variable is set and the current tag is inside of a closed fold then
-the folds will be opened as much as needed for the tag to be visible so it can
-be highlighted. If it is not set then the folds won't be opened and the parent
-tag will be highlighted instead. You can use the |:TagbarShowTag| command to
-open the folds manually.
+If this variable is set to 1 and the current tag is inside of a closed fold
+then the folds will be opened as much as needed for the tag to be visible so
+it can be highlighted. If it is set to 0 then the folds will only be opened
+when opening the Tagbar window and the current tag is insided a closed fold,
+otherwise the folds won't be opened and the parent tag will be highlighted
+instead. If it is set to 2 then the folds will never be opened automatically.
+
+You can use the |:TagbarShowTag| command to open the folds manually.
Example:
>
@@ -535,6 +584,33 @@ Example:
let g:tagbar_systemenc = 'cp936'
<
+ *g:tagbar_status_func*
+g:tagbar_status_func~
+Default: undefined
+
+This is the name of a function whose return value will be used to draw the
+statusline of the Tagbar window.
+
+The function has to take three arguments:
+ 1. current: Whether Tagbar is the current window; 0 or 1.
+ 2. sort: The sort order of the tags; 'Name' if they are sorted by name and
+ 'Order' if they are sorted by their order of appearance in the file.
+ 3. fname: The name of the file that the tags belong to.
+
+In order to avoid possible future additions to the arguments resulting in an
+error it is recommended to add an additional vararg to the signature (see
+|a:0|).
+
+Here is an example that, when put into your vimrc, will emulate Tagbar's
+default statusline:
+>
+ function! TagbarStatusFunc(current, sort, fname, ...) abort
+ let colour = a:current ? '%#StatusLine#' : '%#StatusLineNC#'
+ return colour . '[' . a:sort . '] ' . a:fname
+ endfunction
+ let g:tagbar_status_func = 'TagbarStatusFunc'
+<
+
------------------------------------------------------------------------------
HIGHLIGHT COLOURS *tagbar-highlight*
@@ -793,6 +869,25 @@ ctagsargs: The arguments to be passed to the filetype-specific ctags program
program output its data on stdout. Not used for the normal ctags
program.
+ The value of ctagsargs may be a |List| of strings (a string for
+ each argument), or a single string (|expr-string|) of all the
+ arguments.
+
+ When the value of ctagsargs is a list, tagbar.vim takes care of
+ escaping each argument in the list as required for the current
+ 'shell' type.
+
+ When the value of ctagsargs is a string, it must be properly
+ escaped (if required by the current shell type). The reason
+ tagbar.vim does not attempt to escape the string in this case is
+ because if there is a space, it is ambiguous as to whether the
+ space is delimiting an argument or included in the argument. To
+ avoid this amiguity, tagbar.vim expects the string to be already
+ escaped as required.
+
+ If special escaping is required for different OS shell types or if
+ in doubt, then it is recommended to define ctagsargs with a List.
+
You then have to assign this dictionary to a variable in your vimrc with the
name
@@ -961,6 +1056,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:
View
2 etc/vim/bundle/tagbar/doc/tags
@@ -19,9 +19,11 @@ g:tagbar_foldlevel tagbar.txt /*g:tagbar_foldlevel*
g:tagbar_iconchars tagbar.txt /*g:tagbar_iconchars*
g:tagbar_indent tagbar.txt /*g:tagbar_indent*
g:tagbar_left tagbar.txt /*g:tagbar_left*
+g:tagbar_show_linenumbers tagbar.txt /*g:tagbar_show_linenumbers*
g:tagbar_show_visibility tagbar.txt /*g:tagbar_show_visibility*
g:tagbar_singleclick tagbar.txt /*g:tagbar_singleclick*
g:tagbar_sort tagbar.txt /*g:tagbar_sort*
+g:tagbar_status_func tagbar.txt /*g:tagbar_status_func*
g:tagbar_systemenc tagbar.txt /*g:tagbar_systemenc*
g:tagbar_updateonsave_maxlines tagbar.txt /*g:tagbar_updateonsave_maxlines*
g:tagbar_width tagbar.txt /*g:tagbar_width*
View
102 etc/vim/bundle/tagbar/plugin/tagbar.vim
@@ -42,49 +42,33 @@ if v:version == 700 && !has('patch167')
finish
endif
-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_indent')
- let g:tagbar_indent = 2
-endif
-
-if !exists('g:tagbar_show_visibility')
- let g:tagbar_show_visibility = 1
-endif
-
-if !exists('g:tagbar_expand')
- let g:tagbar_expand = 0
-endif
-
-if !exists('g:tagbar_singleclick')
- let g:tagbar_singleclick = 0
-endif
-
-if !exists('g:tagbar_foldlevel')
- let g:tagbar_foldlevel = 99
-endif
+function! s:init_var(var, value) abort
+ if !exists('g:tagbar_' . a:var)
+ execute 'let g:tagbar_' . a:var . ' = ' . string(a:value)
+ endif
+endfunction
+
+let s:options = [
+ \ ['autoclose', 0],
+ \ ['autofocus', 0],
+ \ ['autoshowtag', 0],
+ \ ['compact', 0],
+ \ ['expand', 0],
+ \ ['foldlevel', 99],
+ \ ['indent', 2],
+ \ ['left', 0],
+ \ ['show_visibility', 1],
+ \ ['show_linenumbers', 0],
+ \ ['singleclick', 0],
+ \ ['sort', 1],
+ \ ['systemenc', &encoding],
+ \ ['width', 40],
+\ ]
+
+for [opt, val] in s:options
+ call s:init_var(opt, val)
+endfor
+unlet s:options
if !exists('g:tagbar_iconchars')
if has('multi_byte') && has('unix') && &encoding == 'utf-8' &&
@@ -95,13 +79,30 @@ if !exists('g:tagbar_iconchars')
endif
endif
-if !exists('g:tagbar_autoshowtag')
- let g:tagbar_autoshowtag = 0
-endif
-
-if !exists('g:tagbar_systemenc')
- let g:tagbar_systemenc = &encoding
-endif
+let s:keymaps = [
+ \ ['jump', '<CR>'],
+ \ ['preview', 'p'],
+ \ ['nexttag', '<C-N>'],
+ \ ['prevtag', '<C-P>'],
+ \ ['showproto', '<Space>'],
+ \
+ \ ['openfold', ['+', '<kPlus>', 'zo']],
+ \ ['closefold', ['-', '<kMinus>', 'zc']],
+ \ ['togglefold', ['o', 'za']],
+ \ ['openallfolds', ['*', '<kMultiply>', 'zR']],
+ \ ['closeallfolds', ['=', 'zM']],
+ \
+ \ ['togglesort', 's'],
+ \ ['zoomwin', 'x'],
+ \ ['close', 'q'],
+ \ ['help', '<F1>'],
+\ ]
+
+for [map, key] in s:keymaps
+ call s:init_var('map_' . map, key)
+ unlet key
+endfor
+unlet s:keymaps
augroup TagbarSession
autocmd!
@@ -109,6 +110,7 @@ augroup TagbarSession
augroup END
" Commands {{{1
+command! -nargs=0 Tagbar call tagbar#ToggleWindow()
command! -nargs=0 TagbarToggle call tagbar#ToggleWindow()
command! -nargs=? TagbarOpen call tagbar#OpenWindow(<f-args>)
command! -nargs=0 TagbarOpenAutoClose call tagbar#OpenWindow('fcj')
View
33 etc/vim/bundle/tagbar/syntax/tagbar.vim
@@ -8,43 +8,40 @@
scriptencoding utf-8
if exists("b:current_syntax")
- finish
+ finish
endif
-let s:ic = g:tagbar_iconchars[0]
-if s:ic =~ '[]^\\-]'
- let s:ic = '\' . s:ic
-endif
-let s:io = g:tagbar_iconchars[1]
-if s:io =~ '[]^\\-]'
- let s:io = '\' . s:io
-endif
-
-let s:pattern = '\([' . s:ic . s:io . '] \?\)\@<=[^-+: ]\+[^:]\+$'
+let s:ics = escape(join(g:tagbar_iconchars, ''), ']^\-')
+let s:pattern = '\(^[' . s:ics . '] \?\)\@<=[^-+: ]\+[^:]\+$'
execute "syntax match TagbarKind '" . s:pattern . "'"
-let s:pattern = '\([' . s:ic . s:io . '][-+# ]\?\)\@<=[^*(]\+\(\*\?\(([^)]\+)\)\? :\)\@='
+let s:pattern = '\(\S\@<![' . s:ics . '][-+# ]\?\)\@<=[^*(]\+\(\*\?\(([^)]\+)\)\? :\)\@='
execute "syntax match TagbarScope '" . s:pattern . "'"
-let s:pattern = '[' . s:ic . s:io . ']\([-+# ]\?\)\@='
+let s:pattern = '\S\@<![' . s:ics . ']\([-+# ]\?\)\@='
execute "syntax match TagbarFoldIcon '" . s:pattern . "'"
-let s:pattern = '\([' . s:ic . s:io . ' ]\)\@<=+\([^-+# ]\)\@='
+let s:pattern = '\(\S\@<![' . s:ics . ' ]\)\@<=+\([^-+# ]\)\@='
execute "syntax match TagbarVisibilityPublic '" . s:pattern . "'"
-let s:pattern = '\([' . s:ic . s:io . ' ]\)\@<=#\([^-+# ]\)\@='
+let s:pattern = '\(\S\@<![' . s:ics . ' ]\)\@<=#\([^-+# ]\)\@='
execute "syntax match TagbarVisibilityProtected '" . s:pattern . "'"
-let s:pattern = '\([' . s:ic . s:io . ' ]\)\@<=-\([^-+# ]\)\@='
+let s:pattern = '\(\S\@<![' . s:ics . ' ]\)\@<=-\([^-+# ]\)\@='
execute "syntax match TagbarVisibilityPrivate '" . s:pattern . "'"
unlet s:pattern
+syntax match TagbarHelp '^".*' contains=TagbarHelpKey,TagbarHelpTitle
+syntax match TagbarHelpKey '" \zs.*\ze:' contained
+syntax match TagbarHelpTitle '" \zs-\+ \w\+ -\+' contained
+
syntax match TagbarNestedKind '^\s\+\[[^]]\+\]$'
-syntax match TagbarComment '^".*'
syntax match TagbarType ' : \zs.*'
syntax match TagbarSignature '(.*)'
syntax match TagbarPseudoID '\*\ze :'
-highlight default link TagbarComment Comment
+highlight default link TagbarHelp Comment
+highlight default link TagbarHelpKey Identifier
+highlight default link TagbarHelpTitle PreProc
highlight default link TagbarKind Identifier
highlight default link TagbarNestedKind TagbarKind
highlight default link TagbarScope Title

0 comments on commit c1ab820

Please sign in to comment.
Something went wrong with that request. Please try again.