Version tidying up.
[profile.git] / .vim / plugin / taglist.vim
index 1393f65..f82e678 100644 (file)
 " File: taglist.vim
 " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
-" Version: 2.3
-" Last Modified: Feb 10, 2003
+" Version: 4.5
+" Last Modified: September 21, 2007
+" Copyright: Copyright (C) 2002-2007 Yegappan Lakshmanan
+"            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.
 "
-" Overview
-" --------
-" The "Tag List" plugin can be used to efficiently browse through your
-" source files. The "Tag List" plugin provides the following features:
+" The "Tag List" plugin is a source code browser plugin for Vim and provides
+" an overview of the structure of the programming language files and allows
+" you to efficiently browse through source code files for different
+" programming languages.  You can visit the taglist plugin home page for more
+" information:
 "
-" 1. Opens a vertically/horizontally split Vim window with a list of tags
-"    (functions, classes, structures, variables, etc) defined in the current
-"    file.
-" 2. Groups the tags by their type and displays them in a foldable tree.
-" 3. Automatically updates the taglist window as you switch between
-"    files/buffers.
-" 4. When a tag name is selected from the taglist window, positions the cursor
-"    at the definition of the tag in the source file
-" 5. Automatically highlights the current tag name.
-" 6. Can display the prototype of a tag from the taglist window.
-" 7. Displays the scope of a tag.
-" 8. Can optionally use the tag prototype instead of the tag name.
-" 9. The tag list can be sorted either by name or by line number.
-" 10. Supports the following language files: Assembly, ASP, Awk, C, C++,
-"     Cobol, Eiffel, Fortran, Java, Lisp, Lua, Make, Pascal, Perl, PHP,
-"     Python, Rexx, Ruby, Scheme, Shell, Slang, Sql, TCL, Verilog, Vim and
-"     Yacc.
-" 11. Runs in all the platforms where the exuberant ctags utility and Vim are
-"     supported (this includes MS-Windows and Unix based systems).
-" 12. Runs in both console/terminal and GUI versions of Vim.
-" 13. The ctags output for a file is cached to speed up displaying the taglist
-"     window.
-" 14. Works with the winmanager plugin. Using the winmanager plugin, you can
-"     use multiple Vim plugins at the same time efficiently.
-" 15. Can be easily extended to support new languages. Support for existing
-"     languages can be modified easily.
+"       http://vim-taglist.sourceforge.net
 "
-" To see the screenshots of the taglist plugin in different environments,
-" visit the following page:
+" You can subscribe to the taglist mailing list to post your questions
+" or suggestions for improvement or to report bugs. Visit the following
+" page for subscribing to the mailing list:
 "
-"       http://www.geocities.com/yegappan/taglist/screenshots.html
+"       http://groups.yahoo.com/group/taglist/
 "
-" This plugin relies on the exuberant ctags utility to dynamically generate
-" the tag listing. You can download the exuberant ctags utility from
-"
-"               http://ctags.sourceforge.net.
-"
-" The exuberant ctags utility must be installed in your system to use this
-" plugin. You should use exuberant ctags version 5.0 and above.  This plugin
-" doesn't use or create a tags file and there is no need to create a tags file
-" to use this plugin.
-"
-" This script relies on the Vim "filetype" detection mechanism to determine
-" the type of the current file. To turn on filetype detection use
-"
-"               :filetype on
-"
-" This plugin will not work in 'compatible' mode.  Make sure the 'compatible'
-" option is not set. This plugin will not work if you run Vim in the
-" restricted mode (using the -Z command-line argument). This plugin also
-" assumes that the system() Vim function is supported.
+" For more information about using this plugin, after installing the
+" taglist plugin, use the ":help taglist" command.
 "
 " Installation
 " ------------
-" 1. Copy the taglist.vim script to the $HOME/.vim/plugin directory. Refer to
-"    ':help add-plugin', ':help add-global-plugin' and ':help runtimepath' for
-"    more details about Vim plugins.
-" 2. Set the Tlist_Ctags_Cmd variable to point to the location of the
-"    exuberant ctags utility (not to the directory).
-" 3. If you are running a terminal/console version of Vim and the terminal
-"    doesn't support changing the window width then set the Tlist_Inc_Winwidth
-"    variable to 0.
-" 4. Restart Vim.
-" 5. You can use the ":Tlist" command to open/close the taglist window. 
-"
-" Usage
-" -----
-" You can open the taglist window by using the ":Tlist" command. Invoking this
-" command will toggle (open or close) the taglist window. You can map a key to
-" invoke this command:
-"
-"               nnoremap <silent> <F8> :Tlist<CR>
-"
-" Add the above mapping to your ~/.vimrc file.  You can also open the taglist
-" window on startup using the following command line:
-"
-"               $ vim +Tlist
-"
-" You can close the taglist window from the taglist window by pressing 'q' or
-" using the Vim ":q" command. You can also use any of the Vim window commands
-" to close the taglist window. Invoking the ":Tlist" command when the taglist
-" window is opened, will close the taglist window.
-"
-" As you switch between source files, the taglist window will be automatically
-" updated with the tag listing for the current source file.  The tag names
-" will grouped by their type (variable, function, class, etc). For tags with
-" scope information (like class members, structures inside structures, etc),
-" the scope information will be displayed in square brackets "[]" after the
-" tagname.
-" 
-" The tag names will be  displayed as a foldable tree using the Vim folding
-" support. You can collapse the tree using the '-' key or using the Vim zc
-" fold command. You can open the tree using the '+' key or using the Vim zo
-" fold command. You can open all the fold using the '*' key or using the Vim
-" zR fold command You can also use the mouse to open/close the folds.
-"
-" You can select a tag either by pressing the <Enter> key or by double
-" clicking the tag name using the mouse. You can configure the taglist plugin
-" by setting the 'Tlist_Use_SingleClick' variable to jump to a tag on a single
-" mouse click.
-"
-" The script will automatically highlight the name of the current tag.  The
-" tag name will be highlighted after 'updatetime' milliseconds. The default
-" value for this Vim option is 4 seconds.  You can also use the ":TlistSync"
-" command to force the highlighting of the current tag. You can map a key to
-" invoke this command:
-"
-"               nnoremap <silent> <F9> :TlistSync<CR>
-"
-" Add the above mapping to your ~/.vimrc file.
-"
-" If you place the cursor on a tag name in the "Tag List" window, then the tag
-" prototype will be displayed at the Vim status line after 'updatetime'
-" milliseconds. The default value for the 'updatetime' Vim option is 4
-" seconds. You can also press the space bar to display the prototype of the
-" tag under the cursor.
-"
-" By default, the tag list will be sorted by the order in which the tags
-" appear in the file. You can sort the tags either by name or by order by
-" pressing the "s" key in the taglist window.
-"
-" You can press the 'x' key in the taglist window to maximize the taglist
-" window width/height. The window will be maximized to the maximum possible
-" width/height without closing the other existing windows. You can again press
-" 'x' to restore the taglist window to the default width/height.
-"
-" You can press the '?' key to display help information about using the
-" taglist window. If you again press the '?' key, the help information will be
-" removed.
-"
-" The following table lists the description of the keys that you can use
-" in the taglist window.
-"
-"       Key           Description
-"
-"       <CR>          Jump to the location where the tag under cursor is
-"                     defined.
-"       o             Jump to the location where the tag under cursor is
-"                     defined in a new window.
-"       <Space>       Display the prototype of the tag under the cursor.
-"       u             Update the tags listed in the taglist window
-"       s             Change the sort order of the tags (by name or by order)
-"       x             Zoom-in or Zoom-out the taglist window
-"       +             Open a fold
-"       -             Close a fold
-"       *             Open all folds
-"       q             Close the taglist window
-"       ?             Display help
-"
-"
-" You can use the ":TlistShowPrototype" command to display the prototype of
-" a function in the specified line number. For example,
-"
-"               :TlistShowPrototype 50
-"
-" If the line number is not supplied, this command will display the prototype
-" of the current function.
-"
-" You can also use the taglist plugin with the winmanager plugin. This will
-" allow you to use the file explorer, buffer explorer and the taglist plugin
-" at the same time in different windows. To use the taglist plugin with the
-" winmanager plugin, set 'TagList' in the 'winManagerWindowLayout' variable.
-" For example, to use the file explorer plugin and the taglist plugin at the
-" same time, use the following setting:
-"
-"               let winManagerWindowLayout = 'FileExplorer|TagList'
-"
-" Configuration
-" -------------
-" By changing the following variables you can configure the behavior of this
-" script. Set the following variables in your .vimrc file using the 'let'
-" command.
-"
-" The script uses the Tlist_Ctags_Cmd variable to locate the ctags utility.
-" By default, this is set to ctags. Set this variable to point to the location
-" of the ctags utility in your system. Note that this variable should point to
-" the fully qualified exuberant ctags location and NOT to the directory in
-" which exuberant ctags is installed.
-"
-"               let Tlist_Ctags_Cmd = 'd:\tools\ctags.exe'
-"               let Tlist_Ctags_Cmd = '/usr/local/bin/ctags'
-"
-" By default, the tag names will be listed in the order in which they are
-" defined in the file. You can alphabetically sort the tag names by pressing
-" the "s" key in the taglist window. You can also change the default order by
-" setting the variable Tlist_Sort_Type to "name" or "order":
-"
-"               let Tlist_Sort_Type = "name"
-"
-" Be default, the tag names will be listed in a vertically split window.  If
-" you prefer a horizontally split window, then set the
-" 'Tlist_Use_Horiz_Window' variable to 1. If you are running MS-Windows
-" version of Vim in a MS-DOS command window, then you should use a
-" horizontally split window instead of a vertically split window.  Also, if
-" you are using an older version of xterm in a Unix system that doesn't
-" support changing the xterm window width, you should use a horizontally split
-" window.
-"
-"               let Tlist_Use_Horiz_Window = 1
-"
-" By default, the vertically split taglist window will appear on the left hand
-" side. If you prefer to open the window on the right hand side, you can set
-" the Tlist_Use_Right_Window variable to one:
-"
-"               let Tlist_Use_Right_Window = 1
-"
-" To automatically open the taglist window, when you start Vim, you can set
-" the Tlist_Auto_Open variable to 1. By default, this variable is set to 0 and
-" the taglist window will not be opened automatically on Vim startup.
-"
-"               let Tlist_Auto_Open = 1
-"
-" By default, only the tag name will be displayed in the taglist window. If
-" you like to see tag prototypes instead of names, set the
-" Tlist_Display_Prototype variable to 1. By default, this variable is set to 0
-" and only tag names will be displayed.
-"
-"               let Tlist_Display_Prototype = 1
-"
-" The default width of the vertically split taglist window will be 30.  This
-" can be changed by modifying the Tlist_WinWidth variable:
-"
-"               let Tlist_WinWidth = 20
-"
-" Note that the value of the 'winwidth' option setting determines the minimum
-" width of the current window. If you set the 'Tlist_WinWidth' variable to a
-" value less than that of the 'winwidth' option setting, then Vim will use the
-" value of the 'winwidth' option.
-"
-" By default, when the width of the window is less than 100 and a new taglist
-" window is opened vertically, then the window width will be increased by the
-" value set in the Tlist_WinWidth variable to accommodate the new window.  The
-" value of this variable is used only if you are using a vertically split
-" taglist window.  If your terminal doesn't support changing the window width
-" from Vim (older version of xterm running in a Unix system) or if you see any
-" weird problems in the screen due to the change in the window width or if you
-" prefer not to adjust the window width then set the 'Tlist_Inc_Winwidth'
-" variable to 0.  CAUTION: If you are using the MS-Windows version of Vim in a
-" MS-DOS command window then you must set this variable to 0, otherwise the
-" system may hang due to a Vim limitation (explained in :help win32-problems)
-"
-"               let Tlist_Inc_Winwidth = 0
-"
-" By default, when you double click on the tag name using the left mouse 
-" button, the cursor will be positioned at the definition of the tag. You 
-" can set the Tlist_Use_SingleClick variable to one to jump to a tag when
-" you single click on the tag name using the mouse. By default this variable
-" is set to zero.
-"
-"               let Tlist_Use_SingleClick = 1
-"
-" Due to a bug in Vim, if you set Tlist_Use_SingleClick to one and try to
-" resize the taglist window using the mouse, then Vim will crash. The fix for
-" this bug will be available in the next version of Vim. In the meantime,
-" instead of resizing the taglist window using the mouse, you can use normal
-" Vim window resizing commands to resize the taglist window.
-"
-" By default, the taglist window will contain text that display the name of
-" the file, sort order information and the key to press to get help. Also,
-" empty lines will be used to separate different groups of tags. If you
-" don't need these information, you can set the Tlist_Compact_Format variable
-" to one to get a compact display.
-"
-"               let Tlist_Compact_Format = 1
-"
-" Extending
-" ---------
-" You can extend exuberant ctags to add support for new languages. For more
-" information, visit the following page
-"
-"               http://ctags.sourceforge.net/EXTENDING.html
-"
-" You can extend the taglist plugin to add support for new languages or modify
-" the support for an already supported language by setting the following
-" variables in the .vimrc file.
-"
-" To modify the support for an already supported language, you have to set the
-" tlist_xxx_settings variable. Replace xxx with the Vim filetype name.  To
-" determine the filetype name used by Vim for a file, use the command
-"
-"               :set filetype
-"
-" The format of the value set in the tlist_xxx_settings variable is
-"
-"          <language_name>;flag1:name1;flag2:name2;flag3:name3
-"
-" The different fields are separated by the ';' character.  The first field
-" 'language_name' is the name used by exuberant ctags. This name can be
-" different from the file type name used by Vim. For example, for C++, the
-" language name used by ctags is 'c++' but the filetype name used by Vim is
-" 'cpp'. The remaining fields follow the format "flag:name". The sub-field
-" 'flag' is the language specific flag used by exuberant ctags to generate the
-" corresponding tags.  For example, for the C language, to list only the
-" functions, the 'f' flag should be used. For more information about the flags
-" supported by exuberant ctags for a particular language, read the help text
-" from the 'ctags --help' comand. The sub-field 'name' specifies the title
-" text to use for displaying the tags of a particular type. For example,
-" 'name' can be set to 'functions'.
-"
-" For example, to list only the classes and functions defined in a C++
-" language file, add the following lines to your .vimrc file
-"
-"       let tlist_cpp_settings = 'c++;c:class;f:function'
-"
-" In the above setting, 'cpp' is the Vim filetype name and 'c++' is the name
-" used by the exuberant ctags tool. 'c' and 'f' are the flags passed to
-" exuberant ctags to list classes and functions.
-"
-" For example, to display only functions defined in a C file and to use "My
-" Functions" as the title for the function group, use 
+" 1. Download the taglist.zip file and unzip the files to the $HOME/.vim
+"    or the $HOME/vimfiles or the $VIM/vimfiles directory. This should
+"    unzip the following two files (the directory structure should be
+"    preserved):
 "
-"       let tlist_c_settings = 'c;f:My Functions'
+"       plugin/taglist.vim - main taglist plugin file
+"       doc/taglist.txt    - documentation (help) file
 "
-" To add support for a new language, set the tlist_xxx_settings variable
-" appropriately as described above.
+"    Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath'
+"    Vim help pages for more details about installing Vim plugins.
+" 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or
+"    $VIM/vimfiles/doc directory, start Vim and run the ":helptags ."
+"    command to process the taglist help file.
+" 3. If the exuberant ctags utility is not present in your PATH, then set the
+"    Tlist_Ctags_Cmd variable to point to the location of the exuberant ctags
+"    utility (not to the directory) in the .vimrc file.
+" 4. If you are running a terminal/console version of Vim and the
+"    terminal doesn't support changing the window width then set the
+"    'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file.
+" 5. Restart Vim.
+" 6. You can now use the ":TlistToggle" command to open/close the taglist
+"    window. You can use the ":help taglist" command to get more
+"    information about using the taglist plugin.
 "
 " ****************** Do not modify after this line ************************
-if exists('loaded_taglist') || &cp
-    finish
-endif
-let loaded_taglist=1
 
-" Location of the exuberant ctags tool
-if !exists('Tlist_Ctags_Cmd')
-    let Tlist_Ctags_Cmd = 'ctags'
-endif
+" Line continuation used here
+let s:cpo_save = &cpo
+set cpo&vim
+
+if !exists('loaded_taglist')
+    " First time loading the taglist plugin
+    "
+    " To speed up the loading of Vim, the taglist plugin uses autoload
+    " mechanism to load the taglist functions.
+    " Only define the configuration variables, user commands and some
+    " auto-commands and finish sourcing the file
+
+    " The taglist plugin requires the built-in Vim system() function. If this
+    " function is not available, then don't load the plugin.
+    if !exists('*system')
+        echomsg 'Taglist: Vim system() built-in function is not available. ' .
+                    \ 'Plugin is not loaded.'
+        let loaded_taglist = 'no'
+        let &cpo = s:cpo_save
+        finish
+    endif
 
-" Tag listing sort type - 'name' or 'order'
-if !exists('Tlist_Sort_Type')
-    let Tlist_Sort_Type = 'order'
-endif
+    " Location of the exuberant ctags tool
+    if !exists('Tlist_Ctags_Cmd')
+        if executable('exuberant-ctags')
+            " On Debian Linux, exuberant ctags is installed
+            " as exuberant-ctags
+            let Tlist_Ctags_Cmd = 'exuberant-ctags'
+        elseif executable('exctags')
+            " On Free-BSD, exuberant ctags is installed as exctags
+            let Tlist_Ctags_Cmd = 'exctags'
+        elseif executable('ctags')
+            let Tlist_Ctags_Cmd = 'ctags'
+        elseif executable('ctags.exe')
+            let Tlist_Ctags_Cmd = 'ctags.exe'
+        elseif executable('tags')
+            let Tlist_Ctags_Cmd = 'tags'
+        else
+            "echomsg 'Taglist: Exuberant ctags (http://ctags.sf.net) ' .
+            "            \ 'not found in PATH. Plugin is not loaded.'
+            " Skip loading the plugin
+            let loaded_taglist = 'no'
+            let &cpo = s:cpo_save
+            finish
+        endif
+    endif
 
-" Tag listing window split (horizontal/vertical) control
-if !exists('Tlist_Use_Horiz_Window')
-    let Tlist_Use_Horiz_Window = 0
-endif
 
-" Open the vertically split taglist window on the left or on the right side.
-" This setting is relevant only if Tlist_Use_Horiz_Window is set to zero (i.e.
-" only for vertically split windows)
-if !exists('Tlist_Use_Right_Window')
-    let Tlist_Use_Right_Window = 0
-endif
+    " Automatically open the taglist window on Vim startup
+    if !exists('Tlist_Auto_Open')
+        let Tlist_Auto_Open = 0
+    endif
 
-" Increase Vim window width to display vertically split taglist window.  For
-" MS-Windows version of Vim running in a MS-DOS window, this must be set to 0
-" otherwise the system may hang due to a Vim limitation.
-if !exists('Tlist_Inc_Winwidth')
-    if (has('win16') || has('win95')) && !has('gui_running')
-        let Tlist_Inc_Winwidth = 0
-    else
-        let Tlist_Inc_Winwidth = 1
+    " When the taglist window is toggle opened, move the cursor to the
+    " taglist window
+    if !exists('Tlist_GainFocus_On_ToggleOpen')
+        let Tlist_GainFocus_On_ToggleOpen = 0
     endif
-endif
 
-" Vertically split taglist window width setting
-if !exists('Tlist_WinWidth')
-    let Tlist_WinWidth = 30
-endif
+    " Process files even when the taglist window is not open
+    if !exists('Tlist_Process_File_Always')
+        let Tlist_Process_File_Always = 0
+    endif
 
-" Horizontally split taglist window height setting
-if !exists('Tlist_WinHeight')
-    let Tlist_WinHeight = 10
-endif
+    if !exists('Tlist_Show_Menu')
+        let Tlist_Show_Menu = 0
+    endif
 
-" Automatically open the taglist window on Vim startup
-if !exists('Tlist_Auto_Open')
-    let Tlist_Auto_Open = 0
-endif
+    " Tag listing sort type - 'name' or 'order'
+    if !exists('Tlist_Sort_Type')
+        let Tlist_Sort_Type = 'order'
+    endif
+
+    " Tag listing window split (horizontal/vertical) control
+    if !exists('Tlist_Use_Horiz_Window')
+        let Tlist_Use_Horiz_Window = 0
+    endif
+
+    " Open the vertically split taglist window on the left or on the right
+    " side.  This setting is relevant only if Tlist_Use_Horiz_Window is set to
+    " zero (i.e.  only for vertically split windows)
+    if !exists('Tlist_Use_Right_Window')
+        let Tlist_Use_Right_Window = 0
+    endif
+
+    " Increase Vim window width to display vertically split taglist window.
+    " For MS-Windows version of Vim running in a MS-DOS window, this must be
+    " set to 0 otherwise the system may hang due to a Vim limitation.
+    if !exists('Tlist_Inc_Winwidth')
+        if (has('win16') || has('win95')) && !has('gui_running')
+            let Tlist_Inc_Winwidth = 0
+        else
+            let Tlist_Inc_Winwidth = 1
+        endif
+    endif
+
+    " Vertically split taglist window width setting
+    if !exists('Tlist_WinWidth')
+        let Tlist_WinWidth = 30
+    endif
+
+    " Horizontally split taglist window height setting
+    if !exists('Tlist_WinHeight')
+        let Tlist_WinHeight = 10
+    endif
+
+    " Display tag prototypes or tag names in the taglist window
+    if !exists('Tlist_Display_Prototype')
+        let Tlist_Display_Prototype = 0
+    endif
+
+    " Display tag scopes in the taglist window
+    if !exists('Tlist_Display_Tag_Scope')
+        let Tlist_Display_Tag_Scope = 1
+    endif
+
+    " Use single left mouse click to jump to a tag. By default this is disabled.
+    " Only double click using the mouse will be processed.
+    if !exists('Tlist_Use_SingleClick')
+        let Tlist_Use_SingleClick = 0
+    endif
+
+    " Control whether additional help is displayed as part of the taglist or
+    " not.  Also, controls whether empty lines are used to separate the tag
+    " tree.
+    if !exists('Tlist_Compact_Format')
+        let Tlist_Compact_Format = 0
+    endif
+
+    " Exit Vim if only the taglist window is currently open. By default, this is
+    " set to zero.
+    if !exists('Tlist_Exit_OnlyWindow')
+        let Tlist_Exit_OnlyWindow = 0
+    endif
+
+    " Automatically close the folds for the non-active files in the taglist
+    " window
+    if !exists('Tlist_File_Fold_Auto_Close')
+        let Tlist_File_Fold_Auto_Close = 0
+    endif
+
+    " Close the taglist window when a tag is selected
+    if !exists('Tlist_Close_On_Select')
+        let Tlist_Close_On_Select = 0
+    endif
+
+    " Automatically update the taglist window to display tags for newly
+    " edited files
+    if !exists('Tlist_Auto_Update')
+        let Tlist_Auto_Update = 1
+    endif
+
+    " Automatically highlight the current tag
+    if !exists('Tlist_Auto_Highlight_Tag')
+        let Tlist_Auto_Highlight_Tag = 1
+    endif
+    
+    " Automatically highlight the current tag on entering a buffer
+    if !exists('Tlist_Highlight_Tag_On_BufEnter')
+        let Tlist_Highlight_Tag_On_BufEnter = 1
+    endif
+
+    " Enable fold column to display the folding for the tag tree
+    if !exists('Tlist_Enable_Fold_Column')
+        let Tlist_Enable_Fold_Column = 1
+    endif
+
+    " Display the tags for only one file in the taglist window
+    if !exists('Tlist_Show_One_File')
+        let Tlist_Show_One_File = 0
+    endif
+
+    if !exists('Tlist_Max_Submenu_Items')
+        let Tlist_Max_Submenu_Items = 20
+    endif
+
+    if !exists('Tlist_Max_Tag_Length')
+        let Tlist_Max_Tag_Length = 10
+    endif
+
+    " Do not change the name of the taglist title variable. The winmanager
+    " plugin relies on this name to determine the title for the taglist
+    " plugin.
+    let TagList_title = "__Tag_List__"
+
+    " Taglist debug messages
+    let s:tlist_msg = ''
+
+    " Define the taglist autocommand to automatically open the taglist window
+    " on Vim startup
+    if g:Tlist_Auto_Open
+        autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open()
+    endif
+
+    " Refresh the taglist
+    if g:Tlist_Process_File_Always
+        autocmd BufEnter * call s:Tlist_Refresh()
+    endif
+
+    if g:Tlist_Show_Menu
+        autocmd GUIEnter * call s:Tlist_Menu_Init()
+    endif
+
+    " When the taglist buffer is created when loading a Vim session file,
+    " the taglist buffer needs to be initialized. The BufFilePost event
+    " is used to handle this case.
+    autocmd BufFilePost __Tag_List__ call s:Tlist_Vim_Session_Load()
+
+    " Define the user commands to manage the taglist window
+    command! -nargs=0 -bar TlistToggle call s:Tlist_Window_Toggle()
+    command! -nargs=0 -bar TlistOpen call s:Tlist_Window_Open()
+    " For backwards compatiblity define the Tlist command
+    command! -nargs=0 -bar Tlist TlistToggle
+    command! -nargs=+ -complete=file TlistAddFiles
+                \  call s:Tlist_Add_Files(<f-args>)
+    command! -nargs=+ -complete=dir TlistAddFilesRecursive
+                \ call s:Tlist_Add_Files_Recursive(<f-args>)
+    command! -nargs=0 -bar TlistClose call s:Tlist_Window_Close()
+    command! -nargs=0 -bar TlistUpdate call s:Tlist_Update_Current_File()
+    command! -nargs=0 -bar TlistHighlightTag call s:Tlist_Window_Highlight_Tag(
+                        \ fnamemodify(bufname('%'), ':p'), line('.'), 2, 1)
+    " For backwards compatiblity define the TlistSync command
+    command! -nargs=0 -bar TlistSync TlistHighlightTag
+    command! -nargs=* -complete=buffer TlistShowPrototype
+                \ echo Tlist_Get_Tag_Prototype_By_Line(<f-args>)
+    command! -nargs=* -complete=buffer TlistShowTag
+                \ echo Tlist_Get_Tagname_By_Line(<f-args>)
+    command! -nargs=* -complete=file TlistSessionLoad
+                \ call s:Tlist_Session_Load(<q-args>)
+    command! -nargs=* -complete=file TlistSessionSave
+                \ call s:Tlist_Session_Save(<q-args>)
+    command! -bar TlistLock let Tlist_Auto_Update=0
+    command! -bar TlistUnlock let Tlist_Auto_Update=1
+
+    " Commands for enabling/disabling debug and to display debug messages
+    command! -nargs=? -complete=file -bar TlistDebug
+                \ call s:Tlist_Debug_Enable(<q-args>)
+    command! -nargs=0 -bar TlistUndebug  call s:Tlist_Debug_Disable()
+    command! -nargs=0 -bar TlistMessages call s:Tlist_Debug_Show()
+
+    " Define autocommands to autoload the taglist plugin when needed.
+
+    " Trick to get the current script ID
+    map <SID>xx <SID>xx
+    let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$',
+                                \ '\1', '')
+    unmap <SID>xx
+
+    exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' .
+                \ escape(expand('<sfile>'), ' ')
+    exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' .
+                \ escape(expand('<sfile>'), ' ')
+    exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' .
+                \ escape(expand('<sfile>'), ' ')
+    exe 'autocmd FuncUndefined Tlist_* source ' .
+                \ escape(expand('<sfile>'), ' ')
+    exe 'autocmd FuncUndefined TagList_* source ' .
+                \ escape(expand('<sfile>'), ' ')
+
+    let loaded_taglist = 'fast_load_done'
+
+    if g:Tlist_Show_Menu && has('gui_running')
+        call s:Tlist_Menu_Init()
+    endif
 
-" Display tag prototypes or tag names in the taglist window
-if !exists('Tlist_Display_Prototype')
-    let Tlist_Display_Prototype = 0
+    " restore 'cpo'
+    let &cpo = s:cpo_save
+    finish
 endif
 
-" Use single left mouse click to jump to a tag. By default this is disabled.
-" Only double click using the mouse will be processed.
-if !exists('Tlist_Use_SingleClick')
-    let Tlist_Use_SingleClick = 0
+if !exists('s:tlist_sid')
+    " Two or more versions of taglist plugin are installed. Don't
+    " load this version of the plugin.
+    finish
 endif
 
-" Control whether additional help is displayed as part of the taglist or not.
-" Also, controls whether empty lines are used to separate the tag tree.
-if !exists('Tlist_Compact_Format')
-    let Tlist_Compact_Format = 0
+unlet! s:tlist_sid
+
+if loaded_taglist != 'fast_load_done'
+    " restore 'cpo'
+    let &cpo = s:cpo_save
+    finish
 endif
 
+" Taglist plugin functionality is available
+let loaded_taglist = 'available'
+
+"------------------- end of user configurable options --------------------
+
+" Default language specific settings for supported file types and tag types
+"
+" Variable name format:
+"
+"       s:tlist_def_{vim_ftype}_settings
+" 
+" vim_ftype - Filetype detected by Vim
+"
+" Value format:
+"
+"       <ctags_ftype>;<flag>:<name>;<flag>:<name>;...
+"
+" ctags_ftype - File type supported by exuberant ctags
+" flag        - Flag supported by exuberant ctags to generate a tag type
+" name        - Name of the tag type used in the taglist window to display the
+"               tags of this type
+"
+
 " assembly language
 let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type'
 
 " aspperl language
-let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub'
+let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable'
 
 " aspvbs language
-let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub'
+let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable'
 
 " awk language
 let s:tlist_def_awk_settings = 'awk;f:function'
 
 " beta language
-let s:tlist_def_beta_settings = 'beta;f:fragment;s:pattern;v:virtual'
+let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern'
 
 " c language
 let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' .
                            \ 'v:variable;f:function'
 
 " c++ language
-let s:tlist_def_cpp_settings = 'c++;v:variable;d:macro;t:typedef;c:class;' .
-                             \ 'g:enum;s:struct;u:union;f:function'
+let s:tlist_def_cpp_settings = 'c++;n:namespace;v:variable;d:macro;t:typedef;' .
+                             \ 'c:class;g:enum;s:struct;u:union;f:function'
+
+" c# language
+let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' .
+                             \ 'E:event;g:enum;s:struct;i:interface;' .
+                             \ 'p:properties;m:method'
 
 " cobol language
 let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
@@ -425,15 +398,27 @@ let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
 " eiffel language
 let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature'
 
+" erlang language
+let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function'
+
+" expect (same as tcl) language
+let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure'
+
 " fortran language
 let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' .
                     \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' .
                     \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine'
 
+" HTML language
+let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function'
+
 " java language
 let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
                               \ 'f:field;m:method'
 
+" javascript language
+let s:tlist_def_javascript_settings = 'javascript;f:function'
+
 " lisp language
 let s:tlist_def_lisp_settings = 'lisp;f:function'
 
@@ -447,10 +432,10 @@ let s:tlist_def_make_settings = 'make;m:macro'
 let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure'
 
 " perl language
-let s:tlist_def_perl_settings = 'perl;p:package;s:subroutine'
+let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine'
 
 " php language
-let s:tlist_def_php_settings = 'php;c:class;f:function'
+let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function'
 
 " python language
 let s:tlist_def_python_settings = 'python;c:class;m:member;f:function'
@@ -477,75 +462,341 @@ let s:tlist_def_zsh_settings = 'sh;f:function'
 " slang language
 let s:tlist_def_slang_settings = 'slang;n:namespace;f:function'
 
+" sml language
+let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' .
+                             \ 'r:structure;t:type;v:value;f:function'
+
 " sql language
 let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' .
             \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure'
 
 " tcl language
-let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;p:procedure'
+let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure'
+
+" vera language
+let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' .
+                                \ 'f:function;g:enum;m:member;p:program;' .
+                                \ 'P:prototype;t:task;T:typedef;v:variable;' .
+                                \ 'x:externvar'
 
 "verilog language
-let s:tlist_def_verilog_settings = 'verilog;m:module;P:parameter;r:reg;' .
-                                 \ 't:task;w:write;p:port;v:variable;f:function'
+let s:tlist_def_verilog_settings = 'verilog;m:module;c:constant;P:parameter;' .
+            \ 'e:event;r:register;t:task;w:write;p:port;v:variable;f:function'
 
 " vim language
-let s:tlist_def_vim_settings = 'vim;v:variable;f:function'
+let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function'
 
 " yacc language
 let s:tlist_def_yacc_settings = 'yacc;l:label'
 
-" Initialize the taglist script local variables for the supported file types
-" and tag types
-let s:tlist_winsize_chgd = 0
+"------------------- end of language specific options --------------------
+
+" Vim window size is changed by the taglist plugin or not
+let s:tlist_winsize_chgd = -1
+" Taglist window is maximized or not
 let s:tlist_win_maximized = 0
-let s:tlist_part_of_winmanager = 0
-" Do not change the name of the taglist title variable. The winmanager plugin
-" relies on this name to determine the title for the taglist plugin.
-let TagList_title = "__Tag_List__"
+" Name of files in the taglist
+let s:tlist_file_names=''
+" Number of files in the taglist
+let s:tlist_file_count = 0
+" Number of filetypes supported by taglist
+let s:tlist_ftype_count = 0
+" Is taglist part of other plugins like winmanager or cream?
+let s:tlist_app_name = "none"
+" Are we displaying brief help text
+let s:tlist_brief_help = 1
+" List of files removed on user request
+let s:tlist_removed_flist = ""
+" Index of current file displayed in the taglist window
+let s:tlist_cur_file_idx = -1
+" Taglist menu is empty or not
+let s:tlist_menu_empty = 1
+
+" An autocommand is used to refresh the taglist window when entering any
+" buffer. We don't want to refresh the taglist window if we are entering the
+" file window from one of the taglist functions. The 'Tlist_Skip_Refresh'
+" variable is used to skip the refresh of the taglist window and is set
+" and cleared appropriately.
+let s:Tlist_Skip_Refresh = 0
 
-function! s:Tlist_Show_Help()
-    if g:Tlist_Compact_Format == 1
+" Tlist_Window_Display_Help()
+function! s:Tlist_Window_Display_Help()
+    if s:tlist_app_name == "winmanager"
+        " To handle a bug in the winmanager plugin, add a space at the
+        " last line
+        call setline('$', ' ')
+    endif
+
+    if s:tlist_brief_help
+        " Add the brief help
+        call append(0, '" Press <F1> to display help text')
+    else
+        " Add the extensive help
+        call append(0, '" <enter> : Jump to tag definition')
+        call append(1, '" o : Jump to tag definition in new window')
+        call append(2, '" p : Preview the tag definition')
+        call append(3, '" <space> : Display tag prototype')
+        call append(4, '" u : Update tag list')
+        call append(5, '" s : Select sort field')
+        call append(6, '" d : Remove file from taglist')
+        call append(7, '" x : Zoom-out/Zoom-in taglist window')
+        call append(8, '" + : Open a fold')
+        call append(9, '" - : Close a fold')
+        call append(10, '" * : Open all folds')
+        call append(11, '" = : Close all folds')
+        call append(12, '" [[ : Move to the start of previous file')
+        call append(13, '" ]] : Move to the start of next file')
+        call append(14, '" q : Close the taglist window')
+        call append(15, '" <F1> : Remove help text')
+    endif
+endfunction
+
+" Tlist_Window_Toggle_Help_Text()
+" Toggle taglist plugin help text between the full version and the brief
+" version
+function! s:Tlist_Window_Toggle_Help_Text()
+    if g:Tlist_Compact_Format
         " In compact display mode, do not display help
         return
     endif
-    if exists("s:tlist_show_help") && s:tlist_show_help == 1
-        let s:tlist_show_help = 0
+
+    " Include the empty line displayed after the help text
+    let brief_help_size = 1
+    let full_help_size = 16
+
+    setlocal modifiable
+
+    " Set report option to a huge value to prevent informational messages
+    " while deleting the lines
+    let old_report = &report
+    set report=99999
+
+    " Remove the currently highlighted tag. Otherwise, the help text
+    " might be highlighted by mistake
+    match none
+
+    " Toggle between brief and full help text
+    if s:tlist_brief_help
+        let s:tlist_brief_help = 0
+
+        " Remove the previous help
+        exe '1,' . brief_help_size . ' delete _'
+
+        " Adjust the start/end line numbers for the files
+        call s:Tlist_Window_Update_Line_Offsets(0, 1, full_help_size - brief_help_size)
     else
-        let s:tlist_show_help = 1
+        let s:tlist_brief_help = 1
+
+        " Remove the previous help
+        exe '1,' . full_help_size . ' delete _'
+
+        " Adjust the start/end line numbers for the files
+        call s:Tlist_Window_Update_Line_Offsets(0, 0, full_help_size - brief_help_size)
     endif
 
-    call s:Tlist_Open_Window()
+    call s:Tlist_Window_Display_Help()
 
-    call s:Tlist_Init_Window(b:tlist_bufnum)
+    " Restore the report option
+    let &report = old_report
 
-    " Update the taglist window
-    call s:Tlist_Explore_File(b:tlist_bufnum)
+    setlocal nomodifiable
 endfunction
 
-" An autocommand is used to refresh the taglist window when entering any
-" buffer. We don't want to refresh the taglist window if we are entering the
-" file window from one of the taglist functions. The 'Tlist_Skip_Refresh'
-" variable is used to skip the refresh of the taglist window
-let s:Tlist_Skip_Refresh = 0
+" Taglist debug support
+let s:tlist_debug = 0
 
+" File for storing the debug messages
+let s:tlist_debug_file = ''
+
+" Tlist_Debug_Enable
+" Enable logging of taglist debug messages.
+function! s:Tlist_Debug_Enable(...)
+    let s:tlist_debug = 1
+
+    " Check whether a valid file name is supplied.
+    if a:1 != ''
+        let s:tlist_debug_file = fnamemodify(a:1, ':p')
+
+        " Empty the log file
+        exe 'redir! > ' . s:tlist_debug_file
+        redir END
+
+        " Check whether the log file is present/created
+        if !filewritable(s:tlist_debug_file)
+            call s:Tlist_Warning_Msg('Taglist: Unable to create log file '
+                        \ . s:tlist_debug_file)
+            let s:tlist_debug_file = ''
+        endif
+    endif
+endfunction
+
+" Tlist_Debug_Disable
+" Disable logging of taglist debug messages.
+function! s:Tlist_Debug_Disable(...)
+    let s:tlist_debug = 0
+    let s:tlist_debug_file = ''
+endfunction
+
+" Tlist_Debug_Show
+" Display the taglist debug messages in a new window
+function! s:Tlist_Debug_Show()
+    if s:tlist_msg == ''
+        call s:Tlist_Warning_Msg('Taglist: No debug messages')
+        return
+    endif
+
+    " Open a new window to display the taglist debug messages
+    new taglist_debug.txt
+    " Delete all the lines (if the buffer already exists)
+    silent! %delete _
+    " Add the messages
+    silent! put =s:tlist_msg
+    " Move the cursor to the first line
+    normal! gg
+endfunction
+
+" Tlist_Log_Msg
+" Log the supplied debug message along with the time
+function! s:Tlist_Log_Msg(msg)
+    if s:tlist_debug
+        if s:tlist_debug_file != ''
+            exe 'redir >> ' . s:tlist_debug_file
+            silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n"
+            redir END
+        else
+            " Log the message into a variable
+            " Retain only the last 3000 characters
+            let len = strlen(s:tlist_msg)
+            if len > 3000
+                let s:tlist_msg = strpart(s:tlist_msg, len - 3000)
+            endif
+            let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' . 
+                        \ a:msg . "\n"
+        endif
+    endif
+endfunction
+
+" Tlist_Warning_Msg()
+" Display a message using WarningMsg highlight group
 function! s:Tlist_Warning_Msg(msg)
     echohl WarningMsg
     echomsg a:msg
     echohl None
 endfunction
 
-" Tlist_Skip_Buffer()
-" Check whether tag listing is supported for the specified buffer.
-function! s:Tlist_Skip_Buffer(bufnum)
-    " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
-    if getbufvar(a:bufnum, '&buftype') != ''
-        return 1
+" Last returned file index for file name lookup.
+" Used to speed up file lookup
+let s:tlist_file_name_idx_cache = -1
+
+" Tlist_Get_File_Index()
+" Return the index of the specified filename
+function! s:Tlist_Get_File_Index(fname)
+    if s:tlist_file_count == 0 || a:fname == ''
+        return -1
+    endif
+
+    " If the new filename is same as the last accessed filename, then
+    " return that index
+    if s:tlist_file_name_idx_cache != -1 &&
+                \ s:tlist_file_name_idx_cache < s:tlist_file_count
+        if s:tlist_{s:tlist_file_name_idx_cache}_filename == a:fname
+            " Same as the last accessed file
+            return s:tlist_file_name_idx_cache
+        endif
+    endif
+
+    " First, check whether the filename is present
+    let s_fname = a:fname . "\n"
+    let i = stridx(s:tlist_file_names, s_fname)
+    if i == -1
+        let s:tlist_file_name_idx_cache = -1
+        return -1
+    endif
+
+    " Second, compute the file name index
+    let nl_txt = substitute(strpart(s:tlist_file_names, 0, i), "[^\n]", '', 'g')
+    let s:tlist_file_name_idx_cache = strlen(nl_txt)
+    return s:tlist_file_name_idx_cache
+endfunction
+
+" Last returned file index for line number lookup.
+" Used to speed up file lookup
+let s:tlist_file_lnum_idx_cache = -1
+
+" Tlist_Window_Get_File_Index_By_Linenum()
+" Return the index of the filename present in the specified line number
+" Line number refers to the line number in the taglist window
+function! s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+    call s:Tlist_Log_Msg('Tlist_Window_Get_File_Index_By_Linenum (' . a:lnum . ')')
+
+    " First try to see whether the new line number is within the range
+    " of the last returned file
+    if s:tlist_file_lnum_idx_cache != -1 &&
+                \ s:tlist_file_lnum_idx_cache < s:tlist_file_count
+        if a:lnum >= s:tlist_{s:tlist_file_lnum_idx_cache}_start &&
+                    \ a:lnum <= s:tlist_{s:tlist_file_lnum_idx_cache}_end
+            return s:tlist_file_lnum_idx_cache
+        endif
+    endif
+
+    let fidx = -1
+
+    if g:Tlist_Show_One_File
+        " Displaying only one file in the taglist window. Check whether
+        " the line is within the tags displayed for that file
+        if s:tlist_cur_file_idx != -1
+            if a:lnum >= s:tlist_{s:tlist_cur_file_idx}_start
+                        \ && a:lnum <= s:tlist_{s:tlist_cur_file_idx}_end
+                let fidx = s:tlist_cur_file_idx
+            endif
+
+        endif
+    else
+        " Do a binary search in the taglist
+        let left = 0
+        let right = s:tlist_file_count - 1
+
+        while left < right
+            let mid = (left + right) / 2
+
+            if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end
+                let s:tlist_file_lnum_idx_cache = mid
+                return mid
+            endif
+
+            if a:lnum < s:tlist_{mid}_start
+                let right = mid - 1
+            else
+                let left = mid + 1
+            endif
+        endwhile
+
+        if left >= 0 && left < s:tlist_file_count
+                    \ && a:lnum >= s:tlist_{left}_start
+                    \ && a:lnum <= s:tlist_{left}_end
+            let fidx = left
+        endif
     endif
 
-    let ftype = getbufvar(a:bufnum, '&filetype')
+    let s:tlist_file_lnum_idx_cache = fidx
+
+    return fidx
+endfunction
+
+" Tlist_Exe_Cmd_No_Acmds
+" Execute the specified Ex command after disabling autocommands
+function! s:Tlist_Exe_Cmd_No_Acmds(cmd)
+    let old_eventignore = &eventignore
+    set eventignore=all
+    exe a:cmd
+    let &eventignore = old_eventignore
+endfunction
 
-    " Skip buffers with filetype not set
-    if ftype == ''
+" Tlist_Skip_File()
+" Check whether tag listing is supported for the specified file
+function! s:Tlist_Skip_File(filename, ftype)
+    " Skip buffers with no names and buffers with filetype not set
+    if a:filename == '' || a:ftype == ''
         return 1
     endif
 
@@ -554,34 +805,52 @@ function! s:Tlist_Skip_Buffer(bufnum)
     " If it is not available, then check whether user specified settings are
     " available. If both are not available, then don't list the tags for this
     " filetype
-    let var = 's:tlist_def_' . ftype . '_settings'
+    let var = 's:tlist_def_' . a:ftype . '_settings'
     if !exists(var)
-        let var = 'g:tlist_' . ftype . '_settings'
+        let var = 'g:tlist_' . a:ftype . '_settings'
         if !exists(var)
             return 1
         endif
     endif
 
-    let filename = fnamemodify(bufname(a:bufnum), '%:p')
-
-    " Skip buffers with no names
-    if filename == ''
-        return 1
-    endif
-
     " Skip files which are not readable or files which are not yet stored
     " to the disk
-    if !filereadable(filename)
+    if !filereadable(a:filename)
         return 1
     endif
 
     return 0
 endfunction
 
-" Tlist_FileType_Init
-" Initialize the ctags arguments and tag variable for the specified
-" file type
+" Tlist_User_Removed_File
+" Returns 1 if a file is removed by a user from the taglist
+function! s:Tlist_User_Removed_File(filename)
+    return stridx(s:tlist_removed_flist, a:filename . "\n") != -1
+endfunction
+
+" Tlist_Update_Remove_List
+" Update the list of user removed files from the taglist
+" add == 1, add the file to the removed list
+" add == 0, delete the file from the removed list
+function! s:Tlist_Update_Remove_List(filename, add)
+    if a:add
+        let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n"
+    else
+        let idx = stridx(s:tlist_removed_flist, a:filename . "\n")
+        let text_before = strpart(s:tlist_removed_flist, 0, idx)
+        let rem_text = strpart(s:tlist_removed_flist, idx)
+        let next_idx = stridx(rem_text, "\n")
+        let text_after = strpart(rem_text, next_idx + 1)
+
+        let s:tlist_removed_flist = text_before . text_after
+    endif
+endfunction
+
+" Tlist_FileType_Init
+" Initialize the ctags arguments and tag variable for the specified
+" file type
 function! s:Tlist_FileType_Init(ftype)
+    call s:Tlist_Log_Msg('Tlist_FileType_Init (' . a:ftype . ')')
     " If the user didn't specify any settings, then use the default
     " ctags args. Otherwise, use the settings specified by the user
     let var = 'g:tlist_' . a:ftype . '_settings'
@@ -599,9 +868,14 @@ function! s:Tlist_FileType_Init(ftype)
         let settings = s:tlist_def_{a:ftype}_settings . ';'
     endif
 
-    let msg = 'Invalid ctags option setting - ' . settings
+    let msg = 'Taglist: Invalid ctags option setting - ' . settings
 
-    " Extract the file type to pass to ctags. This can be different from the
+    " Format of the option that specifies the filetype and ctags arugments:
+    "
+    "       <language_name>;flag1:name1;flag2:name2;flag3:name3
+    "
+
+    " Extract the file type to pass to ctags. This may be different from the
     " file type detected by Vim
     let pos = stridx(settings, ';')
     if pos == -1
@@ -639,7 +913,7 @@ function! s:Tlist_FileType_Init(ftype)
             call s:Tlist_Warning_Msg(msg)
             return 0
         endif
-        let flag = strpart(settings, 0, pos) 
+        let flag = strpart(settings, 0, pos)
         if flag == ''
             call s:Tlist_Warning_Msg(msg)
             return 0
@@ -672,123 +946,404 @@ function! s:Tlist_FileType_Init(ftype)
     let s:tlist_{a:ftype}_count = cnt
     let s:tlist_{a:ftype}_ctags_flags = ctags_flags
 
+    " Save the filetype name
+    let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype
+    let s:tlist_ftype_count = s:tlist_ftype_count + 1
+
     return 1
 endfunction
 
-" Tlist_Cleanup()
-" Cleanup all the taglist window variables.
-function! s:Tlist_Cleanup()
-    if has('syntax')
-        silent! syntax clear TagListTitle
+" Tlist_Detect_Filetype
+" Determine the filetype for the specified file using the filetypedetect
+" autocmd.
+function! s:Tlist_Detect_Filetype(fname)
+    " Ignore the filetype autocommands
+    let old_eventignore = &eventignore
+    set eventignore=FileType
+
+    " Save the 'filetype', as this will be changed temporarily
+    let old_filetype = &filetype
+
+    " Run the filetypedetect group of autocommands to determine
+    " the filetype
+    exe 'doautocmd filetypedetect BufRead ' . a:fname
+
+    " Save the detected filetype
+    let ftype = &filetype
+
+    " Restore the previous state
+    let &filetype = old_filetype
+    let &eventignore = old_eventignore
+
+    return ftype
+endfunction
+
+" Tlist_Get_Buffer_Filetype
+" Get the filetype for the specified buffer
+function! s:Tlist_Get_Buffer_Filetype(bnum)
+    let buf_ft = getbufvar(a:bnum, '&filetype')
+
+    if bufloaded(a:bnum)
+        " For loaded buffers, the 'filetype' is already determined
+        return buf_ft
     endif
-    match none
 
-    if exists('b:tlist_ftype') && b:tlist_ftype != ''
-        let count_var_name = 's:tlist_' . b:tlist_ftype . '_count'
-        if exists(count_var_name)
-            let old_ftype = b:tlist_ftype
-            let i = 1
-            while i <= s:tlist_{old_ftype}_count
-                let ttype = s:tlist_{old_ftype}_{i}_name
-                let j = 1
-                let var_name = 'b:tlist_' . old_ftype . '_' . ttype . '_count'
-                if exists(var_name)
-                    let cnt = b:tlist_{old_ftype}_{ttype}_count
-                else
-                    let cnt = 0
-                endif
-                while j <= cnt
-                    unlet! b:tlist_{old_ftype}_{ttype}_{j}
-                    let j = j + 1
-                endwhile
-                unlet! b:tlist_{old_ftype}_{ttype}_count
-                unlet! b:tlist_{old_ftype}_{ttype}_start
-                let i = i + 1
+    " For unloaded buffers, if the 'filetype' option is set, return it
+    if buf_ft != ''
+        return buf_ft
+    endif
+
+    " Skip non-existent buffers
+    if !bufexists(a:bnum)
+        return ''
+    endif
+
+    " For buffers whose filetype is not yet determined, try to determine
+    " the filetype
+    let bname = bufname(a:bnum)
+
+    return s:Tlist_Detect_Filetype(bname)
+endfunction
+
+" Tlist_Discard_TagInfo
+" Discard the stored tag information for a file
+function! s:Tlist_Discard_TagInfo(fidx)
+    call s:Tlist_Log_Msg('Tlist_Discard_TagInfo (' .
+                \ s:tlist_{a:fidx}_filename . ')')
+    let ftype = s:tlist_{a:fidx}_filetype
+
+    " Discard information about the tags defined in the file
+    let i = 1
+    while i <= s:tlist_{a:fidx}_tag_count
+        let fidx_i = 's:tlist_' . a:fidx . '_' . i
+        unlet! {fidx_i}_tag
+        unlet! {fidx_i}_tag_name
+        unlet! {fidx_i}_tag_type
+        unlet! {fidx_i}_ttype_idx
+        unlet! {fidx_i}_tag_proto
+        unlet! {fidx_i}_tag_searchpat
+        unlet! {fidx_i}_tag_linenum
+        let i = i + 1
+    endwhile
+
+    let s:tlist_{a:fidx}_tag_count = 0
+
+    " Discard information about tag type groups
+    let i = 1
+    while i <= s:tlist_{ftype}_count
+        let ttype = s:tlist_{ftype}_{i}_name
+        if s:tlist_{a:fidx}_{ttype} != ''
+            let fidx_ttype = 's:tlist_' . a:fidx . '_' . ttype
+            let {fidx_ttype} = ''
+            let {fidx_ttype}_offset = 0
+            let cnt = {fidx_ttype}_count
+            let {fidx_ttype}_count = 0
+            let j = 1
+            while j <= cnt
+                unlet! {fidx_ttype}_{j}
+                let j = j + 1
             endwhile
         endif
+        let i = i + 1
+    endwhile
+
+    " Discard the stored menu command also
+    let s:tlist_{a:fidx}_menu_cmd = ''
+endfunction
+
+" Tlist_Window_Update_Line_Offsets
+" Update the line offsets for tags for files starting from start_idx
+" and displayed in the taglist window by the specified offset
+function! s:Tlist_Window_Update_Line_Offsets(start_idx, increment, offset)
+    let i = a:start_idx
+
+    while i < s:tlist_file_count
+        if s:tlist_{i}_visible
+            " Update the start/end line number only if the file is visible
+            if a:increment
+                let s:tlist_{i}_start = s:tlist_{i}_start + a:offset
+                let s:tlist_{i}_end = s:tlist_{i}_end + a:offset
+            else
+                let s:tlist_{i}_start = s:tlist_{i}_start - a:offset
+                let s:tlist_{i}_end = s:tlist_{i}_end - a:offset
+            endif
+        endif
+        let i = i + 1
+    endwhile
+endfunction
+
+" Tlist_Discard_FileInfo
+" Discard the stored information for a file
+function! s:Tlist_Discard_FileInfo(fidx)
+    call s:Tlist_Log_Msg('Tlist_Discard_FileInfo (' .
+                \ s:tlist_{a:fidx}_filename . ')')
+    call s:Tlist_Discard_TagInfo(a:fidx)
+
+    let ftype = s:tlist_{a:fidx}_filetype
+
+    let i = 1
+    while i <= s:tlist_{ftype}_count
+        let ttype = s:tlist_{ftype}_{i}_name
+        unlet! s:tlist_{a:fidx}_{ttype}
+        unlet! s:tlist_{a:fidx}_{ttype}_offset
+        unlet! s:tlist_{a:fidx}_{ttype}_count
+        let i = i + 1
+    endwhile
+
+    unlet! s:tlist_{a:fidx}_filename
+    unlet! s:tlist_{a:fidx}_sort_type
+    unlet! s:tlist_{a:fidx}_filetype
+    unlet! s:tlist_{a:fidx}_mtime
+    unlet! s:tlist_{a:fidx}_start
+    unlet! s:tlist_{a:fidx}_end
+    unlet! s:tlist_{a:fidx}_valid
+    unlet! s:tlist_{a:fidx}_visible
+    unlet! s:tlist_{a:fidx}_tag_count
+    unlet! s:tlist_{a:fidx}_menu_cmd
+endfunction
+
+" Tlist_Window_Remove_File_From_Display
+" Remove the specified file from display
+function! s:Tlist_Window_Remove_File_From_Display(fidx)
+    call s:Tlist_Log_Msg('Tlist_Window_Remove_File_From_Display (' .
+                \ s:tlist_{a:fidx}_filename . ')')
+    " If the file is not visible then no need to remove it
+    if !s:tlist_{a:fidx}_visible
+        return
+    endif
+
+    " Remove the tags displayed for the specified file from the window
+    let start = s:tlist_{a:fidx}_start
+    " Include the empty line after the last line also
+    if g:Tlist_Compact_Format
+        let end = s:tlist_{a:fidx}_end
+    else
+        let end = s:tlist_{a:fidx}_end + 1
+    endif
+
+    setlocal modifiable
+    exe 'silent! ' . start . ',' . end . 'delete _'
+    setlocal nomodifiable
+
+    " Correct the start and end line offsets for all the files following
+    " this file, as the tags for this file are removed
+    call s:Tlist_Window_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1)
+endfunction
+
+" Tlist_Remove_File
+" Remove the file under the cursor or the specified file index
+" user_request - User requested to remove the file from taglist
+function! s:Tlist_Remove_File(file_idx, user_request)
+    let fidx = a:file_idx
+
+    if fidx == -1
+        let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+        if fidx == -1
+            return
+        endif
     endif
+    call s:Tlist_Log_Msg('Tlist_Remove_File (' .
+                \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')')
 
-    " Clean up all the variables containing the tags output
-    if exists('b:tlist_tag_count')
-        while b:tlist_tag_count > 0
-            unlet! b:tlist_tag_{b:tlist_tag_count}
-            let b:tlist_tag_count = b:tlist_tag_count - 1
-        endwhile
+    let save_winnr = winnr()
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum != -1
+        " Taglist window is open, remove the file from display
+
+        if save_winnr != winnum
+            let old_eventignore = &eventignore
+            set eventignore=all
+            exe winnum . 'wincmd w'
+        endif
+
+        call s:Tlist_Window_Remove_File_From_Display(fidx)
+
+        if save_winnr != winnum
+            exe save_winnr . 'wincmd w'
+            let &eventignore = old_eventignore
+        endif
+    endif
+
+    let fname = s:tlist_{fidx}_filename
+
+    if a:user_request
+        " As the user requested to remove the file from taglist,
+        " add it to the removed list
+        call s:Tlist_Update_Remove_List(fname, 1)
     endif
 
-    unlet! b:tlist_bufnum
-    unlet! b:tlist_bufname
-    unlet! b:tlist_ftype
+    " Remove the file name from the taglist list of filenames
+    let idx = stridx(s:tlist_file_names, fname . "\n")
+    let text_before = strpart(s:tlist_file_names, 0, idx)
+    let rem_text = strpart(s:tlist_file_names, idx)
+    let next_idx = stridx(rem_text, "\n")
+    let text_after = strpart(rem_text, next_idx + 1)
+    let s:tlist_file_names = text_before . text_after
+
+    call s:Tlist_Discard_FileInfo(fidx)
+
+    " Shift all the file variables by one index
+    let i = fidx + 1
+
+    while i < s:tlist_file_count
+        let j = i - 1
+
+        let s:tlist_{j}_filename = s:tlist_{i}_filename
+        let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type
+        let s:tlist_{j}_filetype = s:tlist_{i}_filetype
+        let s:tlist_{j}_mtime = s:tlist_{i}_mtime
+        let s:tlist_{j}_start = s:tlist_{i}_start
+        let s:tlist_{j}_end = s:tlist_{i}_end
+        let s:tlist_{j}_valid = s:tlist_{i}_valid
+        let s:tlist_{j}_visible = s:tlist_{i}_visible
+        let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count
+        let s:tlist_{j}_menu_cmd = s:tlist_{i}_menu_cmd
+
+        let k = 1
+        while k <= s:tlist_{j}_tag_count
+            let s:tlist_{j}_{k}_tag = s:tlist_{i}_{k}_tag
+            let s:tlist_{j}_{k}_tag_name = s:tlist_{i}_{k}_tag_name
+            let s:tlist_{j}_{k}_tag_type = s:Tlist_Get_Tag_Type_By_Tag(i, k)
+            let s:tlist_{j}_{k}_ttype_idx = s:tlist_{i}_{k}_ttype_idx
+            let s:tlist_{j}_{k}_tag_proto = s:Tlist_Get_Tag_Prototype(i, k)
+            let s:tlist_{j}_{k}_tag_searchpat = s:Tlist_Get_Tag_SearchPat(i, k)
+            let s:tlist_{j}_{k}_tag_linenum = s:Tlist_Get_Tag_Linenum(i, k)
+            let k = k + 1
+        endwhile
+
+        let ftype = s:tlist_{i}_filetype
+
+        let k = 1
+        while k <= s:tlist_{ftype}_count
+            let ttype = s:tlist_{ftype}_{k}_name
+            let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype}
+            let s:tlist_{j}_{ttype}_offset = s:tlist_{i}_{ttype}_offset
+            let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count
+            if s:tlist_{j}_{ttype} != ''
+                let l = 1
+                while l <= s:tlist_{j}_{ttype}_count
+                    let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l}
+                    let l = l + 1
+                endwhile
+            endif
+            let k = k + 1
+        endwhile
+
+        " As the file and tag information is copied to the new index,
+        " discard the previous information
+        call s:Tlist_Discard_FileInfo(i)
+
+        let i = i + 1
+    endwhile
+
+    " Reduce the number of files displayed
+    let s:tlist_file_count = s:tlist_file_count - 1
+
+    if g:Tlist_Show_One_File
+        " If the tags for only one file is displayed and if we just
+        " now removed that file, then invalidate the current file idx
+        if s:tlist_cur_file_idx == fidx
+            let s:tlist_cur_file_idx = -1
+        endif
+    endif
 endfunction
 
-" Tlist_Open_Window
-" Create a new taglist window. If it is already open, clear it
-function! s:Tlist_Open_Window()
-    " If used with winmanager don't open windows. Winmanager will handle
-    " the window/buffer management
-    if s:tlist_part_of_winmanager
-        return
+" Tlist_Window_Goto_Window
+" Goto the taglist window
+function! s:Tlist_Window_Goto_Window()
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum != -1
+        if winnr() != winnum
+            call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
+        endif
     endif
+endfunction
 
-    " Cleanup the taglist window listing, if the window is open
+" Tlist_Window_Create
+" Create a new taglist window. If it is already open, jump to it
+function! s:Tlist_Window_Create()
+    call s:Tlist_Log_Msg('Tlist_Window_Create()')
+    " If the window is open, jump to it
     let winnum = bufwinnr(g:TagList_title)
     if winnum != -1
         " Jump to the existing window
         if winnr() != winnum
             exe winnum . 'wincmd w'
         endif
+        return
+    endif
+
+    " If used with winmanager don't open windows. Winmanager will handle
+    " the window/buffer management
+    if s:tlist_app_name == "winmanager"
+        return
+    endif
+
+    " Create a new window. If user prefers a horizontal window, then open
+    " a horizontally split window. Otherwise open a vertically split
+    " window
+    if g:Tlist_Use_Horiz_Window
+        " Open a horizontally split window
+        let win_dir = 'botright'
+        " Horizontal window height
+        let win_size = g:Tlist_WinHeight
     else
-        " Create a new window. If user prefers a horizontal window, then open
-        " a horizontally split window. Otherwise open a vertically split
-        " window
-        if g:Tlist_Use_Horiz_Window == 1
-            " If a single window is used for all files, then open the tag
-            " listing window at the very bottom
-            let win_dir = 'botright'
-            " Horizontal window height
-            let win_size = g:Tlist_WinHeight
-        else
-            " Increase the window size, if needed, to accomodate the new
-            " window
-            if g:Tlist_Inc_Winwidth == 1 &&
+        if s:tlist_winsize_chgd == -1
+            " Open a vertically split window. Increase the window size, if
+            " needed, to accomodate the new window
+            if g:Tlist_Inc_Winwidth &&
                         \ &columns < (80 + g:Tlist_WinWidth)
+                " Save the original window position
+                let s:tlist_pre_winx = getwinposx()
+                let s:tlist_pre_winy = getwinposy()
+
                 " one extra column is needed to include the vertical split
-                let &columns= &columns + (g:Tlist_WinWidth + 1)
+                let &columns= &columns + g:Tlist_WinWidth + 1
+
                 let s:tlist_winsize_chgd = 1
             else
                 let s:tlist_winsize_chgd = 0
             endif
-
-            " Open the window at the leftmost place
-            if g:Tlist_Use_Right_Window == 1
-                let win_dir = 'botright vertical'
-            else
-                let win_dir = 'topleft vertical'
-            endif
-            let win_size = g:Tlist_WinWidth
         endif
 
-        " If the tag listing temporary buffer already exists, then reuse it.
-        " Otherwise create a new buffer
-        let bufnum = bufnr(g:TagList_title)
-        if bufnum == -1
-            " Create a new buffer
-            let wcmd = g:TagList_title
+        if g:Tlist_Use_Right_Window
+            " Open the window at the rightmost place
+            let win_dir = 'botright vertical'
         else
-            " Edit the existing buffer
-            let wcmd = '+buffer' . bufnum
+            " Open the window at the leftmost place
+            let win_dir = 'topleft vertical'
         endif
+        let win_size = g:Tlist_WinWidth
+    endif
 
-        " Create the taglist window
-        exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
+    " If the tag listing temporary buffer already exists, then reuse it.
+    " Otherwise create a new buffer
+    let bufnum = bufnr(g:TagList_title)
+    if bufnum == -1
+        " Create a new buffer
+        let wcmd = g:TagList_title
+    else
+        " Edit the existing buffer
+        let wcmd = '+buffer' . bufnum
     endif
+
+    " Create the taglist window
+    exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
+
+    " Save the new window position
+    let s:tlist_winx = getwinposx()
+    let s:tlist_winy = getwinposy()
+
+    " Initialize the taglist window
+    call s:Tlist_Window_Init()
 endfunction
 
-" Tlist_Zoom_Window
+" Tlist_Window_Zoom
 " Zoom (maximize/minimize) the taglist window
-function! s:Tlist_Zoom_Window()
-    if s:tlist_win_maximized == 1
-        if g:Tlist_Use_Horiz_Window == 1
+function! s:Tlist_Window_Zoom()
+    if s:tlist_win_maximized
+        " Restore the window back to the previous size
+        if g:Tlist_Use_Horiz_Window
             exe 'resize ' . g:Tlist_WinHeight
         else
             exe 'vert resize ' . g:Tlist_WinWidth
@@ -797,7 +1352,7 @@ function! s:Tlist_Zoom_Window()
     else
         " Set the window size to the maximum possible without closing other
         " windows
-        if g:Tlist_Use_Horiz_Window == 1
+        if g:Tlist_Use_Horiz_Window
             resize
         else
             vert resize
@@ -806,123 +1361,163 @@ function! s:Tlist_Zoom_Window()
     endif
 endfunction
 
-" Tlist_Init_Window
-" Set the default options for the taglist window
-function! s:Tlist_Init_Window(bufnum)
-    " Set report option to a huge value to prevent informations messages
-    " while deleting the lines
-    let old_report = &report
-    set report=99999
-
-    " Mark the buffer as modifiable
-    setlocal modifiable
-
-    " Delete the contents of the buffer to the black-hole register
-    silent! %delete _
-
-    " Mark the buffer as not modifiable
-    setlocal nomodifiable
-
-    " Restore the report option
-    let &report = old_report
-
-    " Clean up all the old variables used for the last filetype
-    call <SID>Tlist_Cleanup()
-
-    let filename = fnamemodify(bufname(a:bufnum), ':p')
-
-    " Set the sort type. First time, use the global setting. After that use
-    " the previous setting
-    let b:tlist_sort_type = getbufvar(a:bufnum, 'tlist_sort_type')
-    if b:tlist_sort_type == ''
-        let b:tlist_sort_type = g:Tlist_Sort_Type
+" Tlist_Ballon_Expr
+" When the mouse cursor is over a tag in the taglist window, display the
+" tag prototype (balloon)
+function! Tlist_Ballon_Expr()
+    " Get the file index
+    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(v:beval_lnum)
+    if fidx == -1
+        return ''
     endif
 
-    let b:tlist_tag_count = 0
-    let b:tlist_bufnum = a:bufnum
-    let b:tlist_bufname = fnamemodify(bufname(a:bufnum), ':p')
-    let b:tlist_ftype = getbufvar(a:bufnum, '&filetype')
+    " Get the tag output line for the current tag
+    let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum)
+    if tidx == 0
+        return ''
+    endif
 
-    " Mark the buffer as modifiable
-    setlocal modifiable
+    " Get the tag search pattern and display it
+    return s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
 
-    if s:tlist_part_of_winmanager
-        " To handle a bug in the winmanager plugin, add a space at the
-        " last line
-        call setline('$', ' ')
+" Tlist_Window_Check_Width
+" Check the width of the taglist window. For horizontally split windows, the
+" 'winfixheight' option is used to fix the height of the window. For
+" vertically split windows, Vim doesn't support the 'winfixwidth' option. So
+" need to handle window width changes from this function.
+function! s:Tlist_Window_Check_Width()
+    let tlist_winnr = bufwinnr(g:TagList_title)
+    if tlist_winnr == -1
+        return
     endif
 
-    if g:Tlist_Compact_Format == 0
-        if exists("s:tlist_show_help") && s:tlist_show_help == 1
-            call append(0, '" <enter> : Jump to tag definition')
-            call append(1, '" o : Jump to tag definition in new window')
-            call append(2, '" <space> : Display tag prototype')
-            call append(3, '" u : Update tag list')
-            call append(4, '" s : Select sort field')
-            call append(5, '" x : Zoom-out/Zoom-in taglist window')
-            call append(6, '" + : Open a fold')
-            call append(7, '" - : Close a fold')
-            call append(8, '" * : Open all folds')
-            call append(9, '" q : Close the taglist window')
-            call append(10, '" ? : Remove help text')
-            call append(11, '" Sorted by ' . b:tlist_sort_type)
-            call append(12, '"= ' . fnamemodify(filename, ':t') . ' (' . 
-                                   \ fnamemodify(filename, ':p:h') . ')')
-        else
-            call append(0, '" Press ? to display help text')
-            call append(1, '" Sorted by ' . b:tlist_sort_type)
-            call append(2, '"= ' . fnamemodify(filename, ':t') . ' (' . 
-                                   \ fnamemodify(filename, ':p:h') . ')')
+    let width = winwidth(tlist_winnr)
+    if width != g:Tlist_WinWidth
+        call s:Tlist_Log_Msg("Tlist_Window_Check_Width: Changing window " .
+                    \ "width from " . width . " to " . g:Tlist_WinWidth)
+        let save_winnr = winnr()
+        if save_winnr != tlist_winnr
+            call s:Tlist_Exe_Cmd_No_Acmds(tlist_winnr . 'wincmd w')
+        endif
+        exe 'vert resize ' . g:Tlist_WinWidth
+        if save_winnr != tlist_winnr
+            call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
         endif
     endif
+endfunction
 
-    " Mark the buffer as not modifiable
-    setlocal nomodifiable
-
-    " Highlight the comments
-    if has('syntax')
-        syntax match TagListComment '^" .*'
-        syntax match TagListSortBy  '^" Sorted by .*'
-        syntax match TagListCurDir  '^"= .*'
+" Tlist_Window_Exit_Only_Window
+" If the 'Tlist_Exit_OnlyWindow' option is set, then exit Vim if only the
+" taglist window is present.
+function! s:Tlist_Window_Exit_Only_Window()
+    " Before quitting Vim, delete the taglist buffer so that
+    " the '0 mark is correctly set to the previous buffer.
+    if v:version < 700
+       if winbufnr(2) == -1
+           bdelete
+           quit
+       endif
+    else
+       if winbufnr(2) == -1
+           if tabpagenr('$') == 1
+               " Only one tag page is present
+               bdelete
+               quit
+           else
+               " More than one tab page is present. Close only the current
+               " tab page
+               close
+           endif
+       endif
+    endif
+endfunction
 
-        " Colors used to highlight the selected tag name
-        highlight clear TagName
-        if has('gui_running') || &t_Co > 2
-            highlight link TagName Search
+" Tlist_Window_Init
+" Set the default options for the taglist window
+function! s:Tlist_Window_Init()
+    call s:Tlist_Log_Msg('Tlist_Window_Init()')
+
+    " The 'readonly' option should not be set for the taglist buffer.
+    " If Vim is started as "view/gview" or if the ":view" command is
+    " used, then the 'readonly' option is set for all the buffers.
+    " Unset it for the taglist buffer
+    setlocal noreadonly
+
+    " Set the taglist buffer filetype to taglist
+    setlocal filetype=taglist
+
+    " Define taglist window element highlighting
+    syntax match TagListComment '^" .*'
+    syntax match TagListFileName '^[^" ].*$'
+    syntax match TagListTitle '^  \S.*$'
+    syntax match TagListTagScope  '\s\[.\{-\}\]$'
+
+    " Define the highlighting only if colors are supported
+    if has('gui_running') || &t_Co > 2
+        " Colors to highlight various taglist window elements
+        " If user defined highlighting group exists, then use them.
+        " Otherwise, use default highlight groups.
+        if hlexists('MyTagListTagName')
+            highlight link TagListTagName MyTagListTagName
         else
-            highlight TagName term=reverse cterm=reverse
+            highlight default link TagListTagName Search
         endif
-
         " Colors to highlight comments and titles
-        highlight clear TagListComment
-        highlight link TagListComment Comment
-        highlight clear TagListTitle
-        highlight link TagListTitle Title
-        highlight clear TagListSortBy
-        highlight link TagListSortBy String
-        highlight clear TagListCurDir
-        highlight link TagListCurDir Statement
+        if hlexists('MyTagListComment')
+            highlight link TagListComment MyTagListComment
+        else
+            highlight clear TagListComment
+            highlight default link TagListComment Comment
+        endif
+        if hlexists('MyTagListTitle')
+            highlight link TagListTitle MyTagListTitle
+        else
+            highlight clear TagListTitle
+            highlight default link TagListTitle Title
+        endif
+        if hlexists('MyTagListFileName')
+            highlight link TagListFileName MyTagListFileName
+        else
+            highlight clear TagListFileName
+            highlight default TagListFileName guibg=Grey ctermbg=darkgray
+                        \ guifg=white ctermfg=white
+        endif
+        if hlexists('MyTagListTagScope')
+            highlight link TagListTagScope MyTagListTagScope
+        else
+            highlight clear TagListTagScope
+            highlight default link TagListTagScope Identifier
+        endif
+    else
+        highlight default TagListTagName term=reverse cterm=reverse
     endif
 
     " Folding related settings
-    if has('folding')
-        setlocal foldenable
-        setlocal foldmethod=manual
-        setlocal foldcolumn=2
-        setlocal foldtext=v:folddashes.getline(v:foldstart)
+    setlocal foldenable
+    setlocal foldminlines=0
+    setlocal foldmethod=manual
+    setlocal foldlevel=9999
+    if g:Tlist_Enable_Fold_Column
+        setlocal foldcolumn=3
+    else
+        setlocal foldcolumn=0
     endif
+    setlocal foldtext=v:folddashes.getline(v:foldstart)
 
-    if !s:tlist_part_of_winmanager
-    " Mark buffer as scratch
-    silent! setlocal buftype=nofile
-    silent! setlocal bufhidden=delete
-    silent! setlocal noswapfile
-    " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted
-    " buffers. So if the taglist buffer is unlisted, multiple taglist
-    " windows will be opened. This bug is fixed in Vim 6.1 and above
-    if v:version >= 601
-        silent! setlocal nobuflisted
-    endif
+    if s:tlist_app_name != "winmanager"
+        " Mark buffer as scratch
+        silent! setlocal buftype=nofile
+        if s:tlist_app_name == "none"
+            silent! setlocal bufhidden=delete
+        endif
+        silent! setlocal noswapfile
+        " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted
+        " buffers. So if the taglist buffer is unlisted, multiple taglist
+        " windows will be opened. This bug is fixed in Vim 6.1 and above
+        if v:version >= 601
+            silent! setlocal nobuflisted
+        endif
     endif
 
     silent! setlocal nowrap
@@ -932,272 +1527,354 @@ function! s:Tlist_Init_Window(bufnum)
     " window
     silent! setlocal nonumber
 
+    " Use fixed height when horizontally split window is used
+    if g:Tlist_Use_Horiz_Window
+        if v:version >= 602
+            set winfixheight
+        endif
+    endif
+    if !g:Tlist_Use_Horiz_Window && v:version >= 700
+        set winfixwidth
+    endif
+
+    " Setup balloon evaluation to display tag prototype
+    if v:version >= 700 && has('balloon_eval')
+        setlocal balloonexpr=Tlist_Ballon_Expr()
+        set ballooneval
+    endif
+
+    " Setup the cpoptions properly for the maps to work
+    let old_cpoptions = &cpoptions
+    set cpoptions&vim
+
     " Create buffer local mappings for jumping to the tags and sorting the list
-    nnoremap <buffer> <silent> <CR> :call <SID>Tlist_Jump_To_Tag(0)<CR>
-    nnoremap <buffer> <silent> o :call <SID>Tlist_Jump_To_Tag(1)<CR>
-    nnoremap <buffer> <silent> <2-LeftMouse> :call <SID>Tlist_Jump_To_Tag(0)<CR>
-    nnoremap <buffer> <silent> s :call <SID>Tlist_Change_Sort()<CR>
+    nnoremap <buffer> <silent> <CR>
+                \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+    nnoremap <buffer> <silent> o
+                \ :call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+    nnoremap <buffer> <silent> p
+                \ :call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+    nnoremap <buffer> <silent> P
+                \ :call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+    if v:version >= 700
+    nnoremap <buffer> <silent> t
+                \ :call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+    nnoremap <buffer> <silent> <C-t>
+                \ :call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+    endif
+    nnoremap <buffer> <silent> <2-LeftMouse>
+                \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+    nnoremap <buffer> <silent> s
+                \ :call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
     nnoremap <buffer> <silent> + :silent! foldopen<CR>
     nnoremap <buffer> <silent> - :silent! foldclose<CR>
     nnoremap <buffer> <silent> * :silent! %foldopen!<CR>
+    nnoremap <buffer> <silent> = :silent! %foldclose<CR>
     nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR>
     nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR>
     nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR>
-    nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Show_Tag_Prototype()<CR>
-    nnoremap <buffer> <silent> u :call <SID>Tlist_Update_Window()<CR>
-    nnoremap <buffer> <silent> x :call <SID>Tlist_Zoom_Window()<CR>
-    nnoremap <buffer> <silent> ? :call <SID>Tlist_Show_Help()<CR>
+    nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Window_Show_Info()<CR>
+    nnoremap <buffer> <silent> u :call <SID>Tlist_Window_Update_File()<CR>
+    nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1, 1)<CR>
+    nnoremap <buffer> <silent> x :call <SID>Tlist_Window_Zoom()<CR>
+    nnoremap <buffer> <silent> [[ :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+    nnoremap <buffer> <silent> <BS> :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+    nnoremap <buffer> <silent> ]] :call <SID>Tlist_Window_Move_To_File(1)<CR>
+    nnoremap <buffer> <silent> <Tab> :call <SID>Tlist_Window_Move_To_File(1)<CR>
+    nnoremap <buffer> <silent> <F1> :call <SID>Tlist_Window_Toggle_Help_Text()<CR>
     nnoremap <buffer> <silent> q :close<CR>
 
+    " Insert mode mappings
+    inoremap <buffer> <silent> <CR>
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+    " Windows needs return
+    inoremap <buffer> <silent> <Return>
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+    inoremap <buffer> <silent> o
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+    inoremap <buffer> <silent> p
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+    inoremap <buffer> <silent> P
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+    if v:version >= 700
+    inoremap <buffer> <silent> t
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+    inoremap <buffer> <silent> <C-t>
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+    endif
+    inoremap <buffer> <silent> <2-LeftMouse>
+                \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+    inoremap <buffer> <silent> s
+                \ <C-o>:call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
+    inoremap <buffer> <silent> +             <C-o>:silent! foldopen<CR>
+    inoremap <buffer> <silent> -             <C-o>:silent! foldclose<CR>
+    inoremap <buffer> <silent> *             <C-o>:silent! %foldopen!<CR>
+    inoremap <buffer> <silent> =             <C-o>:silent! %foldclose<CR>
+    inoremap <buffer> <silent> <kPlus>       <C-o>:silent! foldopen<CR>
+    inoremap <buffer> <silent> <kMinus>      <C-o>:silent! foldclose<CR>
+    inoremap <buffer> <silent> <kMultiply>   <C-o>:silent! %foldopen!<CR>
+    inoremap <buffer> <silent> <Space>       <C-o>:call
+                                    \ <SID>Tlist_Window_Show_Info()<CR>
+    inoremap <buffer> <silent> u
+                            \ <C-o>:call <SID>Tlist_Window_Update_File()<CR>
+    inoremap <buffer> <silent> d    <C-o>:call <SID>Tlist_Remove_File(-1, 1)<CR>
+    inoremap <buffer> <silent> x    <C-o>:call <SID>Tlist_Window_Zoom()<CR>
+    inoremap <buffer> <silent> [[   <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+    inoremap <buffer> <silent> <BS> <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+    inoremap <buffer> <silent> ]]   <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+    inoremap <buffer> <silent> <Tab> <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+    inoremap <buffer> <silent> <F1>  <C-o>:call <SID>Tlist_Window_Toggle_Help_Text()<CR>
+    inoremap <buffer> <silent> q    <C-o>:close<CR>
+
     " Map single left mouse click if the user wants this functionality
     if g:Tlist_Use_SingleClick == 1
-    nnoremap <silent> <LeftMouse> <LeftMouse>:if bufname("%") =~ "__Tag_List__"
-                        \ <bar> call <SID>Tlist_Jump_To_Tag(0) <bar> endif <CR>
+        " Contributed by Bindu Wavell
+        " attempt to perform single click mapping, it would be much
+        " nicer if we could nnoremap <buffer> ... however vim does
+        " not fire the <buffer> <leftmouse> when you use the mouse
+        " to enter a buffer.
+        let clickmap = ':if bufname("%") =~ "__Tag_List__" <bar> ' .
+                    \ 'call <SID>Tlist_Window_Jump_To_Tag("useopen") ' .
+                    \ '<bar> endif <CR>'
+        if maparg('<leftmouse>', 'n') == ''
+            " no mapping for leftmouse
+            exe ':nnoremap <silent> <leftmouse> <leftmouse>' . clickmap
+        else
+            " we have a mapping
+            let mapcmd = ':nnoremap <silent> <leftmouse> <leftmouse>'
+            let mapcmd = mapcmd . substitute(substitute(
+                        \ maparg('<leftmouse>', 'n'), '|', '<bar>', 'g'),
+                        \ '\c^<leftmouse>', '', '')
+            let mapcmd = mapcmd . clickmap
+            exe mapcmd
+        endif
     endif
 
-    " Define the autocommand to highlight the current tag
+    " Define the taglist autocommands
     augroup TagListAutoCmds
         autocmd!
         " Display the tag prototype for the tag under the cursor.
-        autocmd CursorHold __Tag_List__ call s:Tlist_Show_Tag_Prototype()
-        " Highlight the current tag 
-        autocmd CursorHold * silent call <SID>Tlist_Highlight_Tag(bufnr('%'), 
-                                        \ line('.'))
-        autocmd BufUnload __Tag_List__ call <SID>Tlist_Close_Window()
-        if !s:tlist_part_of_winmanager
+        autocmd CursorHold __Tag_List__ call s:Tlist_Window_Show_Info()
+        " Highlight the current tag periodically
+        autocmd CursorHold * silent call s:Tlist_Window_Highlight_Tag(
+                            \ fnamemodify(bufname('%'), ':p'), line('.'), 1, 0)
+
         " Adjust the Vim window width when taglist window is closed
-        " Auto refresh the taglisting window
-        autocmd BufEnter * call <SID>Tlist_Refresh_Window()
+        autocmd BufUnload __Tag_List__ call s:Tlist_Post_Close_Cleanup()
+        " Close the fold for this buffer when leaving the buffer
+        if g:Tlist_File_Fold_Auto_Close
+            autocmd BufEnter * silent
+                \ call s:Tlist_Window_Open_File_Fold(expand('<abuf>'))
+        endif
+        " Exit Vim itself if only the taglist window is present (optional)
+        if g:Tlist_Exit_OnlyWindow
+           autocmd BufEnter __Tag_List__ nested
+                       \ call s:Tlist_Window_Exit_Only_Window()
+        endif
+        if s:tlist_app_name != "winmanager" &&
+                    \ !g:Tlist_Process_File_Always &&
+                    \ (!has('gui_running') || !g:Tlist_Show_Menu)
+            " Auto refresh the taglist window
+            autocmd BufEnter * call s:Tlist_Refresh()
+        endif
+
+        if !g:Tlist_Use_Horiz_Window
+            if v:version < 700
+                autocmd WinEnter * call s:Tlist_Window_Check_Width()
+            endif
+        endif
+        if v:version >= 700
+            autocmd TabEnter * silent call s:Tlist_Refresh_Folds()
         endif
     augroup end
+
+    " Restore the previous cpoptions settings
+    let &cpoptions = old_cpoptions
+endfunction
+
+" Tlist_Window_Refresh
+" Display the tags for all the files in the taglist window
+function! s:Tlist_Window_Refresh()
+    call s:Tlist_Log_Msg('Tlist_Window_Refresh()')
+    " Set report option to a huge value to prevent informational messages
+    " while deleting the lines
+    let old_report = &report
+    set report=99999
+
+    " Mark the buffer as modifiable
+    setlocal modifiable
+
+    " Delete the contents of the buffer to the black-hole register
+    silent! %delete _
+
+    " As we have cleared the taglist window, mark all the files
+    " as not visible
+    let i = 0
+    while i < s:tlist_file_count
+        let s:tlist_{i}_visible = 0
+        let i = i + 1
+    endwhile
+
+    if g:Tlist_Compact_Format == 0
+        " Display help in non-compact mode
+        call s:Tlist_Window_Display_Help()
+    endif
+
+    " Mark the buffer as not modifiable
+    setlocal nomodifiable
+
+    " Restore the report option
+    let &report = old_report
+
+    " If the tags for only one file should be displayed in the taglist
+    " window, then no need to add the tags here. The bufenter autocommand
+    " will add the tags for that file.
+    if g:Tlist_Show_One_File
+        return
+    endif
+
+    " List all the tags for the previously processed files
+    " Do this only if taglist is configured to display tags for more than
+    " one file. Otherwise, when Tlist_Show_One_File is configured,
+    " tags for the wrong file will be displayed.
+    let i = 0
+    while i < s:tlist_file_count
+        call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename,
+                    \ s:tlist_{i}_filetype)
+        let i = i + 1
+    endwhile
+
+    if g:Tlist_Auto_Update
+        " Add and list the tags for all buffers in the Vim buffer list
+        let i = 1
+        let last_bufnum = bufnr('$')
+        while i <= last_bufnum
+            if buflisted(i)
+                let fname = fnamemodify(bufname(i), ':p')
+                let ftype = s:Tlist_Get_Buffer_Filetype(i)
+                " If the file doesn't support tag listing, skip it
+                if !s:Tlist_Skip_File(fname, ftype)
+                    call s:Tlist_Window_Refresh_File(fname, ftype)
+                endif
+            endif
+            let i = i + 1
+        endwhile
+    endif
+
+    " If Tlist_File_Fold_Auto_Close option is set, then close all the folds
+    if g:Tlist_File_Fold_Auto_Close
+        " Close all the folds
+        silent! %foldclose
+    endif
+
+    " Move the cursor to the top of the taglist window
+    normal! gg
 endfunction
 
-" Tlist_Close_Window()
+" Tlist_Post_Close_Cleanup()
 " Close the taglist window and adjust the Vim window width
-function! s:Tlist_Close_Window()
-    " Remove the autocommands for the taglist window
+function! s:Tlist_Post_Close_Cleanup()
+    call s:Tlist_Log_Msg('Tlist_Post_Close_Cleanup()')
+    " Mark all the files as not visible
+    let i = 0
+    while i < s:tlist_file_count
+        let s:tlist_{i}_visible = 0
+        let i = i + 1
+    endwhile
+
+    " Remove the taglist autocommands
     silent! autocmd! TagListAutoCmds
 
     " Clear all the highlights
     match none
 
-    if has('syntax')
-        silent! syntax clear TagListTitle
-    endif
+    silent! syntax clear TagListTitle
+    silent! syntax clear TagListComment
+    silent! syntax clear TagListTagScope
 
     " Remove the left mouse click mapping if it was setup initially
-    if g:Tlist_Use_SingleClick == 1
+    if g:Tlist_Use_SingleClick
         if hasmapto('<LeftMouse>')
             nunmap <LeftMouse>
         endif
     endif
 
-    if !s:tlist_part_of_winmanager
+    if s:tlist_app_name != "winmanager"
     if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 ||
-                \ s:tlist_winsize_chgd == 0 ||
+                \ s:tlist_winsize_chgd != 1 ||
                 \ &columns < (80 + g:Tlist_WinWidth)
-        " No need to adjust window width if horizontally split tag listing
+        " No need to adjust window width if using horizontally split taglist
         " window or if columns is less than 101 or if the user chose not to
         " adjust the window width
     else
+        " If the user didn't manually move the window, then restore the window
+        " position to the pre-taglist position
+        if s:tlist_pre_winx != -1 && s:tlist_pre_winy != -1 &&
+                    \ getwinposx() == s:tlist_winx &&
+                    \ getwinposy() == s:tlist_winy
+            exe 'winpos ' . s:tlist_pre_winx . ' ' . s:tlist_pre_winy
+        endif
+
         " Adjust the Vim window width
         let &columns= &columns - (g:Tlist_WinWidth + 1)
     endif
     endif
+
+    let s:tlist_winsize_chgd = -1
+
+    " Reset taglist state variables
+    if s:tlist_app_name == "winmanager"
+        let s:tlist_app_name = "none"
+    endif
+    let s:tlist_window_initialized = 0
 endfunction
 
-" Tlist_Explore_File()
+" Tlist_Window_Refresh_File()
 " List the tags defined in the specified file in a Vim window
-function! s:Tlist_Explore_File(bufnum)
-    " Get the filename and file type
-    let filename = fnamemodify(bufname(a:bufnum), ':p')
-    let ftype = getbufvar(a:bufnum, '&filetype')
-
-    " Check for valid filename and valid filetype
-    if filename == '' || !filereadable(filename) || ftype == ''
-        return
+function! s:Tlist_Window_Refresh_File(filename, ftype)
+    call s:Tlist_Log_Msg('Tlist_Window_Refresh_File (' . a:filename . ')')
+    " First check whether the file already exists
+    let fidx = s:Tlist_Get_File_Index(a:filename)
+    if fidx != -1
+        let file_listed = 1
+    else
+        let file_listed = 0
     endif
 
-    " If the tag types for this filetype are not yet created, then create
-    " them now
-    let var = 's:tlist_' . ftype . '_count'
-    if !exists(var)
-        if s:Tlist_FileType_Init(ftype) == 0
+    if !file_listed
+        " Check whether this file is removed based on user request
+        " If it is, then don't display the tags for this file
+        if s:Tlist_User_Removed_File(a:filename)
             return
         endif
     endif
 
-    " If the cached ctags output exists for the specified buffer, then use it.
-    " Otherwise run ctags to get the output
-    let valid_cache = getbufvar(a:bufnum, 'tlist_valid_cache')
-    if valid_cache != ''
-        " Load the cached processed tags output from the buffer local
-        " variables
-        let b:tlist_tag_count = getbufvar(a:bufnum, 'tlist_tag_count') + 0
-        let i = 1
-        while i <= b:tlist_tag_count
-            let var_name = 'tlist_tag_' . i
-            let b:tlist_tag_{i} =  getbufvar(a:bufnum, var_name)
-            let i = i + 1
-        endwhile
-
-        let i = 1
-        while i <= s:tlist_{ftype}_count
-            let ttype = s:tlist_{ftype}_{i}_name
-            let var_name = 'tlist_' . ttype . '_start'
-            let b:tlist_{ftype}_{ttype}_start = 
-                        \ getbufvar(a:bufnum, var_name) + 0
-            let var_name = 'tlist_' . ttype . '_count'
-            let cnt = getbufvar(a:bufnum, var_name) + 0
-            let b:tlist_{ftype}_{ttype}_count = cnt
-            let var_name = 'tlist_' . ttype
-            let l:tlist_{ftype}_{ttype} = getbufvar(a:bufnum, var_name)
-            let j = 1
-            while j <= cnt
-                let var_name = 'tlist_' . ttype . '_' . j
-                let b:tlist_{ftype}_{ttype}_{j} = getbufvar(a:bufnum, var_name)
-                let j = j + 1
-            endwhile
-            let i = i + 1
-        endwhile
-    else
-        " Exuberant ctags arguments to generate a tag list
-        let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks '
-
-        " Form the ctags argument depending on the sort type 
-        if b:tlist_sort_type == 'name'
-            let ctags_args = ctags_args . ' --sort=yes '
-        else
-            let ctags_args = ctags_args . ' --sort=no '
-        endif
-
-        " Add the filetype specific arguments
-        let ctags_args = ctags_args . ' ' . s:tlist_{ftype}_ctags_args
+    if file_listed && s:tlist_{fidx}_visible
+        " Check whether the file tags are currently valid
+        if s:tlist_{fidx}_valid
+            " Goto the first line in the file
+            exe s:tlist_{fidx}_start
 
-        " Ctags command to produce output with regexp for locating the tags
-        let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args
-        let ctags_cmd = ctags_cmd . ' "' . filename . '"'
-
-        " Run ctags and get the tag list
-        let cmd_output = system(ctags_cmd)
-
-        " Cache the ctags output with a buffer local variable
-        call setbufvar(a:bufnum, 'tlist_valid_cache', 'Yes')
-        call setbufvar(a:bufnum, 'tlist_sort_type', b:tlist_sort_type)
-
-        " Handle errors
-        if v:shell_error && cmd_output != ''
-            call s:Tlist_Warning_Msg(cmd_output)
+            " If the line is inside a fold, open the fold
+            if foldclosed('.') != -1
+                exe "silent! " . s:tlist_{fidx}_start . "," .
+                            \ s:tlist_{fidx}_end . "foldopen!"
+            endif
             return
         endif
 
-        " No tags for current file
-        if cmd_output == ''
-            call s:Tlist_Warning_Msg('No tags found for ' . filename)
+        " Discard and remove the tags for this file from display
+        call s:Tlist_Discard_TagInfo(fidx)
+        call s:Tlist_Window_Remove_File_From_Display(fidx)
+    endif
+
+    " Process and generate a list of tags defined in the file
+    if !file_listed || !s:tlist_{fidx}_valid
+        let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype)
+        if ret_fidx == -1
             return
         endif
-
-        " Initialize variables for the new filetype
-        let i = 1
-        while i <= s:tlist_{ftype}_count
-            let ttype = s:tlist_{ftype}_{i}_name
-            let b:tlist_{ftype}_{ttype}_start = 0
-            let b:tlist_{ftype}_{ttype}_count = 0
-            let l:tlist_{ftype}_{ttype} = ''
-            let i = i + 1
-        endwhile
-
-        " Process the ctags output one line at a time. Separate the tag output
-        " based on the tag type and store it in the tag type variable
-        while cmd_output != ''
-            " Extract one line at a time
-            let one_line = strpart(cmd_output, 0, stridx(cmd_output, "\n"))
-            " Remove the line from the tags output
-            let cmd_output = strpart(cmd_output, stridx(cmd_output, "\n") + 1)
-
-            if one_line == ''
-                " Line is not in proper tags format
-                continue
-            endif
-
-            " Extract the tag type
-            let ttype = s:Tlist_Extract_Tagtype(one_line)
-
-            if ttype == ''
-                " Line is not in proper tags format
-                continue
-            endif
-
-            " make sure the tag type is supported
-            if s:tlist_{ftype}_ctags_flags !~# ttype
-                continue
-            endif
-
-            " Extract the tag name
-            if g:Tlist_Display_Prototype == 0
-                let ttxt = '  ' . strpart(one_line, 0, stridx(one_line, "\t"))
-
-                " Add the tag scope, if it is available. Tag scope is the last
-                " field after the 'line:<num>\t' field
-                let start = strridx(one_line, 'line:')
-                let end = strridx(one_line, "\t")
-                if end > start
-                    let tscope = strpart(one_line, end + 1)
-                    let tscope = strpart(tscope, stridx(tscope, ':') + 1)
-                    if tscope != ''
-                        let ttxt = ttxt . ' [' . tscope . ']'
-                    endif
-                endif
-            else
-                let start = stridx(one_line, '/^') + 2
-                let end = strridx(one_line, '/;"' . "\t")
-                if one_line[end - 1] == '$'
-                    let end = end -1
-                endif
-                let ttxt = strpart(one_line, start, end - start)
-            endif
-
-            " Update the count of this tag type
-            let cnt = b:tlist_{ftype}_{ttype}_count + 1
-            let b:tlist_{ftype}_{ttype}_count = cnt
-
-            " Add this tag to the tag type variable
-            let l:tlist_{ftype}_{ttype} = l:tlist_{ftype}_{ttype} . ttxt . "\n"
-
-            " Update the total tag count
-            let b:tlist_tag_count = b:tlist_tag_count + 1
-            let b:tlist_tag_{b:tlist_tag_count} = cnt . ':' . one_line
-
-            let b:tlist_{ftype}_{ttype}_{cnt} = b:tlist_tag_count
-        endwhile
-
-        " Cache the processed tags output using buffer local variables
-        call setbufvar(a:bufnum, 'tlist_tag_count', b:tlist_tag_count)
-        let i = 1
-        while i <= b:tlist_tag_count
-            let var_name = 'tlist_tag_' . i
-            call setbufvar(a:bufnum, var_name, b:tlist_tag_{i})
-            let i = i + 1
-        endwhile
-
-        let i = 1
-        while i <= s:tlist_{ftype}_count
-            let ttype = s:tlist_{ftype}_{i}_name
-            let var_name = 'tlist_' . ttype . '_start'
-            call setbufvar(a:bufnum, var_name, b:tlist_{ftype}_{ttype}_start)
-            let cnt = b:tlist_{ftype}_{ttype}_count
-            let var_name = 'tlist_' . ttype . '_count'
-            call setbufvar(a:bufnum, var_name, cnt)
-            let var_name = 'tlist_' . ttype
-            call setbufvar(a:bufnum, var_name, l:tlist_{ftype}_{ttype})
-            let j = 1
-            while j <= cnt
-                let var_name = 'tlist_' . ttype . '_' . j
-                call setbufvar(a:bufnum, var_name, b:tlist_{ftype}_{ttype}_{j})
-                let j = j + 1
-            endwhile
-            let i = i + 1
-        endwhile
+        let fidx = ret_fidx
     endif
 
     " Set report option to a huge value to prevent informational messages
@@ -1205,46 +1882,109 @@ function! s:Tlist_Explore_File(bufnum)
     let old_report = &report
     set report=99999
 
+    if g:Tlist_Show_One_File
+        " Remove the previous file
+        if s:tlist_cur_file_idx != -1
+            call s:Tlist_Window_Remove_File_From_Display(s:tlist_cur_file_idx)
+            let s:tlist_{s:tlist_cur_file_idx}_visible = 0
+            let s:tlist_{s:tlist_cur_file_idx}_start = 0
+            let s:tlist_{s:tlist_cur_file_idx}_end = 0
+        endif
+        let s:tlist_cur_file_idx = fidx
+    endif
+
     " Mark the buffer as modifiable
     setlocal modifiable
 
+    " Add new files to the end of the window. For existing files, add them at
+    " the same line where they were previously present. If the file is not
+    " visible, then add it at the end
+    if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible
+        if g:Tlist_Compact_Format
+            let s:tlist_{fidx}_start = line('$')
+        else
+            let s:tlist_{fidx}_start = line('$') + 1
+        endif
+    endif
+
+    let s:tlist_{fidx}_visible = 1
+
+    " Goto the line where this file should be placed
+    if g:Tlist_Compact_Format
+        exe s:tlist_{fidx}_start
+    else
+        exe s:tlist_{fidx}_start - 1
+    endif
+
+    let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' .
+                \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')'
+    if g:Tlist_Compact_Format == 0
+        silent! put =txt
+    else
+        silent! put! =txt
+        " Move to the next line
+        exe line('.') + 1
+    endif
+    let file_start = s:tlist_{fidx}_start
+
     " Add the tag names grouped by tag type to the buffer with a title
     let i = 1
-    while i <= s:tlist_{ftype}_count
-        let ttype = s:tlist_{ftype}_{i}_name
+    let ttype_cnt = s:tlist_{a:ftype}_count
+    while i <= ttype_cnt
+        let ttype = s:tlist_{a:ftype}_{i}_name
         " Add the tag type only if there are tags for that type
-        if l:tlist_{ftype}_{ttype} != ''
+        let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
+        let ttype_txt = {fidx_ttype}
+        if ttype_txt != ''
+            let txt = '  ' . s:tlist_{a:ftype}_{i}_fullname
             if g:Tlist_Compact_Format == 0
-                let b:tlist_{ftype}_{ttype}_start = line('.') + 1
-                silent! put =s:tlist_{ftype}_{i}_fullname
+                let ttype_start_lnum = line('.') + 1
+                silent! put =txt
             else
-                let b:tlist_{ftype}_{ttype}_start = line('.')
-                silent! put! =s:tlist_{ftype}_{i}_fullname
+                let ttype_start_lnum = line('.')
+                silent! put! =txt
             endif
-            silent! put =l:tlist_{ftype}_{ttype}
+            silent! put =ttype_txt
+
+            let {fidx_ttype}_offset = ttype_start_lnum - file_start
 
             " create a fold for this tag type
-            if has('folding')
-                let fold_start = b:tlist_{ftype}_{ttype}_start
-                let fold_end = fold_start + b:tlist_{ftype}_{ttype}_count
-                exe fold_start . ',' . fold_end  . 'fold'
-            endif
+            let fold_start = ttype_start_lnum
+            let fold_end = fold_start + {fidx_ttype}_count
+            exe fold_start . ',' . fold_end  . 'fold'
 
-            " Syntax highlight the tag type names
-            if has('syntax')
-                exe 'syntax match TagListTitle /\%' . 
-                            \ b:tlist_{ftype}_{ttype}_start . 'l.*/'
+            " Adjust the cursor position
+            if g:Tlist_Compact_Format == 0
+                exe ttype_start_lnum + {fidx_ttype}_count
+            else
+                exe ttype_start_lnum + {fidx_ttype}_count + 1
             endif
-            " Separate the tag types with a empty line
-            normal! G
+
             if g:Tlist_Compact_Format == 0
+                " Separate the tag types by a empty line
                 silent! put =''
             endif
         endif
         let i = i + 1
     endwhile
 
-    if s:tlist_part_of_winmanager
+    if s:tlist_{fidx}_tag_count == 0
+        if g:Tlist_Compact_Format == 0
+            silent! put =''
+        endif
+    endif
+
+    let s:tlist_{fidx}_end = line('.') - 1
+
+    " Create a fold for the entire file
+    exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
+    exe 'silent! ' . s:tlist_{fidx}_start . ',' .
+                \ s:tlist_{fidx}_end . 'foldopen!'
+
+    " Goto the starting line for this file,
+    exe s:tlist_{fidx}_start
+
+    if s:tlist_app_name == "winmanager"
         " To handle a bug in the winmanager plugin, add a space at the
         " last line
         call setline('$', ' ')
@@ -1256,626 +1996,2540 @@ function! s:Tlist_Explore_File(bufnum)
     " Restore the report option
     let &report = old_report
 
-    " Initially open all the folds
-    if has('folding')
-        silent! %foldopen!
+    " Update the start and end line numbers for all the files following this
+    " file
+    let start = s:tlist_{fidx}_start
+    " include the empty line after the last line
+    if g:Tlist_Compact_Format
+        let end = s:tlist_{fidx}_end
+    else
+        let end = s:tlist_{fidx}_end + 1
     endif
+    call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1)
 
-    " Goto the first line in the buffer
-    go
+    " Now that we have updated the taglist window, update the tags
+    " menu (if present)
+    if g:Tlist_Show_Menu
+        call s:Tlist_Menu_Update_File(1)
+    endif
+endfunction
 
-    return
+" Tlist_Init_File
+" Initialize the variables for a new file
+function! s:Tlist_Init_File(filename, ftype)
+    call s:Tlist_Log_Msg('Tlist_Init_File (' . a:filename . ')')
+    " Add new files at the end of the list
+    let fidx = s:tlist_file_count
+    let s:tlist_file_count = s:tlist_file_count + 1
+    " Add the new file name to the taglist list of file names
+    let s:tlist_file_names = s:tlist_file_names . a:filename . "\n"
+
+    " Initialize the file variables
+    let s:tlist_{fidx}_filename = a:filename
+    let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type
+    let s:tlist_{fidx}_filetype = a:ftype
+    let s:tlist_{fidx}_mtime = -1
+    let s:tlist_{fidx}_start = 0
+    let s:tlist_{fidx}_end = 0
+    let s:tlist_{fidx}_valid = 0
+    let s:tlist_{fidx}_visible = 0
+    let s:tlist_{fidx}_tag_count = 0
+    let s:tlist_{fidx}_menu_cmd = ''
+
+    " Initialize the tag type variables
+    let i = 1
+    while i <= s:tlist_{a:ftype}_count
+        let ttype = s:tlist_{a:ftype}_{i}_name
+        let s:tlist_{fidx}_{ttype} = ''
+        let s:tlist_{fidx}_{ttype}_offset = 0
+        let s:tlist_{fidx}_{ttype}_count = 0
+        let i = i + 1
+    endwhile
+
+    return fidx
 endfunction
 
-" Tlist_Toggle_Window()
-" Open or close a taglist window
-function! s:Tlist_Toggle_Window(bufnum)
-    let curline = line('.')
+" Tlist_Get_Tag_Type_By_Tag
+" Return the tag type for the specified tag index
+function! s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
+    let ttype_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_type'
 
-    " If taglist window is open then close it.
-    let winnum = bufwinnr(g:TagList_title)
-    if winnum != -1
-        if winnr() == winnum
-            " Already in the taglist window. Close it and return
-            close
-        else
-            " Goto the taglist window, close it and then come back to the
-            " original window
-            let curbufnr = bufnr('%')
-            exe winnum . '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
-                exe winnum . 'wincmd w'
-            endif
-        endif
-        return
+    " Already parsed and have the tag name
+    if exists(ttype_var)
+        return {ttype_var}
     endif
 
-    let s:tlist_part_of_winmanager = 0
+    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+    let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line)
 
-    " Open the taglist window
-    call s:Tlist_Open_Window()
+    return {ttype_var}
+endfunction
 
-    " Initialize the taglist window
-    call s:Tlist_Init_Window(a:bufnum)
+" Tlist_Get_Tag_Prototype
+function! s:Tlist_Get_Tag_Prototype(fidx, tidx)
+    let tproto_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_proto'
 
-    " List the tags defined in a file
-    call s:Tlist_Explore_File(a:bufnum)
+    " Already parsed and have the tag prototype
+    if exists(tproto_var)
+        return {tproto_var}
+    endif
 
-    " Highlight the current tag
-    call s:Tlist_Highlight_Tag(a:bufnum, curline)
+    " Parse and extract the tag prototype
+    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+    let start = stridx(tag_line, '/^') + 2
+    let end = stridx(tag_line, '/;"' . "\t")
+    if tag_line[end - 1] == '$'
+        let end = end -1
+    endif
+    let tag_proto = strpart(tag_line, start, end - start)
+    let {tproto_var} = substitute(tag_proto, '\s*', '', '')
 
-    " Go back to the original window
-    let s:Tlist_Skip_Refresh = 1
-    wincmd p
-    let s:Tlist_Skip_Refresh = 0
+    return {tproto_var}
 endfunction
 
-" Tlist_Extract_Tagtype
-" Extract the tag type from the tag text
-function! s:Tlist_Extract_Tagtype(tag_txt)
-    " The tag type is after the tag prototype field. The prototype field
-    " ends with the /;"\t string. We add 4 at the end to skip the characters
-    " in this special string..
-    let start = strridx(a:tag_txt, '/;"' . "\t") + 4
-    let end = strridx(a:tag_txt, 'line:') - 1
-    let ttype = strpart(a:tag_txt, start, end - start)
+" Tlist_Get_Tag_SearchPat
+function! s:Tlist_Get_Tag_SearchPat(fidx, tidx)
+    let tpat_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_searchpat'
 
-    return ttype
-endfunction
+    " Already parsed and have the tag search pattern
+    if exists(tpat_var)
+        return {tpat_var}
+    endif
 
-" Tlist_Extract_Tag_Prototype
-" Extract the tag protoype from the tag text
-function! s:Tlist_Extract_Tag_Prototype(tag_txt)
-    let start = stridx(a:tag_txt, '/^') + 2
-    let end = strridx(a:tag_txt, '/;"' . "\t")
-    if a:tag_txt[end - 1] == '$'
+    " Parse and extract the tag search pattern
+    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+    let start = stridx(tag_line, '/^') + 2
+    let end = stridx(tag_line, '/;"' . "\t")
+    if tag_line[end - 1] == '$'
         let end = end -1
     endif
-    let tag_pat = strpart(a:tag_txt, start, end - start)
-
-    " Remove all the leading space characters
-    let tag_pat = matchstr(tag_pat, '^\s*\zs.*')
+    let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) .
+                        \ (tag_line[end] == '$' ? '\$' : '')
 
-    return tag_pat
+    return {tpat_var}
 endfunction
 
-" Tlist_Refresh_Window()
-" Refresh the taglist window
-function! s:Tlist_Refresh_Window()
-    " We are entering the buffer from one of the taglist functions. So no need
-    " to refresh the taglist window again
-    if s:Tlist_Skip_Refresh == 1
-        return
-    endif
+" Tlist_Get_Tag_Linenum
+" Return the tag line number, given the tag index
+function! s:Tlist_Get_Tag_Linenum(fidx, tidx)
+    let tline_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_linenum'
 
-    " If the buffer doesn't support tag listing, skip it
-    if s:Tlist_Skip_Buffer(bufnr('%'))
-        return
+    " Already parsed and have the tag line number
+    if exists(tline_var)
+        return {tline_var}
     endif
 
-    let filename = expand('%:p')
+    " Parse and extract the tag line number
+    let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
+    let start = strridx(tag_line, 'line:') + 5
+    let end = strridx(tag_line, "\t")
+    if end < start
+        let {tline_var} = strpart(tag_line, start) + 0
+    else
+        let {tline_var} = strpart(tag_line, start, end - start) + 0
+    endif
 
-    let curline = line('.')
+    return {tline_var}
+endfunction
 
-    " Make sure the taglist window is open. Otherwise, no need to refresh
-    let winnum = bufwinnr(g:TagList_title)
-    if winnum == -1
+" Tlist_Parse_Tagline
+" Parse a tag line from the ctags output. Separate the tag output based on the
+" tag type and store it in the tag type variable.
+" The format of each line in the ctags output is:
+"
+"     tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields
+"
+function! s:Tlist_Parse_Tagline(tag_line)
+    if a:tag_line == ''
+        " Skip empty lines
         return
     endif
 
-    let bno = bufnr(g:TagList_title)
-
-    let cur_bufnr = bufnr('%')
+    " Extract the tag type
+    let ttype = s:Tlist_Extract_Tagtype(a:tag_line)
 
-    " If the tag listing for the current window is already present, no need to
-    " refresh it
-    if getbufvar(bno, 'tlist_bufnum') == cur_bufnr && 
-                \ getbufvar(bno, 'tlist_bufname') == filename
+    " Make sure the tag type is a valid and supported one
+    if ttype == '' || stridx(s:ctags_flags, ttype) == -1
+        " Line is not in proper tags format or Tag type is not supported
         return
     endif
 
-    " Save the current window number
-    let cur_winnr = winnr()
+    " Update the total tag count
+    let s:tidx = s:tidx + 1
 
-    call s:Tlist_Open_Window()
+    " The following variables are used to optimize this code.  Vim is slow in
+    " using curly brace names. To reduce the amount of processing needed, the
+    " curly brace variables are pre-processed here
+    let fidx_tidx = 's:tlist_' . s:fidx . '_' . s:tidx
+    let fidx_ttype = 's:tlist_' . s:fidx . '_' . ttype
 
-    call s:Tlist_Init_Window(cur_bufnr)
+    " Update the count of this tag type
+    let ttype_idx = {fidx_ttype}_count + 1
+    let {fidx_ttype}_count = ttype_idx
 
-    " Update the taglist window
-    call s:Tlist_Explore_File(cur_bufnr)
+    " Store the ctags output for this tag
+    let {fidx_tidx}_tag = a:tag_line
 
-    " Highlight the current tag
-    call s:Tlist_Highlight_Tag(cur_bufnr, curline)
+    " Store the tag index and the tag type index (back pointers)
+    let {fidx_ttype}_{ttype_idx} = s:tidx
+    let {fidx_tidx}_ttype_idx = ttype_idx
 
-    " Refresh the taglist window
-    redraw
+    " Extract the tag name
+    let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t"))
 
-    if !s:tlist_part_of_winmanager
-    " Jump back to the original window
-    exe cur_winnr . 'wincmd w'
+    " Extract the tag scope/prototype
+    if g:Tlist_Display_Prototype
+        let ttxt = '    ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx)
+    else
+        let ttxt = '    ' . tag_name
+
+        " Add the tag scope, if it is available and is configured. Tag
+        " scope is the last field after the 'line:<num>\t' field
+        if g:Tlist_Display_Tag_Scope
+            let tag_scope = s:Tlist_Extract_Tag_Scope(a:tag_line)
+            if tag_scope != ''
+                let ttxt = ttxt . ' [' . tag_scope . ']'
+            endif
+        endif
     endif
+
+    " Add this tag to the tag type variable
+    let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
+
+    " Save the tag name
+    let {fidx_tidx}_tag_name = tag_name
 endfunction
 
-" Tlist_Change_Sort()
-" Change the sort order of the tag listing
-function! s:Tlist_Change_Sort()
-    if !exists('b:tlist_bufnum') || !exists('b:tlist_ftype')
-        return
+" Tlist_Process_File
+" Get the list of tags defined in the specified file and store them
+" in Vim variables. Returns the file index where the tags are stored.
+function! s:Tlist_Process_File(filename, ftype)
+    call s:Tlist_Log_Msg('Tlist_Process_File (' . a:filename . ', ' .
+                \ a:ftype . ')')
+    " Check whether this file is supported
+    if s:Tlist_Skip_File(a:filename, a:ftype)
+        return -1
     endif
 
-    let sort_type = getbufvar(b:tlist_bufnum, 'tlist_sort_type')
+    " If the tag types for this filetype are not yet created, then create
+    " them now
+    let var = 's:tlist_' . a:ftype . '_count'
+    if !exists(var)
+        if s:Tlist_FileType_Init(a:ftype) == 0
+            return -1
+        endif
+    endif
 
-    " Toggle the sort order from 'name' to 'order' and vice versa
-    if sort_type == 'name'
-        call setbufvar(b:tlist_bufnum, 'tlist_sort_type', 'order')
+    " If this file is already processed, then use the cached values
+    let fidx = s:Tlist_Get_File_Index(a:filename)
+    if fidx == -1
+        " First time, this file is loaded
+        let fidx = s:Tlist_Init_File(a:filename, a:ftype)
     else
-        call setbufvar(b:tlist_bufnum, 'tlist_sort_type', 'name')
+        " File was previously processed. Discard the tag information
+        call s:Tlist_Discard_TagInfo(fidx)
     endif
 
-    " Save the current line for later restoration
-    let curline = '\V\^' . getline('.') . '\$'
+    let s:tlist_{fidx}_valid = 1
 
-    " Clear out the cached taglist information
-    call setbufvar(b:tlist_bufnum, 'tlist_valid_cache', '')
+    " Exuberant ctags arguments to generate a tag list
+    let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks '
 
-    call s:Tlist_Open_Window()
-
-    call s:Tlist_Init_Window(b:tlist_bufnum)
+    " Form the ctags argument depending on the sort type
+    if s:tlist_{fidx}_sort_type == 'name'
+        let ctags_args = ctags_args . '--sort=yes'
+    else
+        let ctags_args = ctags_args . '--sort=no'
+    endif
 
-    call s:Tlist_Explore_File(b:tlist_bufnum)
+    " Add the filetype specific arguments
+    let ctags_args = ctags_args . ' ' . s:tlist_{a:ftype}_ctags_args
 
-    " Go back to the tag line before the list is sorted
-    call search(curline, 'w')
-endfunction
+    " Ctags command to produce output with regexp for locating the tags
+    let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args
+    let ctags_cmd = ctags_cmd . ' "' . a:filename . '"'
 
-" Tlist_Update_Window()
-" Update the window by regenerating the tag list
-function! s:Tlist_Update_Window()
-    if !exists('b:tlist_bufnum') || !exists('b:tlist_ftype')
-        return
+    if &shellxquote == '"'
+        " Double-quotes within double-quotes will not work in the
+        " command-line.If the 'shellxquote' option is set to double-quotes,
+        " then escape the double-quotes in the ctags command-line.
+        let ctags_cmd = escape(ctags_cmd, '"')
     endif
 
-    " Save the current line for later restoration
-    let curline = '\V\^' . getline('.') . '\$'
-
-    " Clear out the cached taglist information
-    call setbufvar(b:tlist_bufnum, 'tlist_valid_cache', '')
-
-    call s:Tlist_Open_Window()
+    " In Windows 95, if not using cygwin, disable the 'shellslash'
+    " option. Otherwise, this will cause problems when running the
+    " ctags command.
+    if has('win95') && !has('win32unix')
+        let old_shellslash = &shellslash
+        set noshellslash
+    endif
 
-    call s:Tlist_Init_Window(b:tlist_bufnum)
+    if has('win32') && !has('win32unix') && !has('win95')
+                \ && (&shell =~ 'cmd.exe')
+        " Windows does not correctly deal with commands that have more than 1
+        " set of double quotes.  It will strip them all resulting in:
+        " 'C:\Program' is not recognized as an internal or external command
+        " operable program or batch file.  To work around this, place the
+        " command inside a batch file and call the batch file.
+        " Do this only on Win2K, WinXP and above.
+        " Contributed by: David Fishburn.
+        let s:taglist_tempfile = fnamemodify(tempname(), ':h') .
+                    \ '\taglist.cmd'
+        exe 'redir! > ' . s:taglist_tempfile
+        silent echo ctags_cmd
+        redir END
+
+        call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd)
+        let ctags_cmd = '"' . s:taglist_tempfile . '"'
+    endif
 
-    " Update the taglist window
-    call s:Tlist_Explore_File(b:tlist_bufnum)
+    call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd)
 
-    " Go back to the tag line before the list is sorted
-    call search(curline, 'w')
-endfunction
+    " Run ctags and get the tag list
+    let cmd_output = system(ctags_cmd)
 
-" Tlist_Get_Tag_Linenr()
-" Return the tag line for the current line
-function! s:Tlist_Get_Tag_Linenr()
-    if !exists('b:tlist_ftype')
-        return 0
+    " Restore the value of the 'shellslash' option.
+    if has('win95') && !has('win32unix')
+        let &shellslash = old_shellslash
     endif
 
-    let lnum = line('.')
-    let ftype = b:tlist_ftype
+    if exists('s:taglist_tempfile')
+        " Delete the temporary cmd file created on MS-Windows
+        call delete(s:taglist_tempfile)
+    endif
 
-    " Determine to which tag type the current line number belongs to using the
-    " tag type start line number and the number of tags in a tag type
-    let i = 1
-    while i <= s:tlist_{ftype}_count
-        let ttype = s:tlist_{ftype}_{i}_name
-        let end = b:tlist_{ftype}_{ttype}_start + b:tlist_{ftype}_{ttype}_count
-        if lnum >= b:tlist_{ftype}_{ttype}_start && lnum <= end
-            break
+    " Handle errors
+    if v:shell_error
+        let msg = "Taglist: Failed to generate tags for " . a:filename
+        call s:Tlist_Warning_Msg(msg)
+        if cmd_output != ''
+            call s:Tlist_Warning_Msg(cmd_output)
         endif
-        let i = i + 1
-    endwhile
-
-    " Current line doesn't belong to any of the displayed tag types
-    if i > s:tlist_{ftype}_count
-        return 0
+        return fidx
     endif
 
-    " Compute the offset into the displayed tags for the tag type
-    let offset = lnum - b:tlist_{ftype}_{ttype}_start
-    if offset == 0
-        return 0
+    " Store the modification time for the file
+    let s:tlist_{fidx}_mtime = getftime(a:filename)
+
+    " No tags for current file
+    if cmd_output == ''
+        call s:Tlist_Log_Msg('No tags defined in ' . a:filename)
+        return fidx
     endif
 
-    " Get the corresponding tag line and return it
-    return b:tlist_{ftype}_{ttype}_{offset}
-endfunction
+    call s:Tlist_Log_Msg('Generated tags information for ' . a:filename)
 
-function! s:Tlist_Highlight_Tagline()
-    " Clear previously selected name
-    match none
+    if v:version > 601
+        " The following script local variables are used by the
+        " Tlist_Parse_Tagline() function.
+        let s:ctags_flags = s:tlist_{a:ftype}_ctags_flags
+        let s:fidx = fidx
+        let s:tidx = 0
 
-    " Highlight the current selected name
-    if g:Tlist_Display_Prototype == 0
-        exe 'match TagName /\%' . line('.') . 'l\s\+\zs.*/'
+        " Process the ctags output one line at a time.  The substitute()
+        " command is used to parse the tag lines instead of using the
+        " matchstr()/stridx()/strpart() functions for performance reason
+        call substitute(cmd_output, "\\([^\n]\\+\\)\n",
+                    \ '\=s:Tlist_Parse_Tagline(submatch(1))', 'g')
+
+        " Save the number of tags for this file
+        let s:tlist_{fidx}_tag_count = s:tidx
+
+        " The following script local variables are no longer needed
+        unlet! s:ctags_flags
+        unlet! s:tidx
+        unlet! s:fidx
     else
-        exe 'match TagName /\%' . line('.') . 'l.*/'
-    endif
-endfunction
+        " Due to a bug in Vim earlier than version 6.1,
+        " we cannot use substitute() to parse the ctags output.
+        " Instead the slow str*() functions are used
+        let ctags_flags = s:tlist_{a:ftype}_ctags_flags
+        let tidx = 0
 
-" Tlist_Jump_To_Tag()
-" Jump to the location of the current tag
-function! s:Tlist_Jump_To_Tag(new_window)
-    " Do not process comment lines and empty lines
-    let curline = getline('.')
-    if curline == '' || curline[0] == '"'
-        return
-    endif
+        while cmd_output != ''
+            " Extract one line at a time
+            let idx = stridx(cmd_output, "\n")
+            let one_line = strpart(cmd_output, 0, idx)
+            " Remove the line from the tags output
+            let cmd_output = strpart(cmd_output, idx + 1)
 
-    " If inside a fold, then don't try to jump to the tag
-    if foldclosed('.') != -1
-        return
-    endif
+            if one_line == ''
+                " Line is not in proper tags format
+                continue
+            endif
 
-    " Get the tag output for the current tag
-    let lnum = s:Tlist_Get_Tag_Linenr()
-    if lnum == 0
-        return
-    endif
+            " Extract the tag type
+            let ttype = s:Tlist_Extract_Tagtype(one_line)
 
-    let mtxt = b:tlist_tag_{lnum}
-    let start = stridx(mtxt, '/^') + 2
-    let end = strridx(mtxt, '/;"' . "\t")
-    if mtxt[end - 1] == '$'
-        let end = end - 1
-    endif
-    let tagpat = '\V\^' . strpart(mtxt, start, end - start) .
-                                        \ (mtxt[end] == '$' ? '\$' : '')
+            " Make sure the tag type is a valid and supported one
+            if ttype == '' || stridx(ctags_flags, ttype) == -1
+                " Line is not in proper tags format or Tag type is not
+                " supported
+                continue
+            endif
 
-    " Highlight the tagline
-    call s:Tlist_Highlight_Tagline()
+            " Update the total tag count
+            let tidx = tidx + 1
 
-    let s:Tlist_Skip_Refresh = 1
+            " The following variables are used to optimize this code.  Vim is
+            " slow in using curly brace names. To reduce the amount of
+            " processing needed, the curly brace variables are pre-processed
+            " here
+            let fidx_tidx = 's:tlist_' . fidx . '_' . tidx
+            let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
 
-    if s:tlist_part_of_winmanager
-        call WinManagerFileEdit(bufname(b:tlist_bufnum), a:new_window)
-    else
-    " Goto the window containing the file.  If the window is not there, open a
-    " new window
-    let winnum = bufwinnr(b:tlist_bufnum)
-    if winnum == -1
-        if g:Tlist_Use_Horiz_Window == 1
-            exe 'leftabove split #' . b:tlist_bufnum
-            " Go to the taglist window to change the window size to the user
-            " configured value
-            wincmd p
-            exe 'resize ' . g:Tlist_WinHeight
-            " Go back to the file window
-            wincmd p
-        else
-            " Open the file in a window and skip refreshing the taglist window
-            exe 'rightbelow vertical split #' . b:tlist_bufnum
-            " Go to the taglist window to change the window size to the user
-            " configured value
-            wincmd p
-            exe 'vertical resize ' . g:Tlist_WinWidth
-            " Go back to the file window
-            wincmd p
+            " Update the count of this tag type
+            let ttype_idx = {fidx_ttype}_count + 1
+            let {fidx_ttype}_count = ttype_idx
+
+            " Store the ctags output for this tag
+            let {fidx_tidx}_tag = one_line
+
+            " Store the tag index and the tag type index (back pointers)
+            let {fidx_ttype}_{ttype_idx} = tidx
+            let {fidx_tidx}_ttype_idx = ttype_idx
+
+            " Extract the tag name
+            let tag_name = strpart(one_line, 0, stridx(one_line, "\t"))
+
+            " Extract the tag scope/prototype
+            if g:Tlist_Display_Prototype
+                let ttxt = '    ' . s:Tlist_Get_Tag_Prototype(fidx, tidx)
+            else
+                let ttxt = '    ' . tag_name
+
+                " Add the tag scope, if it is available and is configured. Tag
+                " scope is the last field after the 'line:<num>\t' field
+                if g:Tlist_Display_Tag_Scope
+                    let tag_scope = s:Tlist_Extract_Tag_Scope(one_line)
+                    if tag_scope != ''
+                        let ttxt = ttxt . ' [' . tag_scope . ']'
+                    endif
+                endif
+            endif
+
+            " Add this tag to the tag type variable
+            let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
+
+            " Save the tag name
+            let {fidx_tidx}_tag_name = tag_name
+        endwhile
+
+        " Save the number of tags for this file
+        let s:tlist_{fidx}_tag_count = tidx
+    endif
+
+    call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count . 
+                \ ' tags in ' . a:filename)
+
+    return fidx
+endfunction
+
+" Tlist_Update_File
+" Update the tags for a file (if needed)
+function! Tlist_Update_File(filename, ftype)
+    call s:Tlist_Log_Msg('Tlist_Update_File (' . a:filename . ')')
+    " If the file doesn't support tag listing, skip it
+    if s:Tlist_Skip_File(a:filename, a:ftype)
+        return
+    endif
+
+    " Convert the file name to a full path
+    let fname = fnamemodify(a:filename, ':p')
+
+    " First check whether the file already exists
+    let fidx = s:Tlist_Get_File_Index(fname)
+
+    if fidx != -1 && s:tlist_{fidx}_valid
+        " File exists and the tags are valid
+        " Check whether the file was modified after the last tags update
+        " If it is modified, then update the tags
+        if s:tlist_{fidx}_mtime == getftime(fname)
+            return
+        endif
+    else
+        " If the tags were removed previously based on a user request,
+        " as we are going to update the tags (based on the user request),
+        " remove the filename from the deleted list
+        call s:Tlist_Update_Remove_List(fname, 0)
+    endif
+
+    " If the taglist window is opened, update it
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum == -1
+        " Taglist window is not present. Just update the taglist
+        " and return
+        call s:Tlist_Process_File(fname, a:ftype)
+    else
+        if g:Tlist_Show_One_File && s:tlist_cur_file_idx != -1
+            " If tags for only one file are displayed and we are not
+            " updating the tags for that file, then no need to
+            " refresh the taglist window. Otherwise, the taglist
+            " window should be updated.
+            if s:tlist_{s:tlist_cur_file_idx}_filename != fname
+                call s:Tlist_Process_File(fname, a:ftype)
+                return
+            endif
+        endif
+
+        " Save the current window number
+        let save_winnr = winnr()
+
+        " Goto the taglist window
+        call s:Tlist_Window_Goto_Window()
+
+        " Save the cursor position
+        let save_line = line('.')
+        let save_col = col('.')
+
+        " Update the taglist window
+        call s:Tlist_Window_Refresh_File(fname, a:ftype)
+
+        " Restore the cursor position
+        if v:version >= 601
+            call cursor(save_line, save_col)
+        else
+            exe save_line
+            exe 'normal! ' . save_col . '|'
+        endif
+
+        if winnr() != save_winnr
+            " Go back to the original window
+            call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
+        endif
+    endif
+
+    " Update the taglist menu
+    if g:Tlist_Show_Menu
+        call s:Tlist_Menu_Update_File(1)
+    endif
+endfunction
+
+" Tlist_Window_Close
+" Close the taglist window
+function! s:Tlist_Window_Close()
+    call s:Tlist_Log_Msg('Tlist_Window_Close()')
+    " Make sure the taglist window exists
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum == -1
+        call s:Tlist_Warning_Msg('Error: Taglist window is not open')
+        return
+    endif
+
+    if winnr() == winnum
+        " Already in the taglist window. Close it and return
+        if winbufnr(2) != -1
+            " If a window other than the taglist window is open,
+            " then only close the taglist window.
+            close
+        endif
+    else
+        " Goto the taglist window, close it and then come back to the
+        " original window
+        let curbufnr = bufnr('%')
+        exe winnum . '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
+            exe winnum . 'wincmd w'
+        endif
+    endif
+endfunction
+
+" Tlist_Window_Mark_File_Window
+" Mark the current window as the file window to use when jumping to a tag.
+" Only if the current window is a non-plugin, non-preview and non-taglist
+" window
+function! s:Tlist_Window_Mark_File_Window()
+    if getbufvar('%', '&buftype') == '' && !&previewwindow
+        let w:tlist_file_window = "yes"
+    endif
+endfunction
+
+" Tlist_Window_Open
+" Open and refresh the taglist window
+function! s:Tlist_Window_Open()
+    call s:Tlist_Log_Msg('Tlist_Window_Open()')
+    " If the window is open, jump to it
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum != -1
+        " Jump to the existing window
+        if winnr() != winnum
+            exe winnum . 'wincmd w'
+        endif
+        return
+    endif
+
+    if s:tlist_app_name == "winmanager"
+        " Taglist plugin is no longer part of the winmanager app
+        let s:tlist_app_name = "none"
+    endif
+
+    " Get the filename and filetype for the specified buffer
+    let curbuf_name = fnamemodify(bufname('%'), ':p')
+    let curbuf_ftype = s:Tlist_Get_Buffer_Filetype('%')
+    let cur_lnum = line('.')
+
+    " Mark the current window as the desired window to open a file when a tag
+    " is selected.
+    call s:Tlist_Window_Mark_File_Window()
+
+    " Open the taglist window
+    call s:Tlist_Window_Create()
+
+    call s:Tlist_Window_Refresh()
+
+    if g:Tlist_Show_One_File
+        " Add only the current buffer and file
+        "
+        " If the file doesn't support tag listing, skip it
+        if !s:Tlist_Skip_File(curbuf_name, curbuf_ftype)
+            call s:Tlist_Window_Refresh_File(curbuf_name, curbuf_ftype)
+        endif
+    endif
+
+    if g:Tlist_File_Fold_Auto_Close
+        " Open the fold for the current file, as all the folds in
+        " the taglist window are closed
+        let fidx = s:Tlist_Get_File_Index(curbuf_name)
+        if fidx != -1
+            exe "silent! " . s:tlist_{fidx}_start . "," .
+                        \ s:tlist_{fidx}_end . "foldopen!"
+        endif
+    endif
+
+    " Highlight the current tag
+    call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1)
+endfunction
+
+" Tlist_Window_Toggle()
+" Open or close a taglist window
+function! s:Tlist_Window_Toggle()
+    call s:Tlist_Log_Msg('Tlist_Window_Toggle()')
+    " If taglist window is open then close it.
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum != -1
+        call s:Tlist_Window_Close()
+        return
+    endif
+
+    call s:Tlist_Window_Open()
+
+    " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not
+    " set
+    if !g:Tlist_GainFocus_On_ToggleOpen
+        call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+    endif
+
+    " Update the taglist menu
+    if g:Tlist_Show_Menu
+        call s:Tlist_Menu_Update_File(0)
+    endif
+endfunction
+
+" Tlist_Process_Filelist
+" Process multiple files. Each filename is separated by "\n"
+" Returns the number of processed files
+function! s:Tlist_Process_Filelist(file_names)
+    let flist = a:file_names
+
+    " Enable lazy screen updates
+    let old_lazyredraw = &lazyredraw
+    set lazyredraw
+
+    " Keep track of the number of processed files
+    let fcnt = 0
+
+    " Process one file at a time
+    while flist != ''
+        let nl_idx = stridx(flist, "\n")
+        let one_file = strpart(flist, 0, nl_idx)
+
+        " Remove the filename from the list
+        let flist = strpart(flist, nl_idx + 1)
+
+        if one_file == ''
+            continue
+        endif
+
+        " Skip directories
+        if isdirectory(one_file)
+            continue
+        endif
+
+        let ftype = s:Tlist_Detect_Filetype(one_file)
+
+        echon "\r                                                              "
+        echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t')
+
+        let fcnt = fcnt + 1
+
+        call Tlist_Update_File(one_file, ftype)
+    endwhile
+
+    " Clear the displayed informational messages
+    echon "\r                                                            "
+
+    " Restore the previous state
+    let &lazyredraw = old_lazyredraw
+
+    return fcnt
+endfunction
+
+" Tlist_Process_Dir
+" Process the files in a directory matching the specified pattern
+function! s:Tlist_Process_Dir(dir_name, pat)
+    let flist = glob(a:dir_name . '/' . a:pat) . "\n"
+
+    let fcnt = s:Tlist_Process_Filelist(flist)
+
+    let len = strlen(a:dir_name)
+    if a:dir_name[len - 1] == '\' || a:dir_name[len - 1] == '/'
+        let glob_expr = a:dir_name . '*'
+    else
+        let glob_expr = a:dir_name . '/*'
+    endif
+    let all_files = glob(glob_expr) . "\n"
+
+    while all_files != ''
+        let nl_idx = stridx(all_files, "\n")
+        let one_file = strpart(all_files, 0, nl_idx)
+
+        let all_files = strpart(all_files, nl_idx + 1)
+        if one_file == ''
+            continue
+        endif
+
+        " Skip non-directory names
+        if !isdirectory(one_file)
+            continue
+        endif
+
+        echon "\r                                                              "
+        echon "\rProcessing files in directory " . fnamemodify(one_file, ':t')
+        let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat)
+    endwhile
+
+    return fcnt
+endfunction
+
+" Tlist_Add_Files_Recursive
+" Add files recursively from a directory
+function! s:Tlist_Add_Files_Recursive(dir, ...)
+    let dir_name = fnamemodify(a:dir, ':p')
+    if !isdirectory(dir_name)
+        call s:Tlist_Warning_Msg('Error: ' . dir_name . ' is not a directory')
+        return
+    endif
+
+    if a:0 == 1
+        " User specified file pattern
+        let pat = a:1
+    else
+        " Default file pattern
+        let pat = '*'
+    endif
+
+    echon "\r                                                              "
+    echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t')
+    let fcnt = s:Tlist_Process_Dir(dir_name, pat)
+
+    echon "\rAdded " . fcnt . " files to the taglist"
+endfunction
+
+" Tlist_Add_Files
+" Add the specified list of files to the taglist
+function! s:Tlist_Add_Files(...)
+    let flist = ''
+    let i = 1
+
+    " Get all the files matching the file patterns supplied as argument
+    while i <= a:0
+        let flist = flist . glob(a:{i}) . "\n"
+        let i = i + 1
+    endwhile
+
+    if flist == ''
+        call s:Tlist_Warning_Msg('Error: No matching files are found')
+        return
+    endif
+
+    let fcnt = s:Tlist_Process_Filelist(flist)
+    echon "\rAdded " . fcnt . " files to the taglist"
+endfunction
+
+" Tlist_Extract_Tagtype
+" Extract the tag type from the tag text
+function! s:Tlist_Extract_Tagtype(tag_line)
+    " The tag type is after the tag prototype field. The prototype field
+    " ends with the /;"\t string. We add 4 at the end to skip the characters
+    " in this special string..
+    let start = strridx(a:tag_line, '/;"' . "\t") + 4
+    let end = strridx(a:tag_line, 'line:') - 1
+    let ttype = strpart(a:tag_line, start, end - start)
+
+    return ttype
+endfunction
+
+" Tlist_Extract_Tag_Scope
+" Extract the tag scope from the tag text
+function! s:Tlist_Extract_Tag_Scope(tag_line)
+    let start = strridx(a:tag_line, 'line:')
+    let end = strridx(a:tag_line, "\t")
+    if end <= start
+        return ''
+    endif
+
+    let tag_scope = strpart(a:tag_line, end + 1)
+    let tag_scope = strpart(tag_scope, stridx(tag_scope, ':') + 1)
+
+    return tag_scope
+endfunction
+
+" Tlist_Refresh()
+" Refresh the taglist
+function! s:Tlist_Refresh()
+    call s:Tlist_Log_Msg('Tlist_Refresh (Skip_Refresh = ' .
+                \ s:Tlist_Skip_Refresh . ', ' . bufname('%') . ')')
+    " If we are entering the buffer from one of the taglist functions, then
+    " no need to refresh the taglist window again.
+    if s:Tlist_Skip_Refresh
+        " We still need to update the taglist menu
+        if g:Tlist_Show_Menu
+            call s:Tlist_Menu_Update_File(0)
+        endif
+        return
+    endif
+
+    " If part of the winmanager plugin and not configured to process
+    " tags always and not configured to display the tags menu, then return
+    if (s:tlist_app_name == 'winmanager') && !g:Tlist_Process_File_Always
+                \ && !g:Tlist_Show_Menu
+        return
+    endif
+
+    " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
+    if &buftype != ''
+        return
+    endif
+
+    let filename = fnamemodify(bufname('%'), ':p')
+    let ftype = s:Tlist_Get_Buffer_Filetype('%')
+
+    " If the file doesn't support tag listing, skip it
+    if s:Tlist_Skip_File(filename, ftype)
+        return
+    endif
+
+    let tlist_win = bufwinnr(g:TagList_title)
+
+    " If the taglist window is not opened and not configured to process
+    " tags always and not displaying the tags menu, then return
+    if tlist_win == -1 && !g:Tlist_Process_File_Always && !g:Tlist_Show_Menu
+        return
+    endif
+
+    let fidx = s:Tlist_Get_File_Index(filename)
+    if fidx == -1
+        " Check whether this file is removed based on user request
+        " If it is, then don't display the tags for this file
+        if s:Tlist_User_Removed_File(filename)
+            return
+        endif
+
+        " If the taglist should not be auto updated, then return
+        if !g:Tlist_Auto_Update
+            return
+        endif
+    endif
+
+    let cur_lnum = line('.')
+
+    if fidx == -1
+        " Update the tags for the file
+        let fidx = s:Tlist_Process_File(filename, ftype)
+    else
+        let mtime = getftime(filename)
+        if s:tlist_{fidx}_mtime != mtime
+            " Invalidate the tags listed for this file
+            let s:tlist_{fidx}_valid = 0
+
+            " Update the taglist and the window
+            call Tlist_Update_File(filename, ftype)
+
+            " Store the new file modification time
+            let s:tlist_{fidx}_mtime = mtime
+        endif
+    endif
+
+    " Update the taglist window
+    if tlist_win != -1
+        " Disable screen updates
+        let old_lazyredraw = &lazyredraw
+        set nolazyredraw
+
+        " Save the current window number
+        let save_winnr = winnr()
+
+        " Goto the taglist window
+        call s:Tlist_Window_Goto_Window()
+
+        if !g:Tlist_Auto_Highlight_Tag || !g:Tlist_Highlight_Tag_On_BufEnter
+            " Save the cursor position
+            let save_line = line('.')
+            let save_col = col('.')
+        endif
+
+        " Update the taglist window
+        call s:Tlist_Window_Refresh_File(filename, ftype)
+
+        " Open the fold for the file
+        exe "silent! " . s:tlist_{fidx}_start . "," .
+                    \ s:tlist_{fidx}_end . "foldopen!"
+
+        if g:Tlist_Highlight_Tag_On_BufEnter && g:Tlist_Auto_Highlight_Tag
+            if g:Tlist_Show_One_File && s:tlist_cur_file_idx != fidx
+                " If displaying tags for only one file in the taglist
+                " window and about to display the tags for a new file,
+                " then center the current tag line for the new file
+                let center_tag_line = 1
+            else
+                let center_tag_line = 0
+            endif
+
+            " Highlight the current tag
+            call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line)
+        else
+            " Restore the cursor position
+            if v:version >= 601
+                call cursor(save_line, save_col)
+            else
+                exe save_line
+                exe 'normal! ' . save_col . '|'
+            endif
+        endif
+
+        " Jump back to the original window
+        if save_winnr != winnr()
+            call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
+        endif
+
+        " Restore screen updates
+        let &lazyredraw = old_lazyredraw
+    endif
+
+    " Update the taglist menu
+    if g:Tlist_Show_Menu
+        call s:Tlist_Menu_Update_File(0)
+    endif
+endfunction
+
+" Tlist_Change_Sort()
+" Change the sort order of the tag listing
+" caller == 'cmd', command used in the taglist window
+" caller == 'menu', taglist menu
+" action == 'toggle', toggle sort from name to order and vice versa
+" action == 'set', set the sort order to sort_type
+function! s:Tlist_Change_Sort(caller, action, sort_type)
+    call s:Tlist_Log_Msg('Tlist_Change_Sort (caller = ' . a:caller .
+            \ ', action = ' . a:action . ', sort_type = ' . a:sort_type . ')')
+    if a:caller == 'cmd'
+        let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+        if fidx == -1
+            return
+        endif
+
+        " Remove the previous highlighting
+        match none
+    elseif a:caller == 'menu'
+        let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+        if fidx == -1
+            return
+        endif
+    endif
+
+    if a:action == 'toggle'
+        let sort_type = s:tlist_{fidx}_sort_type
+
+        " Toggle the sort order from 'name' to 'order' and vice versa
+        if sort_type == 'name'
+            let s:tlist_{fidx}_sort_type = 'order'
+        else
+            let s:tlist_{fidx}_sort_type = 'name'
+        endif
+    else
+        let s:tlist_{fidx}_sort_type = a:sort_type
+    endif
+
+    " Invalidate the tags listed for this file
+    let s:tlist_{fidx}_valid = 0
+
+    if a:caller  == 'cmd'
+        " Save the current line for later restoration
+        let curline = '\V\^' . getline('.') . '\$'
+
+        call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
+                    \   s:tlist_{fidx}_filetype)
+
+        exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
+
+        " Go back to the cursor line before the tag list is sorted
+        call search(curline, 'w')
+
+        call s:Tlist_Menu_Update_File(1)
+    else
+        call s:Tlist_Menu_Remove_File()
+
+        call s:Tlist_Refresh()
+    endif
+endfunction
+
+" Tlist_Update_Current_File()
+" Update taglist for the current buffer by regenerating the tag list
+" Contributed by WEN Guopeng.
+function! s:Tlist_Update_Current_File()
+    call s:Tlist_Log_Msg('Tlist_Update_Current_File()')
+    if winnr() == bufwinnr(g:TagList_title)
+        " In the taglist window. Update the current file
+        call s:Tlist_Window_Update_File()
+    else
+        " Not in the taglist window. Update the current buffer
+        let filename = fnamemodify(bufname('%'), ':p')
+        let fidx = s:Tlist_Get_File_Index(filename)
+        if fidx != -1
+            let s:tlist_{fidx}_valid = 0
+        endif
+        let ft = s:Tlist_Get_Buffer_Filetype('%')
+        call Tlist_Update_File(filename, ft)
+    endif
+endfunction
+
+" Tlist_Window_Update_File()
+" Update the tags displayed in the taglist window
+function! s:Tlist_Window_Update_File()
+    call s:Tlist_Log_Msg('Tlist_Window_Update_File()')
+    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+    if fidx == -1
+        return
+    endif
+
+    " Remove the previous highlighting
+    match none
+
+    " Save the current line for later restoration
+    let curline = '\V\^' . getline('.') . '\$'
+
+    let s:tlist_{fidx}_valid = 0
+
+    " Update the taglist window
+    call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
+                \ s:tlist_{fidx}_filetype)
+
+    exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
+
+    " Go back to the tag line before the list is updated
+    call search(curline, 'w')
+endfunction
+
+" Tlist_Window_Get_Tag_Type_By_Linenum()
+" Return the tag type index for the specified line in the taglist window
+function! s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
+    let ftype = s:tlist_{a:fidx}_filetype
+
+    " Determine to which tag type the current line number belongs to using the
+    " tag type start line number and the number of tags in a tag type
+    let i = 1
+    while i <= s:tlist_{ftype}_count
+        let ttype = s:tlist_{ftype}_{i}_name
+        let start_lnum =
+                    \ s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
+        let end =  start_lnum + s:tlist_{a:fidx}_{ttype}_count
+        if a:lnum >= start_lnum && a:lnum <= end
+            break
+        endif
+        let i = i + 1
+    endwhile
+
+    " Current line doesn't belong to any of the displayed tag types
+    if i > s:tlist_{ftype}_count
+        return ''
+    endif
+
+    return ttype
+endfunction
+
+" Tlist_Window_Get_Tag_Index()
+" Return the tag index for the specified line in the taglist window
+function! s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+    let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(a:fidx, a:lnum)
+
+    " Current line doesn't belong to any of the displayed tag types
+    if ttype == ''
+        return 0
+    endif
+
+    " Compute the index into the displayed tags for the tag type
+    let ttype_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
+    let tidx = a:lnum - ttype_lnum
+    if tidx == 0
+        return 0
+    endif
+
+    " Get the corresponding tag line and return it
+    return s:tlist_{a:fidx}_{ttype}_{tidx}
+endfunction
+
+" Tlist_Window_Highlight_Line
+" Highlight the current line
+function! s:Tlist_Window_Highlight_Line()
+    " Clear previously selected name
+    match none
+
+    " Highlight the current line
+    if g:Tlist_Display_Prototype == 0
+        let pat = '/\%' . line('.') . 'l\s\+\zs.*/'
+    else
+        let pat = '/\%' . line('.') . 'l.*/'
+    endif
+
+    exe 'match TagListTagName ' . pat
+endfunction
+
+" Tlist_Window_Open_File
+" Open the specified file in either a new window or an existing window
+" and place the cursor at the specified tag pattern
+function! s:Tlist_Window_Open_File(win_ctrl, filename, tagpat)
+    call s:Tlist_Log_Msg('Tlist_Window_Open_File (' . a:filename . ',' .
+                \ a:win_ctrl . ')')
+    let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh
+    let s:Tlist_Skip_Refresh = 1
+
+    if s:tlist_app_name == "winmanager"
+        " Let the winmanager edit the file
+        call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin')
+    else
+
+    if a:win_ctrl == 'newtab'
+        " Create a new tab
+        exe 'tabnew ' . escape(a:filename, ' ')
+        " Open the taglist window in the new tab
+        call s:Tlist_Window_Open()
+    endif
+
+    if a:win_ctrl == 'checktab'
+        " Check whether the file is present in any of the tabs.
+        " If the file is present in the current tab, then use the
+        " current tab.
+        if bufwinnr(a:filename) != -1
+            let file_present_in_tab = 1
+            let i = tabpagenr()
+        else
+            let i = 1
+            let bnum = bufnr(a:filename)
+            let file_present_in_tab = 0
+            while i <= tabpagenr('$')
+                if index(tabpagebuflist(i), bnum) != -1
+                    let file_present_in_tab = 1
+                    break
+                endif
+                let i += 1
+            endwhile
+        endif
+
+        if file_present_in_tab
+            " Goto the tab containing the file
+            exe 'tabnext ' . i
+        else
+            " Open a new tab
+            exe 'tabnew ' . escape(a:filename, ' ')
+
+            " Open the taglist window
+            call s:Tlist_Window_Open()
+        endif
+    endif
+
+    let winnum = -1
+    if a:win_ctrl == 'prevwin'
+        " Open the file in the previous window, if it is usable
+        let cur_win = winnr()
+        wincmd p
+        if &buftype == '' && !&previewwindow
+            exe "edit " . escape(a:filename, ' ')
+            let winnum = winnr()
+        else
+            " Previous window is not usable
+            exe cur_win . 'wincmd w'
+        endif
+    endif
+
+    " Goto the window containing the file.  If the window is not there, open a
+    " new window
+    if winnum == -1
+        let winnum = bufwinnr(a:filename)
+    endif
+
+    if winnum == -1
+        " Locate the previously used window for opening a file
+        let fwin_num = 0
+        let first_usable_win = 0
+
+        let i = 1
+        let bnum = winbufnr(i)
+        while bnum != -1
+            if getwinvar(i, 'tlist_file_window') == 'yes'
+                let fwin_num = i
+                break
+            endif
+            if first_usable_win == 0 &&
+                        \ getbufvar(bnum, '&buftype') == '' &&
+                        \ !getwinvar(i, '&previewwindow')
+                " First non-taglist, non-plugin and non-preview window
+                let first_usable_win = i
+            endif
+            let i = i + 1
+            let bnum = winbufnr(i)
+        endwhile
+
+        " If a previously used window is not found, then use the first
+        " non-taglist window
+        if fwin_num == 0
+            let fwin_num = first_usable_win
+        endif
+
+        if fwin_num != 0
+            " Jump to the file window
+            exe fwin_num . "wincmd w"
+
+            " If the user asked to jump to the tag in a new window, then split
+            " the existing window into two.
+            if a:win_ctrl == 'newwin'
+                split
+            endif
+            exe "edit " . escape(a:filename, ' ')
+        else
+            " Open a new window
+            if g:Tlist_Use_Horiz_Window
+                exe 'leftabove split ' . escape(a:filename, ' ')
+            else
+                if winbufnr(2) == -1
+                    " Only the taglist window is present
+                    if g:Tlist_Use_Right_Window
+                        exe 'leftabove vertical split ' .
+                                    \ escape(a:filename, ' ')
+                    else
+                        exe 'rightbelow vertical split ' .
+                                    \ escape(a:filename, ' ')
+                    endif
+
+                    " Go to the taglist window to change the window size to
+                    " the user configured value
+                    call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+                    if g:Tlist_Use_Horiz_Window
+                        exe 'resize ' . g:Tlist_WinHeight
+                    else
+                        exe 'vertical resize ' . g:Tlist_WinWidth
+                    endif
+                    " Go back to the file window
+                    call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
+                else
+                    " A plugin or help window is also present
+                    wincmd w
+                    exe 'leftabove split ' . escape(a:filename, ' ')
+                endif
+            endif
+        endif
+        " Mark the window, so that it can be reused.
+        call s:Tlist_Window_Mark_File_Window()
+    else
+        if v:version >= 700
+            " If the file is opened in more than one window, then check
+            " whether the last accessed window has the selected file.
+            " If it does, then use that window.
+            let lastwin_bufnum = winbufnr(winnr('#'))
+            if bufnr(a:filename) == lastwin_bufnum
+                let winnum = winnr('#')
+            endif
+        endif
+        exe winnum . 'wincmd w'
+
+        " If the user asked to jump to the tag in a new window, then split the
+        " existing window into two.
+        if a:win_ctrl == 'newwin'
+            split
+        endif
+    endif
+    endif
+
+    " Jump to the tag
+    if a:tagpat != ''
+        " Add the current cursor position to the jump list, so that user can
+        " jump back using the ' and ` marks.
+        mark '
+        silent call search(a:tagpat, 'w')
+
+        " Bring the line to the middle of the window
+        normal! z.
+
+        " If the line is inside a fold, open the fold
+        if foldclosed('.') != -1
+            .foldopen
+        endif
+    endif
+
+    " If the user selects to preview the tag then jump back to the
+    " taglist window
+    if a:win_ctrl == 'preview'
+        " Go back to the taglist window
+        let winnum = bufwinnr(g:TagList_title)
+        exe winnum . 'wincmd w'
+    else
+        " If the user has selected to close the taglist window, when a
+        " tag is selected, close the taglist  window
+        if g:Tlist_Close_On_Select
+            call s:Tlist_Window_Goto_Window()
+            close
+
+            " Go back to the window displaying the selected file
+            let wnum = bufwinnr(a:filename)
+            if wnum != -1 && wnum != winnr()
+                call s:Tlist_Exe_Cmd_No_Acmds(wnum . 'wincmd w')
+            endif
+        endif
+    endif
+
+    let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh
+endfunction
+
+" Tlist_Window_Jump_To_Tag()
+" Jump to the location of the current tag
+" win_ctrl == useopen - Reuse the existing file window
+" win_ctrl == newwin - Open a new window
+" win_ctrl == preview - Preview the tag
+" win_ctrl == prevwin - Open in previous window
+" win_ctrl == newtab - Open in new tab
+function! s:Tlist_Window_Jump_To_Tag(win_ctrl)
+    call s:Tlist_Log_Msg('Tlist_Window_Jump_To_Tag(' . a:win_ctrl . ')')
+    " Do not process comment lines and empty lines
+    let curline = getline('.')
+    if curline =~ '^\s*$' || curline[0] == '"'
+        return
+    endif
+
+    " If inside a closed fold, then use the first line of the fold
+    " and jump to the file.
+    let lnum = foldclosed('.')
+    if lnum == -1
+        " Jump to the selected tag or file
+        let lnum = line('.')
+    else
+        " Open the closed fold
+        .foldopen!
+    endif
+
+    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+    if fidx == -1
+        return
+    endif
+
+    " Get the tag output for the current tag
+    let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+    if tidx != 0
+        let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx)
+
+        " Highlight the tagline
+        call s:Tlist_Window_Highlight_Line()
+    else
+        " Selected a line which is not a tag name. Just edit the file
+        let tagpat = ''
+    endif
+
+    call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat)
+endfunction
+
+" Tlist_Window_Show_Info()
+" Display information about the entry under the cursor
+function! s:Tlist_Window_Show_Info()
+    call s:Tlist_Log_Msg('Tlist_Window_Show_Info()')
+
+    " Clear the previously displayed line
+    echo
+
+    " Do not process comment lines and empty lines
+    let curline = getline('.')
+    if curline =~ '^\s*$' || curline[0] == '"'
+        return
+    endif
+
+    " If inside a fold, then don't display the prototype
+    if foldclosed('.') != -1
+        return
+    endif
+
+    let lnum = line('.')
+
+    " Get the file index
+    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
+    if fidx == -1
+        return
+    endif
+
+    if lnum == s:tlist_{fidx}_start
+        " Cursor is on a file name
+        let fname = s:tlist_{fidx}_filename
+        if strlen(fname) > 50
+            let fname = fnamemodify(fname, ':t')
+        endif
+        echo fname . ', Filetype=' . s:tlist_{fidx}_filetype .
+                    \  ', Tag count=' . s:tlist_{fidx}_tag_count
+        return
+    endif
+
+    " Get the tag output line for the current tag
+    let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
+    if tidx == 0
+        " Cursor is on a tag type
+        let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
+        if ttype == ''
+            return
+        endif
+
+        let ttype_name = ''
+
+        let ftype = s:tlist_{fidx}_filetype
+        let i = 1
+        while i <= s:tlist_{ftype}_count
+            if ttype == s:tlist_{ftype}_{i}_name
+                let ttype_name = s:tlist_{ftype}_{i}_fullname
+                break
+            endif
+            let i = i + 1
+        endwhile
+
+        echo 'Tag type=' . ttype_name .
+                    \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count
+        return
+    endif
+
+    " Get the tag search pattern and display it
+    echo s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Find_Nearest_Tag_Idx
+" Find the tag idx nearest to the supplied line number
+" Returns -1, if a tag couldn't be found for the specified line number
+function! s:Tlist_Find_Nearest_Tag_Idx(fidx, linenum)
+    let sort_type = s:tlist_{a:fidx}_sort_type
+
+    let left = 1
+    let right = s:tlist_{a:fidx}_tag_count
+
+    if sort_type == 'order'
+        " Tags sorted by order, use a binary search.
+        " The idea behind this function is taken from the ctags.vim script (by
+        " Alexey Marinichev) available at the Vim online website.
+
+        " If the current line is the less than the first tag, then no need to
+        " search
+        let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1)
+
+        if a:linenum < first_lnum
+            return -1
+        endif
+
+        while left < right
+            let middle = (right + left + 1) / 2
+            let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle)
+
+            if middle_lnum == a:linenum
+                let left = middle
+                break
+            endif
+
+            if middle_lnum > a:linenum
+                let right = middle - 1
+            else
+                let left = middle
+            endif
+        endwhile
+    else
+        " Tags sorted by name, use a linear search. (contributed by Dave
+        " Eggum).
+        " Look for a tag with a line number less than or equal to the supplied
+        " line number. If multiple tags are found, then use the tag with the
+        " line number closest to the supplied line number. IOW, use the tag
+        " with the highest line number.
+        let closest_lnum = 0
+        let final_left = 0
+        while left <= right
+            let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left)
+
+            if lnum < a:linenum && lnum > closest_lnum
+                let closest_lnum = lnum
+                let final_left = left
+            elseif lnum == a:linenum
+                let closest_lnum = lnum
+                let final_left = left
+                break
+            else
+                let left = left + 1
+            endif
+        endwhile
+        if closest_lnum == 0
+            return -1
+        endif
+        if left >= right
+            let left = final_left
         endif
+    endif
+
+    return left
+endfunction
+
+" Tlist_Window_Highlight_Tag()
+" Highlight the current tag
+" cntx == 1, Called by the taglist plugin itself
+" cntx == 2, Forced by the user through the TlistHighlightTag command
+" center = 1, move the tag line to the center of the taglist window
+function! s:Tlist_Window_Highlight_Tag(filename, cur_lnum, cntx, center)
+    " Highlight the current tag only if the user configured the
+    " taglist plugin to do so or if the user explictly invoked the
+    " command to highlight the current tag.
+    if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1
+        return
+    endif
+
+    if a:filename == ''
+        return
+    endif
+
+    " Make sure the taglist window is present
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum == -1
+        call s:Tlist_Warning_Msg('Error: Taglist window is not open')
+        return
+    endif
+
+    let fidx = s:Tlist_Get_File_Index(a:filename)
+    if fidx == -1
+        return
+    endif
+
+    " If the file is currently not displayed in the taglist window, then retrn
+    if !s:tlist_{fidx}_visible
+        return
+    endif
+
+    " If there are no tags for this file, then no need to proceed further
+    if s:tlist_{fidx}_tag_count == 0
+        return
+    endif
+
+    " Ignore all autocommands
+    let old_ei = &eventignore
+    set eventignore=all
+
+    " Save the original window number
+    let org_winnr = winnr()
+
+    if org_winnr == winnum
+        let in_taglist_window = 1
     else
+        let in_taglist_window = 0
+    endif
+
+    " Go to the taglist window
+    if !in_taglist_window
         exe winnum . 'wincmd w'
+    endif
+
+    " Clear previously selected name
+    match none
+
+    let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum)
+    if tidx == -1
+        " Make sure the current tag line is visible in the taglist window.
+        " Calling the winline() function makes the line visible.  Don't know
+        " of a better way to achieve this.
+        let lnum = line('.')
+
+        if lnum < s:tlist_{fidx}_start || lnum > s:tlist_{fidx}_end
+            " Move the cursor to the beginning of the file
+            exe s:tlist_{fidx}_start
+        endif
+
+        if foldclosed('.') != -1
+            .foldopen
+        endif
+
+        call winline()
+
+        if !in_taglist_window
+            exe org_winnr . 'wincmd w'
+        endif
+
+        " Restore the autocommands
+        let &eventignore = old_ei
+        return
+    endif
+
+    " Extract the tag type
+    let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
+
+    " Compute the line number
+    " Start of file + Start of tag type + offset
+    let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset +
+                \ s:tlist_{fidx}_{tidx}_ttype_idx
+
+    " Goto the line containing the tag
+    exe lnum
+
+    " Open the fold
+    if foldclosed('.') != -1
+        .foldopen
+    endif
+
+    if a:center
+        " Move the tag line to the center of the taglist window
+        normal! z.
+    else
+        " Make sure the current tag line is visible in the taglist window.
+        " Calling the winline() function makes the line visible.  Don't know
+        " of a better way to achieve this.
+        call winline()
+    endif
+
+    " Highlight the tag name
+    call s:Tlist_Window_Highlight_Line()
+
+    " Go back to the original window
+    if !in_taglist_window
+        exe org_winnr . 'wincmd w'
+    endif
+
+    " Restore the autocommands
+    let &eventignore = old_ei
+    return
+endfunction
+
+" Tlist_Get_Tag_Prototype_By_Line
+" Get the prototype for the tag on or before the specified line number in the
+" current buffer
+function! Tlist_Get_Tag_Prototype_By_Line(...)
+    if a:0 == 0
+        " Arguments are not supplied. Use the current buffer name
+        " and line number
+        let filename = bufname('%')
+        let linenr = line('.')
+    elseif a:0 == 2
+        " Filename and line number are specified
+        let filename = a:1
+        let linenr = a:2
+        if linenr !~ '\d\+'
+            " Invalid line number
+            return ""
+        endif
+    else
+        " Sufficient arguments are not supplied
+        let msg =  'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' .
+                                \ '<line_number>'
+        call s:Tlist_Warning_Msg(msg)
+        return ""
+    endif
+
+    " Expand the file to a fully qualified name
+    let filename = fnamemodify(filename, ':p')
+    if filename == ''
+        return ""
+    endif
+
+    let fidx = s:Tlist_Get_File_Index(filename)
+    if fidx == -1
+        return ""
+    endif
+
+    " If there are no tags for this file, then no need to proceed further
+    if s:tlist_{fidx}_tag_count == 0
+        return ""
+    endif
+
+    " Get the tag text using the line number
+    let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
+    if tidx == -1
+        return ""
+    endif
+
+    return s:Tlist_Get_Tag_Prototype(fidx, tidx)
+endfunction
+
+" Tlist_Get_Tagname_By_Line
+" Get the tag name on or before the specified line number in the
+" current buffer
+function! Tlist_Get_Tagname_By_Line(...)
+    if a:0 == 0
+        " Arguments are not supplied. Use the current buffer name
+        " and line number
+        let filename = bufname('%')
+        let linenr = line('.')
+    elseif a:0 == 2
+        " Filename and line number are specified
+        let filename = a:1
+        let linenr = a:2
+        if linenr !~ '\d\+'
+            " Invalid line number
+            return ""
+        endif
+    else
+        " Sufficient arguments are not supplied
+        let msg =  'Usage: Tlist_Get_Tagname_By_Line <filename> <line_number>'
+        call s:Tlist_Warning_Msg(msg)
+        return ""
+    endif
+
+    " Make sure the current file has a name
+    let filename = fnamemodify(filename, ':p')
+    if filename == ''
+        return ""
+    endif
+
+    let fidx = s:Tlist_Get_File_Index(filename)
+    if fidx == -1
+        return ""
+    endif
+
+    " If there are no tags for this file, then no need to proceed further
+    if s:tlist_{fidx}_tag_count == 0
+        return ""
+    endif
+
+    " Get the tag name using the line number
+    let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
+    if tidx == -1
+        return ""
+    endif
+
+    return s:tlist_{fidx}_{tidx}_tag_name
+endfunction
+
+" Tlist_Window_Move_To_File
+" Move the cursor to the beginning of the current file or the next file
+" or the previous file in the taglist window
+" dir == -1, move to start of current or previous function
+" dir == 1, move to start of next function
+function! s:Tlist_Window_Move_To_File(dir)
+    if foldlevel('.') == 0
+        " Cursor is on a non-folded line (it is not in any of the files)
+        " Move it to a folded line
+        if a:dir == -1
+            normal! zk
+        else
+            " While moving down to the start of the next fold,
+            " no need to do go to the start of the next file.
+            normal! zj
+            return
+        endif
+    endif
+
+    let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
+    if fidx == -1
+        return
+    endif
+
+    let cur_lnum = line('.')
+
+    if a:dir == -1
+        if cur_lnum > s:tlist_{fidx}_start
+            " Move to the beginning of the current file
+            exe s:tlist_{fidx}_start
+            return
+        endif
+
+        if fidx != 0
+            " Move to the beginning of the previous file
+            let fidx = fidx - 1
+        else
+            " Cursor is at the first file, wrap around to the last file
+            let fidx = s:tlist_file_count - 1
+        endif
+
+        exe s:tlist_{fidx}_start
+        return
+    else
+        " Move to the beginning of the next file
+        let fidx = fidx + 1
+
+        if fidx >= s:tlist_file_count
+            " Cursor is at the last file, wrap around to the first file
+            let fidx = 0
+        endif
+
+        if s:tlist_{fidx}_start != 0
+            exe s:tlist_{fidx}_start
+        endif
+        return
+    endif
+endfunction
+
+" Tlist_Session_Load
+" Load a taglist session (information about all the displayed files
+" and the tags) from the specified file
+function! s:Tlist_Session_Load(...)
+    if a:0 == 0 || a:1 == ''
+        call s:Tlist_Warning_Msg('Usage: TlistSessionLoad <filename>')
+        return
+    endif
+
+    let sessionfile = a:1
+
+    if !filereadable(sessionfile)
+        let msg = 'Taglist: Error - Unable to open file ' . sessionfile
+        call s:Tlist_Warning_Msg(msg)
+        return
+    endif
+
+    " Mark the current window as the file window
+    call s:Tlist_Window_Mark_File_Window()
+
+    " Source the session file
+    exe 'source ' . sessionfile
+
+    let new_file_count = g:tlist_file_count
+    unlet! g:tlist_file_count
+
+    let i = 0
+    while i < new_file_count
+        let ftype = g:tlist_{i}_filetype
+        unlet! g:tlist_{i}_filetype
+
+        if !exists('s:tlist_' . ftype . '_count')
+            if s:Tlist_FileType_Init(ftype) == 0
+                let i = i + 1
+                continue
+            endif
+        endif
+
+        let fname = g:tlist_{i}_filename
+        unlet! g:tlist_{i}_filename
+
+        let fidx = s:Tlist_Get_File_Index(fname)
+        if fidx != -1
+            let s:tlist_{fidx}_visible = 0
+            let i = i + 1
+            continue
+        else
+            " As we are loading the tags from the session file, if this
+            " file was previously deleted by the user, now we need to
+            " add it back. So remove the file from the deleted list.
+            call s:Tlist_Update_Remove_List(fname, 0)
+        endif
+
+        let fidx = s:Tlist_Init_File(fname, ftype)
+
+        let s:tlist_{fidx}_filename = fname
+
+        let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type
+        unlet! g:tlist_{i}_sort_type
+
+        let s:tlist_{fidx}_filetype = ftype
+        let s:tlist_{fidx}_mtime = getftime(fname)
+
+        let s:tlist_{fidx}_start = 0
+        let s:tlist_{fidx}_end = 0
+
+        let s:tlist_{fidx}_valid = 1
+
+        let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count
+        unlet! g:tlist_{i}_tag_count
+
+        let j = 1
+        while j <= s:tlist_{fidx}_tag_count
+            let s:tlist_{fidx}_{j}_tag = g:tlist_{i}_{j}_tag
+            let s:tlist_{fidx}_{j}_tag_name = g:tlist_{i}_{j}_tag_name
+            let s:tlist_{fidx}_{j}_ttype_idx = g:tlist_{i}_{j}_ttype_idx
+            unlet! g:tlist_{i}_{j}_tag
+            unlet! g:tlist_{i}_{j}_tag_name
+            unlet! g:tlist_{i}_{j}_ttype_idx
+            let j = j + 1
+        endwhile
+
+        let j = 1
+        while j <= s:tlist_{ftype}_count
+            let ttype = s:tlist_{ftype}_{j}_name
+
+            if exists('g:tlist_' . i . '_' . ttype)
+                let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype}
+                unlet! g:tlist_{i}_{ttype}
+                let s:tlist_{fidx}_{ttype}_offset = 0
+                let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count
+                unlet! g:tlist_{i}_{ttype}_count
+
+                let k = 1
+                while k <= s:tlist_{fidx}_{ttype}_count
+                    let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k}
+                    unlet! g:tlist_{i}_{ttype}_{k}
+                    let k = k + 1
+                endwhile
+            else
+                let s:tlist_{fidx}_{ttype} = ''
+                let s:tlist_{fidx}_{ttype}_offset = 0
+                let s:tlist_{fidx}_{ttype}_count = 0
+            endif
+
+            let j = j + 1
+        endwhile
 
-        " If the user asked to jump to the tag in a new window, then split the
-        " existing window into two.
-        if a:new_window
-            split
+        let i = i + 1
+    endwhile
+
+    " If the taglist window is open, then update it
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum != -1
+        let save_winnr = winnr()
+
+        " Goto the taglist window
+        call s:Tlist_Window_Goto_Window()
+
+        " Refresh the taglist window
+        call s:Tlist_Window_Refresh()
+
+        " Go back to the original window
+        if save_winnr != winnr()
+            call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
         endif
     endif
+endfunction
+
+" Tlist_Session_Save
+" Save a taglist session (information about all the displayed files
+" and the tags) into the specified file
+function! s:Tlist_Session_Save(...)
+    if a:0 == 0 || a:1 == ''
+        call s:Tlist_Warning_Msg('Usage: TlistSessionSave <filename>')
+        return
     endif
 
-    " Jump to the tag
-    silent call search(tagpat, 'w')
+    let sessionfile = a:1
 
-    " Bring the line to the middle of the window
-    normal! z.
+    if s:tlist_file_count == 0
+        " There is nothing to save
+        call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.')
+        return
+    endif
 
-    " If the line is inside a fold, open the fold
-    if has('folding')
-        if foldlevel('.') != 0
-            normal zo
+    if filereadable(sessionfile)
+        let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?')
+        if ans !=? 'y'
+            return
         endif
+
+        echo "\n"
     endif
 
-    let s:Tlist_Skip_Refresh = 0
+    let old_verbose = &verbose
+    set verbose&vim
+
+    exe 'redir! > ' . sessionfile
+
+    silent! echo '" Taglist session file. This file is auto-generated.'
+    silent! echo '" File information'
+    silent! echo 'let tlist_file_count = ' . s:tlist_file_count
+
+    let i = 0
+
+    while i < s:tlist_file_count
+        " Store information about the file
+        silent! echo 'let tlist_' . i . "_filename = '" .
+                                            \ s:tlist_{i}_filename . "'"
+        silent! echo 'let tlist_' . i . '_sort_type = "' .
+                                                \ s:tlist_{i}_sort_type . '"'
+        silent! echo 'let tlist_' . i . '_filetype = "' .
+                                            \ s:tlist_{i}_filetype . '"'
+        silent! echo 'let tlist_' . i . '_tag_count = ' .
+                                                        \ s:tlist_{i}_tag_count
+        " Store information about all the tags
+        let j = 1
+        while j <= s:tlist_{i}_tag_count
+            let txt = escape(s:tlist_{i}_{j}_tag, '"\\')
+            silent! echo 'let tlist_' . i . '_' . j . '_tag = "' . txt . '"'
+            silent! echo 'let tlist_' . i . '_' . j . '_tag_name = "' .
+                        \ s:tlist_{i}_{j}_tag_name . '"'
+            silent! echo 'let tlist_' . i . '_' . j . '_ttype_idx' . ' = ' .
+                        \ s:tlist_{i}_{j}_ttype_idx
+            let j = j + 1
+        endwhile
+
+        " Store information about all the tags grouped by their type
+        let ftype = s:tlist_{i}_filetype
+        let j = 1
+        while j <= s:tlist_{ftype}_count
+            let ttype = s:tlist_{ftype}_{j}_name
+            if s:tlist_{i}_{ttype}_count != 0
+                let txt = escape(s:tlist_{i}_{ttype}, '"\')
+                let txt = substitute(txt, "\n", "\\\\n", 'g')
+                silent! echo 'let tlist_' . i . '_' . ttype . ' = "' .
+                                                \ txt . '"'
+                silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' .
+                                                     \ s:tlist_{i}_{ttype}_count
+                let k = 1
+                while k <= s:tlist_{i}_{ttype}_count
+                    silent! echo 'let tlist_' . i . '_' . ttype . '_' . k .
+                                \ ' = ' . s:tlist_{i}_{ttype}_{k}
+                    let k = k + 1
+                endwhile
+            endif
+            let j = j + 1
+        endwhile
+
+        silent! echo
+
+        let i = i + 1
+    endwhile
+
+    redir END
+
+    let &verbose = old_verbose
 endfunction
 
-" Tlist_Show_Tag_Prototype()
-" Display the prototype of the tag under the cursor
-function! s:Tlist_Show_Tag_Prototype()
-    " If we have already display prototype in the tag window, no need to
-    " display it in the status line
-    if g:Tlist_Display_Prototype == 1
+" Tlist_Buffer_Removed
+" A buffer is removed from the Vim buffer list. Remove the tags defined
+" for that file
+function! s:Tlist_Buffer_Removed(filename)
+    call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename .  ')')
+
+    " Make sure a valid filename is supplied
+    if a:filename == ''
         return
     endif
 
-    " Clear the previously displayed line
-    echo
-
-    " Do not process comment lines and empty lines
-    let curline = getline('.')
-    if curline == '' || curline[0] == '"'
+    " Get tag list index of the specified file
+    let fidx = s:Tlist_Get_File_Index(a:filename)
+    if fidx == -1
+        " File not present in the taglist
         return
     endif
 
-    " If inside a fold, then don't display the prototype
-    if foldclosed('.') != -1
+    " Remove the file from the list
+    call s:Tlist_Remove_File(fidx, 0)
+endfunction
+
+" When a buffer is deleted, remove the file from the taglist
+autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand('<afile>:p'))
+
+" Tlist_Window_Open_File_Fold
+" Open the fold for the specified file and close the fold for all the
+" other files
+function! s:Tlist_Window_Open_File_Fold(acmd_bufnr)
+    call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')')
+
+    " Make sure the taglist window is present
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum == -1
+        call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open')
         return
     endif
 
-    " Get the tag output line for the current tag
-    let lnum = s:Tlist_Get_Tag_Linenr()
-    if lnum == 0
+    " Save the original window number
+    let org_winnr = winnr()
+    if org_winnr == winnum
+        let in_taglist_window = 1
+    else
+        let in_taglist_window = 0
+    endif
+
+    if in_taglist_window
+        " When entering the taglist window, no need to update the folds
         return
     endif
 
-    let mtxt = b:tlist_tag_{lnum}
+    " Go to the taglist window
+    if !in_taglist_window
+        call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
+    endif
 
-    " Get the tag search pattern and display it
-    echo s:Tlist_Extract_Tag_Prototype(mtxt)
-endfunction
+    " Close all the folds
+    silent! %foldclose
+
+    " Get tag list index of the specified file
+    let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p')
+    if filereadable(fname)
+        let fidx = s:Tlist_Get_File_Index(fname)
+        if fidx != -1
+            " Open the fold for the file
+            exe "silent! " . s:tlist_{fidx}_start . "," .
+                        \ s:tlist_{fidx}_end . "foldopen"
+        endif
+    endif
 
-" Tlist_Locate_Tag_Text
-" Locate the tag text given the line number in the source window
-function! s:Tlist_Locate_Tag_Text(sort_type, linenum)
-    let left = 1
-    let right = b:tlist_tag_count
+    " Go back to the original window
+    if !in_taglist_window
+        call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w')
+    endif
+endfunction
 
-    if a:sort_type == 'order'
-        " Tag list sorted by order, do a binary search comparing the line
-        " numbers
+" Tlist_Window_Check_Auto_Open
+" Open the taglist window automatically on Vim startup.
+" Open the window only when files present in any of the Vim windows support
+" tags.
+function! s:Tlist_Window_Check_Auto_Open()
+    let open_window = 0
 
-        " If the current line is the less than the first tag, then no need to
-        " search
-        let txt = b:tlist_tag_1
-        let start = strridx(txt, 'line:') + strlen('line:')
-        let end = strridx(txt, "\t")
-        if end < start
-            let first_lnum = strpart(txt, start) + 0
-        else
-            let first_lnum = strpart(txt, start, end - start) + 0
+    let i = 1
+    let buf_num = winbufnr(i)
+    while buf_num != -1
+        let filename = fnamemodify(bufname(buf_num), ':p')
+        let ft = s:Tlist_Get_Buffer_Filetype(buf_num)
+        if !s:Tlist_Skip_File(filename, ft)
+            let open_window = 1
+            break
         endif
+        let i = i + 1
+        let buf_num = winbufnr(i)
+    endwhile
 
-        if a:linenum < first_lnum
-            return ""
-        endif
+    if open_window
+        call s:Tlist_Window_Toggle()
+    endif
+endfunction
 
-        while left < right
-            let middle = (right + left + 1) / 2
-            let txt = b:tlist_tag_{middle}
+" Tlist_Refresh_Folds
+" Remove and create the folds for all the files displayed in the taglist
+" window. Used after entering a tab. If this is not done, then the folds
+" are not properly created for taglist windows displayed in multiple tabs.
+function! s:Tlist_Refresh_Folds()
+    let winnum = bufwinnr(g:TagList_title)
+    if winnum == -1
+        return
+    endif
 
-            let start = strridx(txt, 'line:') + strlen('line:')
-            let end = strridx(txt, "\t")
-            if end < start
-                let middle_lnum = strpart(txt, start) + 0
-            else
-                let middle_lnum = strpart(txt, start, end - start) + 0
+    let save_wnum = winnr()
+    exe winnum . 'wincmd w'
+
+    " First remove all the existing folds
+    normal! zE
+
+    " Create the folds for each in the tag list
+    let fidx = 0
+    while fidx < s:tlist_file_count
+        let ftype = s:tlist_{fidx}_filetype
+
+        " Create the folds for each tag type in a file
+        let j = 1
+        while j <= s:tlist_{ftype}_count
+            let ttype = s:tlist_{ftype}_{j}_name
+            if s:tlist_{fidx}_{ttype}_count
+                let s = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset
+                let e = s + s:tlist_{fidx}_{ttype}_count
+                exe s . ',' . e . 'fold'
             endif
+            let j = j + 1
+        endwhile
 
-            if middle_lnum == a:linenum
-                let left = middle
-                break
+        exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
+        exe 'silent! ' . s:tlist_{fidx}_start . ',' .
+                    \ s:tlist_{fidx}_end . 'foldopen!'
+        let fidx = fidx + 1
+    endwhile
+
+    exe save_wnum . 'wincmd w'
+endfunction
+
+function! s:Tlist_Menu_Add_Base_Menu()
+    call s:Tlist_Log_Msg('Adding the base menu')
+
+    " Add the menu
+    anoremenu <silent> T&ags.Refresh\ menu :call <SID>Tlist_Menu_Refresh()<CR>
+    anoremenu <silent> T&ags.Sort\ menu\ by.Name
+                    \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+    anoremenu <silent> T&ags.Sort\ menu\ by.Order
+                    \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+    anoremenu T&ags.-SEP1-           :
+
+    if &mousemodel =~ 'popup'
+        anoremenu <silent> PopUp.T&ags.Refresh\ menu
+                    \ :call <SID>Tlist_Menu_Refresh()<CR>
+        anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Name
+                  \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+        anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Order
+                  \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+        anoremenu PopUp.T&ags.-SEP1-           :
+    endif
+endfunction
+
+let s:menu_char_prefix =
+            \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+
+" Tlist_Menu_Get_Tag_Type_Cmd
+" Get the menu command for the specified tag type
+" fidx - File type index
+" ftype - File Type
+" add_ttype_name - To add or not to add the tag type name to the menu entries
+" ttype_idx - Tag type index
+function! s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, ttype_idx)
+    " Curly brace variable name optimization
+    let ftype_ttype_idx = a:ftype . '_' . a:ttype_idx
+
+    let ttype = s:tlist_{ftype_ttype_idx}_name
+    if a:add_ttype_name
+        " If the tag type name contains space characters, escape it. This
+        " will be used to create the menu entries.
+        let ttype_fullname = escape(s:tlist_{ftype_ttype_idx}_fullname, ' ')
+    endif
+
+    " Curly brace variable name optimization
+    let fidx_ttype = a:fidx . '_' . ttype
+
+    " Number of tag entries for this tag type
+    let tcnt = s:tlist_{fidx_ttype}_count
+    if tcnt == 0 " No entries for this tag type
+        return ''
+    endif
+
+    let mcmd = ''
+
+    " Create the menu items for the tags.
+    " Depending on the number of tags of this type, split the menu into
+    " multiple sub-menus, if needed.
+    if tcnt > g:Tlist_Max_Submenu_Items
+        let j = 1
+        while j <= tcnt
+            let final_index = j + g:Tlist_Max_Submenu_Items - 1
+            if final_index > tcnt
+                let final_index = tcnt
             endif
 
-            if middle_lnum > a:linenum
-                let right = middle - 1
-            else
-                let left = middle
+            " Extract the first and last tag name and form the
+            " sub-menu name
+            let tidx = s:tlist_{fidx_ttype}_{j}
+            let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name
+
+            let tidx = s:tlist_{fidx_ttype}_{final_index}
+            let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name
+
+            " Truncate the names, if they are greater than the
+            " max length
+            let first_tag = strpart(first_tag, 0, g:Tlist_Max_Tag_Length)
+            let last_tag = strpart(last_tag, 0, g:Tlist_Max_Tag_Length)
+
+            " Form the menu command prefix
+            let m_prefix = 'anoremenu <silent> T\&ags.'
+            if a:add_ttype_name
+                let m_prefix = m_prefix . ttype_fullname . '.'
             endif
+            let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.'
+
+            " Character prefix used to number the menu items (hotkey)
+            let m_prefix_idx = 0
+
+            while j <= final_index
+                let tidx = s:tlist_{fidx_ttype}_{j}
+
+                let tname = s:tlist_{a:fidx}_{tidx}_tag_name
+
+                let mcmd = mcmd . m_prefix . '\&' .
+                            \ s:menu_char_prefix[m_prefix_idx] . '\.' .
+                            \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' .
+                            \ tidx . ')<CR>|'
+
+                let m_prefix_idx = m_prefix_idx + 1
+                let j = j + 1
+            endwhile
         endwhile
     else
-        " sorted by name, brute force method (Dave Eggum)
-        let closest_lnum = 0
-        let final_left = 0
-        while left < right
-            let txt = b:tlist_tag_{left}
+        " Character prefix used to number the menu items (hotkey)
+        let m_prefix_idx = 0
 
-            let start = strridx(txt, 'line:') + strlen('line:')
-            let end = strridx(txt, "\t")
-            if end < start
-                let lnum = strpart(txt, start) + 0
-            else
-                let lnum = strpart(txt, start, end - start) + 0
-            endif
+        let m_prefix = 'anoremenu <silent> T\&ags.'
+        if a:add_ttype_name
+            let m_prefix = m_prefix . ttype_fullname . '.'
+        endif
+        let j = 1
+        while j <= tcnt
+            let tidx = s:tlist_{fidx_ttype}_{j}
 
-            if lnum < a:linenum && lnum > closest_lnum
-                let closest_lnum = lnum
-                let final_left = left
-            elseif lnum == a:linenum
-                let closest_lnum = lnum
-                break
-            else
-                let left = left + 1
-            endif
+            let tname = s:tlist_{a:fidx}_{tidx}_tag_name
+
+            let mcmd = mcmd . m_prefix . '\&' .
+                        \ s:menu_char_prefix[m_prefix_idx] . '\.' .
+                        \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . tidx
+                        \ . ')<CR>|'
+
+            let m_prefix_idx = m_prefix_idx + 1
+            let j = j + 1
         endwhile
-        if closest_lnum == 0
-            return ""
-        endif
-        if left == right
-            let left = final_left
-        endif
     endif
 
-    return b:tlist_tag_{left}
+    return mcmd
 endfunction
 
-" Tlist_Highlight_Tag()
-" Do a binary search in the array of tag names and pick a tag entry that
-" contains the current line and highlight it.  The idea behind this function
-" is taken from the ctags.vim script available at the Vim online website.
-function! s:Tlist_Highlight_Tag(bufnum, curline)
-    let filename = fnamemodify(bufname(a:bufnum), ':p')
-    if filename == ''
-        return
+" Update the taglist menu with the tags for the specified file
+function! s:Tlist_Menu_File_Refresh(fidx)
+    call s:Tlist_Log_Msg('Refreshing the tag menu for ' . s:tlist_{a:fidx}_filename)
+    " The 'B' flag is needed in the 'cpoptions' option
+    let old_cpoptions = &cpoptions
+    set cpoptions&vim
+
+    exe s:tlist_{a:fidx}_menu_cmd
+
+    " Update the popup menu (if enabled)
+    if &mousemodel =~ 'popup'
+        let cmd = substitute(s:tlist_{a:fidx}_menu_cmd, ' T\\&ags\.',
+                                        \ ' PopUp.T\\\&ags.', "g")
+        exe cmd
     endif
 
-    " Make sure the taglist window is present
-    let winnum = bufwinnr(g:TagList_title)
-    if winnum == -1
+    " The taglist menu is not empty now
+    let s:tlist_menu_empty = 0
+
+    " Restore the 'cpoptions' settings
+    let &cpoptions = old_cpoptions
+endfunction
+
+" Tlist_Menu_Update_File
+" Add the taglist menu
+function! s:Tlist_Menu_Update_File(clear_menu)
+    if !has('gui_running')
+        " Not running in GUI mode
         return
     endif
 
-    let bno = bufnr(g:TagList_title)
+    call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu)
+
+    " Remove the tags menu
+    if a:clear_menu
+        call s:Tlist_Menu_Remove_File()
 
-    " Make sure we have the tag listing for the current file
-    if getbufvar(bno, 'tlist_bufnum') != a:bufnum
+    endif
+
+    " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
+    if &buftype != ''
         return
     endif
 
-    " If there are no tags for this file, then no need to proceed further
-    if getbufvar(bno, 'tlist_tag_count') == 0
+    let filename = fnamemodify(bufname('%'), ':p')
+    let ftype = s:Tlist_Get_Buffer_Filetype('%')
+
+    " If the file doesn't support tag listing, skip it
+    if s:Tlist_Skip_File(filename, ftype)
         return
     endif
 
-    " If part of winmanager then disable winmanager autocommands
-    if s:tlist_part_of_winmanager
-        call WinManagerSuspendAUs()
+    let fidx = s:Tlist_Get_File_Index(filename)
+    if fidx == -1 || !s:tlist_{fidx}_valid
+        " Check whether this file is removed based on user request
+        " If it is, then don't display the tags for this file
+        if s:Tlist_User_Removed_File(filename)
+            return
+        endif
+
+        " Process the tags for the file
+        let fidx = s:Tlist_Process_File(filename, ftype)
+        if fidx == -1
+            return
+        endif
     endif
 
-    " Save the original window number
-    let org_winnr = winnr()
+    let fname = escape(fnamemodify(bufname('%'), ':t'), '.')
+    if fname != ''
+        exe 'anoremenu T&ags.' .  fname . ' <Nop>'
+        anoremenu T&ags.-SEP2-           :
+    endif
 
-    if org_winnr == winnum
-        let in_taglist_window = 1
-    else
-        let in_taglist_window = 0
+    if !s:tlist_{fidx}_tag_count
+        return
     endif
 
-    " Go to the taglist window
-    if !in_taglist_window
-        exe winnum . 'wincmd w'
+    if s:tlist_{fidx}_menu_cmd != ''
+        " Update the menu with the cached command
+        call s:Tlist_Menu_File_Refresh(fidx)
+
+        return
     endif
 
-    " Clear previously selected name
-    match none
+    " We are going to add entries to the tags menu, so the menu won't be
+    " empty
+    let s:tlist_menu_empty = 0
 
-    let tag_txt = s:Tlist_Locate_Tag_Text(getbufvar(bno, 'tlist_sort_type'),
-                                          \ a:curline)
-    if tag_txt == ""
-        if !in_taglist_window
-            let s:Tlist_Skip_Refresh = 1
-            exe org_winnr . 'wincmd w'
-            let s:Tlist_Skip_Refresh = 0
+    let cmd = ''
+
+    " Determine whether the tag type name needs to be added to the menu
+    " If more than one tag type is present in the taglisting for a file,
+    " then the tag type name needs to be present
+    let add_ttype_name = -1
+    let i = 1
+    while i <= s:tlist_{ftype}_count && add_ttype_name < 1
+        let ttype = s:tlist_{ftype}_{i}_name
+        if s:tlist_{fidx}_{ttype}_count
+            let add_ttype_name = add_ttype_name + 1
         endif
-        if s:tlist_part_of_winmanager
-            call WinManagerResumeAUs()
+        let i = i + 1
+    endwhile
+
+    " Process the tags by the tag type and get the menu command
+    let i = 1
+    while i <= s:tlist_{ftype}_count
+        let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i)
+        if mcmd != ''
+            let cmd = cmd . mcmd
         endif
+
+        let i = i + 1
+    endwhile
+
+    " Cache the menu command for reuse
+    let s:tlist_{fidx}_menu_cmd = cmd
+
+    " Update the menu
+    call s:Tlist_Menu_File_Refresh(fidx)
+endfunction
+
+" Tlist_Menu_Remove_File
+" Remove the tags displayed in the tags menu
+function! s:Tlist_Menu_Remove_File()
+    if !has('gui_running') || s:tlist_menu_empty
         return
     endif
 
-    " Extract the tag type
-    let ttype = s:Tlist_Extract_Tagtype(tag_txt)
-
-    " Extract the tag offset
-    let offset = strpart(tag_txt, 0, stridx(tag_txt, ':')) + 0
+    call s:Tlist_Log_Msg('Removing the tags menu for a file')
 
-    " Compute the line number
-    let lnum = b:tlist_{b:tlist_ftype}_{ttype}_start + offset
+    " Cleanup the Tags menu
+    silent! unmenu T&ags
+    if &mousemodel =~ 'popup'
+        silent! unmenu PopUp.T&ags
+    endif
 
-    " Goto the line containing the tag
-    exe lnum
+    " Add a dummy menu item to retain teared off menu
+    noremenu T&ags.Dummy l
 
-    " Open the fold
-    if has('folding')
-        silent! .foldopen
+    silent! unmenu! T&ags
+    if &mousemodel =~ 'popup'
+        silent! unmenu! PopUp.T&ags
     endif
 
-    " Call winline() to make sure the target line is visible in the taglist
-    " window. This is a side effect of calling winline(). Don't know of a
-    " better way to achieve this.
-    call winline()
+    call s:Tlist_Menu_Add_Base_Menu()
 
-    " Highlight the tag name
-    call s:Tlist_Highlight_Tagline()
+    " Remove the dummy menu item
+    unmenu T&ags.Dummy
 
-    " Go back to the original window
-    if !in_taglist_window
-        let s:Tlist_Skip_Refresh = 1
-        exe org_winnr . 'wincmd w'
-        let s:Tlist_Skip_Refresh = 0
-    endif
+    let s:tlist_menu_empty = 1
+endfunction
 
-    if s:tlist_part_of_winmanager
-        call WinManagerResumeAUs()
+" Tlist_Menu_Refresh
+" Refresh the taglist menu
+function! s:Tlist_Menu_Refresh()
+    call s:Tlist_Log_Msg('Refreshing the tags menu')
+    let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+    if fidx != -1
+        " Invalidate the cached menu command
+        let s:tlist_{fidx}_menu_cmd = ''
     endif
 
-    return
+    " Update the taglist, menu and window
+    call s:Tlist_Update_Current_File()
 endfunction
 
-" Tlist_Get_Tag_Prototype_By_Line
-function! s:Tlist_Get_Tag_Prototype_By_Line(linenum)
-    " Make sure the current file has a name
-    let filename = fnamemodify(bufname("%"), ':p')
-    if filename == ''
-        return ""
+" Tlist_Menu_Jump_To_Tag
+" Jump to the selected tag
+function! s:Tlist_Menu_Jump_To_Tag(tidx)
+    let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
+    if fidx == -1
+        return
     endif
 
-    let linenr = a:linenum
-    if linenr == ""
-        " Default is the current line
-        let linenr = line('.')
+    let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx)
+    if tagpat == ''
+        return
     endif
 
-    " If there are no tags for this file, then no need to proceed further
-    if !exists("b:tlist_tag_count") || b:tlist_tag_count == 0
-        return ""
-    endif
+    " Add the current cursor position to the jump list, so that user can
+    " jump back using the ' and ` marks.
+    mark '
 
-    " Get the tag text using the line number
-    let tag_txt = s:Tlist_Locate_Tag_Text(b:tlist_sort_type, linenr)
-    if tag_txt == ""
-        return ""
+    silent call search(tagpat, 'w')
+
+    " Bring the line to the middle of the window
+    normal! z.
+
+    " If the line is inside a fold, open the fold
+    if foldclosed('.') != -1
+        .foldopen
     endif
+endfunction
+
+" Tlist_Menu_Init
+" Initialize the taglist menu
+function! s:Tlist_Menu_Init()
+    call s:Tlist_Menu_Add_Base_Menu()
+
+    " Automatically add the tags defined in the current file to the menu
+    augroup TagListMenuCmds
+        autocmd!
+
+        if !g:Tlist_Process_File_Always
+            autocmd BufEnter * call s:Tlist_Refresh()
+        endif
+        autocmd BufLeave * call s:Tlist_Menu_Remove_File()
+    augroup end
 
-    " Extract the tag search pattern and return it
-    return s:Tlist_Extract_Tag_Prototype(tag_txt)
+    call s:Tlist_Menu_Update_File(0)
 endfunction
 
-" Define tag listing autocommand to automatically open the taglist window on
-" Vim startup
-if g:Tlist_Auto_Open
-    autocmd VimEnter * nested Tlist
-endif
+" Tlist_Vim_Session_Load
+" Initialize the taglist window/buffer, which is created when loading
+" a Vim session file.
+function! s:Tlist_Vim_Session_Load()
+    call s:Tlist_Log_Msg('Tlist_Vim_Session_Load')
 
-" Define the 'Tlist' and 'TlistSync' user commands to open/close taglist
-" window
-command! -nargs=0 Tlist call s:Tlist_Toggle_Window(bufnr('%'))
-command! -nargs=0 TlistSync call s:Tlist_Highlight_Tag(bufnr('%'), line('.'))
-command! -nargs=? TlistShowPrototype echo s:Tlist_Get_Tag_Prototype_By_Line(<q-args>)
+    " Initialize the taglist window
+    call s:Tlist_Window_Init()
+
+    " Refresh the taglist window
+    call s:Tlist_Window_Refresh()
+endfunction
+
+" Tlist_Set_App
+" Set the name of the external plugin/application to which taglist
+" belongs.
+" Taglist plugin is part of another plugin like cream or winmanager.
+function! Tlist_Set_App(name)
+    if a:name == ""
+        return
+    endif
+
+    let s:tlist_app_name = a:name
+endfunction
 
 " Winmanager integration
 
 " Initialization required for integration with winmanager
 function! TagList_Start()
-    let s:tlist_part_of_winmanager = 1
-
+    " If current buffer is not taglist buffer, then don't proceed
     if bufname('%') != '__Tag_List__'
         return
     endif
 
-    let bufnum = WinManagerGetLastEditedFile()
+    call Tlist_Set_App('winmanager')
 
-    " If the tags for the buffer is already listed, then no need to do
-    " anything
-    if exists('b:tlist_bufnum') && bufnum == b:tlist_bufnum
-        return
+    " Get the current filename from the winmanager plugin
+    let bufnum = WinManagerGetLastEditedFile()
+    if bufnum != -1
+        let filename = fnamemodify(bufname(bufnum), ':p')
+        let ftype = s:Tlist_Get_Buffer_Filetype(bufnum)
     endif
 
-    call s:Tlist_Init_Window(bufnum)
+    " Initialize the taglist window, if it is not already initialized
+    if !exists('s:tlist_window_initialized') || !s:tlist_window_initialized
+        call s:Tlist_Window_Init()
+        call s:Tlist_Window_Refresh()
+        let s:tlist_window_initialized = 1
+    endif
 
-    " Open the taglist window
-    call s:Tlist_Explore_File(bufnum)
+    " Update the taglist window
+    if bufnum != -1
+        if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update
+            call s:Tlist_Window_Refresh_File(filename, ftype)
+        endif
+    endif
 endfunction
 
 function! TagList_IsValid()
@@ -1885,3 +4539,8 @@ endfunction
 function! TagList_WrapUp()
     return 0
 endfunction
+
+" restore 'cpo'
+let &cpo = s:cpo_save
+unlet s:cpo_save
+