Commits

Matthew Turk committed 58db9da

Adding tagbar code

Comments (0)

Files changed (6)

vim/.VimballRecord

 command-t-1.4.vba: call delete('/home/mturk/.vim/ruby/command-t/controller.rb')|call delete('/home/mturk/.vim/ruby/command-t/extconf.rb')|call delete('/home/mturk/.vim/ruby/command-t/finder/buffer_finder.rb')|call delete('/home/mturk/.vim/ruby/command-t/finder/file_finder.rb')|call delete('/home/mturk/.vim/ruby/command-t/finder/jump_finder.rb')|call delete('/home/mturk/.vim/ruby/command-t/finder/tag_finder.rb')|call delete('/home/mturk/.vim/ruby/command-t/finder.rb')|call delete('/home/mturk/.vim/ruby/command-t/match_window.rb')|call delete('/home/mturk/.vim/ruby/command-t/prompt.rb')|call delete('/home/mturk/.vim/ruby/command-t/scanner/buffer_scanner.rb')|call delete('/home/mturk/.vim/ruby/command-t/scanner/file_scanner.rb')|call delete('/home/mturk/.vim/ruby/command-t/scanner/jump_scanner.rb')|call delete('/home/mturk/.vim/ruby/command-t/scanner/tag_scanner.rb')|call delete('/home/mturk/.vim/ruby/command-t/scanner.rb')|call delete('/home/mturk/.vim/ruby/command-t/settings.rb')|call delete('/home/mturk/.vim/ruby/command-t/stub.rb')|call delete('/home/mturk/.vim/ruby/command-t/vim/path_utilities.rb')|call delete('/home/mturk/.vim/ruby/command-t/vim/screen.rb')|call delete('/home/mturk/.vim/ruby/command-t/vim/window.rb')|call delete('/home/mturk/.vim/ruby/command-t/vim.rb')|call delete('/home/mturk/.vim/ruby/command-t/ext.c')|call delete('/home/mturk/.vim/ruby/command-t/match.c')|call delete('/home/mturk/.vim/ruby/command-t/matcher.c')|call delete('/home/mturk/.vim/ruby/command-t/ext.h')|call delete('/home/mturk/.vim/ruby/command-t/match.h')|call delete('/home/mturk/.vim/ruby/command-t/matcher.h')|call delete('/home/mturk/.vim/ruby/command-t/ruby_compat.h')|call delete('/home/mturk/.vim/ruby/command-t/depend')|call delete('/home/mturk/.vim/doc/command-t.txt')|call delete('/home/mturk/.vim/plugin/command-t.vim')
+download_script.php?src_id=18273: call delete('/home/mturk/.vim/autoload/tagbar.vim')|call delete('/home/mturk/.vim/doc/tagbar.txt')|call delete('/home/mturk/.vim/plugin/tagbar.vim')|call delete('/home/mturk/.vim/syntax/tagbar.vim')

vim/autoload/tagbar.vim

+" ============================================================================
+" File:        tagbar.vim
+" Description: List the current file's tags in a sidebar, ordered by class etc
+" Author:      Jan Larres <jan@majutsushi.net>
+" Licence:     Vim licence
+" Website:     http://majutsushi.github.com/tagbar/
+" Version:     2.4.1
+" Note:        This plugin was heavily inspired by the 'Taglist' plugin by
+"              Yegappan Lakshmanan and uses a small amount of code from it.
+"
+" Original taglist copyright notice:
+"              Permission is hereby granted to use and distribute this code,
+"              with or without modifications, provided that this copyright
+"              notice is copied with it. Like anything else that's free,
+"              taglist.vim is provided *as is* and comes with no warranty of
+"              any kind, either expressed or implied. In no event will the
+"              copyright holder be liable for any damamges resulting from the
+"              use of this software.
+" ============================================================================
+
+scriptencoding utf-8
+
+" Initialization {{{1
+
+" If another plugin calls an autoloaded Tagbar function on startup before the
+" plugin/tagbar.vim file got loaded, load it explicitly
+if exists(':Tagbar') == 0
+    runtime plugin/tagbar.vim
+endif
+
+" Basic init {{{2
+
+redir => s:ftype_out
+silent filetype
+redir END
+if s:ftype_out !~# 'detection:ON'
+    echomsg 'Tagbar: Filetype detection is turned off, skipping plugin'
+    unlet s:ftype_out
+    finish
+endif
+unlet s:ftype_out
+
+let s:icon_closed = g:tagbar_iconchars[0]
+let s:icon_open   = g:tagbar_iconchars[1]
+
+let s:type_init_done      = 0
+let s:autocommands_done   = 0
+" 0: not checked yet; 1: checked and found; 2: checked and not found
+let s:checked_ctags       = 0
+let s:checked_ctags_types = 0
+let s:ctags_types         = {}
+let s:window_expanded     = 0
+
+
+let s:access_symbols = {
+    \ 'public'    : '+',
+    \ 'protected' : '#',
+    \ 'private'   : '-'
+\ }
+
+let g:loaded_tagbar = 1
+
+let s:last_highlight_tline = 0
+let s:debug = 0
+let s:debug_file = ''
+
+" s:Init() {{{2
+function! s:Init(silent)
+    if s:checked_ctags == 2 && a:silent
+        return 0
+    elseif s:checked_ctags != 1
+        if !s:CheckForExCtags(a:silent)
+            return 0
+        endif
+    endif
+
+    if !s:checked_ctags_types
+        call s:GetSupportedFiletypes()
+    endif
+
+    if !s:type_init_done
+        call s:InitTypes()
+    endif
+
+    if !s:autocommands_done
+        call s:CreateAutocommands()
+        doautocmd CursorHold
+    endif
+
+    return 1
+endfunction
+
+" s:InitTypes() {{{2
+function! s:InitTypes()
+    call s:LogDebugMessage('Initializing types')
+
+    let s:known_types = {}
+
+    " Ant {{{3
+    let type_ant = s:TypeInfo.New()
+    let type_ant.ctagstype = 'ant'
+    let type_ant.kinds     = [
+        \ {'short' : 'p', 'long' : 'projects', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'targets',  'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.ant = type_ant
+    " Asm {{{3
+    let type_asm = s:TypeInfo.New()
+    let type_asm.ctagstype = 'asm'
+    let type_asm.kinds     = [
+        \ {'short' : 'm', 'long' : 'macros',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'types',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'd', 'long' : 'defines', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'l', 'long' : 'labels',  'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.asm = type_asm
+    " ASP {{{3
+    let type_aspvbs = s:TypeInfo.New()
+    let type_aspvbs.ctagstype = 'asp'
+    let type_aspvbs.kinds     = [
+        \ {'short' : 'd', 'long' : 'constants',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'classes',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables',   'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.aspvbs = type_aspvbs
+    " Awk {{{3
+    let type_awk = s:TypeInfo.New()
+    let type_awk.ctagstype = 'awk'
+    let type_awk.kinds     = [
+        \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.awk = type_awk
+    " Basic {{{3
+    let type_basic = s:TypeInfo.New()
+    let type_basic.ctagstype = 'basic'
+    let type_basic.kinds     = [
+        \ {'short' : 'c', 'long' : 'constants',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'g', 'long' : 'enumerations', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'l', 'long' : 'labels',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'types',        'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables',    'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.basic = type_basic
+    " BETA {{{3
+    let type_beta = s:TypeInfo.New()
+    let type_beta.ctagstype = 'beta'
+    let type_beta.kinds     = [
+        \ {'short' : 'f', 'long' : 'fragments', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'slots',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'patterns',  'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.beta = type_beta
+    " C {{{3
+    let type_c = s:TypeInfo.New()
+    let type_c.ctagstype = 'c'
+    let type_c.kinds     = [
+        \ {'short' : 'd', 'long' : 'macros',      'fold' : 1, 'stl' : 0},
+        \ {'short' : 'p', 'long' : 'prototypes',  'fold' : 1, 'stl' : 0},
+        \ {'short' : 'g', 'long' : 'enums',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 't', 'long' : 'typedefs',    'fold' : 0, 'stl' : 0},
+        \ {'short' : 's', 'long' : 'structs',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'u', 'long' : 'unions',      'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'members',     'fold' : 0, 'stl' : 0},
+        \ {'short' : 'v', 'long' : 'variables',   'fold' : 0, 'stl' : 0},
+        \ {'short' : 'f', 'long' : 'functions',   'fold' : 0, 'stl' : 1}
+    \ ]
+    let type_c.sro        = '::'
+    let type_c.kind2scope = {
+        \ 'g' : 'enum',
+        \ 's' : 'struct',
+        \ 'u' : 'union'
+    \ }
+    let type_c.scope2kind = {
+        \ 'enum'   : 'g',
+        \ 'struct' : 's',
+        \ 'union'  : 'u'
+    \ }
+    let s:known_types.c = type_c
+    " C++ {{{3
+    let type_cpp = s:TypeInfo.New()
+    let type_cpp.ctagstype = 'c++'
+    let type_cpp.kinds     = [
+        \ {'short' : 'd', 'long' : 'macros',      'fold' : 1, 'stl' : 0},
+        \ {'short' : 'p', 'long' : 'prototypes',  'fold' : 1, 'stl' : 0},
+        \ {'short' : 'g', 'long' : 'enums',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 't', 'long' : 'typedefs',    'fold' : 0, 'stl' : 0},
+        \ {'short' : 'n', 'long' : 'namespaces',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'classes',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'structs',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'u', 'long' : 'unions',      'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'members',     'fold' : 0, 'stl' : 0},
+        \ {'short' : 'v', 'long' : 'variables',   'fold' : 0, 'stl' : 0}
+    \ ]
+    let type_cpp.sro        = '::'
+    let type_cpp.kind2scope = {
+        \ 'g' : 'enum',
+        \ 'n' : 'namespace',
+        \ 'c' : 'class',
+        \ 's' : 'struct',
+        \ 'u' : 'union'
+    \ }
+    let type_cpp.scope2kind = {
+        \ 'enum'      : 'g',
+        \ 'namespace' : 'n',
+        \ 'class'     : 'c',
+        \ 'struct'    : 's',
+        \ 'union'     : 'u'
+    \ }
+    let s:known_types.cpp = type_cpp
+    " C# {{{3
+    let type_cs = s:TypeInfo.New()
+    let type_cs.ctagstype = 'c#'
+    let type_cs.kinds     = [
+        \ {'short' : 'd', 'long' : 'macros',      'fold' : 1, 'stl' : 0},
+        \ {'short' : 'f', 'long' : 'fields',      'fold' : 0, 'stl' : 1},
+        \ {'short' : 'g', 'long' : 'enums',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 't', 'long' : 'typedefs',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'n', 'long' : 'namespaces',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'i', 'long' : 'interfaces',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'classes',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'structs',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'E', 'long' : 'events',      'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'methods',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'properties',  'fold' : 0, 'stl' : 1}
+    \ ]
+    let type_cs.sro        = '.'
+    let type_cs.kind2scope = {
+        \ 'n' : 'namespace',
+        \ 'i' : 'interface',
+        \ 'c' : 'class',
+        \ 's' : 'struct',
+        \ 'g' : 'enum'
+    \ }
+    let type_cs.scope2kind = {
+        \ 'namespace' : 'n',
+        \ 'interface' : 'i',
+        \ 'class'     : 'c',
+        \ 'struct'    : 's',
+        \ 'enum'      : 'g'
+    \ }
+    let s:known_types.cs = type_cs
+    " COBOL {{{3
+    let type_cobol = s:TypeInfo.New()
+    let type_cobol.ctagstype = 'cobol'
+    let type_cobol.kinds     = [
+        \ {'short' : 'd', 'long' : 'data items',        'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'file descriptions', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'g', 'long' : 'group items',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'paragraphs',        'fold' : 0, 'stl' : 1},
+        \ {'short' : 'P', 'long' : 'program ids',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'sections',          'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.cobol = type_cobol
+    " DOS Batch {{{3
+    let type_dosbatch = s:TypeInfo.New()
+    let type_dosbatch.ctagstype = 'dosbatch'
+    let type_dosbatch.kinds     = [
+        \ {'short' : 'l', 'long' : 'labels',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.dosbatch = type_dosbatch
+    " Eiffel {{{3
+    let type_eiffel = s:TypeInfo.New()
+    let type_eiffel.ctagstype = 'eiffel'
+    let type_eiffel.kinds     = [
+        \ {'short' : 'c', 'long' : 'classes',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'features', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let type_eiffel.sro        = '.' " Not sure, is nesting even possible?
+    let type_eiffel.kind2scope = {
+        \ 'c' : 'class',
+        \ 'f' : 'feature'
+    \ }
+    let type_eiffel.scope2kind = {
+        \ 'class'   : 'c',
+        \ 'feature' : 'f'
+    \ }
+    let s:known_types.eiffel = type_eiffel
+    " Erlang {{{3
+    let type_erlang = s:TypeInfo.New()
+    let type_erlang.ctagstype = 'erlang'
+    let type_erlang.kinds     = [
+        \ {'short' : 'm', 'long' : 'modules',            'fold' : 0, 'stl' : 1},
+        \ {'short' : 'd', 'long' : 'macro definitions',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 'r', 'long' : 'record definitions', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let type_erlang.sro        = '.' " Not sure, is nesting even possible?
+    let type_erlang.kind2scope = {
+        \ 'm' : 'module'
+    \ }
+    let type_erlang.scope2kind = {
+        \ 'module' : 'm'
+    \ }
+    let s:known_types.erlang = type_erlang
+    " Flex {{{3
+    " Vim doesn't support Flex out of the box, this is based on rough
+    " guesses and probably requires
+    " http://www.vim.org/scripts/script.php?script_id=2909
+    " Improvements welcome!
+    let type_as = s:TypeInfo.New()
+    let type_as.ctagstype = 'flex'
+    let type_as.kinds     = [
+        \ {'short' : 'v', 'long' : 'global variables', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 'c', 'long' : 'classes',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'methods',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'properties',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',        'fold' : 0, 'stl' : 1},
+        \ {'short' : 'x', 'long' : 'mxtags',           'fold' : 0, 'stl' : 0}
+    \ ]
+    let type_as.sro        = '.'
+    let type_as.kind2scope = {
+        \ 'c' : 'class'
+    \ }
+    let type_as.scope2kind = {
+        \ 'class' : 'c'
+    \ }
+    let s:known_types.mxml = type_as
+    let s:known_types.actionscript = type_as
+    " Fortran {{{3
+    let type_fortran = s:TypeInfo.New()
+    let type_fortran.ctagstype = 'fortran'
+    let type_fortran.kinds     = [
+        \ {'short' : 'm', 'long' : 'modules',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'programs',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'k', 'long' : 'components', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'derived types and structures', 'fold' : 0,
+         \ 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'common blocks', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'b', 'long' : 'block data',    'fold' : 0, 'stl' : 0},
+        \ {'short' : 'e', 'long' : 'entry points',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'subroutines',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'l', 'long' : 'labels',        'fold' : 0, 'stl' : 1},
+        \ {'short' : 'n', 'long' : 'namelists',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables',     'fold' : 0, 'stl' : 0}
+    \ ]
+    let type_fortran.sro        = '.' " Not sure, is nesting even possible?
+    let type_fortran.kind2scope = {
+        \ 'm' : 'module',
+        \ 'p' : 'program',
+        \ 'f' : 'function',
+        \ 's' : 'subroutine'
+    \ }
+    let type_fortran.scope2kind = {
+        \ 'module'     : 'm',
+        \ 'program'    : 'p',
+        \ 'function'   : 'f',
+        \ 'subroutine' : 's'
+    \ }
+    let s:known_types.fortran = type_fortran
+    " HTML {{{3
+    let type_html = s:TypeInfo.New()
+    let type_html.ctagstype = 'html'
+    let type_html.kinds     = [
+        \ {'short' : 'f', 'long' : 'JavaScript funtions', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'a', 'long' : 'named anchors',       'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.html = type_html
+    " Java {{{3
+    let type_java = s:TypeInfo.New()
+    let type_java.ctagstype = 'java'
+    let type_java.kinds     = [
+        \ {'short' : 'p', 'long' : 'packages',       'fold' : 1, 'stl' : 0},
+        \ {'short' : 'f', 'long' : 'fields',         'fold' : 0, 'stl' : 0},
+        \ {'short' : 'g', 'long' : 'enum types',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'enum constants', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 'i', 'long' : 'interfaces',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'classes',        'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'methods',        'fold' : 0, 'stl' : 1}
+    \ ]
+    let type_java.sro        = '.'
+    let type_java.kind2scope = {
+        \ 'g' : 'enum',
+        \ 'i' : 'interface',
+        \ 'c' : 'class'
+    \ }
+    let type_java.scope2kind = {
+        \ 'enum'      : 'g',
+        \ 'interface' : 'i',
+        \ 'class'     : 'c'
+    \ }
+    let s:known_types.java = type_java
+    " JavaScript {{{3
+    " JavaScript is weird -- it does have scopes, but ctags doesn't seem to
+    " properly generate the information for them, instead it simply uses the
+    " complete name. So ctags has to be fixed before I can do anything here.
+    " Alternatively jsctags/doctorjs will be used if available.
+    let type_javascript = s:TypeInfo.New()
+    let type_javascript.ctagstype = 'javascript'
+    let jsctags = s:CheckFTCtags('jsctags', 'javascript')
+    if jsctags != ''
+        let type_javascript.kinds = [
+            \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 0},
+            \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}
+        \ ]
+        let type_javascript.sro        = '.'
+        let type_javascript.kind2scope = {
+            \ 'v' : 'namespace',
+            \ 'f' : 'namespace'
+        \ }
+        let type_javascript.scope2kind = {
+            \ 'namespace' : 'v'
+        \ }
+        let type_javascript.ctagsbin   = jsctags
+        let type_javascript.ctagsargs  = '-f -'
+    else
+        let type_javascript.kinds = [
+            \ {'short' : 'v', 'long' : 'global variables', 'fold' : 0, 'stl' : 0},
+            \ {'short' : 'c', 'long' : 'classes',          'fold' : 0, 'stl' : 1},
+            \ {'short' : 'p', 'long' : 'properties',       'fold' : 0, 'stl' : 0},
+            \ {'short' : 'm', 'long' : 'methods',          'fold' : 0, 'stl' : 1},
+            \ {'short' : 'f', 'long' : 'functions',        'fold' : 0, 'stl' : 1}
+        \ ]
+    endif
+    let s:known_types.javascript = type_javascript
+    " Lisp {{{3
+    let type_lisp = s:TypeInfo.New()
+    let type_lisp.ctagstype = 'lisp'
+    let type_lisp.kinds     = [
+        \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.lisp = type_lisp
+    " Lua {{{3
+    let type_lua = s:TypeInfo.New()
+    let type_lua.ctagstype = 'lua'
+    let type_lua.kinds     = [
+        \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.lua = type_lua
+    " Make {{{3
+    let type_make = s:TypeInfo.New()
+    let type_make.ctagstype = 'make'
+    let type_make.kinds     = [
+        \ {'short' : 'm', 'long' : 'macros', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.make = type_make
+    " Matlab {{{3
+    let type_matlab = s:TypeInfo.New()
+    let type_matlab.ctagstype = 'matlab'
+    let type_matlab.kinds     = [
+        \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.matlab = type_matlab
+    " Ocaml {{{3
+    let type_ocaml = s:TypeInfo.New()
+    let type_ocaml.ctagstype = 'ocaml'
+    let type_ocaml.kinds     = [
+        \ {'short' : 'M', 'long' : 'modules or functors', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'global variables',    'fold' : 0, 'stl' : 0},
+        \ {'short' : 'c', 'long' : 'classes',             'fold' : 0, 'stl' : 1},
+        \ {'short' : 'C', 'long' : 'constructors',        'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'methods',             'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'exceptions',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'type names',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',           'fold' : 0, 'stl' : 1},
+        \ {'short' : 'r', 'long' : 'structure fields',    'fold' : 0, 'stl' : 0}
+    \ ]
+    let type_ocaml.sro        = '.' " Not sure, is nesting even possible?
+    let type_ocaml.kind2scope = {
+        \ 'M' : 'Module',
+        \ 'c' : 'class',
+        \ 't' : 'type'
+    \ }
+    let type_ocaml.scope2kind = {
+        \ 'Module' : 'M',
+        \ 'class'  : 'c',
+        \ 'type'   : 't'
+    \ }
+    let s:known_types.ocaml = type_ocaml
+    " Pascal {{{3
+    let type_pascal = s:TypeInfo.New()
+    let type_pascal.ctagstype = 'pascal'
+    let type_pascal.kinds     = [
+        \ {'short' : 'f', 'long' : 'functions',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.pascal = type_pascal
+    " Perl {{{3
+    let type_perl = s:TypeInfo.New()
+    let type_perl.ctagstype = 'perl'
+    let type_perl.kinds     = [
+        \ {'short' : 'p', 'long' : 'packages',    'fold' : 1, 'stl' : 0},
+        \ {'short' : 'c', 'long' : 'constants',   '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}
+    \ ]
+    let s:known_types.perl = type_perl
+    " PHP {{{3
+    let type_php = s:TypeInfo.New()
+    let type_php.ctagstype = 'php'
+    let type_php.kinds     = [
+        \ {'short' : 'i', 'long' : 'interfaces',           'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'classes',              'fold' : 0, 'stl' : 1},
+        \ {'short' : 'd', 'long' : 'constant definitions', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 'f', 'long' : 'functions',            'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables',            'fold' : 0, 'stl' : 0},
+        \ {'short' : 'j', 'long' : 'javascript functions', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.php = type_php
+    " Python {{{3
+    let type_python = s:TypeInfo.New()
+    let type_python.ctagstype = 'python'
+    let type_python.kinds     = [
+        \ {'short' : 'i', 'long' : 'imports',   'fold' : 1, 'stl' : 0},
+        \ {'short' : 'c', 'long' : 'classes',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'members',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables', 'fold' : 0, 'stl' : 0}
+    \ ]
+    let type_python.sro        = '.'
+    let type_python.kind2scope = {
+        \ 'c' : 'class',
+        \ 'f' : 'function',
+        \ 'm' : 'function'
+    \ }
+    let type_python.scope2kind = {
+        \ 'class'    : 'c',
+        \ 'function' : 'f'
+    \ }
+    let s:known_types.python = type_python
+    " REXX {{{3
+    let type_rexx = s:TypeInfo.New()
+    let type_rexx.ctagstype = 'rexx'
+    let type_rexx.kinds     = [
+        \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.rexx = type_rexx
+    " Ruby {{{3
+    let type_ruby = s:TypeInfo.New()
+    let type_ruby.ctagstype = 'ruby'
+    let type_ruby.kinds     = [
+        \ {'short' : 'm', 'long' : 'modules',           'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'classes',           'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'methods',           'fold' : 0, 'stl' : 1},
+        \ {'short' : 'F', 'long' : 'singleton methods', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let type_ruby.sro        = '.'
+    let type_ruby.kind2scope = {
+        \ 'c' : 'class',
+        \ 'm' : 'class'
+    \ }
+    let type_ruby.scope2kind = {
+        \ 'class' : 'c'
+    \ }
+    let s:known_types.ruby = type_ruby
+    " Scheme {{{3
+    let type_scheme = s:TypeInfo.New()
+    let type_scheme.ctagstype = 'scheme'
+    let type_scheme.kinds     = [
+        \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'sets',      'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.scheme = type_scheme
+    " Shell script {{{3
+    let type_sh = s:TypeInfo.New()
+    let type_sh.ctagstype = 'sh'
+    let type_sh.kinds     = [
+        \ {'short' : 'f', 'long' : 'functions', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.sh = type_sh
+    let s:known_types.csh = type_sh
+    let s:known_types.zsh = type_sh
+    " SLang {{{3
+    let type_slang = s:TypeInfo.New()
+    let type_slang.ctagstype = 'slang'
+    let type_slang.kinds     = [
+        \ {'short' : 'n', 'long' : 'namespaces', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',  'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.slang = type_slang
+    " SML {{{3
+    let type_sml = s:TypeInfo.New()
+    let type_sml.ctagstype = 'sml'
+    let type_sml.kinds     = [
+        \ {'short' : 'e', 'long' : 'exception declarations', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 'f', 'long' : 'function definitions',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'functor definitions',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'signature declarations', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 'r', 'long' : 'structure declarations', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 't', 'long' : 'type definitions',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'value bindings',         'fold' : 0, 'stl' : 0}
+    \ ]
+    let s:known_types.sml = type_sml
+    " SQL {{{3
+    " The SQL ctags parser seems to be buggy for me, so this just uses the
+    " normal kinds even though scopes should be available. Improvements
+    " welcome!
+    let type_sql = s:TypeInfo.New()
+    let type_sql.ctagstype = 'sql'
+    let type_sql.kinds     = [
+        \ {'short' : 'P', 'long' : 'packages',               'fold' : 1, 'stl' : 1},
+        \ {'short' : 'd', 'long' : 'prototypes',             'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'cursors',                'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',              'fold' : 0, 'stl' : 1},
+        \ {'short' : 'F', 'long' : 'record fields',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 'L', 'long' : 'block label',            'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'procedures',             'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'subtypes',               'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'tables',                 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'T', 'long' : 'triggers',               'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables',              'fold' : 0, 'stl' : 1},
+        \ {'short' : 'i', 'long' : 'indexes',                'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'events',                 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'U', 'long' : 'publications',           'fold' : 0, 'stl' : 1},
+        \ {'short' : 'R', 'long' : 'services',               'fold' : 0, 'stl' : 1},
+        \ {'short' : 'D', 'long' : 'domains',                'fold' : 0, 'stl' : 1},
+        \ {'short' : 'V', 'long' : 'views',                  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'n', 'long' : 'synonyms',               'fold' : 0, 'stl' : 1},
+        \ {'short' : 'x', 'long' : 'MobiLink Table Scripts', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 'y', 'long' : 'MobiLink Conn Scripts',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'z', 'long' : 'MobiLink Properties',    'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.sql = type_sql
+    " Tcl {{{3
+    let type_tcl = s:TypeInfo.New()
+    let type_tcl.ctagstype = 'tcl'
+    let type_tcl.kinds     = [
+        \ {'short' : 'c', 'long' : 'classes',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'methods',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.tcl = type_tcl
+    " LaTeX {{{3
+    let type_tex = s:TypeInfo.New()
+    let type_tex.ctagstype = 'tex'
+    let type_tex.kinds     = [
+        \ {'short' : 'i', 'long' : 'includes',       'fold' : 1, 'stl' : 0},
+        \ {'short' : 'p', 'long' : 'parts',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'chapters',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 's', 'long' : 'sections',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'u', 'long' : 'subsections',    'fold' : 0, 'stl' : 1},
+        \ {'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}
+    \ ]
+    let type_tex.sro        = '""'
+    let type_tex.kind2scope = {
+        \ 'p' : 'part',
+        \ 'c' : 'chapter',
+        \ 's' : 'section',
+        \ 'u' : 'subsection',
+        \ 'b' : 'subsubsection'
+    \ }
+    let type_tex.scope2kind = {
+        \ 'part'          : 'p',
+        \ 'chapter'       : 'c',
+        \ 'section'       : 's',
+        \ 'subsection'    : 'u',
+        \ 'subsubsection' : 'b'
+    \ }
+    let type_tex.sort = 0
+    let s:known_types.tex = type_tex
+    " Vala {{{3
+    " Vala is supported by the ctags fork provided by Anjuta, so only add the
+    " type if the fork is used to prevent error messages otherwise
+    if has_key(s:ctags_types, 'vala') || executable('anjuta-tags')
+        let type_vala = s:TypeInfo.New()
+        let type_vala.ctagstype = 'vala'
+        let type_vala.kinds     = [
+            \ {'short' : 'e', 'long' : 'Enumerations',       'fold' : 0, 'stl' : 1},
+            \ {'short' : 'v', 'long' : 'Enumeration values', 'fold' : 0, 'stl' : 0},
+            \ {'short' : 's', 'long' : 'Structures',         'fold' : 0, 'stl' : 1},
+            \ {'short' : 'i', 'long' : 'Interfaces',         'fold' : 0, 'stl' : 1},
+            \ {'short' : 'd', 'long' : 'Delegates',          'fold' : 0, 'stl' : 1},
+            \ {'short' : 'c', 'long' : 'Classes',            'fold' : 0, 'stl' : 1},
+            \ {'short' : 'p', 'long' : 'Properties',         'fold' : 0, 'stl' : 0},
+            \ {'short' : 'f', 'long' : 'Fields',             'fold' : 0, 'stl' : 0},
+            \ {'short' : 'm', 'long' : 'Methods',            'fold' : 0, 'stl' : 1},
+            \ {'short' : 'E', 'long' : 'Error domains',      'fold' : 0, 'stl' : 1},
+            \ {'short' : 'r', 'long' : 'Error codes',        'fold' : 0, 'stl' : 1},
+            \ {'short' : 'S', 'long' : 'Signals',            'fold' : 0, 'stl' : 1}
+        \ ]
+        let type_vala.sro = '.'
+        " 'enum' doesn't seem to be used as a scope, but it can't hurt to have
+        " it here
+        let type_vala.kind2scope = {
+            \ 's' : 'struct',
+            \ 'i' : 'interface',
+            \ 'c' : 'class',
+            \ 'e' : 'enum'
+        \ }
+        let type_vala.scope2kind = {
+            \ 'struct'    : 's',
+            \ 'interface' : 'i',
+            \ 'class'     : 'c',
+            \ 'enum'      : 'e'
+        \ }
+        let s:known_types.vala = type_vala
+    endif
+    if !has_key(s:ctags_types, 'vala') && executable('anjuta-tags')
+        let s:known_types.vala.ctagsbin = 'anjuta-tags'
+    endif
+    " Vera {{{3
+    " Why are variables 'virtual'?
+    let type_vera = s:TypeInfo.New()
+    let type_vera.ctagstype = 'vera'
+    let type_vera.kinds     = [
+        \ {'short' : 'd', 'long' : 'macros',      'fold' : 1, 'stl' : 0},
+        \ {'short' : 'g', 'long' : 'enums',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'T', 'long' : 'typedefs',    'fold' : 0, 'stl' : 0},
+        \ {'short' : 'c', 'long' : 'classes',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0, 'stl' : 0},
+        \ {'short' : 'm', 'long' : 'members',     'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'tasks',       'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables',   'fold' : 0, 'stl' : 0},
+        \ {'short' : 'p', 'long' : 'programs',    'fold' : 0, 'stl' : 1}
+    \ ]
+    let type_vera.sro        = '.' " Nesting doesn't seem to be possible
+    let type_vera.kind2scope = {
+        \ 'g' : 'enum',
+        \ 'c' : 'class',
+        \ 'v' : 'virtual'
+    \ }
+    let type_vera.scope2kind = {
+        \ 'enum'      : 'g',
+        \ 'class'     : 'c',
+        \ 'virtual'   : 'v'
+    \ }
+    let s:known_types.vera = type_vera
+    " Verilog {{{3
+    let type_verilog = s:TypeInfo.New()
+    let type_verilog.ctagstype = 'verilog'
+    let type_verilog.kinds     = [
+        \ {'short' : 'c', 'long' : 'constants',           'fold' : 0, 'stl' : 0},
+        \ {'short' : 'e', 'long' : 'events',              'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',           'fold' : 0, 'stl' : 1},
+        \ {'short' : 'm', 'long' : 'modules',             'fold' : 0, 'stl' : 1},
+        \ {'short' : 'n', 'long' : 'net data types',      'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'ports',               'fold' : 0, 'stl' : 1},
+        \ {'short' : 'r', 'long' : 'register data types', 'fold' : 0, 'stl' : 1},
+        \ {'short' : 't', 'long' : 'tasks',               'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.verilog = type_verilog
+    " VHDL {{{3
+    " The VHDL ctags parser unfortunately doesn't generate proper scopes
+    let type_vhdl = s:TypeInfo.New()
+    let type_vhdl.ctagstype = 'vhdl'
+    let type_vhdl.kinds     = [
+        \ {'short' : 'P', 'long' : 'packages',   'fold' : 1, 'stl' : 0},
+        \ {'short' : 'c', 'long' : 'constants',  'fold' : 0, 'stl' : 0},
+        \ {'short' : 't', 'long' : 'types',      'fold' : 0, 'stl' : 1},
+        \ {'short' : 'T', 'long' : 'subtypes',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'r', 'long' : 'records',    'fold' : 0, 'stl' : 1},
+        \ {'short' : 'e', 'long' : 'entities',   'fold' : 0, 'stl' : 1},
+        \ {'short' : 'f', 'long' : 'functions',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.vhdl = type_vhdl
+    " Vim {{{3
+    let type_vim = s:TypeInfo.New()
+    let type_vim.ctagstype = 'vim'
+    let type_vim.kinds     = [
+        \ {'short' : 'n', 'long' : 'vimball filenames',  'fold' : 0, 'stl' : 1},
+        \ {'short' : 'v', 'long' : 'variables',          'fold' : 1, 'stl' : 0},
+        \ {'short' : 'f', 'long' : 'functions',          'fold' : 0, 'stl' : 1},
+        \ {'short' : 'a', 'long' : 'autocommand groups', 'fold' : 1, 'stl' : 1},
+        \ {'short' : 'c', 'long' : 'commands',           'fold' : 0, 'stl' : 0},
+        \ {'short' : 'm', 'long' : 'maps',               'fold' : 1, 'stl' : 0}
+    \ ]
+    let s:known_types.vim = type_vim
+    " YACC {{{3
+    let type_yacc = s:TypeInfo.New()
+    let type_yacc.ctagstype = 'yacc'
+    let type_yacc.kinds     = [
+        \ {'short' : 'l', 'long' : 'labels', 'fold' : 0, 'stl' : 1}
+    \ ]
+    let s:known_types.yacc = type_yacc
+    " }}}3
+
+    call s:LoadUserTypeDefs()
+
+    for type in values(s:known_types)
+        call s:CreateTypeKinddict(type)
+    endfor
+
+    let s:type_init_done = 1
+endfunction
+
+" s:LoadUserTypeDefs() {{{2
+function! s:LoadUserTypeDefs(...)
+    if a:0 > 0
+        let type = a:1
+
+        call s:LogDebugMessage("Initializing user type '" . type . "'")
+
+        let defdict = {}
+        let defdict[type] = g:tagbar_type_{type}
+    else
+        call s:LogDebugMessage('Initializing user types')
+
+        let defdict = tagbar#getusertypes()
+    endif
+
+    " Transform the 'kind' definitions into dictionary format
+    for def in values(defdict)
+        if has_key(def, 'kinds')
+            let kinds = def.kinds
+            let def.kinds = []
+            for kind in kinds
+                let kindlist = split(kind, ':')
+                let kinddict = {'short' : kindlist[0], 'long' : kindlist[1]}
+                if len(kindlist) == 4
+                    let kinddict.fold = kindlist[2]
+                    let kinddict.stl  = kindlist[3]
+                elseif len(kindlist) == 3
+                    let kinddict.fold = kindlist[2]
+                    let kinddict.stl  = 1
+                else
+                    let kinddict.fold = 0
+                    let kinddict.stl  = 1
+                endif
+                call add(def.kinds, kinddict)
+            endfor
+        endif
+
+        " If the user only specified one of kind2scope and scope2kind use it
+        " to generate the other one
+        if has_key(def, 'kind2scope') && !has_key(def, 'scope2kind')
+            let def.scope2kind = {}
+            for [key, value] in items(def.kind2scope)
+                let def.scope2kind[value] = key
+            endfor
+        elseif has_key(def, 'scope2kind') && !has_key(def, 'kind2scope')
+            let def.kind2scope = {}
+            for [key, value] in items(def.scope2kind)
+                let def.kind2scope[value] = key
+            endfor
+        endif
+    endfor
+    unlet! key value
+
+    for [key, value] in items(defdict)
+        if !has_key(s:known_types, key) ||
+         \ (has_key(value, 'replace') && value.replace)
+            let s:known_types[key] = s:TypeInfo.New(value)
+        else
+            call extend(s:known_types[key], value)
+        endif
+    endfor
+
+    if a:0 > 0
+        call s:CreateTypeKinddict(s:known_types[type])
+    endif
+endfunction
+
+" s:CreateTypeKinddict() {{{2
+function! s:CreateTypeKinddict(type)
+    " Create a dictionary of the kind order for fast access in sorting
+    " functions
+    let i = 0
+    for kind in a:type.kinds
+        let a:type.kinddict[kind.short] = i
+        let i += 1
+    endfor
+endfunction
+
+" s:RestoreSession() {{{2
+" Properly restore Tagbar after a session got loaded
+function! s:RestoreSession()
+    call s:LogDebugMessage('Restoring session')
+
+    let curfile = fnamemodify(bufname('%'), ':p')
+
+    let tagbarwinnr = bufwinnr('__Tagbar__')
+    if tagbarwinnr == -1
+        " Tagbar wasn't open in the saved session, nothing to do
+        return
+    else
+        let in_tagbar = 1
+        if winnr() != tagbarwinnr
+            call s:winexec(tagbarwinnr . 'wincmd w')
+            let in_tagbar = 0
+        endif
+    endif
+
+    let s:last_autofocus = 0
+
+    call s:Init(0)
+
+    call s:InitWindow(g:tagbar_autoclose)
+
+    call s:AutoUpdate(curfile)
+
+    if !in_tagbar
+        call s:winexec('wincmd p')
+    endif
+endfunction
+
+" s:MapKeys() {{{2
+function! s:MapKeys()
+    call s:LogDebugMessage('Mapping keys')
+
+    nnoremap <script> <silent> <buffer> <2-LeftMouse>
+                                              \ :call <SID>JumpToTag(0)<CR>
+    nnoremap <script> <silent> <buffer> <LeftRelease>
+                                 \ <LeftRelease>:call <SID>CheckMouseClick()<CR>
+
+    inoremap <script> <silent> <buffer> <2-LeftMouse>
+                                              \ <C-o>:call <SID>JumpToTag(0)<CR>
+    inoremap <script> <silent> <buffer> <LeftRelease>
+                            \ <LeftRelease><C-o>:call <SID>CheckMouseClick()<CR>
+
+    nnoremap <script> <silent> <buffer> <CR>    :call <SID>JumpToTag(0)<CR>
+    nnoremap <script> <silent> <buffer> p       :call <SID>JumpToTag(1)<CR>
+    nnoremap <script> <silent> <buffer> <Space> :call <SID>ShowPrototype()<CR>
+
+    nnoremap <script> <silent> <buffer> +        :call <SID>OpenFold()<CR>
+    nnoremap <script> <silent> <buffer> <kPlus>  :call <SID>OpenFold()<CR>
+    nnoremap <script> <silent> <buffer> zo       :call <SID>OpenFold()<CR>
+    nnoremap <script> <silent> <buffer> -        :call <SID>CloseFold()<CR>
+    nnoremap <script> <silent> <buffer> <kMinus> :call <SID>CloseFold()<CR>
+    nnoremap <script> <silent> <buffer> zc       :call <SID>CloseFold()<CR>
+    nnoremap <script> <silent> <buffer> o        :call <SID>ToggleFold()<CR>
+    nnoremap <script> <silent> <buffer> za       :call <SID>ToggleFold()<CR>
+
+    nnoremap <script> <silent> <buffer> *    :call <SID>SetFoldLevel(99, 1)<CR>
+    nnoremap <script> <silent> <buffer> <kMultiply>
+                                           \ :call <SID>SetFoldLevel(99, 1)<CR>
+    nnoremap <script> <silent> <buffer> zR   :call <SID>SetFoldLevel(99, 1)<CR>
+    nnoremap <script> <silent> <buffer> =    :call <SID>SetFoldLevel(0, 1)<CR>
+    nnoremap <script> <silent> <buffer> zM   :call <SID>SetFoldLevel(0, 1)<CR>
+
+    nnoremap <script> <silent> <buffer> <C-N>
+                                        \ :call <SID>GotoNextToplevelTag(1)<CR>
+    nnoremap <script> <silent> <buffer> <C-P>
+                                        \ :call <SID>GotoNextToplevelTag(-1)<CR>
+
+    nnoremap <script> <silent> <buffer> s    :call <SID>ToggleSort()<CR>
+    nnoremap <script> <silent> <buffer> x    :call <SID>ZoomWindow()<CR>
+    nnoremap <script> <silent> <buffer> q    :call <SID>CloseWindow()<CR>
+    nnoremap <script> <silent> <buffer> <F1> :call <SID>ToggleHelp()<CR>
+endfunction
+
+" s:CreateAutocommands() {{{2
+function! s:CreateAutocommands()
+    call s:LogDebugMessage('Creating autocommands')
+
+    augroup TagbarAutoCmds
+        autocmd!
+        autocmd BufEnter   __Tagbar__ nested call s:QuitIfOnlyWindow()
+        autocmd CursorHold __Tagbar__ call s:ShowPrototype()
+
+        autocmd BufWritePost *
+            \ if line('$') < g:tagbar_updateonsave_maxlines |
+                \ call s:AutoUpdate(fnamemodify(expand('<afile>'), ':p')) |
+            \ endif
+        autocmd BufEnter,CursorHold,FileType * call
+                    \ s:AutoUpdate(fnamemodify(expand('<afile>'), ':p'))
+        autocmd BufDelete,BufUnload,BufWipeout * call
+                    \ s:known_files.rm(fnamemodify(expand('<afile>'), ':p'))
+
+        autocmd VimEnter * call s:CorrectFocusOnStartup()
+    augroup END
+
+    let s:autocommands_done = 1
+endfunction
+
+" s:CheckForExCtags() {{{2
+" Test whether the ctags binary is actually Exuberant Ctags and not GNU ctags
+" (or something else)
+function! s:CheckForExCtags(silent)
+    call s:LogDebugMessage('Checking for Exuberant Ctags')
+
+    if !exists('g:tagbar_ctags_bin')
+        let ctagsbins  = []
+        let ctagsbins += ['ctags-exuberant'] " Debian
+        let ctagsbins += ['exuberant-ctags']
+        let ctagsbins += ['exctags'] " FreeBSD, NetBSD
+        let ctagsbins += ['/usr/local/bin/ctags'] " Homebrew
+        let ctagsbins += ['/opt/local/bin/ctags'] " Macports
+        let ctagsbins += ['ectags'] " OpenBSD
+        let ctagsbins += ['ctags']
+        let ctagsbins += ['ctags.exe']
+        let ctagsbins += ['tags']
+        for ctags in ctagsbins
+            if executable(ctags)
+                let g:tagbar_ctags_bin = ctags
+                break
+            endif
+        endfor
+        if !exists('g:tagbar_ctags_bin')
+            if !a:silent
+                echoerr 'Tagbar: Exuberant ctags not found!'
+                echomsg 'Please download Exuberant Ctags from ctags.sourceforge.net'
+                      \ 'and install it in a directory in your $PATH'
+                      \ 'or set g:tagbar_ctags_bin.'
+            endif
+            let s:checked_ctags = 2
+            return 0
+        endif
+    else
+        " reset 'wildignore' temporarily in case *.exe is included in it
+        let wildignore_save = &wildignore
+        set wildignore&
+
+        let g:tagbar_ctags_bin = expand(g:tagbar_ctags_bin)
+
+        let &wildignore = wildignore_save
+
+        if !executable(g:tagbar_ctags_bin)
+            if !a:silent
+                echoerr "Tagbar: Exuberant ctags not found at " .
+                      \ "'" . g:tagbar_ctags_bin . "'!"
+                echomsg 'Please check your g:tagbar_ctags_bin setting.'
+            endif
+            let s:checked_ctags = 2
+            return 0
+        endif
+    endif
+
+    let ctags_cmd = s:EscapeCtagsCmd(g:tagbar_ctags_bin, '--version')
+    if ctags_cmd == ''
+        let s:checked_ctags = 2
+        return 0
+    endif
+
+    let ctags_output = s:ExecuteCtags(ctags_cmd)
+
+    if v:shell_error || ctags_output !~# 'Exuberant Ctags'
+        if !a:silent
+            echoerr 'Tagbar: Ctags doesn''t seem to be Exuberant Ctags!'
+            echomsg 'GNU ctags will NOT WORK.'
+                  \ 'Please download Exuberant Ctags from ctags.sourceforge.net'
+                  \ 'and install it in a directory in your $PATH'
+                  \ 'or set g:tagbar_ctags_bin.'
+            echomsg 'Executed command: "' . ctags_cmd . '"'
+            if !empty(ctags_output)
+                echomsg 'Command output:'
+                for line in split(ctags_output, '\n')
+                    echomsg line
+                endfor
+            endif
+        endif
+        let s:checked_ctags = 2
+        return 0
+    elseif !s:CheckExCtagsVersion(ctags_output)
+        if !a:silent
+            echoerr 'Tagbar: Exuberant Ctags is too old!'
+            echomsg 'You need at least version 5.5 for Tagbar to work.'
+                \ 'Please download a newer version from ctags.sourceforge.net.'
+            echomsg 'Executed command: "' . ctags_cmd . '"'
+            if !empty(ctags_output)
+                echomsg 'Command output:'
+                for line in split(ctags_output, '\n')
+                    echomsg line
+                endfor
+            endif
+        endif
+        let s:checked_ctags = 2
+        return 0
+    else
+        let s:checked_ctags = 1
+        return 1
+    endif
+endfunction
+
+" s:CheckExCtagsVersion() {{{2
+function! s:CheckExCtagsVersion(output)
+    call s:LogDebugMessage('Checking Exuberant Ctags version')
+
+    if a:output =~ 'Exuberant Ctags Development'
+        return 1
+    endif
+
+    let matchlist = matchlist(a:output, '\vExuberant Ctags (\d+)\.(\d+)')
+    let major     = matchlist[1]
+    let minor     = matchlist[2]
+
+    return major >= 6 || (major == 5 && minor >= 5)
+endfunction
+
+" s:CheckFTCtags() {{{2
+function! s:CheckFTCtags(bin, ftype)
+    if executable(a:bin)
+        return a:bin
+    endif
+
+    if exists('g:tagbar_type_' . a:ftype)
+        execute 'let userdef = ' . 'g:tagbar_type_' . a:ftype
+        if has_key(userdef, 'ctagsbin')
+            return userdef.ctagsbin
+        else
+            return ''
+        endif
+    endif
+
+    return ''
+endfunction
+
+" s:GetSupportedFiletypes() {{{2
+function! s:GetSupportedFiletypes()
+    call s:LogDebugMessage('Getting filetypes sypported by Exuberant Ctags')
+
+    let ctags_cmd = s:EscapeCtagsCmd(g:tagbar_ctags_bin, '--list-languages')
+    if ctags_cmd == ''
+        return
+    endif
+
+    let ctags_output = s:ExecuteCtags(ctags_cmd)
+
+    if v:shell_error
+        " this shouldn't happen as potential problems would have already been
+        " caught by the previous ctags checking
+        return
+    endif
+
+    let types = split(ctags_output, '\n\+')
+
+    for type in types
+        let s:ctags_types[tolower(type)] = 1
+    endfor
+
+    let s:checked_ctags_types = 1
+endfunction
+
+" Prototypes {{{1
+" Base tag {{{2
+let s:BaseTag = {}
+
+" s:BaseTag.New() {{{3
+function! s:BaseTag.New(name) dict
+    let newobj = copy(self)
+
+    call newobj._init(a:name)
+
+    return newobj
+endfunction
+
+" s:BaseTag._init() {{{3
+function! s:BaseTag._init(name) dict
+    let self.name          = a:name
+    let self.fields        = {}
+    let self.fields.line   = 0
+    let self.fields.column = 1
+    let self.path          = ''
+    let self.fullpath      = a:name
+    let self.depth         = 0
+    let self.parent        = {}
+    let self.tline         = -1
+    let self.fileinfo      = {}
+    let self.typeinfo      = {}
+endfunction
+
+" s:BaseTag.isNormalTag() {{{3
+function! s:BaseTag.isNormalTag() dict
+    return 0
+endfunction
+
+" s:BaseTag.isPseudoTag() {{{3
+function! s:BaseTag.isPseudoTag() dict
+    return 0
+endfunction
+
+" s:BaseTag.isKindheader() {{{3
+function! s:BaseTag.isKindheader() dict
+    return 0
+endfunction
+
+" s:BaseTag.getPrototype() {{{3
+function! s:BaseTag.getPrototype() dict
+    return ''
+endfunction
+
+" s:BaseTag._getPrefix() {{{3
+function! s:BaseTag._getPrefix() dict
+    let fileinfo = self.fileinfo
+
+    if has_key(self, 'children') && !empty(self.children)
+        if fileinfo.tagfolds[self.fields.kind][self.fullpath]
+            let prefix = s:icon_closed
+        else
+            let prefix = s:icon_open
+        endif
+    else
+        let prefix = ' '
+    endif
+    if has_key(self.fields, 'access')
+        let prefix .= get(s:access_symbols, self.fields.access, ' ')
+    else
+        let prefix .= ' '
+    endif
+
+    return prefix
+endfunction
+
+" s:BaseTag.initFoldState() {{{3
+function! s:BaseTag.initFoldState() dict
+    let fileinfo = self.fileinfo
+
+    if s:known_files.has(fileinfo.fpath) &&
+     \ has_key(fileinfo._tagfolds_old[self.fields.kind], self.fullpath)
+        " The file has been updated and the tag was there before, so copy its
+        " old fold state
+        let fileinfo.tagfolds[self.fields.kind][self.fullpath] =
+                    \ fileinfo._tagfolds_old[self.fields.kind][self.fullpath]
+    elseif self.depth >= fileinfo.foldlevel
+        let fileinfo.tagfolds[self.fields.kind][self.fullpath] = 1
+    else
+        let fileinfo.tagfolds[self.fields.kind][self.fullpath] =
+                    \ fileinfo.kindfolds[self.fields.kind]
+    endif
+endfunction
+
+" s:BaseTag.getClosedParentTline() {{{3
+function! s:BaseTag.getClosedParentTline() dict
+    let tagline  = self.tline
+    let fileinfo = self.fileinfo
+
+    " Find the first closed parent, starting from the top of the hierarchy.
+    let parents   = []
+    let curparent = self.parent
+    while !empty(curparent)
+        call add(parents, curparent)
+        let curparent = curparent.parent
+    endwhile
+    for parent in reverse(parents)
+        if parent.isFolded()
+            let tagline = parent.tline
+            break
+        endif
+    endfor
+
+    return tagline
+endfunction
+
+" s:BaseTag.isFoldable() {{{3
+function! s:BaseTag.isFoldable() dict
+    return has_key(self, 'children') && !empty(self.children)
+endfunction
+
+" s:BaseTag.isFolded() {{{3
+function! s:BaseTag.isFolded() dict
+    return self.fileinfo.tagfolds[self.fields.kind][self.fullpath]
+endfunction
+
+" s:BaseTag.openFold() {{{3
+function! s:BaseTag.openFold() dict
+    if self.isFoldable()
+        let self.fileinfo.tagfolds[self.fields.kind][self.fullpath] = 0
+    endif
+endfunction
+
+" s:BaseTag.closeFold() {{{3
+function! s:BaseTag.closeFold() dict
+    let newline = line('.')
+
+    if !empty(self.parent) && self.parent.isKindheader()
+        " Tag is child of generic 'kind'
+        call self.parent.closeFold()
+        let newline = self.parent.tline
+    elseif self.isFoldable() && !self.isFolded()
+        " Tag is parent of a scope and is not folded
+        let self.fileinfo.tagfolds[self.fields.kind][self.fullpath] = 1
+        let newline = self.tline
+    elseif !empty(self.parent)
+        " Tag is normal child, so close parent
+        let parent = self.parent
+        let self.fileinfo.tagfolds[parent.fields.kind][parent.fullpath] = 1
+        let newline = parent.tline
+    endif
+
+    return newline
+endfunction
+
+" s:BaseTag.setFolded() {{{3
+function! s:BaseTag.setFolded(folded) dict
+    let self.fileinfo.tagfolds[self.fields.kind][self.fullpath] = a:folded
+endfunction
+
+" s:BaseTag.openParents() {{{3
+function! s:BaseTag.openParents() dict
+    let parent = self.parent
+
+    while !empty(parent)
+        call parent.openFold()
+        let parent = parent.parent
+    endwhile
+endfunction
+
+" Normal tag {{{2
+let s:NormalTag = copy(s:BaseTag)
+
+" s:NormalTag.isNormalTag() {{{3
+function! s:NormalTag.isNormalTag() dict
+    return 1
+endfunction
+
+" s:NormalTag.strfmt() {{{3
+function! s:NormalTag.strfmt() dict
+    let fileinfo = self.fileinfo
+    let typeinfo = self.typeinfo
+
+    let suffix = get(self.fields, 'signature', '')
+    if has_key(self.fields, 'type')
+        let suffix .= ' : ' . self.fields.type
+    elseif has_key(typeinfo, 'kind2scope') &&
+         \ has_key(typeinfo.kind2scope, self.fields.kind)
+        let suffix .= ' : ' . typeinfo.kind2scope[self.fields.kind]
+    endif
+
+    return self._getPrefix() . self.name . suffix . "\n"
+endfunction
+
+" s:NormalTag.str() {{{3
+function! s:NormalTag.str(longsig, full) dict
+    if a:full && self.path != ''
+        let str = self.path . self.typeinfo.sro . self.name
+    else
+        let str = self.name
+    endif
+
+    if has_key(self.fields, 'signature')
+        if a:longsig
+            let str .= self.fields.signature
+        else
+            let str .= '()'
+        endif
+    endif
+
+    return str
+endfunction
+
+" s:NormalTag.getPrototype() {{{3
+function! s:NormalTag.getPrototype() dict
+    return self.prototype
+endfunction
+
+" Pseudo tag {{{2
+let s:PseudoTag = copy(s:BaseTag)
+
+" s:PseudoTag.isPseudoTag() {{{3
+function! s:PseudoTag.isPseudoTag() dict
+    return 1
+endfunction
+
+" s:PseudoTag.strfmt() {{{3
+function! s:PseudoTag.strfmt() dict
+    let fileinfo = self.fileinfo
+    let typeinfo = self.typeinfo
+
+    let suffix = get(self.fields, 'signature', '')
+    if has_key(typeinfo.kind2scope, self.fields.kind)
+        let suffix .= ' : ' . typeinfo.kind2scope[self.fields.kind]
+    endif
+
+    return self._getPrefix() . self.name . '*' . suffix
+endfunction
+
+" Kind header {{{2
+let s:KindheaderTag = copy(s:BaseTag)
+
+" s:KindheaderTag.isKindheader() {{{3
+function! s:KindheaderTag.isKindheader() dict
+    return 1
+endfunction
+
+" s:KindheaderTag.getPrototype() {{{3
+function! s:KindheaderTag.getPrototype() dict
+    return self.name . ': ' .
+         \ self.numtags . ' ' . (self.numtags > 1 ? 'tags' : 'tag')
+endfunction
+
+" s:KindheaderTag.isFoldable() {{{3
+function! s:KindheaderTag.isFoldable() dict
+    return 1
+endfunction
+
+" s:KindheaderTag.isFolded() {{{3
+function! s:KindheaderTag.isFolded() dict
+    return self.fileinfo.kindfolds[self.short]
+endfunction
+
+" s:KindheaderTag.openFold() {{{3
+function! s:KindheaderTag.openFold() dict
+    let self.fileinfo.kindfolds[self.short] = 0
+endfunction
+
+" s:KindheaderTag.closeFold() {{{3
+function! s:KindheaderTag.closeFold() dict
+    let self.fileinfo.kindfolds[self.short] = 1
+    return line('.')
+endfunction
+
+" s:KindheaderTag.toggleFold() {{{3
+function! s:KindheaderTag.toggleFold() dict
+    let fileinfo = s:known_files.getCurrent()
+
+    let fileinfo.kindfolds[self.short] = !fileinfo.kindfolds[self.short]
+endfunction
+
+" Type info {{{2
+let s:TypeInfo = {}
+
+" s:TypeInfo.New() {{{3
+function! s:TypeInfo.New(...) dict
+    let newobj = copy(self)
+
+    let newobj.kinddict = {}
+
+    if a:0 > 0
+        call extend(newobj, a:1)
+    endif
+
+    return newobj
+endfunction
+
+" s:TypeInfo.getKind() {{{3
+function! s:TypeInfo.getKind(kind) dict
+    let idx = self.kinddict[a:kind]
+    return self.kinds[idx]
+endfunction
+
+" File info {{{2
+let s:FileInfo = {}
+
+" s:FileInfo.New() {{{3
+function! s:FileInfo.New(fname, ftype) dict
+    let newobj = copy(self)
+
+    " The complete file path
+    let newobj.fpath = a:fname
+
+    " File modification time
+    let newobj.mtime = getftime(a:fname)
+
+    " The vim file type
+    let newobj.ftype = a:ftype
+
+    " List of the tags that are present in the file, sorted according to the
+    " value of 'g:tagbar_sort'
+    let newobj.tags = []
+
+    " Dictionary of the tags, indexed by line number in the file
+    let newobj.fline = {}
+
+    " Dictionary of the tags, indexed by line number in the tagbar
+    let newobj.tline = {}
+
+    " Dictionary of the folding state of 'kind's, indexed by short name
+    let newobj.kindfolds = {}
+    let typeinfo = s:known_types[a:ftype]
+    let newobj.typeinfo = typeinfo
+    " copy the default fold state from the type info
+    for kind in typeinfo.kinds
+        let newobj.kindfolds[kind.short] =
+                    \ g:tagbar_foldlevel == 0 ? 1 : kind.fold
+    endfor
+
+    " Dictionary of dictionaries of the folding state of individual tags,
+    " indexed by kind and full path
+    let newobj.tagfolds = {}
+    for kind in typeinfo.kinds
+        let newobj.tagfolds[kind.short] = {}
+    endfor
+
+    " The current foldlevel of the file
+    let newobj.foldlevel = g:tagbar_foldlevel
+
+    return newobj
+endfunction
+
+" s:FileInfo.reset() {{{3
+" Reset stuff that gets regenerated while processing a file and save the old
+" tag folds
+function! s:FileInfo.reset() dict
+    let self.mtime = getftime(self.fpath)
+    let self.tags  = []
+    let self.fline = {}
+    let self.tline = {}
+
+    let self._tagfolds_old = self.tagfolds
+    let self.tagfolds = {}
+
+    let typeinfo = s:known_types[self.ftype]
+    for kind in typeinfo.kinds
+        let self.tagfolds[kind.short] = {}
+    endfor
+endfunction
+
+" s:FileInfo.clearOldFolds() {{{3
+function! s:FileInfo.clearOldFolds() dict
+    if exists('self._tagfolds_old')
+        unlet self._tagfolds_old
+    endif
+endfunction
+
+" s:FileInfo.sortTags() {{{3
+function! s:FileInfo.sortTags() dict
+    if has_key(s:compare_typeinfo, 'sort')
+        if s:compare_typeinfo.sort
+            call s:SortTags(self.tags, 's:CompareByKind')
+        else
+            call s:SortTags(self.tags, 's:CompareByLine')
+        endif
+    elseif g:tagbar_sort
+        call s:SortTags(self.tags, 's:CompareByKind')
+    else
+        call s:SortTags(self.tags, 's:CompareByLine')
+    endif
+endfunction
+
+" s:FileInfo.openKindFold() {{{3
+function! s:FileInfo.openKindFold(kind) dict
+    let self.kindfolds[a:kind.short] = 0
+endfunction
+
+" s:FileInfo.closeKindFold() {{{3
+function! s:FileInfo.closeKindFold(kind) dict
+    let self.kindfolds[a:kind.short] = 1
+endfunction
+
+" Known files {{{2
+let s:known_files = {
+    \ '_current' : {},
+    \ '_files'   : {}
+\ }
+
+" s:known_files.getCurrent() {{{3
+function! s:known_files.getCurrent() dict
+    return self._current
+endfunction
+
+" s:known_files.setCurrent() {{{3
+function! s:known_files.setCurrent(fileinfo) dict
+    let self._current = a:fileinfo
+endfunction
+
+" s:known_files.get() {{{3
+function! s:known_files.get(fname) dict
+    return get(self._files, a:fname, {})
+endfunction
+
+" s:known_files.put() {{{3
+" Optional second argument is the filename
+function! s:known_files.put(fileinfo, ...) dict
+    if a:0 == 1
+        let self._files[a:1] = a:fileinfo
+    else
+        let fname = a:fileinfo.fpath
+        let self._files[fname] = a:fileinfo
+    endif
+endfunction
+
+" s:known_files.has() {{{3
+function! s:known_files.has(fname) dict
+    return has_key(self._files, a:fname)
+endfunction
+
+" s:known_files.rm() {{{3
+function! s:known_files.rm(fname) dict
+    if s:known_files.has(a:fname)
+        call remove(self._files, a:fname)
+    endif
+endfunction
+
+" Window management {{{1
+" s:ToggleWindow() {{{2
+function! s:ToggleWindow()
+    call s:LogDebugMessage('ToggleWindow called')
+
+    let tagbarwinnr = bufwinnr("__Tagbar__")
+    if tagbarwinnr != -1
+        call s:CloseWindow()
+        return
+    endif
+
+    call s:OpenWindow('')
+
+    call s:LogDebugMessage('ToggleWindow finished')
+endfunction
+
+" s:OpenWindow() {{{2
+function! s:OpenWindow(flags)
+    call s:LogDebugMessage("OpenWindow called with flags: '" . a:flags . "'")
+
+    let autofocus = a:flags =~# 'f'
+    let jump      = a:flags =~# 'j'
+    let autoclose = a:flags =~# 'c'
+
+    let curfile = fnamemodify(bufname('%'), ':p')
+    let curline = line('.')
+
+    " If the tagbar window is already open check jump flag
+    " Also set the autoclose flag if requested
+    let tagbarwinnr = bufwinnr('__Tagbar__')
+    if tagbarwinnr != -1
+        if winnr() != tagbarwinnr && jump
+            call s:winexec(tagbarwinnr . 'wincmd w')
+            if autoclose
+                let w:autoclose = autoclose
+            endif
+            call s:HighlightTag(1, curline)
+        endif
+        call s:LogDebugMessage("OpenWindow finished, Tagbar already open")
+        return
+    endif
+
+    " This is only needed for the CorrectFocusOnStartup() function
+    let s:last_autofocus = autofocus
+
+    if !s:Init(0)
+        return 0
+    endif
+
+    " Expand the Vim window to accomodate for the Tagbar window if requested
+    if g:tagbar_expand && !s:window_expanded && has('gui_running')
+        let &columns += g:tagbar_width + 1
+        let s:window_expanded = 1
+    endif
+
+    let eventignore_save = &eventignore
+    set eventignore=all
+
+    let openpos = g:tagbar_left ? 'topleft vertical ' : 'botright vertical '
+    exe 'silent keepalt ' . openpos . g:tagbar_width . 'split ' . '__Tagbar__'
+
+    let &eventignore = eventignore_save
+
+    call s:InitWindow(autoclose)
+
+    call s:AutoUpdate(curfile)
+    call s:HighlightTag(1, curline)
+
+    if !(g:tagbar_autoclose || autofocus || g:tagbar_autofocus)
+        call s:winexec('wincmd p')
+    endif
+
+    call s:LogDebugMessage('OpenWindow finished')
+endfunction
+
+" s:InitWindow() {{{2
+function! s:InitWindow(autoclose)
+    call s:LogDebugMessage('InitWindow called with autoclose: ' . a:autoclose)
+
+    setlocal filetype=tagbar
+
+    setlocal noreadonly " in case the "view" mode is used
+    setlocal buftype=nofile
+    setlocal bufhidden=hide
+    setlocal noswapfile
+    setlocal nobuflisted
+    setlocal nomodifiable
+    setlocal nolist
+    setlocal nonumber
+    setlocal nowrap
+    setlocal winfixwidth
+    setlocal textwidth=0
+    setlocal nocursorline
+    setlocal nocursorcolumn
+    setlocal nospell
+
+    if exists('+relativenumber')
+        setlocal norelativenumber
+    endif
+
+    setlocal nofoldenable
+    setlocal foldcolumn=0
+    " Reset fold settings in case a plugin set them globally to something
+    " expensive. Apparently 'foldexpr' gets executed even if 'foldenable' is
+    " off, and then for every appended line (like with :put).
+    setlocal foldmethod&
+    setlocal foldexpr&
+
+    " Earlier versions have a bug in local, evaluated statuslines
+    if v:version > 701 || (v:version == 701 && has('patch097'))
+        setlocal statusline=%!TagbarGenerateStatusline()
+    else
+        setlocal statusline=Tagbar
+    endif
+
+    " Script-local variable needed since compare functions can't
+    " take extra arguments
+    let s:compare_typeinfo = {}
+
+    let s:is_maximized = 0
+    let s:short_help   = 1
+    let s:new_window   = 1
+
+    let w:autoclose = a:autoclose
+
+    if has('balloon_eval')
+        setlocal balloonexpr=TagbarBalloonExpr()
+        set ballooneval
+    endif
+
+    let cpoptions_save = &cpoptions
+    set cpoptions&vim
+
+    if !hasmapto('JumpToTag', 'n')
+        call s:MapKeys()
+    endif
+
+    let &cpoptions = cpoptions_save
+
+    call s:LogDebugMessage('InitWindow finished')
+endfunction
+
+" s:CloseWindow() {{{2
+function! s:CloseWindow()
+    call s:LogDebugMessage('CloseWindow called')
+
+    let tagbarwinnr = bufwinnr('__Tagbar__')
+    if tagbarwinnr == -1
+        return
+    endif
+
+    let tagbarbufnr = winbufnr(tagbarwinnr)
+
+    if winnr() == tagbarwinnr
+        if winbufnr(2) != -1
+            " Other windows are open, only close the tagbar one
+
+            let curfile = s:known_files.getCurrent()
+
+            call s:winexec('close')
+
+            " Try to jump to the correct window after closing
+            call s:winexec('wincmd p')
+
+            if !empty(curfile)
+                let filebufnr = bufnr(curfile.fpath)
+
+                if bufnr('%') != filebufnr
+                    let filewinnr = bufwinnr(filebufnr)
+                    if filewinnr != -1
+                        call s:winexec(filewinnr . 'wincmd w')
+                    endif
+                endif
+            endif
+        endif
+    else
+        " Go to the tagbar window, close it and then come back to the
+        " original window
+        let curbufnr = bufnr('%')
+        call s:winexec(tagbarwinnr . 'wincmd w')
+        close
+        " Need to jump back to the original window only if we are not
+        " already in that window
+        let winnum = bufwinnr(curbufnr)
+        if winnr() != winnum
+            call s:winexec(winnum . 'wincmd w')
+        endif
+    endif
+
+    " If the Vim window has been expanded, and Tagbar is not open in any other
+    " tabpages, shrink the window again
+    if s:window_expanded
+        let tablist = []
+        for i in range(tabpagenr('$'))
+            call extend(tablist, tabpagebuflist(i + 1))
+        endfor
+
+        if index(tablist, tagbarbufnr) == -1
+            let &columns -= g:tagbar_width + 1
+            let s:window_expanded = 0
+        endif
+    endif
+
+    call s:LogDebugMessage('CloseWindow finished')
+endfunction
+
+" s:ZoomWindow() {{{2
+function! s:ZoomWindow()
+    if s:is_maximized
+        execute 'vert resize ' . g:tagbar_width
+        let s:is_maximized = 0
+    else
+        vert resize
+        let s:is_maximized = 1
+    endif
+endfunction
+
+" s:CorrectFocusOnStartup() {{{2
+" For whatever reason the focus will be on the Tagbar window if
+" tagbar#autoopen is used with a FileType autocommand on startup and
+" g:tagbar_left is set. This should work around it by jumping to the window of
+" the current file after startup.
+function! s:CorrectFocusOnStartup()
+    if bufwinnr('__Tagbar__') != -1 && !g:tagbar_autofocus && !s:last_autofocus
+        let curfile = s:known_files.getCurrent()
+        if !empty(curfile) && curfile.fpath != fnamemodify(bufname('%'), ':p')
+            let winnr = bufwinnr(curfile.fpath)
+            if winnr != -1
+                call s:winexec(winnr . 'wincmd w')
+            endif
+        endif
+    endif
+endfunction
+
+" Tag processing {{{1
+" s:ProcessFile() {{{2
+" Execute ctags and put the information into a 'FileInfo' object
+function! s:ProcessFile(fname, ftype)
+    call s:LogDebugMessage('ProcessFile called on ' . a:fname)
+
+    if !s:IsValidFile(a:fname, a:ftype)
+        call s:LogDebugMessage('Not a valid file, returning')
+        return
+    endif
+
+    let ctags_output = s:ExecuteCtagsOnFile(a:fname, a:ftype)
+
+    if ctags_output == -1
+        call s:LogDebugMessage('Ctags error when processing file')
+        " put an empty entry into known_files so the error message is only
+        " shown once
+        call s:known_files.put({}, a:fname)
+        return
+    elseif ctags_output == ''
+        call s:LogDebugMessage('Ctags output empty')
+        " No need to go through the tag processing if there are no tags, and
+        " preserving the old fold state also isn't necessary
+        call s:known_files.put(s:FileInfo.New(a:fname, a:ftype), a:fname)
+        return
+    endif
+
+    " If the file has only been updated preserve the fold states, otherwise
+    " create a new entry
+    if s:known_files.has(a:fname)
+        let fileinfo = s:known_files.get(a:fname)
+        call fileinfo.reset()
+    else
+        let fileinfo = s:FileInfo.New(a:fname, a:ftype)
+    endif
+
+    let typeinfo = fileinfo.typeinfo
+
+    " Parse the ctags output lines
+    call s:LogDebugMessage('Parsing ctags output')
+    let rawtaglist = split(ctags_output, '\n\+')
+    for line in rawtaglist
+        " skip comments
+        if line =~# '^!_TAG_'
+            continue
+        endif
+
+        let parts = split(line, ';"')
+        if len(parts) == 2 " Is a valid tag line
+            let taginfo = s:ParseTagline(parts[0], parts[1], typeinfo, fileinfo)
+            let fileinfo.fline[taginfo.fields.line] = taginfo
+            call add(fileinfo.tags, taginfo)
+        endif
+    endfor
+
+    " Process scoped tags
+    let processedtags = []
+    if has_key(typeinfo, 'kind2scope')
+        call s:LogDebugMessage('Processing scoped tags')
+
+        let scopedtags = []
+        let is_scoped = 'has_key(typeinfo.kind2scope, v:val.fields.kind) ||
+                       \ has_key(v:val, "scope")'
+        let scopedtags += filter(copy(fileinfo.tags), is_scoped)
+        call filter(fileinfo.tags, '!(' . is_scoped . ')')
+
+        call s:AddScopedTags(scopedtags, processedtags, {}, 0,
+                           \ typeinfo, fileinfo)
+
+        if !empty(scopedtags)
+            echoerr 'Tagbar: ''scopedtags'' not empty after processing,'
+                  \ 'this should never happen!'
+                  \ 'Please contact the script maintainer with an example.'
+        endif
+    endif
+    call s:LogDebugMessage('Number of top-level tags: ' . len(processedtags))
+
+    " Create a placeholder tag for the 'kind' header for folding purposes
+    for kind in typeinfo.kinds
+
+        let curtags = filter(copy(fileinfo.tags),
+                           \ 'v:val.fields.kind ==# kind.short')
+        call s:LogDebugMessage('Processing kind: ' . kind.short .
+                             \ ', number of tags: ' . len(curtags))
+
+        if empty(curtags)
+            continue
+        endif
+
+        let kindtag          = s:KindheaderTag.New(kind.long)
+        let kindtag.short    = kind.short
+        let kindtag.numtags  = len(curtags)
+        let kindtag.fileinfo = fileinfo
+
+        for tag in curtags
+            let tag.parent = kindtag
+        endfor
+    endfor
+
+    if !empty(processedtags)
+        call extend(fileinfo.tags, processedtags)
+    endif
+
+    " Clear old folding information from previous file version to prevent leaks
+    call fileinfo.clearOldFolds()
+
+    " Sort the tags
+    let s:compare_typeinfo = typeinfo
+    call fileinfo.sortTags()
+
+    call s:known_files.put(fileinfo)
+endfunction
+
+" s:ExecuteCtagsOnFile() {{{2
+function! s:ExecuteCtagsOnFile(fname, ftype)
+    call s:LogDebugMessage('ExecuteCtagsOnFile called on ' . a:fname)
+
+    let typeinfo = s:known_types[a:ftype]
+
+    if has_key(typeinfo, 'ctagsargs')
+        let ctags_args = ' ' . typeinfo.ctagsargs . ' '
+    else
+        let ctags_args  = ' -f - '
+        let ctags_args .= ' --format=2 '
+        let ctags_args .= ' --excmd=pattern '
+        let ctags_args .= ' --fields=nksSa '
+        let ctags_args .= ' --extra= '
+        let ctags_args .= ' --sort=yes '
+
+        " Include extra type definitions
+        if has_key(typeinfo, 'deffile')
+            let ctags_args .= ' --options=' . typeinfo.deffile . ' '
+        endif
+
+        let ctags_type = typeinfo.ctagstype
+
+        let ctags_kinds = ''
+        for kind in typeinfo.kinds
+            let ctags_kinds .= kind.short
+        endfor
+
+        let ctags_args .= ' --language-force=' . ctags_type .
+                        \ ' --' . ctags_type . '-kinds=' . ctags_kinds . ' '
+    endif
+
+    if has_key(typeinfo, 'ctagsbin')
+        " reset 'wildignore' temporarily in case *.exe is included in it
+        let wildignore_save = &wildignore
+        set wildignore&
+        let ctags_bin = expand(typeinfo.ctagsbin)
+        let &wildignore = wildignore_save
+    else
+        let ctags_bin = g:tagbar_ctags_bin
+    endif
+
+    let ctags_cmd = s:EscapeCtagsCmd(ctags_bin, ctags_args, a:fname)
+    if ctags_cmd == ''
+        return ''
+    endif
+
+    let ctags_output = s:ExecuteCtags(ctags_cmd)
+
+    if v:shell_error || ctags_output =~ 'Warning: cannot open source file'
+        echoerr 'Tagbar: Could not execute ctags for ' . a:fname . '!'
+        echomsg 'Executed command: "' . ctags_cmd . '"'
+        if !empty(ctags_output)
+            call s:LogDebugMessage('Command output:')
+            call s:LogDebugMessage(ctags_output)
+            echomsg 'Command output:'
+            for line in split(ctags_output, '\n')
+                echomsg line
+            endfor
+        endif
+        return -1
+    endif
+
+    call s:LogDebugMessage('Ctags executed successfully')
+    return ctags_output
+endfunction
+
+" s:ParseTagline() {{{2
+" Structure of a tag line:
+" tagname<TAB>filename<TAB>expattern;"fields
+" fields: <TAB>name:value
+" fields that are always present: kind, line
+function! s:ParseTagline(part1, part2, typeinfo, fileinfo)
+    let basic_info  = split(a:part1, '\t')
+
+    let taginfo      = s:NormalTag.New(basic_info[0])
+    let taginfo.file = basic_info[1]
+
+    " 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")
+    let start   = 2 " skip the slash and the ^
+    let end     = strlen(pattern) - 1
+    if pattern[end - 1] ==# '$'
+        let end -= 1
+        let dollar = '\$'
+    else
+        let dollar = ''
+    endif
+    let pattern           = strpart(pattern, start, end - start)
+    let taginfo.pattern   = '\V\^\C' . pattern . dollar
+    let prototype         = substitute(pattern,   '^[[:space:]]\+', '', '')
+    let prototype         = substitute(prototype, '[[:space:]]\+$', '', '')
+    let taginfo.prototype = prototype
+
+    let fields = split(a:part2, '\t')
+    let taginfo.fields.kind = remove(fields, 0)
+    for field in fields
+        " can't use split() since the value can contain ':'
+        let delimit = stridx(field, ':')
+        let key     = strpart(field, 0, delimit)
+        let val     = strpart(field, delimit + 1)
+        if len(val) > 0
+            let taginfo.fields[key] = val
+        endif
+    endfor
+    " Needed for jsctags
+    if has_key(taginfo.fields, 'lineno')
+        let taginfo.fields.line = taginfo.fields.lineno
+    endif
+
+    " Make some information easier accessible
+    if has_key(a:typeinfo, 'scope2kind')
+        for scope in keys(a:typeinfo.scope2kind)
+            if has_key(taginfo.fields, scope)
+                let taginfo.scope = scope
+                let taginfo.path  = taginfo.fields[scope]
+
+                let taginfo.fullpath = taginfo.path . a:typeinfo.sro .
+                                     \ taginfo.name
+                break
+            endif
+        endfor
+        let taginfo.depth = len(split(taginfo.path, '\V' . a:typeinfo.sro))
+    endif
+
+    let taginfo.fileinfo = a:fileinfo
+    let taginfo.typeinfo = a:typeinfo
+
+    " Needed for folding
+    try
+        call taginfo.initFoldState()
+    catch /^Vim(\a\+):E716:/ " 'Key not present in Dictionary'
+        " The tag has a 'kind' that doesn't exist in the type definition
+        echoerr 'Your ctags and Tagbar configurations are out of sync!'
+              \ 'Please read '':help tagbar-extend''.'
+    endtry
+
+    return taginfo
+endfunction
+
+" s:AddScopedTags() {{{2
+" Recursively process tags. Unfortunately there is a problem: not all tags in
+" a hierarchy are actually there. For example, in C++ a class can be defined
+" in a header file and implemented in a .cpp file (so the class itself doesn't
+" appear in the .cpp file and thus doesn't generate a tag). Another example
+" are anonymous structures like namespaces, structs, enums, and unions, that
+" also don't get a tag themselves. These tags are thus called 'pseudo-tags' in
+" Tagbar. Properly parsing them is quite tricky, so try not to think about it
+" too much.
+function! s:AddScopedTags(tags, processedtags, parent, depth,
+                        \ typeinfo, fileinfo)
+    if !empty(a:parent)
+        let curpath = a:parent.fullpath
+        let pscope  = a:typeinfo.kind2scope[a:parent.fields.kind]
+    else
+        let curpath = ''
+        let pscope  = ''
+    endif
+
+    let is_cur_tag = 'v:val.depth == a:depth'
+
+    if !empty(curpath)
+        " Check whether the tag is either a direct child at the current depth
+        " or at least a proper grandchild with pseudo-tags in between. If it
+        " is a direct child also check for matching scope.
+        let is_cur_tag .= ' &&
+        \ (v:val.path ==# curpath ||
+         \ match(v:val.path, ''\V\^\C'' . curpath . a:typeinfo.sro) == 0) &&
+        \ (v:val.path ==# curpath ? (v:val.scope ==# pscope) : 1)'
+    endif
+
+    let curtags = filter(copy(a:tags), is_cur_tag)
+
+    if !empty(curtags)
+        call filter(a:tags, '!(' . is_cur_tag . ')')
+
+        let realtags   = []
+        let pseudotags = []
+
+        while !empty(curtags)
+            let tag = remove(curtags, 0)
+
+            if tag.path != curpath
+                " tag is child of a pseudo-tag, so create a new pseudo-tag and
+                " add all its children to it
+                let pseudotag = s:ProcessPseudoTag(curtags, tag, a:parent,
+                                                 \ a:typeinfo, a:fileinfo)
+
+                call add(pseudotags, pseudotag)
+            else
+                call add(realtags, tag)
+            endif
+        endwhile
+
+        " Recursively add the children of the tags on the current level
+        for tag in realtags
+            let tag.parent = a:parent
+
+            if !has_key(a:typeinfo.kind2scope, tag.fields.kind)
+                continue
+            endif
+
+            if !has_key(tag, 'children')
+                let tag.children = []
+            endif
+
+            call s:AddScopedTags(a:tags, tag.children, tag, a:depth + 1,
+                               \ a:typeinfo, a:fileinfo)
+        endfor
+        call extend(a:processedtags, realtags)
+
+        " Recursively add the children of the tags that are children of the
+        " pseudo-tags on the current level
+        for tag in pseudotags
+            call s:ProcessPseudoChildren(a:tags, tag, a:depth, a:typeinfo,
+                                       \ a:fileinfo)
+        endfor
+        call extend(a:processedtags, pseudotags)
+    endif
+
+    " Now we have to check if there are any pseudo-tags at the current level
+    " so we have to check for real tags at a lower level, i.e. grandchildren
+    let is_grandchild = 'v:val.depth > a:depth'
+
+    if !empty(curpath)
+        let is_grandchild .=
+        \ ' && match(v:val.path, ''\V\^\C'' . curpath . a:typeinfo.sro) == 0'
+    endif
+
+    let grandchildren = filter(copy(a:tags), is_grandchild)
+
+    if !empty(grandchildren)
+        call s:AddScopedTags(a:tags, a:processedtags, a:parent, a:depth + 1,
+                           \ a:typeinfo, a:fileinfo)
+    endif
+endfunction
+
+" s:ProcessPseudoTag() {{{2
+function! s:ProcessPseudoTag(curtags, tag, parent, typeinfo, fileinfo)