diff --git a/bundle/tagbar/.github/FUNDING.yml b/bundle/tagbar/.github/FUNDING.yml new file mode 100644 index 000000000..f4973c7e6 --- /dev/null +++ b/bundle/tagbar/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [alerque] +custom: ['https://paypal.me/alerque', 'https://paypal.me/dhegland42'] diff --git a/bundle/tagbar/.github/workflows/check.yml b/bundle/tagbar/.github/workflows/check.yml new file mode 100644 index 000000000..59e63f50a --- /dev/null +++ b/bundle/tagbar/.github/workflows/check.yml @@ -0,0 +1,30 @@ +name: Check +on: [push, pull_request] +jobs: + check: + strategy: + fail-fast: false + matrix: + vimFlavor: ["vim", "nvim"] + tagsProvider: ["exuberant-ctags", "universal-ctags"] + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Enable Universe package repository + run: | + sudo add-apt-repository universe + sudo apt-get update + - name: Install ${{ matrix.tagsProvider }} + run: | + sudo apt-get install ${{ matrix.tagsProvider }} + - name: Install ${{ matrix.vimFlavor }} + run: | + sudo apt-get install ${{ matrix.vimFlavor == 'nvim' && 'neovim' || 'vim' }} + - name: Review versions + run: | + ctags --version + ${{ matrix.vimFlavor }} --version + - name: "Try tagbar#OpenWindow()" + run: | + ${{ matrix.vimFlavor == 'nvim' && 'nvim -u /dev/null --headless' || 'vim' }} -i NONE "+set rtp+=$(pwd)" "+call tagbar#OpenWindow() | q" "+cq" plugin/tagbar.vim diff --git a/bundle/tagbar/.github/workflows/reviewdog.yml b/bundle/tagbar/.github/workflows/reviewdog.yml new file mode 100644 index 000000000..421e438b5 --- /dev/null +++ b/bundle/tagbar/.github/workflows/reviewdog.yml @@ -0,0 +1,13 @@ +name: Reviewdog +on: [pull_request] +jobs: + vint: + name: vint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: vint + uses: reviewdog/action-vint@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: github-pr-review diff --git a/bundle/tagbar/.github/workflows/vint.yml b/bundle/tagbar/.github/workflows/vint.yml new file mode 100644 index 000000000..909de43ac --- /dev/null +++ b/bundle/tagbar/.github/workflows/vint.yml @@ -0,0 +1,15 @@ +name: Vint +on: [push] +jobs: + vint: + name: vint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + - name: Setup dependencies + run: pip install vim-vint + - name: Lint Vimscript + run: vint . diff --git a/bundle/tagbar/.vintrc.yaml b/bundle/tagbar/.vintrc.yaml new file mode 100644 index 000000000..c44b6aba8 --- /dev/null +++ b/bundle/tagbar/.vintrc.yaml @@ -0,0 +1,5 @@ +cmdargs: + severity: style_problem + color: true + env: + neovim: false diff --git a/bundle/tagbar/LICENSE b/bundle/tagbar/LICENSE index 5ae1a752a..57339aac2 100644 --- a/bundle/tagbar/LICENSE +++ b/bundle/tagbar/LICENSE @@ -26,7 +26,7 @@ II) It is allowed to distribute a modified (or extended) version of Tagbar, then this license, or a later version, also applies to your changes. The current maintainer is Jan Larres . If this changes it will be announced in appropriate places (most likely - majutsushi.github.io/tagbar and/or github.com/majutsushi/tagbar). + preservim.github.io/tagbar and/or github.com/preservim/tagbar). When it is completely impossible to contact the maintainer, the obligation to send him your changes ceases. Once the maintainer has confirmed that he has received your changes they will not have to be diff --git a/bundle/tagbar/README.md b/bundle/tagbar/README.md index b9e84c3e8..2e260d087 100644 --- a/bundle/tagbar/README.md +++ b/bundle/tagbar/README.md @@ -1,5 +1,7 @@ # Tagbar: a class outline viewer for Vim -> a forked version which is based on [tagbar](https://github.com/majutsushi/tagbar/commit/387bbadda98e1376ff3871aa461b1f0abd4ece70). + +[![Vint](https://github.com/preservim/tagbar/workflows/Vint/badge.svg)](https://github.com/preservim/tagbar/actions?workflow=Vint) +[![Check](https://github.com/preservim/tagbar/workflows/Check/badge.svg)](https://github.com/preservim/tagbar/actions?workflow=Check) ## What Tagbar is @@ -18,10 +20,19 @@ creates the tags it needs on-the-fly in-memory without creating any files. ## Dependencies -[Vim 7.3.1058](http://www.vim.org/) -[Exuberant Ctags 5.5](http://ctags.sourceforge.net/) or -[Universal Ctags](https://ctags.io) (recommended), a maintained fork of -Exuberant Ctags. +* [Vim](http://www.vim.org/) >= 7.3.1058 + or any version of [NeoVim](https://neovim.io/). + +* A ctags implementation: We _highly recommend_ any version of [Universal + Ctags](https://ctags.io). It is a maintained fork of Exuberant Ctags with + many bugfixes, support for many more formats, and proper Unicode support. + + [Exuberant Ctags](http://ctags.sourceforge.net/) 5.5 or higher works to some + degree but will be deprecated eventually. + + Some additional formats can also be handled by other providers such as + [jsctags](https://github.com/sergioramos/jsctags) or + [phpctags](https://github.com/vim-php/phpctags). ## Installation @@ -45,12 +56,12 @@ nmap :TagbarToggle If you do this the F8 key will toggle the Tagbar window. You can of course use any shortcut you want. For more flexible ways to open and close the window -(and the rest of the functionality) see the documentation. +(and the rest of the functionality) see the [documentation](https://github.com/majutsushi/tagbar/blob/master/doc/tagbar.txt) using `:help tagbar`. ## 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 +wiki](https://github.com/preservim/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. @@ -70,7 +81,7 @@ please report it on their website instead, as there is nothing I can do about it in Tagbar. Thank you! You can also have a look at [ctags bugs that have previously been filed -against Tagbar](https://github.com/majutsushi/tagbar/issues?labels=ctags-bug&page=1&state=closed). +against Tagbar](https://github.com/preservim/tagbar/issues?labels=ctags-bug&page=1&state=closed). ## Screenshots @@ -79,8 +90,11 @@ against Tagbar](https://github.com/majutsushi/tagbar/issues?labels=ctags-bug&pag ## License -Vim license, see LICENSE +Tagbar is distributed under the terms of the *Vim license*, see the included [LICENSE](LICENSE) file. -## Maintainer +## Contributors -Jan Larres <[jan@majutsushi.net](mailto:jan@majutsushi.net)> +Tagbar was originally written by [Jan Larres](https://github.com/majutsushi). +It is actively maintained by [Caleb Maclennan](https://github.com/alerque) and [David Hegland](https://github.com/raven42). +At least [75 others have contributed](https://github.com/preservim/tagbar/graphs/contributors) features and bug fixes over the years. +Please document [issues](https://github.com/preservim/tagbar/issues) or submit [pull requests](https://github.com/preservim/tagbar/issues) on Github. diff --git a/bundle/tagbar/autoload/tagbar.vim b/bundle/tagbar/autoload/tagbar.vim index 70cf5b10d..51865f063 100644 --- a/bundle/tagbar/autoload/tagbar.vim +++ b/bundle/tagbar/autoload/tagbar.vim @@ -3,8 +3,8 @@ " 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: 2.7 +" Website: https://preservim.github.io/tagbar +" Version: 3.0.0 " Note: This plugin was heavily inspired by the 'Taglist' plugin by " Yegappan Lakshmanan and uses a small amount of code from it. " @@ -87,6 +87,124 @@ let s:warnings = { \ 'encoding': 0 \ } +let s:singular_types = { + \ 'Classes': 'Class', + \ 'Delegates': 'Delegate', + \ 'Enumeration values': 'Enumeration value', + \ 'Enumerations': 'Enumeration', + \ 'Error codes': 'Error code', + \ 'Error domains': 'Error domain', + \ 'Fields': 'Field', + \ 'Interfaces': 'Interface', + \ 'JavaScript funtions': 'JavaScript function', + \ 'Methods': 'Method', + \ 'MobiLink Conn Scripts': 'MobiLink Conn Script', + \ 'MobiLink Properties': 'MobiLink Property', + \ 'MobiLink Table Scripts': 'MobiLink Table Script', + \ 'Properties': 'Property', + \ 'Signals': 'Signal', + \ 'Structures': 'Structure', + \ 'autocommand groups': 'autocommand group', + \ 'block data': 'block data', + \ 'block label': 'block label', + \ 'chapters': 'chapter', + \ 'classes': 'class', + \ 'commands': 'command', + \ 'common blocks': 'common block', + \ 'components': 'component', + \ 'constant definitions': 'constant definition', + \ 'constants': 'constant', + \ 'constructors': 'constructor', + \ 'cursors': 'cursor', + \ 'data items': 'data item', + \ 'defines': 'define', + \ 'derived types and structures': 'derived type and structure', + \ 'domains': 'domain', + \ 'entities': 'entity', + \ 'entry points': 'entry point', + \ 'embedded': 'embedded', + \ 'enum constants': 'enum constant', + \ 'enum types': 'enum type', + \ 'enumerations': 'enumeration', + \ 'enumerators': 'enumerator', + \ 'enums': 'enum', + \ 'events': 'event', + \ 'exception declarations': 'exception declaration', + \ 'exceptions': 'exception', + \ 'features': 'feature', + \ 'fields': 'field', + \ 'file descriptions': 'file description', + \ 'formats': 'format', + \ 'fragments': 'fragment', + \ 'function definitions': 'function definition', + \ 'functions': 'function', + \ 'functor definitions': 'functor definition', + \ 'global variables': 'global variable', + \ 'group items': 'group item', + \ 'imports': 'import', + \ 'includes': 'include', + \ 'indexes': 'index', + \ 'interfaces': 'interface', + \ 'javascript functions': 'JavaScript function', + \ 'labels': 'label', + \ 'macro definitions': 'macro definition', + \ 'macros': 'macro', + \ 'maps': 'map', + \ 'members': 'member', + \ 'methods': 'method', + \ 'modules or functors': 'module or function', + \ 'modules': 'module', + \ 'mxtags': 'mxtag', + \ 'named anchors': 'named anchor', + \ 'namelists': 'namelist', + \ 'namespaces': 'namespace', + \ 'net data types': 'net data type', + \ 'packages': 'package', + \ 'package': 'package', + \ 'paragraphs': 'paragraph', + \ 'parts': 'part', + \ 'patterns': 'pattern', + \ 'ports': 'port', + \ 'procedures': 'procedure', + \ 'program ids': 'program id', + \ 'programs': 'program', + \ 'projects': 'project', + \ 'properties': 'property', + \ 'prototypes': 'prototype', + \ 'publications': 'publication', + \ 'record definitions': 'record definition', + \ 'record fields': 'record field', + \ 'records': 'record', + \ 'register data types': 'register data type', + \ 'sections': 'section', + \ 'services': 'services', + \ 'sets': 'sets', + \ 'signature declarations': 'signature declaration', + \ 'singleton methods': 'singleton method', + \ 'slots': 'slot', + \ 'structs': 'struct', + \ 'structure declarations': 'structure declaration', + \ 'structure fields': 'structure field', + \ 'subparagraphs': 'subparagraph', + \ 'subroutines': 'subroutine', + \ 'subsections': 'subsection', + \ 'subsubsections': 'subsubsection', + \ 'subtypes': 'subtype', + \ 'synonyms': 'synonym', + \ 'tables': 'table', + \ 'targets': 'target', + \ 'tasks': 'task', + \ 'triggers': 'trigger', + \ 'type definitions': 'type definition', + \ 'type names': 'type name', + \ 'typedefs': 'typedef', + \ 'types': 'type', + \ 'unions': 'union', + \ 'value bindings': 'value binding', + \ 'variables': 'variable', + \ 'views': 'view', + \ 'vimball filenames': 'vimball filename'} + " s:Init() {{{2 function! s:Init(silent) abort if s:checked_ctags == 2 && a:silent @@ -122,9 +240,64 @@ function! s:InitTypes() abort let s:known_types = tagbar#types#ctags#init(supported_types) endif + " Use dart_ctags if available + let dart_ctags = s:CheckFTCtags('dart_ctags', 'dart') + if dart_ctags !=# '' + let supported_types['dart'] = 1 + call tagbar#debug#log('Detected dart_ctags, overriding typedef') + let type_dart = tagbar#prototypes#typeinfo#new() + let type_dart.ctagstype = 'dart' + let type_dart.kinds = [ + \ {'short' : 'l', 'long' : 'library', 'fold' : 0, 'stl' : 0}, + \ {'short' : 't', 'long' : 'export', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'i', 'long' : 'imports', 'fold' : 1, 'stl' : 0}, + \ {'short' : 'D', 'long' : 'dart', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'U', 'long' : 'pub', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'L', 'long' : 'local', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'P', 'long' : 'part', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'p', 'long' : 'part of', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'C', 'long' : 'consts', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'F', 'long' : 'functions', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'E', 'long' : 'enums', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'e', 'long' : 'constants', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'x', 'long' : 'mixins', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'c', 'long' : 'classes', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'd', 'long' : 'extends', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'w', 'long' : 'with', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'z', 'long' : 'implements', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'r', 'long' : 'constructors', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'a', 'long' : 'abstract functions', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'f', 'long' : 'fields', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'm', 'long' : 'methods', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'M', 'long' : 'static methods', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'g', 'long' : 'getters', 'fold' : 0, 'stl' : 0}, + \ {'short' : 's', 'long' : 'setters', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'o', 'long' : 'operators', 'fold' : 0, 'stl' : 0}, + \ ] + let type_dart.sro = ':' + let type_dart.kind2scope = { + \ 'c' : 'class', + \ 'E' : 'enum', + \ 'x' : 'mixin', + \ 'i' : 'directive' + \ } + let type_dart.scope2kind = { + \ 'class' : 'c', + \ 'enum' : 'E', + \ 'mixin' : 'x', + \ 'directive' : 'i' + \ } + let type_dart.ctagsbin = dart_ctags + let type_dart.ctagsargs = '-l' + let type_dart.ftype = 'dart' + call type_dart.createKinddict() + let s:known_types.dart = type_dart + endif + " Use jsctags/doctorjs if available let jsctags = s:CheckFTCtags('jsctags', 'javascript') - if jsctags != '' + if jsctags !=# '' call tagbar#debug#log('Detected jsctags, overriding typedef') let type_javascript = tagbar#prototypes#typeinfo#new() let type_javascript.ctagstype = 'javascript' @@ -147,6 +320,41 @@ function! s:InitTypes() abort let s:known_types.javascript = type_javascript endif + " Use gotags if available + let gotags = s:CheckFTCtags('gotags', 'go') + if gotags !=# '' + call tagbar#debug#log('Detected gotags, overriding typedef') + let type_go = tagbar#prototypes#typeinfo#new() + let type_go.ctagstype = 'go' + let type_go.kinds = [ + \ {'short' : 'p', 'long' : 'package', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'i', 'long' : 'imports', 'fold' : 1, 'stl' : 0}, + \ {'short' : 'c', 'long' : 'constants', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 0}, + \ {'short' : 't', 'long' : 'types', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'n', 'long' : 'intefaces', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'w', 'long' : 'fields', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'e', 'long' : 'embedded', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'm', 'long' : 'methods', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'r', 'long' : 'constructors', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 0}, + \ ] + let type_go.sro = '.' + let type_go.kind2scope = { + \ 't' : 'ctype', + \ 'n' : 'ntype' + \ } + let type_go.scope2kind = { + \ 'ctype' : 't', + \ 'ntype' : 'n' + \ } + let type_go.ctagsbin = gotags + let type_go.ctagsargs = '-sort -silent' + let type_go.ftype = 'go' + call type_go.createKinddict() + let s:known_types.go = type_go + endif + call s:LoadUserTypeDefs() " Add an 'unknown' kind to the types for pseudotags that we can't @@ -303,6 +511,7 @@ function! s:MapKeys() abort \ ['togglesort', 'ToggleSort()'], \ ['togglecaseinsensitive', 'ToggleCaseInsensitive()'], \ ['toggleautoclose', 'ToggleAutoclose()'], + \ ['togglepause', 'TogglePause()'], \ ['zoomwin', 'ZoomWindow()'], \ ['close', 'CloseWindow()'], \ ['help', 'ToggleHelp()'], @@ -315,14 +524,16 @@ function! s:MapKeys() abort for [map, func] in maps let def = get(g:, 'tagbar_map_' . map) - if type(def) == type("") + if type(def) == type('') let keys = [def] else let keys = def endif for key in keys - execute 'nnoremap' . map_options . key . - \ ' :call ' . func . '' + if !empty(key) + execute 'nnoremap' . map_options . key . + \ ' :call ' . func . '' + endif endfor unlet def endfor @@ -337,16 +548,6 @@ function! s:CreateAutocommands() abort augroup TagbarAutoCmds autocmd! - if !g:tagbar_silent - autocmd CursorHold __Tagbar__.* call s:ShowPrototype(1) - endif - autocmd WinEnter __Tagbar__.* call s:SetStatusLine() - autocmd WinLeave __Tagbar__.* call s:SetStatusLine() - - if g:tagbar_autopreview - autocmd CursorMoved __Tagbar__.* nested call s:ShowInPreviewWin() - endif - autocmd BufEnter * if expand('') !~ '__Tagbar__.*' | \ let s:last_alt_bufnr = bufnr('#') | \ endif @@ -354,28 +555,54 @@ function! s:CreateAutocommands() abort autocmd QuitPre * let s:vim_quitting = 1 endif autocmd WinEnter * nested call s:HandleOnlyWindow() - autocmd WinEnter * if bufwinnr(s:TagbarBufName()) == -1 | - \ call s:ShrinkIfExpanded() | - \ endif - autocmd BufWritePost * - \ call s:HandleBufWrite(fnamemodify(expand(''), ':p')) - autocmd CursorHold,CursorHoldI * call s:do_delayed_update() - " BufReadPost is needed for reloading the current buffer if the file - " was changed by an external command; see commit 17d199f - autocmd BufReadPost,BufEnter,CursorHold,FileType * call - \ s:AutoUpdate(fnamemodify(expand(''), ':p'), 0) - autocmd BufDelete,BufWipeout * - \ nested call s:HandleBufDelete(expand(''), expand('')) + if !g:tagbar_no_autocmds + if !g:tagbar_silent + autocmd CursorHold __Tagbar__.* call s:ShowPrototype(1) + endif + autocmd WinEnter __Tagbar__.* call s:SetStatusLine() + autocmd WinLeave __Tagbar__.* call s:SetStatusLine() - " Suspend Tagbar while grep commands are running, since we don't want - " to process files that only get loaded temporarily to search them - autocmd QuickFixCmdPre *grep* let s:tagbar_qf_active = 1 - autocmd QuickFixCmdPost *grep* if exists('s:tagbar_qf_active') | - \ unlet s:tagbar_qf_active | - \ endif + if g:tagbar_autopreview + autocmd CursorMoved __Tagbar__.* nested call s:ShowInPreviewWin() + endif - autocmd VimEnter * call s:CorrectFocusOnStartup() + autocmd WinEnter * if bufwinnr(s:TagbarBufName()) == -1 | + \ call s:ShrinkIfExpanded() | + \ endif + + autocmd BufWritePost * + \ call s:HandleBufWrite(fnamemodify(expand(''), ':p')) + autocmd CursorHold,CursorHoldI * call s:do_delayed_update() + " BufReadPost is needed for reloading the current buffer if the file + " was changed by an external command; see commit 17d199f + autocmd BufReadPost,BufEnter,CursorHold,FileType * call + \ s:AutoUpdate(fnamemodify(expand(''), ':p'), 0) + if g:tagbar_highlight_follow_insert + autocmd CursorHoldI * call + \ s:AutoUpdate(fnamemodify(expand(''), ':p'), 0) + endif + + " Suspend Tagbar while grep commands are running, since we don't want + " to process files that only get loaded temporarily to search them + autocmd QuickFixCmdPre *grep* let s:tagbar_qf_active = 1 + autocmd QuickFixCmdPost *grep* if exists('s:tagbar_qf_active') | + \ unlet s:tagbar_qf_active | + \ endif + + autocmd VimEnter * call s:CorrectFocusOnStartup() + endif + augroup END + + " Separate these autocmds out from the others as we want to always perform + " these actions even if the tagbar window closes. + augroup TagbarCleanupAutoCmds + autocmd! + + if !g:tagbar_no_autocmds + autocmd BufDelete,BufWipeout * + \ nested call s:HandleBufDelete(expand(''), expand('')) + endif augroup END let s:autocommands_done = 1 @@ -398,6 +625,7 @@ function! s:CheckForExCtags(silent) abort let ctagsbins += ['ctags'] let ctagsbins += ['ctags.exe'] let ctagsbins += ['tags'] + let ctagsbins += ['universal-ctags'] for ctags in ctagsbins if executable(ctags) let g:tagbar_ctags_bin = ctags @@ -405,11 +633,11 @@ function! s:CheckForExCtags(silent) abort endif endfor if !exists('g:tagbar_ctags_bin') - let errmsg = 'Tagbar: Exuberant ctags not found!' - let infomsg = 'Please download Exuberant Ctags from' . + let l:errmsg = 'Tagbar: Exuberant ctags not found!' + let l: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) + call s:CtagsErrMsg(l:errmsg, l:infomsg, a:silent) let s:checked_ctags = 2 return 0 endif @@ -423,17 +651,17 @@ function! s:CheckForExCtags(silent) abort let &wildignore = wildignore_save if !executable(g:tagbar_ctags_bin) - let errmsg = "Tagbar: Exuberant ctags not found at " . + let l: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 l:infomsg = 'Please check your g:tagbar_ctags_bin setting.' + call s:CtagsErrMsg(l:errmsg, l:infomsg, a:silent) let s:checked_ctags = 2 return 0 endif endif let ctags_cmd = s:EscapeCtagsCmd(g:tagbar_ctags_bin, '--version') - if ctags_cmd == '' + if ctags_cmd ==# '' let s:checked_ctags = 2 return 0 endif @@ -441,23 +669,23 @@ function! s:CheckForExCtags(silent) abort let ctags_output = s:ExecuteCtags(ctags_cmd) call tagbar#debug#log("Command output:\n" . ctags_output) - call tagbar#debug#log("Exit code: " . v:shell_error) + call tagbar#debug#log('Exit code: ' . v:shell_error) if v:shell_error || ctags_output !~# '\(Exuberant\|Universal\) Ctags' - let errmsg = 'Tagbar: Ctags doesn''t seem to be Exuberant Ctags!' - let infomsg = 'BSD ctags will NOT WORK.' . + let l:errmsg = 'Tagbar: Ctags doesn''t seem to be Exuberant Ctags!' + let l:infomsg = 'BSD 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, + call s:CtagsErrMsg(l:errmsg, l:infomsg, a:silent, \ ctags_cmd, ctags_output, v:shell_error) let s:checked_ctags = 2 return 0 elseif !s:CheckExCtagsVersion(ctags_output) - let errmsg = 'Tagbar: Exuberant Ctags is too old!' - let infomsg = 'You need at least version 5.5 for Tagbar to work.' . + let l:errmsg = 'Tagbar: Exuberant Ctags is too old!' + let l: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) + call s:CtagsErrMsg(l:errmsg, l:infomsg, a:silent, ctags_cmd, ctags_output) let s:checked_ctags = 2 return 0 else @@ -481,12 +709,12 @@ function! s:CtagsErrMsg(errmsg, infomsg, silent, ...) abort call s:warning(a:errmsg) echomsg a:infomsg - if ctags_cmd == '' + if ctags_cmd ==# '' return endif echomsg 'Executed command: "' . ctags_cmd . '"' - if ctags_output != '' + if ctags_output !=# '' echomsg 'Command output:' for line in split(ctags_output, '\n') echomsg line @@ -505,14 +733,19 @@ endfunction function! s:CheckExCtagsVersion(output) abort call tagbar#debug#log('Checking Exuberant Ctags version') - if a:output =~ 'Universal Ctags' - call tagbar#debug#log("Found Universal Ctags, assuming compatibility") + if a:output =~? 'Universal Ctags' + call tagbar#debug#log('Found Universal Ctags, assuming compatibility') let s:ctags_is_uctags = 1 return 1 endif - if a:output =~ 'Exuberant Ctags Development' - call tagbar#debug#log("Found development version, assuming compatibility") + if a:output =~? 'Exuberant Ctags compatiable PHP enhancement' + call tagbar#debug#log('Found phpctags, assuming compatibility') + return 1 + endif + + if a:output =~? 'Exuberant Ctags Development' + call tagbar#debug#log('Found development version, assuming compatibility') return 1 endif @@ -548,7 +781,7 @@ function! s:GetSupportedFiletypes() abort call tagbar#debug#log('Getting filetypes supported by Exuberant Ctags') let ctags_cmd = s:EscapeCtagsCmd(g:tagbar_ctags_bin, '--list-languages') - if ctags_cmd == '' + if ctags_cmd ==# '' return endif @@ -641,7 +874,7 @@ function! s:OpenWindow(flags) abort call s:goto_win(tagbarwinnr) call s:HighlightTag(g:tagbar_autoshowtag != 2, 1, curline) endif - call tagbar#debug#log("OpenWindow finished, Tagbar already open") + call tagbar#debug#log('OpenWindow finished, Tagbar already open') return endif @@ -683,17 +916,15 @@ function! s:OpenWindow(flags) abort endif let s:window_opening = 1 - if g:tagbar_vertical == 0 + if g:tagbar_position =~# 'vertical' + let size = g:tagbar_width let mode = 'vertical ' - let openpos = g:tagbar_left ? 'topleft ' : 'botright ' - let width = g:tagbar_width else + let size = g:tagbar_height let mode = '' - let openpos = g:tagbar_left ? 'leftabove ' : 'rightbelow ' - let width = g:tagbar_vertical endif - exe 'silent keepalt ' . openpos . mode . width . 'split ' . s:TagbarBufName() - exe 'silent ' . mode . 'resize ' . width + exe 'silent keepalt ' . g:tagbar_position . size . 'split ' . s:TagbarBufName() + exe 'silent ' . mode . 'resize ' . size unlet s:window_opening call s:InitWindow(autoclose) @@ -750,8 +981,13 @@ function! s:InitWindow(autoclose) abort setlocal nobuflisted setlocal nomodifiable setlocal textwidth=0 + setlocal colorcolumn="" - if has('balloon_eval') + if g:tagbar_scrolloff > 0 + execute 'setlocal scrolloff=' . g:tagbar_scrolloff + endif + + if g:tagbar_show_balloon == 1 && has('balloon_eval') setlocal balloonexpr=TagbarBalloonExpr() set ballooneval endif @@ -760,10 +996,24 @@ function! s:InitWindow(autoclose) abort " Window-local options setlocal nolist - setlocal nowrap setlocal winfixwidth setlocal nospell + if g:tagbar_wrap == 0 + setlocal nowrap + else + setlocal wrap + if exists('+linebreak') + setlocal breakindent + setlocal breakindentopt=shift:4 + if g:tagbar_wrap == 1 + setlocal linebreak + elseif g:tagbar_wrap == 2 + setlocal nolinebreak + endif + endif + endif + if g:tagbar_show_linenumbers == 0 setlocal nonumber if exists('+relativenumber') @@ -788,6 +1038,7 @@ function! s:InitWindow(autoclose) abort setlocal foldmethod& setlocal foldexpr& + silent! setlocal signcolumn=no let w:autoclose = a:autoclose @@ -831,6 +1082,7 @@ function! s:CloseWindow() abort " Other windows are open, only close the tagbar one let curfile = tagbar#state#get_current_file(0) + let s:is_maximized = 0 close @@ -862,8 +1114,7 @@ function! s:CloseWindow() abort call s:ShrinkIfExpanded() if s:autocommands_done && !s:statusline_in_use - autocmd! TagbarAutoCmds - let s:autocommands_done = 0 + call tagbar#StopAutoUpdate() endif call tagbar#debug#log('CloseWindow finished') @@ -873,7 +1124,7 @@ endfunction " If the Vim window has been expanded, and Tagbar is not open in any other " tabpages, shrink the window again function! s:ShrinkIfExpanded() abort - if !s:window_expanded || &filetype == 'tagbar' || s:expand_bufnr == -1 + if !s:window_expanded || &filetype ==# 'tagbar' || s:expand_bufnr == -1 return endif @@ -953,6 +1204,17 @@ function! s:ProcessFile(fname, ftype) abort return endif + let l:bufnum = bufnr(a:fname) + + if !bufloaded(l:bufnum) + call tagbar#debug#log('[ProcessFile] Buffer is not loaded exiting...') + return + endif + if !bufexists(l:bufnum) + call tagbar#debug#log('[ProcessFile] Buffer does not exist exiting...') + return + endif + let typeinfo = s:known_types[a:ftype] " If the file has only been updated preserve the fold states, otherwise @@ -976,29 +1238,43 @@ function! s:ProcessFile(fname, ftype) abort call tagbar#debug#log('typeinfo for file to process: ' . string(typeinfo)) - " Use a temporary files for ctags processing instead of the original one. - " This allows using Tagbar for files accessed with netrw, and also doesn't - " slow down Tagbar for files that sit on slow network drives. - let tempfile = tempname() - let ext = fnamemodify(fileinfo.fpath, ':e') - if ext != '' - let tempfile .= '.' . ext - endif - - call tagbar#debug#log('Caching file into: ' . tempfile) - let templines = getbufline(fileinfo.bufnr, 1, '$') - let res = writefile(templines, tempfile) - - if res != 0 - call tagbar#debug#log('Could not create copy '.tempfile) + if g:tagbar_file_size_limit > 0 + \ && fileinfo.fsize > g:tagbar_file_size_limit + \ && !exists('b:tagbar_force_update') + call tagbar#debug#log('File size exceeds defined limit') + let fileinfo.fsize_exceeded = 1 + call s:known_files.put(fileinfo) return - endif - let fileinfo.mtime = getftime(tempfile) + elseif g:tagbar_use_cache + " Use a temporary files for ctags processing instead of the original one. + " This allows using Tagbar for files accessed with netrw, and also doesn't + " slow down Tagbar for files that sit on slow network drives. + let tempfile = tempname() + let ext = fnamemodify(fileinfo.fpath, ':e') + if ext !=# '' + let tempfile .= '.' . ext + endif - let ctags_output = s:ExecuteCtagsOnFile(tempfile, a:fname, typeinfo) + call tagbar#debug#log('Caching file into: ' . tempfile) + let templines = getbufline(fileinfo.bufnr, 1, '$') + let res = writefile(templines, tempfile) - if !tagbar#debug#enabled() - call delete(tempfile) + if res != 0 + call tagbar#debug#log('Could not create copy '.tempfile) + return + endif + let fileinfo.mtime = getftime(tempfile) + let fileinfo.fsize_exceeded = 0 + + let ctags_output = s:ExecuteCtagsOnFile(tempfile, a:fname, typeinfo) + + if !tagbar#debug#enabled() + call delete(tempfile) + endif + else + call tagbar#debug#log('File caching disabled') + let fileinfo.fsize_exceeded = 0 + let ctags_output = s:ExecuteCtagsOnFile(a:fname, a:fname, typeinfo) endif if ctags_output == -1 @@ -1007,7 +1283,7 @@ function! s:ProcessFile(fname, ftype) abort " shown once call s:known_files.put({}, a:fname) return - elseif ctags_output == '' + elseif ctags_output ==# '' call tagbar#debug#log('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 @@ -1021,11 +1297,18 @@ function! s:ProcessFile(fname, ftype) abort " Parse the ctags output lines call tagbar#debug#log('Parsing ctags output') let rawtaglist = split(ctags_output, '\n\+') + let seen = {} for line in rawtaglist - " skip comments - if line =~# '^!_TAG_' + " skip comments and duplicates (can happen when --sort=no) + if line =~# '^!_TAG_' || has_key(seen, line) continue endif + if g:tagbar_ignore_anonymous && line =~# '__anon' + call tagbar#debug#log('anonymous tag found - ignoring per tagbar configuration') + continue + endif + + let seen[line] = 1 let parts = split(line, ';"') if len(parts) == 2 " Is a valid tag line @@ -1086,13 +1369,26 @@ function! s:ExecuteCtagsOnFile(fname, realfname, typeinfo) abort "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', + let ctags_args = [] + if exists('g:tagbar_ctags_options') + for value in g:tagbar_ctags_options + call add(ctags_args, '--options='.value) + endfor + endif + + " universal-ctags deprecated this argument name + if s:ctags_is_uctags + let ctags_args += [ '--extras=+F' ] + else + let ctags_args += [ '--extra=', '--file-scope=yes' ] + endif + + let ctags_args = ctags_args + [ + \ '-f', \ '-', \ '--format=2', \ '--excmd=pattern', - \ '--fields=nksSaf', - \ '--extra=', - \ '--file-scope=yes', + \ '--fields=nksSafet', \ '--sort=no', \ '--append=no' \ ] @@ -1102,11 +1398,6 @@ function! s:ExecuteCtagsOnFile(fname, realfname, typeinfo) abort let ctags_args += [ '-V' ] endif - " Include extra type definitions - if has_key(a:typeinfo, 'deffile') - let ctags_args += ['--options=' . expand(a:typeinfo.deffile)] - endif - " Third-party programs may not necessarily make use of this if has_key(a:typeinfo, 'ctagstype') let ctags_type = a:typeinfo.ctagstype @@ -1121,6 +1412,12 @@ function! s:ExecuteCtagsOnFile(fname, realfname, typeinfo) abort let ctags_args += ['--language-force=' . ctags_type] let ctags_args += ['--' . ctags_type . '-kinds=' . ctags_kinds] endif + + " Include extra type definitions - include last to allow for any + " overrides + if has_key(a:typeinfo, 'deffile') && filereadable(expand(a:typeinfo.deffile)) + let ctags_args += ['--options=' . expand(a:typeinfo.deffile)] + endif endif if has_key(a:typeinfo, 'ctagsbin') @@ -1134,13 +1431,13 @@ function! s:ExecuteCtagsOnFile(fname, realfname, typeinfo) abort endif let ctags_cmd = s:EscapeCtagsCmd(ctags_bin, ctags_args, a:fname) - if ctags_cmd == '' + if ctags_cmd ==# '' return '' endif let ctags_output = s:ExecuteCtags(ctags_cmd) - if v:shell_error || ctags_output =~ 'Warning: cannot open source file' + if v:shell_error || ctags_output =~? 'Warning: cannot open \(source\|input\) file' call tagbar#debug#log('Command output:') call tagbar#debug#log(ctags_output) call tagbar#debug#log('Exit code: ' . v:shell_error) @@ -1181,7 +1478,7 @@ function! s:ParseTagline(part1, part2, typeinfo, fileinfo) abort " the pattern can contain tabs and thus may have been split up, so join " the rest of the items together again let pattern = join(basic_info[2:], "\t") - if pattern[0] == '/' + if pattern[0] ==# '/' let start = 2 " skip the slash and the ^ let end = strlen(pattern) - 1 if pattern[end - 1] ==# '$' @@ -1209,11 +1506,11 @@ 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') " File-restricted scoping - if key == "file" + if key ==# 'file' let fielddict[key] = 'yes' endif if len(val) > 0 - if key == 'line' || key == 'column' + if key ==# 'line' || key ==# 'column' || key ==# 'end' let fielddict[key] = str2nr(val) else let fielddict[key] = val @@ -1240,7 +1537,7 @@ function! s:ParseTagline(part1, part2, typeinfo, fileinfo) abort let part = tagparts[i] call s:ProcessTag(part, filename, pattern, curfielddict, \ i != len(tagparts) - 1, a:typeinfo, a:fileinfo) - if parent != '' + if parent !=# '' let parent = parent . a:typeinfo.sro . part else let parent = part @@ -1255,7 +1552,7 @@ function! s:ParseTagline(part1, part2, typeinfo, fileinfo) abort endfunction " s:ProcessTag() {{{2 -function s:ProcessTag(name, filename, pattern, fields, is_split, typeinfo, fileinfo) abort +function! s:ProcessTag(name, filename, pattern, fields, is_split, typeinfo, fileinfo) abort if a:is_split let taginfo = tagbar#prototypes#splittag#new(a:name) else @@ -1275,11 +1572,27 @@ function s:ProcessTag(name, filename, pattern, fields, is_split, typeinfo, filei let taginfo.fields.line = 0 endif + " Make sure our 'end' is valid + if taginfo.fields.end < taginfo.fields.line + if a:typeinfo.getKind(taginfo.fields.kind).stl + " the config indicates this is a scoped kind due to 'stl', but we + " don't have scope vars, assume scope goes to end of file. This + " can also be the case for exhuberant ctags which doesn't support + " the --fields=e option. + " When we call the GetNearbyTag(), it will look up for the nearest + " tag, so if we have multiples that have scope to the end of the + " file it will still only grab the first one above the current line + let taginfo.fields.end = line('$') + else + let taginfo.fields.end = taginfo.fields.line + endif + endif + if !has_key(taginfo.fields, 'kind') call tagbar#debug#log( - \ "Warning: No 'kind' field found for tag " . basic_info[0] . "!") + \ "Warning: No 'kind' field found for tag " . a:name[0] . '!') if index(s:warnings.type, a:typeinfo.ftype) == -1 - call s:warning("No 'kind' field found for tag " . basic_info[0] . "!" . + call s:warning("No 'kind' field found for tag " . a:name[0] . '!' . \ " Please read the last section of ':help tagbar-extend'.") call add(s:warnings.type, a:typeinfo.ftype) endif @@ -1291,6 +1604,17 @@ function s:ProcessTag(name, filename, pattern, fields, is_split, typeinfo, filei 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') @@ -1414,7 +1738,7 @@ function! s:add_tag_recursive(parent, taginfo, pathlist) abort let parents = [] for tag in name_siblings if tag.fields.kind ==# '?' - \ || get(a:taginfo.typeinfo.kind2scope, tag.fields.kind, "") == a:taginfo.scope + \ || get(a:taginfo.typeinfo.kind2scope, tag.fields.kind, '') ==# a:taginfo.scope call add(parents, tag) endif endfor @@ -1513,7 +1837,7 @@ function! s:create_pseudotag(name, parent, kind, typeinfo, fileinfo) abort let parentscope = substitute(parentscope, \ '\V\^' . escape(a:typeinfo.sro, '\') . '\$', '', '') - if pscope != '' + if pscope !=# '' let pseudotag.fields[pscope] = parentscope let pseudotag.scope = pscope let pseudotag.path = parentscope @@ -1521,9 +1845,7 @@ function! s:create_pseudotag(name, parent, kind, typeinfo, fileinfo) abort \ pseudotag.path . a:typeinfo.sro . pseudotag.name endif let pseudotag.depth = len(split(pseudotag.path, '\V' . escape(a:typeinfo.sro, '\'))) - let pseudotag.parent = a:parent - let pseudotag.fileinfo = a:fileinfo let pseudotag.typeinfo = a:typeinfo @@ -1586,7 +1908,7 @@ function! s:RenderContent(...) abort let tagbarwinnr = bufwinnr(s:TagbarBufName()) - if &filetype == 'tagbar' + if &filetype ==# 'tagbar' let in_tagbar = 1 else let in_tagbar = 0 @@ -1623,7 +1945,16 @@ function! s:RenderContent(...) abort let typeinfo = fileinfo.typeinfo - if !empty(fileinfo.getTags()) + if fileinfo.fsize_exceeded == 1 + if g:tagbar_compact + silent 0put ='\" File size [' . fileinfo.fsize . 'B] exceeds limit' + else + silent put ='\" File size exceeds defined limit' + silent put ='\" File Size [' . fileinfo.fsize . ' bytes]' + silent put ='\" Limit [' . g:tagbar_file_size_limit . ' bytes]' + silent put ='\" Use TagbarForceUpdate override' + endif + elseif !empty(fileinfo.getTags()) " Print tags call s:PrintKinds(typeinfo, fileinfo) else @@ -1637,7 +1968,7 @@ function! s:RenderContent(...) abort " Delete empty lines at the end of the buffer for linenr in range(line('$'), 1, -1) - if getline(linenr) =~ '^$' + if getline(linenr) =~# '^$' execute 'silent ' . linenr . 'delete _' else break @@ -1649,13 +1980,13 @@ function! s:RenderContent(...) abort if !empty(tagbar#state#get_current_file(0)) && \ fileinfo.fpath ==# tagbar#state#get_current_file(0).fpath let scrolloff_save = &scrolloff - set scrolloff=0 + setlocal scrolloff=0 call cursor(topline, 1) normal! zt call cursor(saveline, savecol) - let &scrolloff = scrolloff_save + let &l:scrolloff = scrolloff_save else " Make sure as much of the Tagbar content as possible is shown in the " window by jumping to the top after drawing @@ -1699,8 +2030,8 @@ function! s:PrintKinds(typeinfo, fileinfo) abort for tag in curtags call s:PrintTag(tag, 0, output, a:fileinfo, a:typeinfo) - if !g:tagbar_compact - call add(output, "") + if g:tagbar_compact != 1 + call add(output, '') endif endfor else @@ -1714,7 +2045,12 @@ function! s:PrintKinds(typeinfo, fileinfo) abort endif let padding = g:tagbar_show_visibility ? ' ' : '' - call add(output, foldmarker . padding . kind.long) + if g:tagbar_show_tag_count + let tag_count = ' (' . len(curtags) . ')' + call add(output, foldmarker . padding . kind.long . tag_count) + else + call add(output, foldmarker . padding . kind.long) + endif let curline = len(output) + offset let kindtag.tline = curline @@ -1730,18 +2066,17 @@ function! s:PrintKinds(typeinfo, fileinfo) abort let curline = len(output) + offset let tag.tline = curline let a:fileinfo.tline[curline] = tag - let tag.depth = 1 endfor endif - if !g:tagbar_compact - call add(output, "") + if g:tagbar_compact != 1 + call add(output, '') endif endif endfor let outstr = join(output, "\n") - if g:tagbar_compact && s:short_help + if g:tagbar_compact && !g:tagbar_help_visibility && s:short_help silent 0put =outstr else silent put =outstr @@ -1801,46 +2136,63 @@ endfunction " s:PrintHelp() {{{2 function! s:PrintHelp() abort - if !g:tagbar_compact && s:short_help + if !g:tagbar_compact && !g:tagbar_help_visibility && s:short_help silent 0put ='\" Press ' . s:get_map_str('help') . ' for help' silent put _ - elseif !s:short_help + elseif g:tagbar_help_visibility || !s:short_help + let help_cmds = [ + \ ['jump', 'Jump to tag definition'], + \ ['preview', 'As above, but stay in tagbar window'], + \ ['previewwin', 'Show tag in preview window'], + \ ['nexttag', 'Go to next top-level tag'], + \ ['prevtag', 'Go to previous top-level tag'], + \ ['showproto', 'Display tag prototype'], + \ ['hidenonpublic', 'Hide non-public tags'], + \ ] + let fold_cmds = [ + \ ['openfold', 'Open fold'], + \ ['closefold', 'Close fold'], + \ ['togglefold', 'Toggle fold'], + \ ['openallfolds', 'Open all folds'], + \ ['closeallfolds', 'Close all folds'], + \ ['incrementfolds', 'Increment fold level by 1'], + \ ['decrementfolds', 'Decrement fold level by 1'], + \ ['nextfold', 'Go to next fold'], + \ ['prevfold', 'Go to previous fold'], + \ ] + let misc_cmds = [ + \ ['togglesort', 'Toggle sort'], + \ ['togglecaseinsensitive', 'Toggle case insensitive sort option'], + \ ['toggleautoclose', 'Toggle autoclose option'], + \ ['togglepause', 'Toggle pause'], + \ ['zoomwin', 'Zoom window in/out'], + \ ['close', 'Close window'], + \ ['help', 'Toggle help'], + \ ] + silent 0put ='\" Tagbar keybindings' silent put ='\"' silent put ='\" --------- General ---------' - 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('previewwin') . ': Show tag in preview 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 ='\" ' . s:get_map_str('hidenonpublic') . ': Hide non-public tags' + for [cmd, desc] in help_cmds + if !empty(s:get_map_str(cmd)) | silent put ='\" ' . s:get_map_str(cmd) . ': ' . desc | endif + endfor silent put ='\"' silent put ='\" ---------- 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 ='\" ' . s:get_map_str('incrementfolds') . ': Increment fold level by 1' - silent put ='\" ' . s:get_map_str('decrementfolds') . ': Decrement fold level by 1' - silent put ='\" ' . s:get_map_str('nextfold') . ': Go to next fold' - silent put ='\" ' . s:get_map_str('prevfold') . ': Go to previous fold' + for [cmd, desc] in fold_cmds + if !empty(s:get_map_str(cmd)) | silent put ='\" ' . s:get_map_str(cmd) . ': ' . desc | endif + endfor silent put ='\"' silent put ='\" ---------- Misc -----------' - silent put ='\" ' . s:get_map_str('togglesort') . ': Toggle sort' - silent put ='\" ' . s:get_map_str('togglecaseinsensitive') . ': Toggle case insensitive sort option' - silent put ='\" ' . s:get_map_str('toggleautoclose') . ': Toggle autoclose option' - 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' + for [cmd, desc] in misc_cmds + if !empty(s:get_map_str(cmd)) | silent put ='\" ' . s:get_map_str(cmd) . ': ' . desc | endif + endfor silent put _ endif endfunction + function! s:get_map_str(map) abort let def = get(g:, 'tagbar_map_' . a:map) - if type(def) == type("") + if type(def) ==# type('') return def else return join(def, ', ') @@ -1862,13 +2214,13 @@ function! s:RenderKeepView(...) abort call s:RenderContent() let scrolloff_save = &scrolloff - set scrolloff=0 + setlocal scrolloff=0 call cursor(topline, 1) normal! zt call cursor(line, curcol) - let &scrolloff = scrolloff_save + let &l:scrolloff = scrolloff_save redraw endfunction @@ -1876,14 +2228,22 @@ endfunction " User actions {{{1 " s:HighlightTag() {{{2 function! s:HighlightTag(openfolds, ...) abort + + if g:tagbar_no_autocmds + " If no autocmds are enabled, then it doesn't make sense to highlight + " anything as the cursor can move around and any highlighting would be + " inaccurate + return + endif + let tagline = 0 let force = a:0 > 0 ? a:1 : 0 if a:0 > 1 - let tag = s:GetNearbyTag(1, 0, a:2) + let tag = s:GetNearbyTag(g:tagbar_highlight_method, 0, a:2) else - let tag = s:GetNearbyTag(1, 0) + let tag = s:GetNearbyTag(g:tagbar_highlight_method, 0) endif if !empty(tag) let tagline = tag.tline @@ -1892,7 +2252,7 @@ function! s:HighlightTag(openfolds, ...) abort " Don't highlight the tag again if it's the same one as last time. " This prevents the Tagbar window from jumping back after scrolling with " the mouse. - if !force && tagline == s:last_highlight_tline + if !force && tagline ==# s:last_highlight_tline return else let s:last_highlight_tline = tagline @@ -1941,7 +2301,15 @@ function! s:HighlightTag(openfolds, ...) abort call winline() let foldpat = '[' . g:tagbar#icon_open . g:tagbar#icon_closed . ' ]' - let pattern = '/^\%' . tagline . 'l\s*' . foldpat . '[-+# ]\?\zs[^( ]\+\ze/' + + " If printing the line number of the tag to the left, and the tag is + " visible (I.E. parent isn't folded) + let identifier = '\zs\V' . escape(tag.name, '/\') . '\m\ze' + if g:tagbar_show_tag_linenumbers == 2 && tagline == tag.tline + let pattern = '/^\%' . tagline . 'l\s*' . foldpat . '[-+# ]\[[0-9]\+\] \?' . identifier . '/' + else + let pattern = '/^\%' . tagline . 'l\s*' . foldpat . '[-+# ]\?' . identifier . '/' + endif call tagbar#debug#log("Highlight pattern: '" . pattern . "'") if hlexists('TagbarHighlight') " Safeguard in case syntax highlighting is disabled execute 'match TagbarHighlight ' . pattern @@ -1957,23 +2325,60 @@ function! s:HighlightTag(openfolds, ...) abort endtry endfunction -" s:JumpToTag() {{{2 -function! s:JumpToTag(stay_in_tagbar) abort - let taginfo = s:GetTagInfo(line('.'), 1) +" Is the given line number already visible in the window without +" any scrolling? +function! s:IsLineVisible(line) abort + let topline = line('w0') + let bottomline = line('w$') + let alreadyvisible = (a:line >= topline) && (a:line <= bottomline) + return alreadyvisible +endfunction - let autoclose = w:autoclose +" s:JumpToTag() {{{2 +function! s:JumpToTag(stay_in_tagbar, ...) abort + let taginfo = a:0 > 0 ? a:1 : s:GetTagInfo(line('.'), 1) + let force_lazy_scroll = a:0 > 1 ? a:2 : 0 if empty(taginfo) || !taginfo.isNormalTag() + " Cursor line not on a tag. Check if this is the start of a foldable + " line and if so, initiate the CloseFold() / OpenFold(). First trim + " any whitespace from the start of the line so we don't have to worry + " about multiple nested folds that are indented + " + " NOTE: This will only work with folds that are not also tags. For + " example in a class definition that acts as the start of a fold when + " there are member functions in the class, that line is also a valid + " tag, so hitting on that line will cause it to jump to the tag, + " not fold/unfold that particular fold + let line = substitute(getline('.'), '^\s*\(.\{-}\)\s*$', '\1', '') + + if (match(line, g:tagbar#icon_open . '[-+ ]')) == 0 + call s:CloseFold() + elseif (match(line, g:tagbar#icon_closed . '[-+ ]')) == 0 + call s:OpenFold() + endif return endif let tagbarwinnr = winnr() + if exists('w:autoclose') + let autoclose = w:autoclose + else + let autoclose = 0 + endif call s:GotoFileWindow(taginfo.fileinfo) " Mark current position so it can be jumped back to mark ' + " Check if the tag is already visible in the window. We must do this + " before jumping to the line. + let noscroll = 0 + if g:tagbar_jump_lazy_scroll != 0 || force_lazy_scroll + let noscroll = s:IsLineVisible(taginfo.fields.line) + endif + " Jump to the line where the tag is defined. Don't use the search pattern " since it doesn't take the scope into account and thus can fail if tags " with the same name are defined in different scopes (e.g. classes) @@ -1982,7 +2387,7 @@ function! s:JumpToTag(stay_in_tagbar) abort " If the file has been changed but not saved, the tag may not be on the " saved line anymore, so search for it in the vicinity of the saved line - if taginfo.pattern != '' + if taginfo.pattern !=# '' call tagbar#debug#log('Searching for pattern "' . taginfo.pattern . '"') if match(getline('.'), taginfo.pattern) == -1 let interval = 1 @@ -2008,14 +2413,33 @@ function! s:JumpToTag(stay_in_tagbar) abort let taginfo.fileinfo.fline[curline] = taginfo endif - " Center the tag in the window and jump to the correct column if - " available, otherwise try to find it in the line - normal! z. + if noscroll + " Do not scroll. + else + " Center the tag in the window and jump to the correct column if + " available, otherwise try to find it in the line + normal! z. + + " If configured, adjust the jump_offset and center the window on that + " line. Then fall-through adjust the cursor() position below that + if g:tagbar_jump_offset != 0 && g:tagbar_jump_offset < curline + if g:tagbar_jump_offset > winheight(0) / 2 + let jump_offset = winheight(0) / 2 + elseif g:tagbar_jump_offset < -winheight(0) / 2 + let jump_offset = -winheight(0) / 2 + else + let jump_offset = g:tagbar_jump_offset + endif + execute curline+jump_offset + normal! z. + endif + endif + if taginfo.fields.column > 0 call cursor(taginfo.fields.line, taginfo.fields.column) else call cursor(taginfo.fields.line, 1) - call search(taginfo.name, 'c', line('.')) + call search('\V' . taginfo.name, 'c', line('.')) endif normal! zv @@ -2032,6 +2456,9 @@ function! s:JumpToTag(stay_in_tagbar) abort if s:pwin_by_tagbar pclose endif + if s:is_maximized + call s:ZoomWindow() + endif call s:HighlightTag(0) endif endfunction @@ -2056,7 +2483,7 @@ function! s:ShowInPreviewWin() abort " We want the preview window to be relative to the file window in normal " (horizontal) mode, and relative to the Tagbar window in vertical mode, " to make the best use of space. - if g:tagbar_vertical == 0 + if g:tagbar_position =~# 'vertical' call s:GotoFileWindow(taginfo.fileinfo, 1) call s:mark_window() endif @@ -2067,7 +2494,7 @@ function! s:ShowInPreviewWin() abort silent execute \ g:tagbar_previewwin_pos . ' pedit ' . \ fnameescape(taginfo.fileinfo.fpath) - if g:tagbar_vertical != 0 + if g:tagbar_position !~# 'vertical' silent execute 'vertical resize ' . g:tagbar_width endif " Remember that the preview window was opened by Tagbar so we can @@ -2075,7 +2502,7 @@ function! s:ShowInPreviewWin() abort let s:pwin_by_tagbar = 1 endif - if g:tagbar_vertical != 0 + if g:tagbar_position !~# 'vertical' call s:GotoFileWindow(taginfo.fileinfo, 1) call s:mark_window() endif @@ -2088,7 +2515,7 @@ function! s:ShowInPreviewWin() abort " the searching. Unfortunately the /\%l pattern doesn't seem to work with " psearch. let pattern = taginfo.pattern - if pattern == '' + if pattern ==# '' let pattern = '\V\^' . escape(getline(taginfo.fields.line), '\') . '\$' endif let include_save = &include @@ -2318,7 +2745,7 @@ function! s:OpenParents(...) abort if a:0 == 1 let tag = a:1 else - let tag = s:GetNearbyTag(1, 0) + let tag = s:GetNearbyTag('nearest', 0) endif if !empty(tag) @@ -2417,7 +2844,7 @@ function! s:AutoUpdate(fname, force, ...) abort let ftype = getbufvar(bufnr, '&filetype') " Don't do anything if we're in the tagbar window - if ftype == 'tagbar' + if ftype ==# 'tagbar' call tagbar#debug#log('In Tagbar window, stopping processing') return endif @@ -2516,7 +2943,7 @@ function! s:DetectFiletype(bufnr) abort return ftype endif - if ftype != '' + if ftype !=# '' return ftype endif @@ -2565,7 +2992,7 @@ function! s:EscapeCtagsCmd(ctags_bin, args, ...) abort "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' + if (&shell =~? 'cmd\.exe$' || &shell =~? 'powershell\.exe$' || &shell =~? 'powershell$' || &shell =~? 'pwsh\.exe$' || &shell =~? 'pwsh$') && 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. @@ -2625,14 +3052,14 @@ function! s:EscapeCtagsCmd(ctags_bin, args, ...) abort if has('multi_byte') if g:tagbar_systemenc != &encoding let ctags_cmd = iconv(ctags_cmd, &encoding, g:tagbar_systemenc) - elseif $LANG != '' + elseif $LANG !=# '' let ctags_cmd = iconv(ctags_cmd, &encoding, $LANG) endif endif call tagbar#debug#log('Escaped ctags command: ' . ctags_cmd) - if ctags_cmd == '' + if ctags_cmd ==# '' if !s:warnings.encoding call s:warning('Tagbar: Ctags command encoding conversion failed!' . \ ' Please read ":h g:tagbar_systemenc".') @@ -2643,6 +3070,40 @@ function! s:EscapeCtagsCmd(ctags_bin, args, ...) abort return ctags_cmd endfunction +" run shell command in a proper way: prevent temporary window creation +function! s:run_system(cmd, version) abort + if has('win32') && !has('nvim') && a:version > 0 && (has('python3') || has('python2')) + if a:version == 3 && has('python3') + let pyx = 'py3 ' + let python_eval = 'py3eval' + elseif a:version == 2 && has('python2') + let pyx = 'py2 ' + let python_eval = 'pyeval' + else + let pyx = 'pyx ' + let python_eval = 'pyxeval' + endif + let l:pc = 0 + exec pyx . 'import subprocess, vim' + exec pyx . '__argv = {"args":vim.eval("a:cmd"), "shell":True}' + exec pyx . '__argv["stdout"] = subprocess.PIPE' + exec pyx . '__argv["stderr"] = subprocess.STDOUT' + exec pyx . '__argv["errors"] = "ignore"' + exec pyx . '__pp = subprocess.Popen(**__argv, universal_newlines=True, encoding="utf8")' + exec pyx . '__return_text = __pp.stdout.read()' + exec pyx . '__pp.stdout.close()' + exec pyx . '__return_code = __pp.wait()' + exec 'let l:hr = '. python_eval .'("__return_text")' + exec 'let l:pc = '. python_eval .'("__return_code")' + let s:shell_error = l:pc + return l:hr + endif + let hr = system(a:cmd) + let s:shell_error = v:shell_error + return hr +endfunction + + " s:ExecuteCtags() {{{2 " Execute ctags with necessary shell settings " Partially based on the discussion at @@ -2656,18 +3117,18 @@ function! s:ExecuteCtags(ctags_cmd) abort set shell=sh endif + if &shell =~# 'elvish' + " Reset shell since Elvish isn't really compatible + let shell_save = &shell + set shell=sh + endif + if exists('+shellslash') let shellslash_save = &shellslash set noshellslash endif - if executable('bash') && has('nvim') - let shell_save = &shell - let shellcmdflag_save = &shellcmdflag - set shell=bash - set shellcmdflag=-c - endif - if &shell =~ 'cmd\.exe' + if &shell =~? 'cmd\.exe' let shellxquote_save = &shellxquote set shellxquote=\" let shellcmdflag_save = &shellcmdflag @@ -2680,14 +3141,13 @@ function! s:ExecuteCtags(ctags_cmd) abort call tagbar#debug#log('Exit code: ' . v:shell_error) redraw! else - silent let ctags_output = system(a:ctags_cmd) + let py_version = get(g:, 'tagbar_python', 1) + silent let ctags_output = s:run_system(a:ctags_cmd, py_version) endif - if &shell =~ 'cmd\.exe' + if &shell =~? 'cmd\.exe' let &shellxquote = shellxquote_save let &shellcmdflag = shellcmdflag_save - unlet shellxquote_save - unlet shellcmdflag_save endif if exists('+shellslash') @@ -2698,16 +3158,12 @@ function! s:ExecuteCtags(ctags_cmd) abort let &shell = shell_save endif - if exists('shellcmdflag_save') - let &shellcmdflag = shellcmdflag_save - endif - return ctags_output endfunction " s:GetNearbyTag() {{{2 " Get the tag info for a file near the cursor in the current file -function! s:GetNearbyTag(all, forcecurrent, ...) abort +function! s:GetNearbyTag(request, forcecurrent, ...) abort if s:nearby_disabled return {} endif @@ -2717,23 +3173,39 @@ function! s:GetNearbyTag(all, forcecurrent, ...) abort return {} endif + let curline = a:0 > 0 ? a:1 : line('.') + let direction = a:0 > 1 ? a:2 : -1 + let ignore_curline = a:0 > 2 ? a:3 : 0 + let typeinfo = fileinfo.typeinfo - if a:0 > 0 - let curline = a:1 - else - let curline = line('.') - endif let tag = {} + if direction < 0 + let endline = 1 + let increment = -1 + else + let endline = line('$') + let increment = 1 + endif + " If a tag appears in a file more than once (for example namespaces in " C++) only one of them has a 'tline' entry and can thus be highlighted. " The only way to solve this would be to go over the whole tag list again, " making everything slower. Since this should be a rare occurence and " highlighting isn't /that/ important ignore it for now. - for line in range(curline, 1, -1) + for line in range(curline, endline, increment) if has_key(fileinfo.fline, line) let curtag = fileinfo.fline[line] - if a:all || typeinfo.getKind(curtag.fields.kind).stl + if a:request ==# 'nearest-stl' && typeinfo.getKind(curtag.fields.kind).stl + let tag = curtag + break + elseif a:request ==# 'scoped-stl' + \ && typeinfo.getKind(curtag.fields.kind).stl + \ && curtag.fields.line <= curline + \ && curline <= curtag.fields.end + let tag = curtag + break + elseif a:request ==# 'nearest' || (line == curline && ignore_curline == 0) let tag = curtag break endif @@ -2743,6 +3215,31 @@ function! s:GetNearbyTag(all, forcecurrent, ...) abort return tag endfunction +" s:JumpToNearbyTag() {{{2 +function! s:JumpToNearbyTag(direction, request, flags) abort + let fileinfo = tagbar#state#get_current_file(0) + if empty(fileinfo) + return {} + endif + + let lnum = a:direction > 0 ? line('.') + 1 : line('.') - 1 + let lazy_scroll = a:flags =~# 's' ? 0 : 1 + + let tag = s:GetNearbyTag(a:request, 1, lnum, a:direction, 1) + + if empty(tag) + " No next tag found + if a:direction > 0 + echo '...no next tag found' + else + echo '...no previous tag found' + endif + return + endif + + call s:JumpToTag(1, tag, lazy_scroll) +endfunction + " s:GetTagInfo() {{{2 " Return the info dictionary of the tag on the specified line. If the line " does not contain a valid tag (for example because it is empty or only @@ -2756,7 +3253,7 @@ function! s:GetTagInfo(linenr, ignorepseudo) abort " Don't do anything in empty and comment lines let curline = getbufline(bufnr(s:TagbarBufName()), a:linenr)[0] - if curline =~ '^\s*$' || curline[0] == '"' + if curline =~# '^\s*$' || curline[0] ==# '"' return {} endif @@ -2782,7 +3279,7 @@ endfunction " the correct buffer in it. function! s:GetFileWinnr(fileinfo) abort let filewinnr = 0 - let prevwinnr = winnr("#") + let prevwinnr = winnr('#') if winbufnr(prevwinnr) == a:fileinfo.bufnr && \ !getwinvar(prevwinnr, '&previewwindow') @@ -2817,7 +3314,7 @@ function! s:GotoFileWindow(fileinfo, ...) abort if filewinnr == 0 for i in range(1, winnr('$')) call s:goto_win(i, 1) - if &buftype == '' && !&previewwindow + if &buftype ==# '' && !&previewwindow execute 'buffer ' . a:fileinfo.bufnr break endif @@ -2897,12 +3394,12 @@ endfunction function! s:IsValidFile(fname, ftype) abort call tagbar#debug#log('Checking if file is valid [' . a:fname . ']') - if a:fname == '' || a:ftype == '' + if a:fname ==# '' || a:ftype ==# '' call tagbar#debug#log('Empty filename or type') return 0 endif - if !filereadable(a:fname) && getbufvar(a:fname, 'netrw_tmpfile') == '' + if !filereadable(a:fname) && getbufvar(a:fname, 'netrw_tmpfile') ==# '' call tagbar#debug#log('File not readable') return 0 endif @@ -2938,9 +3435,9 @@ function! s:IsValidFile(fname, ftype) abort endfunction " s:SetStatusLine() {{{2 -function! s:SetStatusLine() +function! s:SetStatusLine() abort let tagbarwinnr = bufwinnr(s:TagbarBufName()) - if tagbarwinnr == -1 + if tagbarwinnr == -1 || exists('g:tagbar_no_status_line') return endif @@ -2977,7 +3474,7 @@ function! s:SetStatusLine() else let colour = in_tagbar ? '%#StatusLine#' : '%#StatusLineNC#' let flagstr = join(flags, '') - if flagstr != '' + if flagstr !=# '' let flagstr = '[' . flagstr . '] ' endif let text = colour . '[' . sortstr . '] ' . flagstr . fname @@ -3035,13 +3532,13 @@ function! s:HandleBufDelete(bufname, bufnr) abort return endif + call s:known_files.rm(fnamemodify(a:bufname, ':p')) + let tagbarwinnr = bufwinnr(s:TagbarBufName()) - if tagbarwinnr == -1 || a:bufname =~ '__Tagbar__.*' + if tagbarwinnr == -1 || a:bufname =~# '__Tagbar__.*' return endif - call s:known_files.rm(fnamemodify(a:bufname, ':p')) - if !s:HasOpenFileWindows() if tabpagenr('$') == 1 && exists('t:tagbar_buf_name') " The last normal window closed due to a :bdelete/:bwipeout. @@ -3113,7 +3610,7 @@ function! s:ReopenWindow(delbufname) abort endif autocmd! TagbarAutoCmds BufWinEnter - call s:OpenWindow("") + call s:OpenWindow('') endfunction " s:HasOpenFileWindows() {{{2 @@ -3122,12 +3619,12 @@ function! s:HasOpenFileWindows() abort let buf = winbufnr(i) " skip unlisted buffers, except for netrw - if !buflisted(buf) && getbufvar(buf, '&filetype') != 'netrw' + if !buflisted(buf) && getbufvar(buf, '&filetype') !=# 'netrw' continue endif " skip temporary buffers with buftype set - if getbufvar(buf, '&buftype') != '' + if getbufvar(buf, '&buftype') !=# '' continue endif @@ -3154,11 +3651,23 @@ endfunction " s:goto_win() {{{2 function! s:goto_win(winnr, ...) abort + "Do not go to a popup window to avoid errors. + "Hence, check first if a:winnr is an integer, + "if this integer is equal to 0, + "the window is a popup window + if has('popupwin') + if type(a:winnr) == type(0) && a:winnr == 0 + return + endif + if a:winnr ==# 'p' && winnr('#') == 0 + return + endif + endif let cmd = type(a:winnr) == type(0) ? a:winnr . 'wincmd w' \ : 'wincmd ' . a:winnr let noauto = a:0 > 0 ? a:1 : 0 - call tagbar#debug#log("goto_win(): " . cmd . ", " . noauto) + call tagbar#debug#log('goto_win(): ' . cmd . ', ' . noauto) if noauto noautocmd execute cmd @@ -3200,6 +3709,21 @@ function! s:warning(msg) abort echohl None endfunction +" s:TogglePause() {{{2 +function! s:TogglePause() abort + let s:paused = !s:paused + + if s:paused + call tagbar#state#set_paused() + else + let fileinfo = tagbar#state#get_current_file(0) + let taginfo = fileinfo.getTags()[0] + + call s:GotoFileWindow(taginfo.fileinfo) + call s:AutoUpdate(taginfo.fileinfo.fpath, 1) + endif +endfunction + " TagbarBalloonExpr() {{{2 function! TagbarBalloonExpr() abort let taginfo = s:GetTagInfo(v:beval_lnum, 1) @@ -3212,7 +3736,7 @@ function! TagbarBalloonExpr() abort if has('multi_byte') if g:tagbar_systemenc != &encoding let prototype = iconv(prototype, &encoding, g:tagbar_systemenc) - elseif $LANG != '' + elseif $LANG !=# '' let prototype = iconv(prototype, &encoding, $LANG) endif endif @@ -3222,6 +3746,7 @@ endfunction " Autoload functions {{{1 " Wrappers {{{2 + function! tagbar#ToggleWindow(...) abort let flags = a:0 > 0 ? a:1 : '' call s:ToggleWindow(flags) @@ -3255,8 +3780,28 @@ function! tagbar#RestoreSession() abort call s:RestoreSession() endfunction +function! tagbar#StopAutoUpdate() abort + autocmd! TagbarAutoCmds + let s:autocommands_done = 0 +endfunction + " }}}2 +" tagbar#Update() {{{2 +" Trigger an AutoUpdate() of the currently opened file +function! tagbar#Update() abort + call s:AutoUpdate(fnamemodify(expand('%'), ':p'), 0) +endfunction + +" tagbar#ForceUpdate() {{{2 +function! tagbar#ForceUpdate() abort + if !exists('b:tagbar_force_update') + let b:tagbar_force_update = 1 + call s:AutoUpdate(fnamemodify(expand('%'), ':p'), 1) + unlet b:tagbar_force_update + endif +endfunction + " tagbar#toggle_pause() {{{2 function! tagbar#toggle_pause() abort let s:paused = !s:paused @@ -3274,7 +3819,7 @@ endfunction " tagbar#getusertypes() {{{2 function! tagbar#getusertypes() abort - let userdefs = filter(copy(g:), 'v:key =~ "^tagbar_type_"') + let userdefs = filter(copy(g:), 'v:key =~? "^tagbar_type_"') let typedict = {} for [key, val] in items(userdefs) @@ -3309,28 +3854,67 @@ function! tagbar#autoopen(...) abort call tagbar#debug#log('tagbar#autoopen finished without finding valid file') endfunction +" tagbar#GetTagNearLine() {{{2 +function! tagbar#GetTagNearLine(lnum, ...) abort + if a:0 >= 2 + let fmt = a:1 + let longsig = a:2 =~# 's' + let fullpath = a:2 =~# 'f' + let prototype = a:2 =~# 'p' + if a:0 >= 3 + let search_method = a:3 + else + let search_method = 'nearest-stl' + endif + else + let fmt = '%s' + let longsig = 0 + let fullpath = 0 + let prototype = 0 + let search_method = 'nearest-stl' + endif + + let taginfo = s:GetNearbyTag(search_method, 1, a:lnum) + + if empty(taginfo) + return '' + endif + + if prototype + return taginfo.getPrototype(1) + else + return printf(fmt, taginfo.str(longsig, fullpath)) + endif +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 + if a:0 >= 1 " also test for non-zero value for backwards compatibility let longsig = a:1 =~# 's' || (type(a:1) == type(0) && a:1 != 0) let fullpath = a:1 =~# 'f' let prototype = a:1 =~# 'p' + if a:0 >= 2 + let search_method = a:2 + else + let search_method = g:tagbar_highlight_method + endif else let longsig = 0 let fullpath = 0 let prototype = 0 + let search_method = g:tagbar_highlight_method endif if !s:Init(1) return a:default endif - let tag = s:GetNearbyTag(0, 1) + let tag = s:GetNearbyTag(search_method, 1) if !empty(tag) if prototype @@ -3367,20 +3951,20 @@ function! tagbar#gettypeconfig(type) abort return endif - let output = "let g:tagbar_type_" . a:type . " = {\n" + let output = 'let g:tagbar_type_' . a:type . " = {\n" let output .= " \\ 'kinds' : [\n" for kind in typeinfo.kinds - let output .= " \\ '" . kind.short . ":" . kind.long + let output .= " \\ '" . kind.short . ':' . kind.long if kind.fold || !kind.stl if kind.fold - let output .= ":1" + let output .= ':1' else - let output .= ":0" + let output .= ':0' endif endif if !kind.stl - let output .= ":0" + let output .= ':0' endif let output .= "',\n" endfor @@ -3396,5 +3980,97 @@ function! tagbar#inspect(var) abort return get(s:, a:var) endfunction +" tagbar#currenttagtype() {{{2 +function! tagbar#currenttagtype(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 + let kind = '' + let tag = s:GetNearbyTag('scoped-stl', 1) + + if empty(tag) + return a:default + endif + + let kind = tag.fields.kind + if kind ==# '' + return a:default + endif + + let typeinfo = tag.fileinfo.typeinfo + let plural = typeinfo.kinds[typeinfo.kinddict[kind]].long + if has_key(s:singular_types, plural) + let singular = s:singular_types[plural] + else + let singular = plural + endif + return printf(a:fmt, singular) +endfunction + +" tagbar#printfileinfo() {{{2 +function! tagbar#printfileinfo() abort + if !tagbar#debug#enabled() + echo 'Tagbar debug is disabled - unable to print fileinfo to tagbar log' + return + endif + + let fileinfo = tagbar#state#get_current_file(0) + if empty(fileinfo) + call tagbar#debug#log('File contains no tag entries') + return + endif + let typeinfo = fileinfo.typeinfo + + call tagbar#debug#log('Printing fileinfo [' . fileinfo.fpath . ' lines:' . fileinfo.lnum) + for line in range(1, fileinfo.lnum) + if has_key(fileinfo.fline, line) + let tag = fileinfo.fline[line] + call tagbar#debug#log(' ' + \ . ' line:' . line + \ . ' kind:' . tag.fields.kind + \ . ' depth:' . tag.depth + \ . ' [' . tag.strfmt() . ']' + \ ) + endif + endfor + call tagbar#debug#log('All tags printed') + + echo 'Tagbar fileinfo printed to debug logfile' +endfunction + +" tagbar#IsOpen() {{{2 +function! tagbar#IsOpen() abort + let tagbarwinnr = bufwinnr('__Tagbar__') + if tagbarwinnr != -1 + " Window open + return 1 + else + " Window not open + return 0 + endif +endfunction + +" tagbar#jump() {{{2 +function! tagbar#jump() abort + if &filetype !=# 'tagbar' + " Not in tagbar window - ignore this function call + return + endif + call s:JumpToTag(1) +endfun + +" tagbar#jumpToNearbyTag() {{{2 +" params: +" direction = -1:backwards search 1:forward search +" [search_method] = Search method to use for GetTagNearLine() +" [flags] = list of flags (as a string) to control behavior +" 's' - use the g:tagbar_scroll_offset setting when jumping +function! tagbar#jumpToNearbyTag(direction, ...) abort + let search_method = a:0 >= 1 ? a:1 : 'nearest-stl' + let flags = a:0 >= 2 ? a:2 : '' + + call s:JumpToNearbyTag(a:direction, search_method, flags) +endfunction + " Modeline {{{1 " vim: ts=8 sw=4 sts=4 et foldenable foldmethod=marker foldcolumn=1 diff --git a/bundle/tagbar/autoload/tagbar/debug.vim b/bundle/tagbar/autoload/tagbar/debug.vim index fce82fa60..04caec13d 100644 --- a/bundle/tagbar/autoload/tagbar/debug.vim +++ b/bundle/tagbar/autoload/tagbar/debug.vim @@ -1,5 +1,3 @@ -let s:LOG = SpaceVim#api#import('logger') - function! tagbar#debug#start_debug(...) abort let filename = a:0 > 0 ? a:1 : '' @@ -29,14 +27,6 @@ function! tagbar#debug#stop_debug() abort let s:debug_file = '' endfunction -function! tagbar#debug#info(msg) abort - call s:LOG.info(a:msg) -endfunction - -function! tagbar#debug#warn(msg) abort - call s:LOG.warn(a:msg) -endfunction - function! tagbar#debug#log(msg) abort if s:debug_enabled execute 'redir >> ' . s:debug_file diff --git a/bundle/tagbar/autoload/tagbar/prototypes/basetag.vim b/bundle/tagbar/autoload/tagbar/prototypes/basetag.vim index ea7d948d0..009054fb0 100644 --- a/bundle/tagbar/autoload/tagbar/prototypes/basetag.vim +++ b/bundle/tagbar/autoload/tagbar/prototypes/basetag.vim @@ -3,6 +3,9 @@ let s:visibility_symbols = { \ 'protected' : '#', \ 'private' : '-' \ } +if exists('g:tagbar_visibility_symbols') && !empty(g:tagbar_visibility_symbols) + let s:visibility_symbols = g:tagbar_visibility_symbols +endif function! tagbar#prototypes#basetag#new(name) abort let newobj = {} @@ -11,7 +14,9 @@ function! tagbar#prototypes#basetag#new(name) abort let newobj.fields = {} let newobj.fields.line = 0 let newobj.fields.column = 0 + let newobj.fields.end = 0 let newobj.prototype = '' + let newobj.data_type = '' let newobj.path = '' let newobj.fullpath = a:name let newobj.depth = 0 @@ -27,6 +32,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')) @@ -69,6 +75,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 @@ -227,7 +238,7 @@ endfunction " s:add_snr() {{{1 function! s:add_snr(funcname) abort - if !exists("s:snr") + if !exists('s:snr') let s:snr = matchstr(expand(''), '\d\+_\zeget_snr$') endif return s:snr . a:funcname diff --git a/bundle/tagbar/autoload/tagbar/prototypes/fileinfo.vim b/bundle/tagbar/autoload/tagbar/prototypes/fileinfo.vim index 6cd7e8f8c..fe2ae8661 100644 --- a/bundle/tagbar/autoload/tagbar/prototypes/fileinfo.vim +++ b/bundle/tagbar/autoload/tagbar/prototypes/fileinfo.vim @@ -9,6 +9,12 @@ function! tagbar#prototypes#fileinfo#new(fname, ftype, typeinfo) abort " File modification time let newobj.mtime = getftime(a:fname) + " Get file size + let newobj.fsize = getfsize(a:fname) + + " Get the number of lines in the file + let newobj.lnum = line('$') + " The vim file type let newobj.ftype = a:ftype @@ -52,6 +58,10 @@ function! tagbar#prototypes#fileinfo#new(fname, ftype, typeinfo) abort let newobj.openKindFold = function(s:add_snr('s:openKindFold')) let newobj.closeKindFold = function(s:add_snr('s:closeKindFold')) + " This is used during file processing. If the limit is exceeded at that + " point, then mark this flag for displaying to the tagbar window + let newobj.fsize_exceeded = 0 + return newobj endfunction @@ -136,7 +146,7 @@ endfunction " s:add_snr() {{{1 function! s:add_snr(funcname) abort - if !exists("s:snr") + if !exists('s:snr') let s:snr = matchstr(expand(''), '\d\+_\zeget_snr$') endif return s:snr . a:funcname diff --git a/bundle/tagbar/autoload/tagbar/prototypes/kindheadertag.vim b/bundle/tagbar/autoload/tagbar/prototypes/kindheadertag.vim index de6708658..a4f66364b 100644 --- a/bundle/tagbar/autoload/tagbar/prototypes/kindheadertag.vim +++ b/bundle/tagbar/autoload/tagbar/prototypes/kindheadertag.vim @@ -51,7 +51,7 @@ endfunction " s:add_snr() {{{1 function! s:add_snr(funcname) abort - if !exists("s:snr") + if !exists('s:snr') let s:snr = matchstr(expand(''), '\d\+_\zeget_snr$') endif return s:snr . a:funcname diff --git a/bundle/tagbar/autoload/tagbar/prototypes/normaltag.vim b/bundle/tagbar/autoload/tagbar/prototypes/normaltag.vim index 9bf8cf315..a5916d267 100644 --- a/bundle/tagbar/autoload/tagbar/prototypes/normaltag.vim +++ b/bundle/tagbar/autoload/tagbar/prototypes/normaltag.vim @@ -1,3 +1,12 @@ +function! s:maybe_map_scope(scopestr) abort + if !empty(g:tagbar_scopestrs) + if has_key(g:tagbar_scopestrs, a:scopestr) + return g:tagbar_scopestrs[a:scopestr] + endif + endif + return a:scopestr +endfunction + function! tagbar#prototypes#normaltag#new(name) abort let newobj = tagbar#prototypes#basetag#new(a:name) @@ -5,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 @@ -22,15 +32,29 @@ function! s:strfmt() abort dict if has_key(self.fields, 'type') let suffix .= ' : ' . self.fields.type elseif has_key(get(typeinfo, 'kind2scope', {}), self.fields.kind) - let suffix .= ' : ' . typeinfo.kind2scope[self.fields.kind] + let scope = s:maybe_map_scope(typeinfo.kind2scope[self.fields.kind]) + 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 - return self._getPrefix() . self.name . suffix + if g:tagbar_show_tag_linenumbers == 1 + let suffix .= ' [' . self.fields.line . ']' + elseif g:tagbar_show_tag_linenumbers == 2 + let prefix .= '[' . self.fields.line . '] ' + endif + + return prefix . self.name . suffix endfunction " s:str() {{{1 function! s:str(longsig, full) abort dict - if a:full && self.path != '' + if a:full && self.path !=# '' let str = self.path . self.typeinfo.sro . self.name else let str = self.name @@ -49,7 +73,7 @@ endfunction " s:getPrototype() {{{1 function! s:getPrototype(short) abort dict - if self.prototype != '' + if self.prototype !=# '' let prototype = self.prototype else let bufnr = self.fileinfo.bufnr @@ -61,6 +85,11 @@ function! s:getPrototype(short) abort dict endif let line = getbufline(bufnr, self.fields.line)[0] + " If prototype includes declaration, remove the '=' and anything after + " FIXME: Need to remove this code. This breaks python prototypes that + " can include a '=' in the function paramter list. + " ex: function(arg1, optional_arg2=False) + " let line = substitute(line, '\s*=.*', '', '') let list = split(line, '\zs') let start = index(list, '(') @@ -78,7 +107,7 @@ function! s:getPrototype(short) abort dict let prototype = line let curlinenr = self.fields.line + 1 - while balance > 0 + while balance > 0 && curlinenr < line('$') let curline = getbufline(bufnr, curlinenr)[0] let curlist = split(curline, '\zs') let balance += count(curlist, '(') @@ -107,9 +136,42 @@ 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*' . escape(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") + if !exists('s:snr') let s:snr = matchstr(expand(''), '\d\+_\zeget_snr$') endif return s:snr . a:funcname diff --git a/bundle/tagbar/autoload/tagbar/prototypes/pseudotag.vim b/bundle/tagbar/autoload/tagbar/prototypes/pseudotag.vim index 50e4ad11f..740cd841b 100644 --- a/bundle/tagbar/autoload/tagbar/prototypes/pseudotag.vim +++ b/bundle/tagbar/autoload/tagbar/prototypes/pseudotag.vim @@ -20,13 +20,20 @@ function! s:strfmt() abort dict if has_key(typeinfo.kind2scope, self.fields.kind) let suffix .= ' : ' . typeinfo.kind2scope[self.fields.kind] endif + let prefix = self._getPrefix() - return self._getPrefix() . self.name . '*' . suffix + if g:tagbar_show_tag_linenumbers == 1 + let suffix .= ' [' . self.fields.line . ']' + elseif g:tagbar_show_tag_linenumbers == 2 + let prefix .= '[' . self.fields.line . '] ' + endif + + return prefix . self.name . '*' . suffix endfunction " s:add_snr() {{{1 function! s:add_snr(funcname) abort - if !exists("s:snr") + if !exists('s:snr') let s:snr = matchstr(expand(''), '\d\+_\zeget_snr$') endif return s:snr . a:funcname diff --git a/bundle/tagbar/autoload/tagbar/prototypes/splittag.vim b/bundle/tagbar/autoload/tagbar/prototypes/splittag.vim index 7263cd533..94b6cdc00 100644 --- a/bundle/tagbar/autoload/tagbar/prototypes/splittag.vim +++ b/bundle/tagbar/autoload/tagbar/prototypes/splittag.vim @@ -16,7 +16,7 @@ function! s:isSplitTag() abort dict endfunction function! s:add_snr(funcname) abort - if !exists("s:snr") + if !exists('s:snr') let s:snr = matchstr(expand(''), '\d\+_\zeget_snr$') endif return s:snr . a:funcname diff --git a/bundle/tagbar/autoload/tagbar/prototypes/typeinfo.vim b/bundle/tagbar/autoload/tagbar/prototypes/typeinfo.vim index 1c3f4523f..1ed9588ef 100644 --- a/bundle/tagbar/autoload/tagbar/prototypes/typeinfo.vim +++ b/bundle/tagbar/autoload/tagbar/prototypes/typeinfo.vim @@ -15,7 +15,8 @@ endfunction " s:getKind() {{{1 function! s:getKind(kind) abort dict - let idx = self.kinddict[a:kind] + "let idx = self.kinddict[a:kind] + let idx = has_key(self.kinddict, a:kind) ? self.kinddict[a:kind] : -1 return self.kinds[idx] endfunction @@ -32,7 +33,7 @@ endfunction " s:add_snr() {{{1 function! s:add_snr(funcname) abort - if !exists("s:snr") + if !exists('s:snr') let s:snr = matchstr(expand(''), '\d\+_\zeget_snr$') endif return s:snr . a:funcname diff --git a/bundle/tagbar/autoload/tagbar/sorting.vim b/bundle/tagbar/autoload/tagbar/sorting.vim index ab9b179de..b03faff8d 100644 --- a/bundle/tagbar/autoload/tagbar/sorting.vim +++ b/bundle/tagbar/autoload/tagbar/sorting.vim @@ -6,7 +6,7 @@ function! tagbar#sorting#sort(tags, compareby, compare_typeinfo) abort let s:compare_typeinfo = a:compare_typeinfo let comparemethod = - \ a:compareby == 'kind' ? 's:compare_by_kind' : 's:compare_by_line' + \ a:compareby ==# 'kind' ? 's:compare_by_kind' : 's:compare_by_line' call sort(a:tags, comparemethod) @@ -21,6 +21,12 @@ endfunction function! s:compare_by_kind(tag1, tag2) abort let typeinfo = s:compare_typeinfo + if !has_key(typeinfo.kinddict, a:tag1.fields.kind) + return -1 + endif + if !has_key(typeinfo.kinddict, a:tag2.fields.kind) + return 1 + endif if typeinfo.kinddict[a:tag1.fields.kind] <# \ typeinfo.kinddict[a:tag2.fields.kind] return -1 diff --git a/bundle/tagbar/autoload/tagbar/types/ctags.vim b/bundle/tagbar/autoload/tagbar/types/ctags.vim index 442466c65..ca49ab145 100644 --- a/bundle/tagbar/autoload/tagbar/types/ctags.vim +++ b/bundle/tagbar/autoload/tagbar/types/ctags.vim @@ -115,6 +115,7 @@ function! tagbar#types#ctags#init(supported_types) abort \ 'union' : 'u' \ } let types.c = type_c + let types.lpc = type_c " C++ {{{1 let type_cpp = tagbar#prototypes#typeinfo#new() let type_cpp.ctagstype = 'c++' @@ -194,6 +195,21 @@ function! tagbar#types#ctags#init(supported_types) abort \ {'short' : 's', 'long' : 'sections', 'fold' : 0, 'stl' : 1} \ ] let types.cobol = type_cobol + " Crystal {{{1 + let type_crystal = tagbar#prototypes#typeinfo#new() + let type_crystal.ctagstype = 'crystal' + let type_crystal.kinds = [ + \ {'short' : 'm', 'long' : 'modules', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'c', 'long' : 'classes', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'd', 'long' : 'defs', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'M', 'long' : 'macros', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'l', 'long' : 'libs', 'fold' : 0, 'stl' : 1}, + \ {'short' : 's', 'long' : 'structs', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'a', 'long' : 'aliases', 'fold' : 0, 'stl' : 1} + \ ] + let type_crystal.sro = '::' + let types.crystal = type_crystal " DOS Batch {{{1 let type_dosbatch = tagbar#prototypes#typeinfo#new() let type_dosbatch.ctagstype = 'dosbatch' @@ -292,6 +308,27 @@ function! tagbar#types#ctags#init(supported_types) abort \ 'subroutine' : 's' \ } let types.fortran = type_fortran + " Go {{{1 + let type_go = tagbar#prototypes#typeinfo#new() + let type_go.ctagstype = 'go' + let type_go.kinds = [ + \ {'short' : 'p', 'long' : 'packages', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'i', 'long' : 'interfaces', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'c', 'long' : 'constants', 'fold' : 0, 'stl' : 0}, + \ {'short' : 's', 'long' : 'structs', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'm', 'long' : 'struct members', 'fold' : 0, 'stl' : 0}, + \ {'short' : 't', 'long' : 'types', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 0} + \ ] + let type_go.sro = '.' + let type_go.kind2scope = { + \ 's' : 'struct' + \ } + let type_go.scope2kind = { + \ 'struct' : 's' + \ } + let types.go = type_go " HTML {{{1 let type_html = tagbar#prototypes#typeinfo#new() let type_html.ctagstype = 'html' diff --git a/bundle/tagbar/autoload/tagbar/types/uctags.vim b/bundle/tagbar/autoload/tagbar/types/uctags.vim index bba2479a3..db98384d8 100644 --- a/bundle/tagbar/autoload/tagbar/types/uctags.vim +++ b/bundle/tagbar/autoload/tagbar/types/uctags.vim @@ -215,6 +215,7 @@ function! tagbar#types#uctags#init(supported_types) abort \ 'union' : 'u' \ } let types.c = type_c + let types.lpc = type_c " C++ {{{1 let type_cpp = tagbar#prototypes#typeinfo#new() let type_cpp.ctagstype = 'c++' @@ -250,6 +251,7 @@ function! tagbar#types#uctags#init(supported_types) abort \ } let types.cpp = type_cpp let types.cuda = type_cpp + let types.arduino = type_cpp " C# {{{1 let type_cs = tagbar#prototypes#typeinfo#new() let type_cs.ctagstype = 'c#' @@ -298,6 +300,40 @@ function! tagbar#types#uctags#init(supported_types) abort \ 'namespace' : 'n' \ } let types.clojure = type_clojure + " CMake {{{1 + let type_cmake = tagbar#prototypes#typeinfo#new() + let type_cmake.ctagstype = 'cmake' + let type_cmake.kinds = [ + \ {'short': 'p', 'long': 'projects' , 'fold': 0, 'stl': 1}, + \ {'short': 'm', 'long': 'macros' , 'fold': 0, 'stl': 1}, + \ {'short': 'f', 'long': 'functions', 'fold': 0, 'stl': 1}, + \ {'short': 'D', 'long': 'options' , 'fold': 0, 'stl': 1}, + \ {'short': 'v', 'long': 'variables', 'fold': 0, 'stl': 1}, + \ {'short': 't', 'long': 'targets' , 'fold': 0, 'stl': 1}, + \ ] + let type_cmake.sro = '.' + let type_cmake.kind2scope = { + \ 'f' : 'function', + \ } + let type_cmake.scope2kind = { + \ 'function' : 'f', + \ } + let types.cmake = type_cmake + " Crystal {{{1 + let type_crystal = tagbar#prototypes#typeinfo#new() + let type_crystal.ctagstype = 'crystal' + let type_crystal.kinds = [ + \ {'short' : 'm', 'long' : 'modules', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'c', 'long' : 'classes', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'd', 'long' : 'defs', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'M', 'long' : 'macros', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'l', 'long' : 'libs', 'fold' : 0, 'stl' : 1}, + \ {'short' : 's', 'long' : 'structs', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'a', 'long' : 'aliases', 'fold' : 0, 'stl' : 1} + \ ] + let type_crystal.sro = '::' + let types.crystal = type_crystal " Ctags config {{{1 let type_ctags = tagbar#prototypes#typeinfo#new() let type_ctags.ctagstype = 'ctags' @@ -527,12 +563,28 @@ function! tagbar#types#uctags#init(supported_types) abort " HTML {{{1 let type_html = tagbar#prototypes#typeinfo#new() let type_html.ctagstype = 'html' + let type_html.ctagsargs = [ + \ '--fields=+{roles}', + \ '--extras=+{reference}', + \ '--extras=+F', + \ '-f', + \ '-', + \ '--format=2', + \ '--excmd=pattern', + \ '--fields=nksSafet', + \ '--sort=no', + \ '--append=no', + \ ] let type_html.kinds = [ - \ {'short' : 'a', 'long' : 'named anchors', 'fold' : 0, 'stl' : 1}, - \ {'short' : 'h', 'long' : 'H1 headings', 'fold' : 0, 'stl' : 1}, - \ {'short' : 'i', 'long' : 'H2 headings', 'fold' : 0, 'stl' : 1}, - \ {'short' : 'j', 'long' : 'H3 headings', 'fold' : 0, 'stl' : 1}, - \ ] + \ {'short' : 'a', 'long' : 'named anchors', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'c', 'long' : 'classes', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'C', 'long' : 'stylesheets', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'I', 'long' : 'identifiers', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'J', 'long' : 'scripts', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'h', 'long' : 'H1 headings', 'fold' : 1, 'stl' : 1}, + \ {'short' : 'i', 'long' : 'H2 headings', 'fold' : 1, 'stl' : 1}, + \ {'short' : 'j', 'long' : 'H3 headings', 'fold' : 1, 'stl' : 1}, + \ ] let types.html = type_html " Java {{{1 let type_java = tagbar#prototypes#typeinfo#new() @@ -583,6 +635,31 @@ function! tagbar#types#uctags#init(supported_types) abort \ 'function' : 'f', \ } let types.javascript = type_javascript + + " Kotlin {{{1 + let type_kotlin = tagbar#prototypes#typeinfo#new() + let type_kotlin.ctagstype = 'kotlin' + let type_kotlin.kinds = [ + \ {'short': 'p', 'long': 'packages', 'fold':0, 'stl':0}, + \ {'short': 'c', 'long': 'classes', 'fold':0, 'stl':1}, + \ {'short': 'o', 'long': 'objects', 'fold':0, 'stl':0}, + \ {'short': 'i', 'long': 'interfaces', 'fold':0, 'stl':0}, + \ {'short': 'T', 'long': 'typealiases', 'fold':0, 'stl':0}, + \ {'short': 'm', 'long': 'methods', 'fold':0, 'stl':1}, + \ {'short': 'C', 'long': 'constants', 'fold':0, 'stl':0}, + \ {'short': 'v', 'long': 'variables', 'fold':0, 'stl':0}, + \ ] + let type_kotlin.sro = '.' + " Note: the current universal ctags version does not have proper + " definition for the scope of the tags. So for now we can't add the + " kind2scope / scope2kind for anything until ctags supports the correct + " scope info + let type_kotlin.kind2scope = { + \ } + let type_kotlin.scope2kind = { + \ } + let types.kotlin = type_kotlin + " Lisp {{{1 let type_lisp = tagbar#prototypes#typeinfo#new() let type_lisp.ctagstype = 'lisp' @@ -606,6 +683,36 @@ function! tagbar#types#uctags#init(supported_types) abort \ {'short' : 't', 'long' : 'targets', 'fold' : 0, 'stl' : 1} \ ] let types.make = type_make + " Markdown {{{1 + let type_markdown = tagbar#prototypes#typeinfo#new() + let type_markdown.ctagstype = 'markdown' + let type_markdown.kinds = [ + \ {'short' : 'c', 'long' : 'chapter', 'fold' : 0, 'stl' : 1}, + \ {'short' : 's', 'long' : 'section', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'S', 'long' : 'subsection', 'fold' : 0, 'stl' : 1}, + \ {'short' : 't', 'long' : 'subsubsection', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'T', 'long' : 'l3subsection', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'u', 'long' : 'l4subsection', 'fold' : 0, 'stl' : 1}, + \ ] + let type_markdown.kind2scope = { + \ 'c' : 'chapter', + \ 's' : 'section', + \ 'S' : 'subsection', + \ 't' : 'subsubsection', + \ 'T' : 'l3subsection', + \ 'u' : 'l4subsection', + \ } + let type_markdown.scope2kind = { + \ 'chapter' : 'c', + \ 'section' : 's', + \ 'subsection' : 'S', + \ 'subsubsection' : 't', + \ 'l3subsection' : 'T', + \ 'l4subsection' : 'u', + \ } + let type_markdown.sro = '""' + let type_markdown.sort = 0 + let types.markdown = type_markdown " Matlab {{{1 let type_matlab = tagbar#prototypes#typeinfo#new() let type_matlab.ctagstype = 'matlab' @@ -614,6 +721,23 @@ function! tagbar#types#uctags#init(supported_types) abort \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 0} \ ] let types.matlab = type_matlab + " NRoff {{{1 + let type_nroff = tagbar#prototypes#typeinfo#new() + let type_nroff.ctagstype = 'nroff' + let type_nroff.kinds = [ + \ {'short' : 't', 'long' : 'titles', 'fold' : 0, 'stl' : 1}, + \ {'short' : 's', 'long' : 'sections', 'fold' : 0, 'stl' : 1} + \ ] + let type_nroff.sro = '.' + let type_nroff.kind2scope = { + \ 't' : 'title', + \ 's' : 'section' + \ } + let type_nroff.scope2kind = { + \ 'section' : 't', + \ 'title' : 's' + \ } + let types.nroff = type_nroff " ObjectiveC {{{1 let type_objc = tagbar#prototypes#typeinfo#new() let type_objc.ctagstype = 'objectivec' @@ -688,9 +812,11 @@ function! tagbar#types#uctags#init(supported_types) abort let type_perl.kinds = [ \ {'short' : 'p', 'long' : 'packages', 'fold' : 1, 'stl' : 0}, \ {'short' : 'c', 'long' : 'constants', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'M', 'long' : 'modules', 'fold' : 0, 'stl' : 0}, \ {'short' : 'f', 'long' : 'formats', 'fold' : 0, 'stl' : 0}, \ {'short' : 'l', 'long' : 'labels', 'fold' : 0, 'stl' : 1}, - \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0, 'stl' : 1} + \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'd', 'long' : 'subroutineDeclarations', 'fold' : 0, 'stl' : 0} \ ] let types.perl = type_perl " Perl 6 {{{1 @@ -784,6 +910,36 @@ function! tagbar#types#uctags#init(supported_types) abort \ {'short' : 'v', 'long' : 'function variables', 'fold' : 0, 'stl' : 0}, \ ] let types.r = type_r + " ReStructuredText {{{1 + let type_restructuredtext = tagbar#prototypes#typeinfo#new() + let type_restructuredtext.ctagstype = 'restructuredtext' + let type_restructuredtext.kinds = [ + \ {'short' : 'c', 'long' : 'chapter', 'fold' : 0, 'stl' : 1}, + \ {'short' : 's', 'long' : 'section', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'S', 'long' : 'subsection', 'fold' : 0, 'stl' : 1}, + \ {'short' : 't', 'long' : 'subsubsection', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'T', 'long' : 'l3subsection', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'u', 'long' : 'l4subsection', 'fold' : 0, 'stl' : 1}, + \ ] + let type_restructuredtext.kind2scope = { + \ 'c' : 'chapter', + \ 's' : 'section', + \ 'S' : 'subsection', + \ 't' : 'subsubsection', + \ 'T' : 'l3subsection', + \ 'u' : 'l4subsection', + \ } + let type_restructuredtext.scope2kind = { + \ 'chapter' : 'c', + \ 'section' : 's', + \ 'subsection' : 'S', + \ 'subsubsection' : 't', + \ 'l3subsection' : 'T', + \ 'l4subsection' : 'u', + \ } + let type_restructuredtext.sro = '""' + let type_restructuredtext.sort = 0 + let types.rst = type_restructuredtext " REXX {{{1 let type_rexx = tagbar#prototypes#typeinfo#new() let type_rexx.ctagstype = 'rexx' @@ -928,6 +1084,35 @@ function! tagbar#types#uctags#init(supported_types) abort \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0, 'stl' : 1} \ ] let types.tcl = type_tcl + " TypeScript {{{1 + let type_ts = tagbar#prototypes#typeinfo#new() + let type_ts.ctagstype = 'typescript' + let type_ts.kinds = [ + \ {'short' : 'n', 'long' : 'namespaces', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'i', 'long' : 'interfaces', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'g', 'long' : 'enums', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'e', 'long' : 'enumerations', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'c', 'long' : 'classes', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'C', 'long' : 'constants', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'p', 'long' : 'properties', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 1}, + \ {'short' : 'm', 'long' : 'methods', 'fold' : 0, 'stl' : 1}, + \ ] + let type_ts.sro = '.' + let type_ts.kind2scope = { + \ 'c' : 'class', + \ 'i' : 'interface', + \ 'g' : 'enum', + \ 'n' : 'namespace', + \ } + let type_ts.scope2kind = { + \ 'class' : 'c', + \ 'interface' : 'i', + \ 'enum' : 'g', + \ 'namespace' : 'n' + \ } + let types.typescript = type_ts " LaTeX {{{1 let type_tex = tagbar#prototypes#typeinfo#new() let type_tex.ctagstype = 'tex' @@ -940,7 +1125,8 @@ function! tagbar#types#uctags#init(supported_types) abort \ {'short' : 'b', 'long' : 'subsubsections', 'fold' : 0, 'stl' : 1}, \ {'short' : 'P', 'long' : 'paragraphs', 'fold' : 0, 'stl' : 0}, \ {'short' : 'G', 'long' : 'subparagraphs', 'fold' : 0, 'stl' : 0}, - \ {'short' : 'l', 'long' : 'labels', 'fold' : 0, 'stl' : 0} + \ {'short' : 'l', 'long' : 'labels', 'fold' : 0, 'stl' : 0}, + \ {'short' : 'f', 'long' : 'frames', 'fold' : 0, 'stl' : 1} \ ] let type_tex.sro = '""' let type_tex.kind2scope = { diff --git a/bundle/tagbar/doc/tagbar.txt b/bundle/tagbar/doc/tagbar.txt index 0efcf37d0..9b36754dd 100644 --- a/bundle/tagbar/doc/tagbar.txt +++ b/bundle/tagbar/doc/tagbar.txt @@ -2,8 +2,8 @@ Author: Jan Larres Licence: Vim licence, see |license| -Homepage: http://majutsushi.github.com/tagbar/ -Version: 2.7 +Homepage: https://preservim.github.io/tagbar +Version: 3.0.0 ============================================================================== Contents *tagbar* *tagbar-contents* @@ -103,6 +103,10 @@ The following features are supported by Tagbar: Fortran, HTML, Java, JavaScript, Lisp, Lua, Make, MatLab, OCaml, Pascal, Perl, PHP, Python, REXX, Ruby, Scheme, Shell script, SLang, SML, SQL, Tcl, Tex, Vera, Verilog, VHDL, Vim and YACC. + - Additional languages are supported through universal-ctags, including + CUDA, R, Rust, Go, and many others. See + https://github.com/universal-ctags/ctags/blob/master/docs/news.rst#new-parsers + for the complete list. - Can be extended to support arbitrary new types. ------------------------------------------------------------------------------ @@ -123,12 +127,13 @@ The following requirements have to be met in order to be able to use tagbar: - Vim 7.0 or higher. Older versions will not work since Tagbar uses data structures that were only introduced in Vim 7. - - Exuberant ctags 5.5 or higher. Ctags is the program that generates the - tag information that Tagbar uses. It is shipped with most Linux - distributions, otherwise it can be downloaded from the following - website: + - At a minimum Exuberant Ctags >= 5.5, or (highly recommended) any version + of Universal Ctags which is a currently maintained fork of Exuberant Ctags + with many bugfixes, support for many more formats, and proper Unicode + support. Some additional formats can also be handled by other providers + such as jsctags, phpctags, or others. - http://ctags.sourceforge.net/ + Universal Ctags can be downloaded from https://ctags.io/ Tagbar will work on any platform that ctags runs on -- this includes UNIX derivatives, Mac OS X and Windows. Note that other versions like @@ -179,16 +184,16 @@ There are essentially two ways to use Tagbar: Opening and closing the Tagbar window~ Use |:TagbarOpen| or |:TagbarToggle| to open the Tagbar window if it is closed. By default the window is opened on the right side, set the option -|g:tagbar_left| to open it on the left instead. If the window is already open, +|g:tagbar_position| to open it elsewhere instead. If the window is already open, |:TagbarOpen| will jump to it and |:TagbarToggle| will close it again. |:TagbarClose| will simply close the window if it is open. It is probably a good idea to assign a key to these commands. For example, put this into your |vimrc|: > - nnoremap :TagbarToggle + nnoremap :TagbarToggle < -You can then open and close Tagbar by simply pressing the key. +You can then open and close Tagbar by simply pressing the key. You can also use |:TagbarOpenAutoClose| to open the Tagbar window, jump to it and have it close automatically on tag selection regardless of the @@ -207,6 +212,10 @@ by moving the cursor to a tag and pressing or double-clicking on it with the mouse. The source file will then move to the definition and put the cursor in the corresponding line. This won't work for pseudo-tags. +If the current line of the tagbar window is not on a tag, for example on the +'functions' tag-kind and is hit, then that tag-kind will be folded or +unfolded if possible. + Sorting~ You can sort the tags in the Tagbar window in two ways: by name or by file order. Sorting them by name simply displays the tags in their alphabetical @@ -261,9 +270,11 @@ COMMANDS *tagbar-commands* :TagbarClose *:TagbarClose* Close the Tagbar window if it is open. -:TagbarToggle *:TagbarToggle* -:Tagbar +:TagbarToggle [{flags}] *:TagbarToggle* +:Tagbar [{flags}] Open the Tagbar window if it is closed, or close it if it is open. + Additional behaviour can be specified with the same optional {flags} + argument as :TagbarOpen. :TagbarOpenAutoClose *:TagbarOpenAutoClose* Open the Tagbar window, jump to it and close it on tag selection. This is @@ -284,9 +295,9 @@ COMMANDS *tagbar-commands* Open the parent folds of the current tag in the file window as much as needed for the tag to be visible in the Tagbar window. -:TagbarCurrentTag [{flags}] *:TagbarCurrentTag* - Echo the current tag in the command line. For {flags} see - |tagbar-statusline|. +:TagbarCurrentTag [{flags} [{search-method}]] *:TagbarCurrentTag* + Echo the current tag in the command line. For {flags} and {search-method} + see |tagbar-statusline|. :TagbarGetTypeConfig {filetype} *:TagbarGetTypeConfig* Paste the Tagbar configuration of the vim filetype {filetype} at the @@ -306,72 +317,194 @@ COMMANDS *tagbar-commands* :TagbarDebugEnd *:TagbarDebugEnd* End debug mode, debug messages will no longer be written to the logfile. +:TagbarForceUpdate *:TagbarForceUpdate* + Forcefully update a file even if it exceeds the |g:tagbar_file_size_limit| + value. This will only work for one invocation of the file processing. + After the file is processed and tags are generated, then it will re-enable + the file size limit. So if the file is written and needs to be processed + again, this command will need to be re-executed. + +:TagbarJump *:TagbarJump* + Jump to the tag under the cursor. This only works while the cursor is in + the tagbar window. This will leave the cursor in the tagbar window. It is + the same behavior as the |p| key mapping. + + This command will call the |tagbar#jump()| function. + +:TagbarJumpPrev *:TagbarJumpPrev* + Jump to the previous tag under the cursor. This works in the file window. + This will search for the previous {'nearest-stl'} type tag starting at the + line just before the current line and do a backwards search. + + This command will call the |tagbar#jumpToNearbyTag(-1)| function. + +:TagbarJumpNext *:TagbarJumpNext* + Jump to the next tag under the cursor. This works in the file window. + This will search for the next {'nearest-stl'} type tag starting at the + line just after the current line and do a forward search. + + This command will call the |tagbar#jumpToNearbyTag(1)| function. + +------------------------------------------------------------------------------ +FUNCTIONS *tagbar-functions* + +*tagbar#StopAutoUpdate()* + Remove autocommands that might have been installed to automatically + update tag information. This should be called after you have used + |tagbar#currenttag| manually. + +*tagbar#GetTagNearLine()* + Get the current tag near the specified line number (lnum). Optionally + takes a fmt and signature specification using the same method as the + |tagbar#currenttag()| function. Defaults to GetTagNearLine(lnum, '%s', ''). + + This could be used in a custom foldtext function to show the current tag + the fold current fold is located in. + + This function can also take in a search method similar to the + |tagbar#currenttag()| function. Full syntax is as follows: + tagbar#GetTagNearLine(lnum [, {fmt}, {flags} [, {search-method}]]) + + Example: > + set foldtext=MyFoldFunc() + function! MyFoldFunc() + let tag = tagbar#GetTagNearLine(v:foldend, '%s', 'p') + let lines = v:foldend - v:foldstart + 1 + return tag . ' --- ' . lines . ' lines' + endfunction +< +*tagbar#ForceUpdate()* + Forcefully update a file even if it exceeds the |g:tagbar_file_size_limit| + value. This also clears the internal flags to the file will be re-examined + again. + +*tagbar#printfileinfo()* + This function is used in conjunction with |TagbarDebug| and will print all + the known tags into the tagbar debug logfile. This is useful for looking + at the internal tag information that tagbar tracks. + +*tagbar#IsOpen()* + This function will return 1 if the tagbar window is open, else it will + return 0. + +*tagbar#jump()* + Jump to the tag under the cursor. This only works while the cursor is in + the tagbar window. This will leave the cursor in the tagbar window. It is + the same behavior as the |p| key mapping. + + This is the function called when using the |:TagbarJump| command. + +*tagbar#jumpToNearbyTag()* + This function will jump to the next tag or previous tag starting a search + from the line under the cursor. This works when in the file window instead + of inside the tagbar window like the |tagbar#jump()| function. + + The direction of search must be provided. If the [direction] is greater + than 0, then it will do a forward search. If the [direction] is less + than 0, then it will do a backward search. + + Can also optionally provide a [search_method] which is used in the + |tagbar#GetTagNearLine()| function call and behaves the same way. This + will default to *'nearest-stl'* if not specified. + + Can optionally provide a flags field [flags] to control the nearby tag + jumping. The flags should be a string of characters with the following + meanings: + 's' - use the |g:tagbar_scroll_off| setting when jumping + + Full syntax: + tagbar#jumpToNearbyTag(direction [, {search-method} [, {flags}]]) + + Examples: +> + " These keymaps will jump to the next/prev tag that can be scoped. Ex: + " function calls, class definitions, etc. + nnoremap t] :call tagbar#jumpToNearbyTag(1) + nnoremap t[ :call tagbar#jumpToNearbyTag(-1) + + " These keymaps will jump to the next/prev tag regardless of type. Ex: + " function calls, class definitions, variable definitions, typedefs, etc. + nnoremap t] :call tagbar#jumpToNearbyTag(1, 'nearest') + nnoremap t[ :call tagbar#jumpToNearbyTag(-1, 'nearest') + + " These keymaps will jump to the next/prev tag regardless of type, and + " will also use the jump_offset configuration to position the cursor + nnoremap t] :call tagbar#jumpToNearbyTag(1, 'nearest', 's') + nnoremap t[ :call tagbar#jumpToNearbyTag(-1, 'nearest', 's') +< + ------------------------------------------------------------------------------ KEY MAPPINGS *tagbar-keys* The following mappings are valid in the Tagbar window: /? Display key mapping help. - Map option: tagbar_map_help -/ Jump to the tag under the cursor. Doesn't work for pseudo-tags - or generic headers. - Map option: tagbar_map_jump + Map option: |tagbar_map_help| +/ Jump to the tag under the cursor. Doesn't work for pseudo-tags. + If on generic header, it will fold/unfold that header. + Map option: |tagbar_map_jump| p Jump to the tag under the cursor, but stay in the Tagbar window. - Map option: tagbar_map_preview + Map option: |tagbar_map_preview| P Open the tag in a |preview-window|. - Map option: tagbar_map_previewwin + Map option: |tagbar_map_previewwin| When on a fold icon, open or close the fold depending on the current state. <2-LeftMouse> Same as . See |g:tagbar_singleclick| if you want to use a single- instead of a double-click. Go to the next top-level tag. - Map option: tagbar_map_nexttag + Map option: |tagbar_map_nexttag| Go to the previous top-level tag. - Map option: tagbar_map_prevtag + Map option: |tagbar_map_prevtag| Display the prototype of the current tag (i.e. the line defining it) in the command line. - Map option: tagbar_map_showproto + Map option: |tagbar_map_showproto| v Hide tags that are declared non-public. Tags without any visibility information will still be shown. - Map option: tagbar_map_hidenonpublic + Map option: |tagbar_map_hidenonpublic| +/zo Open the fold under the cursor. - Map option: tagbar_map_openfold + 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 + 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 + Map option: |tagbar_map_togglefold| */zR Open all folds by setting foldlevel to 99. - Map option: tagbar_map_openallfolds + Map option: |tagbar_map_openallfolds| =/zM Close all folds by setting foldlevel to 0. - Map option: tagbar_map_closeallfolds + Map option: |tagbar_map_closeallfolds| zr Increase the fold level of the buffer by 1. Opens all folds one level. - Map option: tagbar_map_incrementfolds + Map option: |tagbar_map_incrementfolds| zm Decrease the fold level of the buffer by 1. Closes all folds one level. - Map option: tagbar_map_decrementfolds + Map option: |tagbar_map_decrementfolds| zj Go to the start of the next fold, like the standard Vim |zj|. - Map option: tagbar_map_nextfold + Map option: |tagbar_map_nextfold| zk Go to the end of the previous fold, like the standard Vim |zk|. - Map option: tagbar_map_prevfold + Map option: |tagbar_map_prevfold| s Toggle sort order between name and file order. - Map option: tagbar_map_togglesort + Map option: |tagbar_map_togglesort| c Toggle the |g:tagbar_autoclose| option. - Map option: tagbar_map_toggleautoclose + Map option: |tagbar_map_toggleautoclose| +t Toggle the pause (like :TagbarTogglePause) + Map option: |tagbar_map_togglepause| x Toggle zooming the window. - Map option: tagbar_map_zoomwin + Map option: |tagbar_map_zoomwin| q Close the Tagbar window. - Map option: tagbar_map_close + 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": +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" < +Alternatively, if you want to disable this mapping, then set to '': +> + let g:tagbar_map_togglesort = '' +< See |key-notation| for how to write special keys like or the keypad keys. @@ -390,10 +523,56 @@ Example: let g:tagbar_ctags_bin = 'C:\Ctags5.8\ctags.exe' < + *g:tagbar_ctags_options* +g:tagbar_ctags_options +Default: undefined + +Use this option to specify a list of filenames to pass to ctags with the +'--options' flag. This is similar to the deffile key for tagbar type +extensions, see |tagbar-extend|, but acts globally. The special value 'NONE' +as the first entry disables reading of the default configuration files (e.g. +~/.ctags). Without this, if ~/.ctags and other files listed in +g:tagbar_ctags_options include some of the same patterns, tagbar might show +duplicate entries. + +Example: +> + let g:tagbar_ctags_options = ['NONE', split(&rtp,",")[0].'/ctags.cnf'] + +This causes ctags to use settings from ~/.vim/ctags.cnf, ignoring other +configuration files. + + + *g:tagbar_position* +g:tagbar_position~ +Default: 'botright vertical' + +By default the Tagbar window will be opened on the right-hand side of vim in a +vertical split. Set this option to one of the standart vim split options such +as 'topleft', 'botright', 'leftabove', or 'rightbelow' to open in the +corresponding position instead. If desiring a vertically split window, then +include a ' vertical' in the field value as well. This can be useful when +activating Tagbar at the same time as another plugin which creates a new +window. It allows for more granular control of the Tagbar position in +relation to the current active window. + +If using a vertical split, |g:tagbar_width| will be used to determine the +window width for the tagbar window. Else |g:tagbar_height| will be used to +determine the window height for the tagbar window. + +See |split| for more details on window positioning. + +Example: +> + let g:tagbar_position = 'leftabove' +< *g:tagbar_left* g:tagbar_left~ Default: 0 +This option has been superceded by |g:tagbar_position| instead. It has been left +around for backward compatibility. + By default the Tagbar window will be opened on the right-hand side of vim. Set this option to open it on the left instead. @@ -409,6 +588,9 @@ Example: g:tagbar_vertical~ Default: 0 +This option has been superceded by |g:tagbar_height| instead. It has been left +around for backward compatibility. + If this is set to a positive value then the Tagbar window will be opened at the top or bottom of the Vim window instead of at the side. This can be useful for monitors that have been rotated into a vertical position. The value of @@ -420,15 +602,32 @@ Example: let g:tagbar_vertical = 30 < + *g:tagbar_height* +g:tagbar_height~ +Default: 0 + +If |g:tagbar_position| does not include a 'vertical' option, then this +value is used to determine the height of the Tagbar window. + +Example: +> + let g:tagbar_height = 30 +< + *g:tagbar_width* g:tagbar_width~ Default: 40 -Width of the Tagbar window in characters. +If |g:tagbar_position| does include a 'vertical' options, then this value is +used to determine the width of the Tagbar window in characters. This value can +also be set using the |winwidth(0)| function call to calculate a dynamic value +to make the tagbar width relative to a percentage of the vim window size as +seen in the example below that will open the tagbar window to 20 percent of +the window width with a limit of no less than 25 characters. Example: > - let g:tagbar_width = 30 + let g:tagbar_width = max([25, winwidth(0) / 5]) < *g:tagbar_zoomwidth* @@ -507,11 +706,24 @@ Setting this option will result in Tagbar omitting the short help at the top of the window and the blank lines in between top-level scopes in order to save screen real estate. +Possible values are: + 0: Show short help and blank lines between top-level scopes + 1: Don't show the short help or the blank lines. + 2: Don't show the short help but show the blank lines. + Example: > let g:tagbar_compact = 1 < + *g:tagbar_help_visibility* +g:tagbar_help_visibility~ +Default: 0 +Setting this option will cause the full help information to be displayed all +the time in the tagbar window. +> + let g:tagbar_help_visibility = 1 +< *g:tagbar_indent* g:tagbar_indent~ Default: 2 @@ -524,6 +736,32 @@ Example: let g:tagbar_indent = 1 < + *g:tagbar_show_balloon* +g:tagbar_show_balloon~ +Default: 1 + +Whether balloon messages should be shown in the Tagbar window. + +Possible values are: + 0: Don't show any balloon messages. + 1: Show balloon messages. This is only available in the GUI when + compiled with the |+balloon_eval| feature. + +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 @@ -535,7 +773,21 @@ Example: > let g:tagbar_show_visibility = 0 < + *g:tagbar_visibility_symbols* +g:tagbar_visibility_symbols +Default: { 'public' : '+', 'protected' : '#', 'private' : '-' } +Symbols to use for visibility (public/protected/private) to the left of the tag +name. See |g:tagbar_show_visibility|. + +Example: +> + let g:tagbar_visibility_symbols = { + \ 'public' : '+', + \ 'protected' : '#', + \ 'private' : '-' + \ } +< *g:tagbar_show_linenumbers* g:tagbar_show_linenumbers~ Default: 0 @@ -552,7 +804,35 @@ Example: > let g:tagbar_show_linenumbers = 2 < + *g:tagbar_show_tag_linenumbers* +g:tagbar_show_tag_linenumbers~ +Default: 0 +This option allows printing the tag line number next to the tag in the tagbar +window. It can be set to the following values: + 0 - The line number will not be printed + 1 - The line number will be printed to the right of the tag > + Example: function1(int i) [123] +< + 2 - The line number will be printed to the left of the tag > + Example: [123] function1(int i) +< +Example: +> + let g:tagbar_show_tag_linenumbers = 1 +< + *g:tagbar_show_tag_count* +g:tagbar_show_tag_count~ +Default: 0 + +This option allows showing the tag count next to the tag kind in the tagbar +window. This will show up like this > + > functions () +< +Example: +> + let g:tagbar_show_tag_count = 1 +< *g:tagbar_hide_nonpublic* g:tagbar_hide_nonpublic~ Default: 0 @@ -621,6 +901,38 @@ just choose other characters in that case): let g:tagbar_iconchars = ['▸', '▾'] let g:tagbar_iconchars = ['▷', '◢'] let g:tagbar_iconchars = ['+', '-'] (default on Windows) +< + *g:tagbar_scopestrs* +g:tagbar_scopestrs~ +Default: {} + +Setting to replace a tag's scope with a user-specified string in Tagbar's +display. If a scope is found in the keys of |g:tagbar_scopestrs|, then the +scope will be displayed as the corresponding value. If the scope is not +found, then the scope will be displayed as normal. + +Example (don't worry if some of the characters aren't displayed correctly, +just choose other characters or strings in that case): +> + let g:tagbar_scopestrs = { + \ 'class': "\uf0e8", + \ 'const': "\uf8ff", + \ 'constant': "\uf8ff", + \ 'enum': "\uf702", + \ 'field': "\uf30b", + \ 'func': "\uf794", + \ 'function': "\uf794", + \ 'getter': "\ufab6", + \ 'implementation': "\uf776", + \ 'interface': "\uf7fe", + \ 'map': "\ufb44", + \ 'member': "\uf02b", + \ 'method': "\uf6a6", + \ 'setter': "\uf7a9", + \ 'variable': "\uf71b", + \ } + + < *g:tagbar_autoshowtag* @@ -718,14 +1030,27 @@ default statusline: > function! TagbarStatusFunc(current, sort, fname, flags, ...) abort let colour = a:current ? '%#StatusLine#' : '%#StatusLineNC#' - let flagstr = join(flags, '') + let flagstr = join(a:flags, '') if flagstr != '' let flagstr = '[' . flagstr . '] ' endif - return colour . '[' . sort . '] ' . flagstr . fname + return colour . '[' . a:sort . '] ' . flagstr . a:fname endfunction let g:tagbar_status_func = 'TagbarStatusFunc' < + *g:tagbar_no_status_line* +g:no_status_line~ +Default: undefined + +This option will prevent any status line updates being done by Tagbar. Use +this in the event where another plugin is being used to update the status +line. If |g:tagbar_status_func| is set, then that function will never be +called. + +Example: +> + let g:no_status_line = 1 +< *g:tagbar_silent* g:tagbar_silent~ @@ -738,6 +1063,231 @@ Example: > let g:tagbar_silent = 1 < + *g:tagbar_use_cache* +g:tagbar_use_cache~ +Default: 1 + +By default the file contents are passed to ctags by writing them to +a temporary file and invoking ctags on that file. This greatly speeds up tag +generation in the event of slow file systems such as network shares and +enables tagbar to run even on netrw virtual files that ctags would otherwise +not be able to find at all. However it does incure the cost of an extra write +operation. Additionally not all sysems are able to let programs share access +to temporary file space (for example Snap packages cannot read from the host +system's temp file space). This setting can disable the cache mechanism +entriely forcing the tags to be generated from the existing copy of the file +on disk rather than the current buffer written to a temporary file. + +Example: +> + let g:tagbar_use_cache = 0 +< + + *g:tagbar_file_size_limit* +g:tagbar_file_size_limit~ +Default: 0 + +By default, all files are processed by tagbar. Setting this value to non-zero +will disable processing for any file with a byte count greater than +|g:tagbar_file_size_limit|. A message will be displayed once for a given buffer +if the limit is exceeded. The file can be forcefully updated with the +|tagbar#ForceUpdate()| function or with the |:TagbarForceUpdate| command. If +the value is set to 0, then the file will always be processed. + +Example: +> + let g:tagbar_file_size_limit = 10000 +< + + *g:tagbar_wrap* +g:tagbar_wrap~ +Default: 0 + +Possible Values: + 0 Disable line wrapping. + 1 Enable the |wrap| option and also enable the |linebreak| option to + split the lines on word boundaries. This will use the default + |breakat| setting in vim. Note: This can cause possible display issues + with tags that exceed the tagbar window width. A very long tag name + will cause the tag itself to wrap resulting in an empty line and + indentation of the tag (see example below). + 2 Enable the |wrap| option but disable the |linebreak| option. This will + split the lines at the end of the tagbar window and can cause it to + wrap in the middle of a word. This should be used if there are tags + that are regularly longer than the tagbar window width. + +This also will use the |breakindent| and |breakindentopt| options in vim to +set the indentation of the wrapped lines. + +Note: This requires VIM to be compiled with the |+linebreak| option for the +wrap intentation to function. + +Examples: +> + " Wrap with linebreak - note the wrap works on word boundaries, but + " a very long tag name does cause an odd display issue. + let g:tagbar_wrap = 1 + +-------------------------------------------+ + | ⯆ functions (106) | + | s:add_tag_recursive(parent,taginfo, | + | pathlist) : function! | + | s:AutoUpdate(fname,force,...) : | + | function! | + | | + | s:SomeReallyLongTagNameThatWillExc| + | eedWindowWidth : function! | + +-------------------------------------------+ + + " Wrap without linbreak - note the display issue is gone for the + " really long tag name, but the other wraps will breakup words. + let g:tagbar_wrap = 2 + +-------------------------------------------+ + | ⯆ functions (106) | + | s:add_tag_recursive(parent,taginfo,pat| + | hlist) : function! | + | s:AutoUpdate(fname,force,...) : functi| + | on! | + | s:SomeReallyLongTagNameThatWillExceedW| + | indowWidth : funciton! | + +-------------------------------------------+ +< + *g:tagbar_no_autocmds* +g:tagbar_no_autocmds~ +Default: 0 + +If set to non-zero, tagbar will not enable any autocmds. Note: This greatly +limits what tagbar can do. When activated, it will generate the tags once and +display the contents once. You can use |:TagbarForceUpdate| to manually update +the tagbar window if this is activated. There will only be two autocmds +created in the tagbar autocmd group to handle closing the tagbar window +automatically on the QuitPre event. + +Example: +> + let g:tagbar_no_autocmds = 1 +< + *g:tagbar_scrolloff* +g:tagbar_scrolloff~ +Default: 0 + +If set to non-zero, the tagbar window initialization will set the |scrolloff| +value local to the tagbar window to the specified value. This is used to +position the current tag in the tagbar window. See the help for |scrolloff| +for more details. If set to a very high value (greater than the height of the +tagbar window), then the current tag should always stay in the center of the +tagbar window. + +Example: +> + let g:tagbar_scrolloff = 10 +< + *g:tagbar_jump_offset* +g:tagbar_jump_offset~ +Default: 0 + +This value can be used to control the jump offset positioning. When jumping to +a tag from the tagbar window, the tag will appear |g:tagbar_jump_offset| lines +above or below the center of the window. For example, if set to 10 and you +jump to a tag, the tag will appear 10 lines above the center of the window. +This can also be set to a negative value if you want the tag jump location to +be below the center of the window. + +If set to greater than |winheight|() then the tag will always appear at the +top of the screen. If set to less than -|winheight|(), then the tag will +always appear at the bottom of the screen. + +Examples: +> + " Set the tag jump location to appear at the top + let g:tagbar_jump_offset = 999 + + " Set the tag jump locaiton to appear at the bottom + let g:tagbar_jump_offset = -999 + + " Set the tag jump location to appear 25% from the top + let g:tagbar_jump_offset = winheight(0) / 4 +< + *g:tagbar_jump_lazy_scroll* +g:tagbar_jump_lazy_scroll~ +Default: 0 + +If set to non-zero, a jump to a tag will only scroll the window if the +tag is not already visible in the window. In other words, when jumping to +a tag that is already visible, the cursor will simply be placed on the line +containing the tag without scrolling the window. If the tag is not visible +in the window then the window will be scrolled and the tag (and cursor) +placed in the location dictated by |g:tagbar_jump_offset|. + + *g:tagbar_highlight_follow_insert* +g:tagbar_highlight_follow_insert~ +Default: 0 + +If set to non-zero, the highlight of the current tag in the Tagbar will follow +the cursor in insert mode as well, after a short pause once the cursor stops +moving. Enabling this option may introduce some lag during the input, so it is +disabled by default. + +Example: +> + let g:tagbar_highlight_follow_insert = 1 +< + *g:tagbar_highlight_method* +g:tagbar_highlight_method~ +Default: 'nearest-stl' + +This configuration controls how the tag highlighting works in the tagbar +window. The possible values are: + 'nearest-stl' - Highlight the nearest tag that is defined with the + {stl} option + 'scoped-stl' - Highlight the nearest tag defined with the {stl} flag + in the kind definition, also taking into account the + scope. + 'nearest' - Highlight the nearest tag regardless of the type or + flags. This was the behavior prior to the introduction + of the 'scoped-stl' idea. If you want to revert to the + old method, set |g:tagbar_highlight_method| to + 'nearest'. + +Use case example: Consider the following example. If the cursor is at line +#10, then the highlight method will behave differently in each case. If set to +'nearest-stl', the tag for some_function() will be highlighted. If set to +'scoped-stl', the tag for 'class A' will be highlighted. If set to 'nearest', +then the tag for 'SOME_MACRO' will be highlighted. + +If the cursor is moded to line #8, then both 'nearest-stl' and 'scoped-stl' +will highlight the tag for 'some_function()'. The 'nearest' method will +highlight the 'SOME_MACRO' tag. +> + 1 class A { + 2 + 3 int some_function(int arg) { + 4 int var1; + 5 int var2; + 6 #define SOME_MACRO 1 + 7 ... + 8 printf("..."); + 9 } + 10 + 11 int another_function(int arg) { + 12 int varA; + 13 printf("###"); + 14 } + 15 } +< +Example: > + let g:tagbar_highlight_method = 'nearest' +< + *g:tagbar_ignore_anonymous* +g:tagbar_ignore_anonymous~ +Default: 0 + +If set, any '__anon' tags generated by ctags will be ignored and will not be +displayed in the tagbar window. Note: this will also mean any child tags of +that anonymous tag will also not be visible. + +Example: > + let g:tagbar_ignore_anonymous = 1 +< ------------------------------------------------------------------------------ HIGHLIGHT COLOURS *tagbar-highlight* @@ -760,6 +1310,9 @@ TagbarScope TagbarType The type of a tag or scope if available. +TagbarTagLineN + The source line number displayed to the right of each tag entry. + TagbarSignature Function signatures. @@ -844,7 +1397,7 @@ read |tagbar-extend| (especially the "kinds" entry) on how to do that. The function has the following signature: -tagbar#currenttag({format}, {default} [, {flags}]) +tagbar#currenttag({format}, {default} [, {flags} [, {search-method}]]) {format} is a |printf()|-compatible format string where "%s" will be replaced by the name of the tag. {default} will be displayed instead of the format string if no tag can be found. @@ -859,14 +1412,52 @@ tagbar#currenttag({format}, {default} [, {flags}]) useful in cases where ctags doesn't report some information, like the signature. Note that this can get quite long. + The optional {search-method} argument specified how to search for the + nearest tag. Valid options are: + 'nearest' This will look for the closest tag above the current line + regardless of type. This will match even one line tags or + other tags not defined with the {stl} flag in their kind + definition. This is the quickest option, but least + accurate. + 'nearest-stl' This will look for the closest tag above the current line + which is defined with the {stl} flag in its kind + definition. This is a little slower, but provides a little + more context and accuracy. + 'scoped-stl' This will look for the closest tag above the current line + taking scope into account as well as the {stl} flag. The + scope is determined by the ctags 'end' field. This is the + slowest of the options as when outside of a function + scope, it could end up searching all the way to the top of + the file for the nearest scoped tag (or possibly none if + not in any scope at all). For example, if you put the following into your statusline: > %{tagbar#currenttag('[%s] ','')} -< then the function "myfunc" will be shown as "[myfunc()] ". +< then the function "myfunc" will be shown as "[myfunc()] ". + As another example, we can use the following in our status line to find + the current scoped tag and also print the full path when found: > + %{tagbar#currenttag('%s', '', 'f', 'scoped-stl')} +< then the function "myfunc" within class "myclass" will be shown as + "myclass::myfunc()". But when outside of the function, it will be shown as + "myclass" +Additionally you can show the kind (type) of the current tag, using following +function: + +tagbar#currenttagtype({format}, {default}) + {format} and {default} are treated in the same way as for + tagbar#currenttag function. + + Altering previous example, like below: > + %{tagbar#currenttag('[%s] ','')}\ %{tagbar#currenttagtype("(%s) ", '') +< the function "myfunc" will be shown as "[myfunc()] (function)". Note that if there is an error when processing the current file no error message will be shown in order to not disrupt the statusline. If the function doesn't seem to work right open the Tagbar window to see any error messages. +Note you should call |tagbar#StopAutoUpdate| manually in case you do not want +to display the current tag anymore. Otherwise the autocommands to update the +state are being executed all the time still. + ------------------------------------------------------------------------------ IGNORING SPECIFIC FILES *tagbar-ignore* @@ -908,7 +1499,7 @@ support package for the language. Some tips on how to write such a program are given at the end of this section. Before writing your own extension have a look at the wiki -(https://github.com/majutsushi/tagbar/wiki) or try googling for existing ones. +(https://github.com/preservim/tagbar/wiki) or try googling for existing ones. If you do end up creating your own extension please consider adding it to the wiki so that others can benefit from it, too. @@ -942,7 +1533,26 @@ kinds: A list of the "language kinds" that should be listed in Tagbar, "f:functions:1" < would list all the function definitions in a file under the header "functions", fold them, and implicitly show them in the statusline - if tagbar#currenttag() is used. + if tagbar#currenttag() is used. The {stl} field is also used to + determine tag that are considered for scoped highlighting in the + tagbar window. By default, whenever the cursor is on a line + containing a known tag, then that tag will be highlighted in the + tagbar window. However if the cursor is not on a line containing a + tag, then only tags of a type that has {stl} set to 1 will be + highlighted. For example, in C the "macro" type has an {stl} value + of 0. So if there is a macro defined within the scope of a + function such as this: +> + int function1(int arg) { + #define BUF_LENGTH 10 + char buffer[BUF_LENGTH + 1]; + snprintf(buffer, BUF_LENGTH, "some string"); + } +< + Then when the cursor is on the #define line, then that macro will + be highlighted in the tagbar window. However if the cursor was on + the snprintf() line, then the tag for function1() would be + highlighted. sro: The scope resolution operator. For example, in C++ it is "::" and in Java it is ".". If in doubt run ctags as shown below and check the output. @@ -962,7 +1572,7 @@ kind2scope: A dictionary describing the mapping of tag kinds (in their int var; }; < We then run ctags in the following way: > - ctags -f - --format=2 --excmd=pattern --extra= --fields=nksaSmt test.cpp + ctags -f - --format=2 --excmd=pattern --extras= --fields=nksaSmt test.cpp < Then the output for the variable "var" would look like this: > var tmp.cpp /^ int var;$/;" kind:m line:11 class:Foo access:private < This shows that the scope name for an entry in a C++ class is @@ -1266,10 +1876,12 @@ try running ctags manually to see whether ctags reports the wrong information or whether that information is correct and Tagbar does something wrong. To run ctags manually execute the following command in a terminal: > - ctags -f - --format=2 --excmd=pattern --extra= --fields=nksaSmt myfile + ctags -f - --format=2 --excmd=pattern --extras= --fields=nksaSmt myfile < If you set the |g:tagbar_ctags_bin| variable you probably have to use the same -value here instead of simply "ctags". +value here instead of simply "ctags". Also, if you use +|:tagbar_ctags_options|, you should include the equivalent --options flag in +the call to ctags. If something more fundamental isn't working right then try running the |:messages| command to see if Tagbar printed any error messages that might @@ -1357,6 +1969,14 @@ Known issues~ ============================================================================== 8. History *tagbar-history* +3.0.0 (2021-01-21) + - Massive rollup with years of small changes, see `git log v2.7..v3.0.0` + - New upstream project namespace (Preservim) and maintainers + - Deprecate Exuberant Ctags, primarily support Universal Ctags + - Add lots of configuration options (see `:help tagbar`) + - Add utility functions to ease integration with other plugins + - Support many new filetypes out of the box + 2.7 (2017-01-09) - Added support for Universal Ctags, courtesy of Dmytro Konstantinov - Added option to arrange Tagbar window vertically diff --git a/bundle/tagbar/plugin/tagbar.vim b/bundle/tagbar/plugin/tagbar.vim index 9eee0d0e6..72439651b 100644 --- a/bundle/tagbar/plugin/tagbar.vim +++ b/bundle/tagbar/plugin/tagbar.vim @@ -3,8 +3,8 @@ " 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: 2.7 +" Website: https://preservim.github.io/tagbar +" Version: 3.0.0 " Note: This plugin was heavily inspired by the 'Taglist' plugin by " Yegappan Lakshmanan and uses a small amount of code from it. " @@ -20,7 +20,7 @@ scriptencoding utf-8 -if &cp || exists('g:loaded_tagbar') +if &compatible || exists('g:loaded_tagbar') finish endif @@ -49,10 +49,39 @@ function! s:init_var(var, value) abort endfunction function! s:setup_options() abort - if !exists('g:tagbar_vertical') || g:tagbar_vertical == 0 - let previewwin_pos = 'topleft' + if exists('g:tagbar_position') + " Map older deprecated values to correct values + if g:tagbar_position ==# 'top' + let g:tagbar_position = 'leftabove' + elseif g:tagbar_position ==# 'bottom' + let g:tagbar_position = 'rightbelow' + elseif g:tagbar_position ==# 'left' + let g:tagbar_position = 'topleft vertical' + elseif g:tagbar_position ==# 'right' + let g:tagbar_position = 'botright vertical' + endif + if g:tagbar_position !~# 'vertical' + let previewwin_pos = 'rightbelow vertical' + else + let previewwin_pos = 'topleft' + endif + let default_pos = g:tagbar_position else - let previewwin_pos = 'rightbelow vertical' + if exists('g:tagbar_vertical') && g:tagbar_vertical > 0 + let previewwin_pos = 'rightbelow vertical' + if exists('g:tagbar_left') && g:tagbar_left + let default_pos = 'leftabove' + else + let default_pos = 'rightbelow' + endif + let g:tagbar_height = g:tagbar_vertical + elseif exists('g:tagbar_left') && g:tagbar_left + let previewwin_pos = 'topleft' + let default_pos = 'topleft vertical' + else + let previewwin_pos = 'topleft' + let default_pos = 'botright vertical' + endif endif let options = [ \ ['autoclose', 0], @@ -62,13 +91,29 @@ function! s:setup_options() abort \ ['case_insensitive', 0], \ ['compact', 0], \ ['expand', 0], + \ ['file_size_limit', 0], \ ['foldlevel', 99], \ ['hide_nonpublic', 0], + \ ['height', 10], \ ['indent', 2], + \ ['jump_offset', 0], + \ ['jump_lazy_scroll', 0], \ ['left', 0], + \ ['help_visibility', 0], + \ ['highlight_follow_insert', 0], + \ ['highlight_method', 'nearest-stl'], + \ ['ignore_anonymous', 0], + \ ['no_autocmds', 0], + \ ['position', default_pos], \ ['previewwin_pos', previewwin_pos], + \ ['scopestrs', {}], + \ ['scrolloff', 0], + \ ['show_balloon', 1], + \ ['show_data_type', 0], \ ['show_visibility', 1], \ ['show_linenumbers', 0], + \ ['show_tag_count', 0], + \ ['show_tag_linenumbers', 0], \ ['singleclick', 0], \ ['sort', 1], \ ['systemenc', &encoding], @@ -76,17 +121,20 @@ function! s:setup_options() abort \ ['width', 40], \ ['zoomwidth', 1], \ ['silent', 0], + \ ['use_cache', 1], + \ ['wrap', 0], \ ] for [opt, val] in options call s:init_var(opt, val) + unlet val endfor endfunction call s:setup_options() if !exists('g:tagbar_iconchars') - if has('multi_byte') && has('unix') && &encoding == 'utf-8' && - \ (empty(&termencoding) || &termencoding == 'utf-8') + if has('multi_byte') && has('unix') && &encoding ==# 'utf-8' && + \ (!exists('+termencoding') || empty(&termencoding) || &termencoding ==# 'utf-8') let g:tagbar_iconchars = ['▶', '▼'] else let g:tagbar_iconchars = ['+', '-'] @@ -116,6 +164,7 @@ function! s:setup_keymaps() abort \ ['togglesort', 's'], \ ['togglecaseinsensitive', 'i'], \ ['toggleautoclose', 'c'], + \ ['togglepause', 't'], \ ['zoomwin', 'x'], \ ['close', 'q'], \ ['help', ['', '?']], @@ -134,18 +183,23 @@ augroup TagbarSession augroup END " Commands {{{1 -command! -nargs=0 Tagbar call tagbar#ToggleWindow() -command! -nargs=0 TagbarToggle call tagbar#ToggleWindow() +command! -nargs=? Tagbar call tagbar#ToggleWindow() +command! -nargs=? TagbarToggle call tagbar#ToggleWindow() command! -nargs=? TagbarOpen call tagbar#OpenWindow() command! -nargs=0 TagbarOpenAutoClose call tagbar#OpenWindow('fcj') command! -nargs=0 TagbarClose call tagbar#CloseWindow() command! -nargs=1 -bang TagbarSetFoldlevel call tagbar#SetFoldLevel(, 0) command! -nargs=0 TagbarShowTag call tagbar#highlighttag(1, 1) -command! -nargs=? TagbarCurrentTag echo tagbar#currenttag('%s', 'No current tag', ) +command! -nargs=* TagbarCurrentTag echo tagbar#currenttag('%s', 'No current tag', ) command! -nargs=1 TagbarGetTypeConfig call tagbar#gettypeconfig() command! -nargs=? TagbarDebug call tagbar#debug#start_debug() command! -nargs=0 TagbarDebugEnd call tagbar#debug#stop_debug() command! -nargs=0 TagbarTogglePause call tagbar#toggle_pause() +command! -nargs=0 TagbarForceUpdate call tagbar#ForceUpdate() +command! -nargs=0 TagbarJump call tagbar#jump() +command! -nargs=0 TagbarJumpPrev call tagbar#jumpToNearbyTag(-1) +command! -nargs=0 TagbarJumpNext call tagbar#jumpToNearbyTag(1) + " Modeline {{{1 " vim: ts=8 sw=4 sts=4 et foldenable foldmethod=marker foldcolumn=1 diff --git a/bundle/tagbar/syntax/tagbar.vim b/bundle/tagbar/syntax/tagbar.vim index 5d67393de..fac1b87f8 100644 --- a/bundle/tagbar/syntax/tagbar.vim +++ b/bundle/tagbar/syntax/tagbar.vim @@ -2,12 +2,12 @@ " Description: Tagbar syntax settings " Author: Jan Larres " Licence: Vim licence -" Website: http://majutsushi.github.com/tagbar/ -" Version: 2.7 +" Website: https://preservim.github.io/tagbar +" Version: 3.0.0 scriptencoding utf-8 -if exists("b:current_syntax") +if exists('b:current_syntax') finish endif @@ -36,8 +36,9 @@ syntax match TagbarHelpKey '" \zs.*\ze:' contained syntax match TagbarHelpTitle '" \zs-\+ \w\+ -\+' contained syntax match TagbarNestedKind '^\s\+\[[^]]\+\]$' -syntax match TagbarType ' : \zs.*' -syntax match TagbarSignature '(.*)' +syntax match TagbarType ' : \zs.*' contains=TagbarTagLineN +syntax match TagbarTagLineN '\s\+\[[0-9]\+\]\(\s\+\|$\)' +syntax match TagbarSignature '\(\