From 601b5c0073e8bce7436e37cbe29cf4cbf8972160 Mon Sep 17 00:00:00 2001 From: raven42 Date: Mon, 2 Nov 2020 15:06:40 -0600 Subject: [PATCH] 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. --- autoload/tagbar.vim | 13 ++++++- autoload/tagbar/prototypes/basetag.vim | 7 ++++ autoload/tagbar/prototypes/normaltag.vim | 44 +++++++++++++++++++++++- doc/tagbar.txt | 10 ++++++ plugin/tagbar.vim | 1 + 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/autoload/tagbar.vim b/autoload/tagbar.vim index 5fe513e..7294888 100644 --- a/autoload/tagbar.vim +++ b/autoload/tagbar.vim @@ -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') diff --git a/autoload/tagbar/prototypes/basetag.vim b/autoload/tagbar/prototypes/basetag.vim index d002afa..ce04a20 100644 --- a/autoload/tagbar/prototypes/basetag.vim +++ b/autoload/tagbar/prototypes/basetag.vim @@ -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 diff --git a/autoload/tagbar/prototypes/normaltag.vim b/autoload/tagbar/prototypes/normaltag.vim index c3ba1f7..ad69c4d 100644 --- a/autoload/tagbar/prototypes/normaltag.vim +++ b/autoload/tagbar/prototypes/normaltag.vim @@ -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') diff --git a/doc/tagbar.txt b/doc/tagbar.txt index 321469f..536e5f5 100644 --- a/doc/tagbar.txt +++ b/doc/tagbar.txt @@ -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 diff --git a/plugin/tagbar.vim b/plugin/tagbar.vim index 08f05d3..4bbf9d5 100644 --- a/plugin/tagbar.vim +++ b/plugin/tagbar.vim @@ -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],