Add tag datatype (#698)

Closes #680

Add `g:tagbar_show_data_type` field to show the tag datatype next to the tag in the tagbar window
This uses the `--fields=t` field to get the datatype from ctags. If not found, then it will attempt to derive the datatype by extracting all the output from the `pattern` preceeding the tag name.

More testing is needed on other languages. So far this has been stable with C / C++ files parsing the datatype from ctags output. It has also been tested with Java files for the inferred datatype by parsing the pattern line and pulling out everything prior to the tag.
This commit is contained in:
raven42 2020-11-02 15:06:40 -06:00 committed by GitHub
parent 99c22f1bb2
commit 601b5c0073
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 2 deletions

View File

@ -1342,7 +1342,7 @@ function! s:ExecuteCtagsOnFile(fname, realfname, typeinfo) abort
\ '-',
\ '--format=2',
\ '--excmd=pattern',
\ '--fields=nksSaf',
\ '--fields=nksSaft',
\ '--sort=no',
\ '--append=no'
\ ]
@ -1541,6 +1541,17 @@ function! s:ProcessTag(name, filename, pattern, fields, is_split, typeinfo, file
let a:fileinfo.fline[taginfo.fields.line] = taginfo
if has_key(taginfo.fields, 'typeref')
let typeref = taginfo.fields.typeref
let delimit = stridx(typeref, ':')
let key = strpart(typeref, 0, delimit)
if key ==# 'typename'
let taginfo.data_type = substitute(strpart(typeref, delimit + 1), '\t', '', 'g')
else
let taginfo.data_type = key
endif
endif
" If this filetype doesn't have any scope information then we can stop
" here after adding the tag to the list
if !has_key(a:typeinfo, 'scope2kind')

View File

@ -15,6 +15,7 @@ function! tagbar#prototypes#basetag#new(name) abort
let newobj.fields.line = 0
let newobj.fields.column = 0
let newobj.prototype = ''
let newobj.data_type = ''
let newobj.path = ''
let newobj.fullpath = a:name
let newobj.depth = 0
@ -30,6 +31,7 @@ function! tagbar#prototypes#basetag#new(name) abort
let newobj.isSplitTag = function(s:add_snr('s:isSplitTag'))
let newobj.isKindheader = function(s:add_snr('s:isKindheader'))
let newobj.getPrototype = function(s:add_snr('s:getPrototype'))
let newobj.getDataType = function(s:add_snr('s:getDataType'))
let newobj._getPrefix = function(s:add_snr('s:_getPrefix'))
let newobj.initFoldState = function(s:add_snr('s:initFoldState'))
let newobj.getClosedParentTline = function(s:add_snr('s:getClosedParentTline'))
@ -72,6 +74,11 @@ function! s:getPrototype(short) abort dict
return self.prototype
endfunction
" s:getDataType() {{{1
function! s:getDataType() abort dict
return self.data_type
endfunction
" s:_getPrefix() {{{1
function! s:_getPrefix() abort dict
let fileinfo = self.fileinfo

View File

@ -14,6 +14,7 @@ function! tagbar#prototypes#normaltag#new(name) abort
let newobj.strfmt = function(s:add_snr('s:strfmt'))
let newobj.str = function(s:add_snr('s:str'))
let newobj.getPrototype = function(s:add_snr('s:getPrototype'))
let newobj.getDataType = function(s:add_snr('s:getDataType'))
return newobj
endfunction
@ -32,10 +33,16 @@ function! s:strfmt() abort dict
let suffix .= ' : ' . self.fields.type
elseif has_key(get(typeinfo, 'kind2scope', {}), self.fields.kind)
let scope = s:maybe_map_scope(typeinfo.kind2scope[self.fields.kind])
let suffix .= ' : ' . scope
if !g:tagbar_show_data_type
let suffix .= ' : ' . scope
endif
endif
let prefix = self._getPrefix()
if g:tagbar_show_data_type && self.getDataType() !=# ''
let suffix .= ' : ' . self.getDataType()
endif
if g:tagbar_show_tag_linenumbers == 1
let suffix .= ' [' . self.fields.line . ']'
elseif g:tagbar_show_tag_linenumbers == 2
@ -78,6 +85,8 @@ function! s:getPrototype(short) abort dict
endif
let line = getbufline(bufnr, self.fields.line)[0]
" If prototype includes declaration, remove the '=' and anything after
let line = substitute(line, '\s*=.*', '', '')
let list = split(line, '\zs')
let start = index(list, '(')
@ -124,6 +133,39 @@ function! s:getPrototype(short) abort dict
return prototype
endfunction
" s:getDataType() {{{1
function! s:getDataType() abort dict
if self.data_type !=# ''
let data_type = self.data_type
else
" This is a fallthrough attempt to derive the data_type from the line
" in the event ctags doesn't return the typeref field
let bufnr = self.fileinfo.bufnr
if self.fields.line == 0 || !bufloaded(bufnr)
" No linenumber available or buffer not loaded (probably due to
" 'nohidden'), try the pattern instead
return substitute(self.pattern, '^\\M\\^\\C\s*\(.*\)\\$$', '\1', '')
endif
let line = getbufline(bufnr, self.fields.line)[0]
let data_type = substitute(line, '\s*' . self.name . '.*', '', '')
" Strip off the path if we have one along with any spaces prior to the
" path
if self.path !=# ''
let data_type = substitute(data_type, '\s*' . self.path . self.typeinfo.sro, '', '')
endif
" Strip off leading spaces
let data_type = substitute(data_type, '^\s\+', '', '')
let self.data_type = data_type
endif
return data_type
endfunction
" s:add_snr() {{{1
function! s:add_snr(funcname) abort
if !exists('s:snr')

View File

@ -671,7 +671,17 @@ Example:
>
let g:tagbar_show_balloon = 0
<
*g:tagbar_show_data_type*
g:tagbar_show_data_type~
Default: 0
When set to non-zero, the tag data-type will be displayed to the right of the
tag in the tagbar window.
Example:
>
let g:tagbar_show_data_type = 1
<
*g:tagbar_show_visibility*
g:tagbar_show_visibility~
Default: 1

View File

@ -104,6 +104,7 @@ function! s:setup_options() abort
\ ['scopestrs', {}],
\ ['scrolloff', 0],
\ ['show_balloon', 1],
\ ['show_data_type', 0],
\ ['show_visibility', 1],
\ ['show_linenumbers', 0],
\ ['show_tag_count', 0],