1 " File: taglist-plus.vim
2 " Authors: Jezreel Ng (jezreel AT gmail DOT com)
3 " Yegappan Lakshmanan (yegappan AT yahoo DOT com)
5 "Last Modified: March 16, 2011
6 "Copyright: Copyright (C) 2011 Jezeel Ng
7 " Copyright (C) 2002-2007 Yegappan Lakshmanan
8 " Permission is hereby granted to use and distribute this code,
9 " with or without modifications, provided that this copyright
10 " notice is copied with it. Like anything else that's free,
11 " taglist.vim is provided *as is* and comes with no warranty of any
12 " kind, either expressed or implied. In no event will the copyright
13 " holder be liable for any damamges resulting from the use of this
16 " For more information about using this plugin, after installing the
17 " taglist plugin, use the ":help taglist" command.
21 " 1. Download the taglist.zip file and unzip the files to the $HOME/.vim
22 " or the $HOME/vimfiles or the $VIM/vimfiles directory. This should
23 " unzip the following two files (the directory structure should be
26 " plugin/taglist-plus.vim - main taglist plugin file
27 " doc/taglist-plus.txt - documentation (help) file
29 " Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath'
30 " Vim help pages for more details about installing Vim plugins.
31 " 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or
32 " $VIM/vimfiles/doc directory, start Vim and run the ":helptags ."
33 " command to process the taglist help file.
34 " 3. If the exuberant ctags utility is not present in your PATH, then set the
35 " Tlist_Ctags_Cmd variable to point to the location of the exuberant ctags
36 " utility (not to the directory) in the .vimrc file.
37 " 4. If you are running a terminal/console version of Vim and the
38 " terminal doesn't support changing the window width then set the
39 " 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file.
41 " 6. You can now use the ":TlistToggle" command to open/close the taglist
42 " window. You can use the ":help taglist" command to get more
43 " information about using the taglist plugin.
45 " ****************** Do not modify after this line ************************
47 " Line continuation used here
51 if !exists('loaded_taglist')
52 " First time loading the taglist plugin
54 " To speed up the loading of Vim, the taglist plugin uses autoload
55 " mechanism to load the taglist functions.
56 " Only define the configuration variables, user commands and some
57 " auto-commands and finish sourcing the file
59 " The taglist plugin requires the built-in Vim system() function. If this
60 " function is not available, then don't load the plugin.
62 echomsg 'Taglist: Vim system() built-in function is not available. ' .
63 \ 'Plugin is not loaded.'
64 let loaded_taglist = 'no'
69 " Location of the exuberant ctags tool
70 if !exists('Tlist_Ctags_Cmd')
71 if executable('exuberant-ctags')
72 " On Debian Linux, exuberant ctags is installed
74 let Tlist_Ctags_Cmd = 'exuberant-ctags'
75 elseif executable('exctags')
76 " On Free-BSD, exuberant ctags is installed as exctags
77 let Tlist_Ctags_Cmd = 'exctags'
78 elseif executable('ctags')
79 let Tlist_Ctags_Cmd = 'ctags'
80 elseif executable('ctags.exe')
81 let Tlist_Ctags_Cmd = 'ctags.exe'
82 elseif executable('tags')
83 let Tlist_Ctags_Cmd = 'tags'
85 echomsg 'Taglist: Exuberant ctags (http://ctags.sf.net) ' .
86 \ 'not found in PATH. Plugin is not loaded.'
87 " Skip loading the plugin
88 let loaded_taglist = 'no'
95 " Automatically open the taglist window on Vim startup
96 if !exists('Tlist_Auto_Open')
97 let Tlist_Auto_Open = 0
100 " When the taglist window is toggle opened, move the cursor to the
102 if !exists('Tlist_GainFocus_On_ToggleOpen')
103 let Tlist_GainFocus_On_ToggleOpen = 0
106 " Process files even when the taglist window is not open
107 if !exists('Tlist_Process_File_Always')
108 let Tlist_Process_File_Always = 0
111 if !exists('Tlist_Show_Menu')
112 let Tlist_Show_Menu = 0
115 " Tag listing sort type - 'name' or 'order'
116 if !exists('Tlist_Sort_Type')
117 let Tlist_Sort_Type = 'order'
120 " Tag listing window split (horizontal/vertical) control
121 if !exists('Tlist_Use_Horiz_Window')
122 let Tlist_Use_Horiz_Window = 0
125 " Open the vertically split taglist window on the left or on the right
126 " side. This setting is relevant only if Tlist_Use_Horiz_Window is set to
127 " zero (i.e. only for vertically split windows)
128 if !exists('Tlist_Use_Right_Window')
129 let Tlist_Use_Right_Window = 0
132 " Increase Vim window width to display vertically split taglist window.
133 " For MS-Windows version of Vim running in a MS-DOS window, this must be
134 " set to 0 otherwise the system may hang due to a Vim limitation.
135 if !exists('Tlist_Inc_Winwidth')
136 if (has('win16') || has('win95')) && !has('gui_running')
137 let Tlist_Inc_Winwidth = 0
139 let Tlist_Inc_Winwidth = 1
143 " Vertically split taglist window width setting
144 if !exists('Tlist_WinWidth')
145 let Tlist_WinWidth = 30
147 elseif Tlist_WinWidth == 'auto'
148 let Tlist_WinWidth = 30
152 " Horizontally split taglist window height setting
153 if !exists('Tlist_WinHeight')
154 let Tlist_WinHeight = 10
157 " Display tag prototypes or tag names in the taglist window
158 if !exists('Tlist_Display_Prototype')
159 let Tlist_Display_Prototype = 0
162 " Display tag scopes in the taglist window
163 if !exists('Tlist_Display_Tag_Scope')
164 let Tlist_Display_Tag_Scope = 1
167 " Use single left mouse click to jump to a tag. By default this is disabled.
168 " Only double click using the mouse will be processed.
169 if !exists('Tlist_Use_SingleClick')
170 let Tlist_Use_SingleClick = 0
173 " Control whether additional help is displayed as part of the taglist or
174 " not. Also, controls whether empty lines are used to separate the tag
176 if !exists('Tlist_Compact_Format')
177 let Tlist_Compact_Format = 0
180 " Exit Vim if only the taglist window is currently open. By default, this is
182 if !exists('Tlist_Exit_OnlyWindow')
183 let Tlist_Exit_OnlyWindow = 0
186 " Automatically close the folds for the non-active files in the taglist
188 if !exists('Tlist_File_Fold_Auto_Close')
189 let Tlist_File_Fold_Auto_Close = 0
192 " Close the taglist window when a tag is selected
193 if !exists('Tlist_Close_On_Select')
194 let Tlist_Close_On_Select = 0
197 " Automatically update the taglist window to display tags for newly
199 if !exists('Tlist_Auto_Update')
200 let Tlist_Auto_Update = 1
203 " Automatically highlight the current tag
204 if !exists('Tlist_Auto_Highlight_Tag')
205 let Tlist_Auto_Highlight_Tag = 1
208 " Automatically highlight the current tag on entering a buffer
209 if !exists('Tlist_Highlight_Tag_On_BufEnter')
210 let Tlist_Highlight_Tag_On_BufEnter = 1
213 " Enable fold column to display the folding for the tag tree
214 if !exists('Tlist_Enable_Fold_Column')
215 let Tlist_Enable_Fold_Column = 1
218 " Display the tags for only one file in the taglist window
219 if !exists('Tlist_Show_One_File')
220 let Tlist_Show_One_File = 0
223 if !exists('Tlist_Max_Submenu_Items')
224 let Tlist_Max_Submenu_Items = 20
227 if !exists('Tlist_Max_Tag_Length')
228 let Tlist_Max_Tag_Length = 10
231 " Do not change the name of the taglist title variable. The winmanager
232 " plugin relies on this name to determine the title for the taglist
234 let TagList_title = "__Tag_List__"
236 " Taglist debug messages
239 " Define the taglist autocommand to automatically open the taglist window
242 autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open()
245 " Refresh the taglist
246 if g:Tlist_Process_File_Always
247 autocmd BufEnter * call s:Tlist_Refresh()
251 autocmd GUIEnter * call s:Tlist_Menu_Init()
254 " When the taglist buffer is created when loading a Vim session file,
255 " the taglist buffer needs to be initialized. The BufFilePost event
256 " is used to handle this case.
257 autocmd BufFilePost __Tag_List__ call s:Tlist_Vim_Session_Load()
259 " Define the user commands to manage the taglist window
260 command! -nargs=0 -bar TlistToggle call s:Tlist_Window_Toggle()
261 command! -nargs=0 -bar TlistOpen call s:Tlist_Window_Open()
262 " For backwards compatiblity define the Tlist command
263 command! -nargs=0 -bar Tlist TlistToggle
264 command! -nargs=+ -complete=file TlistAddFiles
265 \ call s:Tlist_Add_Files(<f-args>)
266 command! -nargs=+ -complete=dir TlistAddFilesRecursive
267 \ call s:Tlist_Add_Files_Recursive(<f-args>)
268 command! -nargs=0 -bar TlistClose call s:Tlist_Window_Close()
269 command! -nargs=0 -bar TlistUpdate call s:Tlist_Update_Current_File()
270 command! -nargs=0 -bar TlistHighlightTag call s:Tlist_Window_Highlight_Tag(
271 \ fnamemodify(bufname('%'), ':p'), line('.'), 2, 1)
272 " For backwards compatiblity define the TlistSync command
273 command! -nargs=0 -bar TlistSync TlistHighlightTag
274 command! -nargs=* -complete=buffer TlistShowPrototype
275 \ echo Tlist_Get_Tag_Prototype_By_Line(<f-args>)
276 command! -nargs=* -complete=buffer TlistShowTag
277 \ echo Tlist_Get_Tagname_By_Line(<f-args>)
278 command! -nargs=* -complete=file TlistSessionLoad
279 \ call s:Tlist_Session_Load(<q-args>)
280 command! -nargs=* -complete=file TlistSessionSave
281 \ call s:Tlist_Session_Save(<q-args>)
282 command! -bar TlistLock let Tlist_Auto_Update=0
283 command! -bar TlistUnlock let Tlist_Auto_Update=1
285 " Commands for enabling/disabling debug and to display debug messages
286 command! -nargs=? -complete=file -bar TlistDebug
287 \ call s:Tlist_Debug_Enable(<q-args>)
288 command! -nargs=0 -bar TlistUndebug call s:Tlist_Debug_Disable()
289 command! -nargs=0 -bar TlistMessages call s:Tlist_Debug_Show()
291 " Define autocommands to autoload the taglist plugin when needed.
293 " Trick to get the current script ID
295 let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$',
299 exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' .
300 \ escape(expand('<sfile>'), ' ')
301 exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' .
302 \ escape(expand('<sfile>'), ' ')
303 exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' .
304 \ escape(expand('<sfile>'), ' ')
305 exe 'autocmd FuncUndefined Tlist_* source ' .
306 \ escape(expand('<sfile>'), ' ')
307 exe 'autocmd FuncUndefined TagList_* source ' .
308 \ escape(expand('<sfile>'), ' ')
310 let loaded_taglist = 'fast_load_done'
312 if g:Tlist_Show_Menu && has('gui_running')
313 call s:Tlist_Menu_Init()
317 let &cpo = s:cpo_save
321 if !exists('s:tlist_sid')
322 " Two or more versions of taglist plugin are installed. Don't
323 " load this version of the plugin.
329 if loaded_taglist != 'fast_load_done'
331 let &cpo = s:cpo_save
335 " Taglist plugin functionality is available
336 let loaded_taglist = 'available'
338 "------------------- end of user configurable options --------------------
340 " Default language specific settings for supported file types and tag types
342 " Variable name format:
344 " s:tlist_def_{vim_ftype}_settings
346 " vim_ftype - Filetype detected by Vim
350 " <ctags_ftype>;<flag>:<name>;<flag>:<name>;...
352 " ctags_ftype - File type supported by exuberant ctags
353 " flag - Flag supported by exuberant ctags to generate a tag type
354 " name - Name of the tag type used in the taglist window to display the
359 let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type'
362 let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable'
365 let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable'
368 let s:tlist_def_awk_settings = 'awk;f:function'
371 let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern'
374 let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' .
375 \ 'v:variable;f:function'
378 let s:tlist_def_cpp_settings = 'c++;n:namespace;v:variable;d:macro;t:typedef;' .
379 \ 'c:class;g:enum;s:struct;u:union;f:function'
382 let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' .
383 \ 'E:event;g:enum;s:struct;i:interface;' .
384 \ 'p:properties;m:method'
387 let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
388 \ 'P:program;s:section'
391 let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature'
394 let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function'
396 " expect (same as tcl) language
397 let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure'
400 let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' .
401 \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' .
402 \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine'
405 let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function'
408 let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
411 " javascript language
412 let s:tlist_def_javascript_settings = 'javascript;f:function;v:variable'
413 if !exists('Tlist_javascript_Ctags_Cmd') && executable('jsctags')
414 let Tlist_javascript_Ctags_Cmd = 'jsctags'
416 let Tlist_javascript_Ctags_Allowed_Flags = ['-f', '--sort']
419 let s:tlist_def_lisp_settings = 'lisp;f:function'
422 let s:tlist_def_lua_settings = 'lua;f:function'
425 let s:tlist_def_make_settings = 'make;m:macro'
428 let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure'
431 let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine'
434 let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function'
437 let s:tlist_def_python_settings = 'python;c:class;m:member;f:function'
440 let s:tlist_def_rexx_settings = 'rexx;s:subroutine'
443 let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' .
444 \ 'm:singleton method'
447 let s:tlist_def_scheme_settings = 'scheme;s:set;f:function'
450 let s:tlist_def_sh_settings = 'sh;f:function'
453 let s:tlist_def_csh_settings = 'sh;f:function'
456 let s:tlist_def_zsh_settings = 'sh;f:function'
459 let s:tlist_def_slang_settings = 'slang;n:namespace;f:function'
462 let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' .
463 \ 'r:structure;t:type;v:value;f:function'
466 let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' .
467 \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure'
470 let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure'
473 let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' .
474 \ 'f:function;g:enum;m:member;p:program;' .
475 \ 'P:prototype;t:task;T:typedef;v:variable;' .
479 let s:tlist_def_verilog_settings = 'verilog;m:module;c:constant;P:parameter;' .
480 \ 'e:event;r:register;t:task;w:write;p:port;v:variable;f:function'
483 let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function'
486 let s:tlist_def_yacc_settings = 'yacc;l:label'
488 "------------------- end of language specific options --------------------
490 " Vim window size is changed by the taglist plugin or not
491 let s:tlist_winsize_chgd = -1
492 " Taglist window is maximized or not
493 let s:tlist_win_maximized = 0
494 " Name of files in the taglist
495 let s:tlist_file_names=''
496 " Number of files in the taglist
497 let s:tlist_file_count = 0
498 " Number of filetypes supported by taglist
499 let s:tlist_ftype_count = 0
500 " Is taglist part of other plugins like winmanager or cream?
501 let s:tlist_app_name = "none"
502 " Are we displaying brief help text
503 let s:tlist_brief_help = 1
504 " List of files removed on user request
505 let s:tlist_removed_flist = ""
506 " Index of current file displayed in the taglist window
507 let s:tlist_cur_file_idx = -1
508 " Taglist menu is empty or not
509 let s:tlist_menu_empty = 1
511 " An autocommand is used to refresh the taglist window when entering any
512 " buffer. We don't want to refresh the taglist window if we are entering the
513 " file window from one of the taglist functions. The 'Tlist_Skip_Refresh'
514 " variable is used to skip the refresh of the taglist window and is set
515 " and cleared appropriately.
516 let s:Tlist_Skip_Refresh = 0
518 " Tlist_Window_Display_Help()
519 function! s:Tlist_Window_Display_Help()
520 if s:tlist_app_name == "winmanager"
521 " To handle a bug in the winmanager plugin, add a space at the
523 call setline('$', ' ')
526 if s:tlist_brief_help
528 call append(0, '" Press <F1> to display help text')
530 " Add the extensive help
531 call append(0, '" <enter> : Jump to tag definition')
532 call append(1, '" o : Jump to tag definition in new window')
533 call append(2, '" p : Preview the tag definition')
534 call append(3, '" <space> : Display tag prototype')
535 call append(4, '" u : Update tag list')
536 call append(5, '" s : Select sort field')
537 call append(6, '" d : Remove file from taglist')
538 call append(7, '" x : Zoom-out/Zoom-in taglist window')
539 call append(8, '" m : Toggle display of more tag info')
540 call append(9, '" + : Open a fold')
541 call append(10, '" - : Close a fold')
542 call append(11, '" * : Open all folds')
543 call append(12, '" = : Close all folds')
544 call append(13, '" [[ : Move to the start of previous file')
545 call append(14, '" ]] : Move to the start of next file')
546 call append(15, '" q : Close the taglist window')
547 call append(16, '" <F1> : Remove help text')
551 " Tlist_Window_Toggle_Help_Text()
552 " Toggle taglist plugin help text between the full version and the brief
554 function! s:Tlist_Window_Toggle_Help_Text()
555 if g:Tlist_Compact_Format
556 " In compact display mode, do not display help
560 " Include the empty line displayed after the help text
561 let brief_help_size = 1
562 let full_help_size = 16
566 " Set report option to a huge value to prevent informational messages
567 " while deleting the lines
568 let old_report = &report
571 " Remove the currently highlighted tag. Otherwise, the help text
572 " might be highlighted by mistake
575 " Toggle between brief and full help text
576 if s:tlist_brief_help
577 let s:tlist_brief_help = 0
579 " Remove the previous help
580 exe '1,' . brief_help_size . ' delete _'
582 " Adjust the start/end line numbers for the files
583 call s:Tlist_Window_Update_Line_Offsets(0, 1, full_help_size - brief_help_size)
585 let s:tlist_brief_help = 1
587 " Remove the previous help
588 exe '1,' . full_help_size . ' delete _'
590 " Adjust the start/end line numbers for the files
591 call s:Tlist_Window_Update_Line_Offsets(0, 0, full_help_size - brief_help_size)
594 call s:Tlist_Window_Display_Help()
596 " Restore the report option
597 let &report = old_report
599 setlocal nomodifiable
602 " Taglist debug support
603 let s:tlist_debug = 0
605 " File for storing the debug messages
606 let s:tlist_debug_file = ''
609 " Enable logging of taglist debug messages.
610 function! s:Tlist_Debug_Enable(...)
611 let s:tlist_debug = 1
613 " Check whether a valid file name is supplied.
615 let s:tlist_debug_file = fnamemodify(a:1, ':p')
618 exe 'redir! > ' . s:tlist_debug_file
621 " Check whether the log file is present/created
622 if !filewritable(s:tlist_debug_file)
623 call s:Tlist_Warning_Msg('Taglist: Unable to create log file '
624 \ . s:tlist_debug_file)
625 let s:tlist_debug_file = ''
630 " Tlist_Debug_Disable
631 " Disable logging of taglist debug messages.
632 function! s:Tlist_Debug_Disable(...)
633 let s:tlist_debug = 0
634 let s:tlist_debug_file = ''
638 " Display the taglist debug messages in a new window
639 function! s:Tlist_Debug_Show()
641 call s:Tlist_Warning_Msg('Taglist: No debug messages')
645 " Open a new window to display the taglist debug messages
646 new taglist_debug.txt
647 " Delete all the lines (if the buffer already exists)
650 silent! put =s:tlist_msg
651 " Move the cursor to the first line
656 " Log the supplied debug message along with the time
657 function! s:Tlist_Log_Msg(msg)
659 if s:tlist_debug_file != ''
660 exe 'redir >> ' . s:tlist_debug_file
661 silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n"
664 " Log the message into a variable
665 " Retain only the last 3000 characters
666 let len = strlen(s:tlist_msg)
668 let s:tlist_msg = strpart(s:tlist_msg, len - 3000)
670 let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' .
676 " Tlist_Warning_Msg()
677 " Display a message using WarningMsg highlight group
678 function! s:Tlist_Warning_Msg(msg)
684 " Last returned file index for file name lookup.
685 " Used to speed up file lookup
686 let s:tlist_file_name_idx_cache = -1
688 " Tlist_Get_File_Index()
689 " Return the index of the specified filename
690 function! s:Tlist_Get_File_Index(fname)
691 if s:tlist_file_count == 0 || a:fname == ''
695 " If the new filename is same as the last accessed filename, then
697 if s:tlist_file_name_idx_cache != -1 &&
698 \ s:tlist_file_name_idx_cache < s:tlist_file_count
699 if s:tlist_{s:tlist_file_name_idx_cache}_filename == a:fname
700 " Same as the last accessed file
701 return s:tlist_file_name_idx_cache
705 " First, check whether the filename is present
706 let s_fname = a:fname . "\n"
707 let i = stridx(s:tlist_file_names, s_fname)
709 let s:tlist_file_name_idx_cache = -1
713 " Second, compute the file name index
714 let nl_txt = substitute(strpart(s:tlist_file_names, 0, i), "[^\n]", '', 'g')
715 let s:tlist_file_name_idx_cache = strlen(nl_txt)
716 return s:tlist_file_name_idx_cache
719 " Last returned file index for line number lookup.
720 " Used to speed up file lookup
721 let s:tlist_file_lnum_idx_cache = -1
723 " Tlist_Window_Get_File_Index_By_Linenum()
724 " Return the index of the filename present in the specified line number
725 " Line number refers to the line number in the taglist window
726 function! s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
727 call s:Tlist_Log_Msg('Tlist_Window_Get_File_Index_By_Linenum (' . a:lnum . ')')
729 " First try to see whether the new line number is within the range
730 " of the last returned file
731 if s:tlist_file_lnum_idx_cache != -1 &&
732 \ s:tlist_file_lnum_idx_cache < s:tlist_file_count
733 if a:lnum >= s:tlist_{s:tlist_file_lnum_idx_cache}_start &&
734 \ a:lnum <= s:tlist_{s:tlist_file_lnum_idx_cache}_end
735 return s:tlist_file_lnum_idx_cache
741 if g:Tlist_Show_One_File
742 " Displaying only one file in the taglist window. Check whether
743 " the line is within the tags displayed for that file
744 if s:tlist_cur_file_idx != -1
745 if a:lnum >= s:tlist_{s:tlist_cur_file_idx}_start
746 \ && a:lnum <= s:tlist_{s:tlist_cur_file_idx}_end
747 let fidx = s:tlist_cur_file_idx
752 " Do a binary search in the taglist
754 let right = s:tlist_file_count - 1
757 let mid = (left + right) / 2
759 if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end
760 let s:tlist_file_lnum_idx_cache = mid
764 if a:lnum < s:tlist_{mid}_start
771 if left >= 0 && left < s:tlist_file_count
772 \ && a:lnum >= s:tlist_{left}_start
773 \ && a:lnum <= s:tlist_{left}_end
778 let s:tlist_file_lnum_idx_cache = fidx
783 " Tlist_Exe_Cmd_No_Acmds
784 " Execute the specified Ex command after disabling autocommands
785 function! s:Tlist_Exe_Cmd_No_Acmds(cmd)
786 let old_eventignore = &eventignore
789 let &eventignore = old_eventignore
793 " Check whether tag listing is supported for the specified file
794 function! s:Tlist_Skip_File(filename, ftype)
795 " Skip buffers with no names and buffers with filetype not set
796 if a:filename == '' || a:ftype == ''
800 " Skip files which are not supported by exuberant ctags
801 " First check whether default settings for this filetype are available.
802 " If it is not available, then check whether user specified settings are
803 " available. If both are not available, then don't list the tags for this
805 let var = 's:tlist_def_' . a:ftype . '_settings'
807 let var = 'g:tlist_' . a:ftype . '_settings'
813 " Skip files which are not readable or files which are not yet stored
815 if !filereadable(a:filename)
822 " Tlist_User_Removed_File
823 " Returns 1 if a file is removed by a user from the taglist
824 function! s:Tlist_User_Removed_File(filename)
825 return stridx(s:tlist_removed_flist, a:filename . "\n") != -1
828 " Tlist_Update_Remove_List
829 " Update the list of user removed files from the taglist
830 " add == 1, add the file to the removed list
831 " add == 0, delete the file from the removed list
832 function! s:Tlist_Update_Remove_List(filename, add)
834 let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n"
836 let idx = stridx(s:tlist_removed_flist, a:filename . "\n")
837 let text_before = strpart(s:tlist_removed_flist, 0, idx)
838 let rem_text = strpart(s:tlist_removed_flist, idx)
839 let next_idx = stridx(rem_text, "\n")
840 let text_after = strpart(rem_text, next_idx + 1)
842 let s:tlist_removed_flist = text_before . text_after
846 " Tlist_FileType_Init
847 " Initialize the ctags arguments and tag variable for the specified
849 function! s:Tlist_FileType_Init(ftype)
850 call s:Tlist_Log_Msg('Tlist_FileType_Init (' . a:ftype . ')')
851 " If the user didn't specify any settings, then use the default
852 " ctags args. Otherwise, use the settings specified by the user
853 let var = 'g:tlist_' . a:ftype . '_settings'
855 " User specified ctags arguments
856 let settings = {var} . ';'
858 " Default ctags arguments
859 let var = 's:tlist_def_' . a:ftype . '_settings'
861 " No default settings for this file type. This filetype is
865 let settings = s:tlist_def_{a:ftype}_settings . ';'
868 let msg = 'Taglist: Invalid ctags option setting - ' . settings
870 " Format of the option that specifies the filetype and ctags arugments:
872 " <language_name>;flag1:name1;flag2:name2;flag3:name3
875 " Extract the file type to pass to ctags. This may be different from the
876 " file type detected by Vim
877 let pos = stridx(settings, ';')
879 call s:Tlist_Warning_Msg(msg)
882 let ctags_ftype = strpart(settings, 0, pos)
884 call s:Tlist_Warning_Msg(msg)
887 " Make sure a valid filetype is supplied. If the user didn't specify a
888 " valid filetype, then the ctags option settings may be treated as the
890 if ctags_ftype =~ ':'
891 call s:Tlist_Warning_Msg(msg)
895 " Remove the file type from settings
896 let settings = strpart(settings, pos + 1)
898 call s:Tlist_Warning_Msg(msg)
902 " Process all the specified ctags flags. The format is
903 " flag1:name1;flag2:name2;flag3:name3
908 let pos = stridx(settings, ':')
910 call s:Tlist_Warning_Msg(msg)
913 let flag = strpart(settings, 0, pos)
915 call s:Tlist_Warning_Msg(msg)
918 " Remove the flag from settings
919 let settings = strpart(settings, pos + 1)
921 " Extract the tag type name
922 let pos = stridx(settings, ';')
924 call s:Tlist_Warning_Msg(msg)
927 let name = strpart(settings, 0, pos)
929 call s:Tlist_Warning_Msg(msg)
932 let settings = strpart(settings, pos + 1)
936 let s:tlist_{a:ftype}_{cnt}_name = flag
937 let s:tlist_{a:ftype}_{cnt}_fullname = name
938 let ctags_flags = ctags_flags . flag
941 let s:tlist_{a:ftype}_ctags_args = { '--language-force=': ctags_ftype,
942 \ '--'.ctags_ftype.'-types=': ctags_flags }
943 let s:tlist_{a:ftype}_count = cnt
944 let s:tlist_{a:ftype}_ctags_flags = ctags_flags
946 " Save the filetype name
947 let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype
948 let s:tlist_ftype_count = s:tlist_ftype_count + 1
953 " Tlist_Detect_Filetype
954 " Determine the filetype for the specified file using the filetypedetect
956 function! s:Tlist_Detect_Filetype(fname)
957 " Ignore the filetype autocommands
958 let old_eventignore = &eventignore
959 set eventignore=FileType
961 " Save the 'filetype', as this will be changed temporarily
962 let old_filetype = &filetype
964 " Run the filetypedetect group of autocommands to determine
966 exe 'doautocmd filetypedetect BufRead ' . a:fname
968 " Save the detected filetype
969 let ftype = &filetype
971 " Restore the previous state
972 let &filetype = old_filetype
973 let &eventignore = old_eventignore
978 " Tlist_Get_Buffer_Filetype
979 " Get the filetype for the specified buffer
980 function! s:Tlist_Get_Buffer_Filetype(bnum)
981 let buf_ft = getbufvar(a:bnum, '&filetype')
984 " For loaded buffers, the 'filetype' is already determined
988 " For unloaded buffers, if the 'filetype' option is set, return it
993 " Skip non-existent buffers
994 if !bufexists(a:bnum)
998 " For buffers whose filetype is not yet determined, try to determine
1000 let bname = bufname(a:bnum)
1002 return s:Tlist_Detect_Filetype(bname)
1005 " Tlist_Discard_TagInfo
1006 " Discard the stored tag information for a file
1007 function! s:Tlist_Discard_TagInfo(fidx)
1008 call s:Tlist_Log_Msg('Tlist_Discard_TagInfo (' .
1009 \ s:tlist_{a:fidx}_filename . ')')
1010 let ftype = s:tlist_{a:fidx}_filetype
1012 " Discard information about the tags defined in the file
1014 while i <= s:tlist_{a:fidx}_tag_count
1015 let fidx_i = 's:tlist_' . a:fidx . '_' . i
1017 unlet! {fidx_i}_tag_name
1018 unlet! {fidx_i}_tag_type
1019 unlet! {fidx_i}_ttype_idx
1020 unlet! {fidx_i}_tag_proto
1021 unlet! {fidx_i}_tag_searchpat
1022 unlet! {fidx_i}_tag_linenum
1026 let s:tlist_{a:fidx}_tag_count = 0
1028 " Discard information about tag type groups
1030 while i <= s:tlist_{ftype}_count
1031 let ttype = s:tlist_{ftype}_{i}_name
1032 if s:tlist_{a:fidx}_{ttype} != ''
1033 let fidx_ttype = 's:tlist_' . a:fidx . '_' . ttype
1034 let {fidx_ttype} = ''
1035 let {fidx_ttype}_offset = 0
1036 let cnt = {fidx_ttype}_count
1037 let {fidx_ttype}_count = 0
1040 unlet! {fidx_ttype}_{j}
1047 " Discard the stored menu command also
1048 let s:tlist_{a:fidx}_menu_cmd = ''
1051 " Tlist_Window_Update_Line_Offsets
1052 " Update the line offsets for tags for files starting from start_idx
1053 " and displayed in the taglist window by the specified offset
1054 function! s:Tlist_Window_Update_Line_Offsets(start_idx, increment, offset)
1057 while i < s:tlist_file_count
1058 if s:tlist_{i}_visible
1059 " Update the start/end line number only if the file is visible
1061 let s:tlist_{i}_start = s:tlist_{i}_start + a:offset
1062 let s:tlist_{i}_end = s:tlist_{i}_end + a:offset
1064 let s:tlist_{i}_start = s:tlist_{i}_start - a:offset
1065 let s:tlist_{i}_end = s:tlist_{i}_end - a:offset
1072 " Tlist_Discard_FileInfo
1073 " Discard the stored information for a file
1074 function! s:Tlist_Discard_FileInfo(fidx)
1075 call s:Tlist_Log_Msg('Tlist_Discard_FileInfo (' .
1076 \ s:tlist_{a:fidx}_filename . ')')
1077 call s:Tlist_Discard_TagInfo(a:fidx)
1079 let ftype = s:tlist_{a:fidx}_filetype
1082 while i <= s:tlist_{ftype}_count
1083 let ttype = s:tlist_{ftype}_{i}_name
1084 unlet! s:tlist_{a:fidx}_{ttype}
1085 unlet! s:tlist_{a:fidx}_{ttype}_offset
1086 unlet! s:tlist_{a:fidx}_{ttype}_count
1090 unlet! s:tlist_{a:fidx}_filename
1091 unlet! s:tlist_{a:fidx}_sort_type
1092 unlet! s:tlist_{a:fidx}_filetype
1093 unlet! s:tlist_{a:fidx}_mtime
1094 unlet! s:tlist_{a:fidx}_start
1095 unlet! s:tlist_{a:fidx}_end
1096 unlet! s:tlist_{a:fidx}_valid
1097 unlet! s:tlist_{a:fidx}_visible
1098 unlet! s:tlist_{a:fidx}_tag_count
1099 unlet! s:tlist_{a:fidx}_menu_cmd
1102 " Tlist_Window_Remove_File_From_Display
1103 " Remove the specified file from display
1104 function! s:Tlist_Window_Remove_File_From_Display(fidx)
1105 call s:Tlist_Log_Msg('Tlist_Window_Remove_File_From_Display (' .
1106 \ s:tlist_{a:fidx}_filename . ')')
1107 " If the file is not visible then no need to remove it
1108 if !s:tlist_{a:fidx}_visible
1112 " Remove the tags displayed for the specified file from the window
1113 let start = s:tlist_{a:fidx}_start
1114 " Include the empty line after the last line also
1115 if g:Tlist_Compact_Format
1116 let end = s:tlist_{a:fidx}_end
1118 let end = s:tlist_{a:fidx}_end + 1
1122 exe 'silent! ' . start . ',' . end . 'delete _'
1123 setlocal nomodifiable
1125 " Correct the start and end line offsets for all the files following
1126 " this file, as the tags for this file are removed
1127 call s:Tlist_Window_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1)
1131 " Remove the file under the cursor or the specified file index
1132 " user_request - User requested to remove the file from taglist
1133 function! s:Tlist_Remove_File(file_idx, user_request)
1134 let fidx = a:file_idx
1137 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
1142 call s:Tlist_Log_Msg('Tlist_Remove_File (' .
1143 \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')')
1145 let save_winnr = winnr()
1146 let winnum = bufwinnr(g:TagList_title)
1148 " Taglist window is open, remove the file from display
1150 if save_winnr != winnum
1151 let old_eventignore = &eventignore
1153 exe winnum . 'wincmd w'
1156 call s:Tlist_Window_Remove_File_From_Display(fidx)
1158 if save_winnr != winnum
1159 exe save_winnr . 'wincmd w'
1160 let &eventignore = old_eventignore
1164 let fname = s:tlist_{fidx}_filename
1167 " As the user requested to remove the file from taglist,
1168 " add it to the removed list
1169 call s:Tlist_Update_Remove_List(fname, 1)
1172 " Remove the file name from the taglist list of filenames
1173 let idx = stridx(s:tlist_file_names, fname . "\n")
1174 let text_before = strpart(s:tlist_file_names, 0, idx)
1175 let rem_text = strpart(s:tlist_file_names, idx)
1176 let next_idx = stridx(rem_text, "\n")
1177 let text_after = strpart(rem_text, next_idx + 1)
1178 let s:tlist_file_names = text_before . text_after
1180 call s:Tlist_Discard_FileInfo(fidx)
1182 " Shift all the file variables by one index
1185 while i < s:tlist_file_count
1188 let s:tlist_{j}_filename = s:tlist_{i}_filename
1189 let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type
1190 let s:tlist_{j}_filetype = s:tlist_{i}_filetype
1191 let s:tlist_{j}_mtime = s:tlist_{i}_mtime
1192 let s:tlist_{j}_start = s:tlist_{i}_start
1193 let s:tlist_{j}_end = s:tlist_{i}_end
1194 let s:tlist_{j}_valid = s:tlist_{i}_valid
1195 let s:tlist_{j}_visible = s:tlist_{i}_visible
1196 let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count
1197 let s:tlist_{j}_menu_cmd = s:tlist_{i}_menu_cmd
1200 while k <= s:tlist_{j}_tag_count
1201 let s:tlist_{j}_{k}_tag = s:tlist_{i}_{k}_tag
1202 let s:tlist_{j}_{k}_tag_name = s:tlist_{i}_{k}_tag_name
1203 let s:tlist_{j}_{k}_tag_type = s:Tlist_Get_Tag_Type_By_Tag(i, k)
1204 let s:tlist_{j}_{k}_ttype_idx = s:tlist_{i}_{k}_ttype_idx
1205 let s:tlist_{j}_{k}_tag_proto = s:Tlist_Get_Tag_Prototype(i, k)
1206 let s:tlist_{j}_{k}_tag_searchpat = s:Tlist_Get_Tag_SearchPat(i, k)
1207 let s:tlist_{j}_{k}_tag_linenum = s:Tlist_Get_Tag_Linenum(i, k)
1211 let ftype = s:tlist_{i}_filetype
1214 while k <= s:tlist_{ftype}_count
1215 let ttype = s:tlist_{ftype}_{k}_name
1216 let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype}
1217 let s:tlist_{j}_{ttype}_offset = s:tlist_{i}_{ttype}_offset
1218 let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count
1219 if s:tlist_{j}_{ttype} != ''
1221 while l <= s:tlist_{j}_{ttype}_count
1222 let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l}
1229 " As the file and tag information is copied to the new index,
1230 " discard the previous information
1231 call s:Tlist_Discard_FileInfo(i)
1236 " Reduce the number of files displayed
1237 let s:tlist_file_count = s:tlist_file_count - 1
1239 if g:Tlist_Show_One_File
1240 " If the tags for only one file is displayed and if we just
1241 " now removed that file, then invalidate the current file idx
1242 if s:tlist_cur_file_idx == fidx
1243 let s:tlist_cur_file_idx = -1
1248 " Tlist_Window_Goto_Window
1249 " Goto the taglist window
1250 function! s:Tlist_Window_Goto_Window()
1251 let winnum = bufwinnr(g:TagList_title)
1253 if winnr() != winnum
1254 call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
1259 " Tlist_Window_Create
1260 " Create a new taglist window. If it is already open, jump to it
1261 function! s:Tlist_Window_Create()
1262 call s:Tlist_Log_Msg('Tlist_Window_Create()')
1263 " If the window is open, jump to it
1264 let winnum = bufwinnr(g:TagList_title)
1266 " Jump to the existing window
1267 if winnr() != winnum
1268 exe winnum . 'wincmd w'
1273 " If used with winmanager don't open windows. Winmanager will handle
1274 " the window/buffer management
1275 if s:tlist_app_name == "winmanager"
1279 " Create a new window. If user prefers a horizontal window, then open
1280 " a horizontally split window. Otherwise open a vertically split
1282 if g:Tlist_Use_Horiz_Window
1283 " Open a horizontally split window
1284 let win_dir = 'botright'
1285 " Horizontal window height
1286 let win_size = g:Tlist_WinHeight
1288 if s:tlist_winsize_chgd == -1
1289 " Open a vertically split window. Increase the window size, if
1290 " needed, to accomodate the new window
1291 if g:Tlist_Inc_Winwidth &&
1292 \ &columns < (80 + g:Tlist_WinWidth)
1293 " Save the original window position
1294 let s:tlist_pre_winx = getwinposx()
1295 let s:tlist_pre_winy = getwinposy()
1297 " one extra column is needed to include the vertical split
1298 let &columns= &columns + g:Tlist_WinWidth + 1
1300 let s:tlist_winsize_chgd = 1
1302 let s:tlist_winsize_chgd = 0
1306 if g:Tlist_Use_Right_Window
1307 " Open the window at the rightmost place
1308 let win_dir = 'botright vertical'
1310 " Open the window at the leftmost place
1311 let win_dir = 'topleft vertical'
1313 let win_size = g:Tlist_WinWidth
1316 " If the tag listing temporary buffer already exists, then reuse it.
1317 " Otherwise create a new buffer
1318 let bufnum = bufnr(g:TagList_title)
1320 " Create a new buffer
1321 let wcmd = g:TagList_title
1323 " Edit the existing buffer
1324 let wcmd = '+buffer' . bufnum
1327 " Create the taglist window
1328 exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
1330 " Save the new window position
1331 let s:tlist_winx = getwinposx()
1332 let s:tlist_winy = getwinposy()
1334 " Initialize the taglist window
1335 call s:Tlist_Window_Init()
1339 " Zoom (maximize/minimize) the taglist window
1340 function! s:Tlist_Window_Zoom()
1341 if s:tlist_win_maximized
1342 " Restore the window back to the previous size
1343 if g:Tlist_Use_Horiz_Window
1344 exe 'resize ' . g:Tlist_WinHeight
1346 exe 'vert resize ' . g:Tlist_WinWidth
1348 let s:tlist_win_maximized = 0
1350 " Set the window size to the maximum possible without closing other
1352 if g:Tlist_Use_Horiz_Window
1357 let s:tlist_win_maximized = 1
1362 " When the mouse cursor is over a tag in the taglist window, display the
1363 " tag prototype (balloon)
1364 function! Tlist_Ballon_Expr()
1365 " Get the file index
1366 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(v:beval_lnum)
1371 " Get the tag output line for the current tag
1372 let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum)
1377 " Get the tag search pattern and display it
1378 return s:Tlist_Get_Tag_Prototype(fidx, tidx)
1381 " Tlist_Window_Check_Width
1382 " Check the width of the taglist window. For horizontally split windows, the
1383 " 'winfixheight' option is used to fix the height of the window. For
1384 " vertically split windows, Vim doesn't support the 'winfixwidth' option. So
1385 " need to handle window width changes from this function.
1386 function! s:Tlist_Window_Check_Width()
1387 let tlist_winnr = bufwinnr(g:TagList_title)
1388 if tlist_winnr == -1
1392 let width = winwidth(tlist_winnr)
1393 if width != g:Tlist_WinWidth
1394 call s:Tlist_Log_Msg("Tlist_Window_Check_Width: Changing window " .
1395 \ "width from " . width . " to " . g:Tlist_WinWidth)
1396 let save_winnr = winnr()
1397 if save_winnr != tlist_winnr
1398 call s:Tlist_Exe_Cmd_No_Acmds(tlist_winnr . 'wincmd w')
1400 exe 'vert resize ' . g:Tlist_WinWidth
1401 if save_winnr != tlist_winnr
1402 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
1407 " Tlist_Window_Exit_Only_Window
1408 " If the 'Tlist_Exit_OnlyWindow' option is set, then exit Vim if only the
1409 " taglist window is present.
1410 function! s:Tlist_Window_Exit_Only_Window()
1411 " Before quitting Vim, delete the taglist buffer so that
1412 " the '0 mark is correctly set to the previous buffer.
1414 if winbufnr(2) == -1
1419 if winbufnr(2) == -1
1420 if tabpagenr('$') == 1
1421 " Only one tag page is present
1425 " More than one tab page is present. Close only the current
1434 " Set the default options for the taglist window
1435 function! s:Tlist_Window_Init()
1436 call s:Tlist_Log_Msg('Tlist_Window_Init()')
1438 " The 'readonly' option should not be set for the taglist buffer.
1439 " If Vim is started as "view/gview" or if the ":view" command is
1440 " used, then the 'readonly' option is set for all the buffers.
1441 " Unset it for the taglist buffer
1444 " Set the taglist buffer filetype to taglist
1445 setlocal filetype=taglist
1447 " Define taglist window element highlighting
1448 syntax match TagListComment '^" .*'
1449 syntax match TagListFileName '^[^" ].*$'
1450 syntax match TagListTitle '^ \S.*$'
1451 syntax region TagListTagScope1 start='\[' end='\]' contains=TagListTagScope1 nextgroup=TagListTagScope2 skipwhite
1452 syntax region TagListTagScope2 start='\[' end='\]' contained contains=TaglistTagScope2
1454 " Define the highlighting only if colors are supported
1455 if has('gui_running') || &t_Co > 2
1456 " Colors to highlight various taglist window elements
1457 " If user defined highlighting group exists, then use them.
1458 " Otherwise, use default highlight groups.
1459 if hlexists('MyTagListTagName')
1460 highlight link TagListTagName MyTagListTagName
1462 highlight default link TagListTagName Search
1464 " Colors to highlight comments and titles
1465 if hlexists('MyTagListComment')
1466 highlight link TagListComment MyTagListComment
1468 highlight clear TagListComment
1469 highlight default link TagListComment Comment
1471 if hlexists('MyTagListTitle')
1472 highlight link TagListTitle MyTagListTitle
1474 highlight clear TagListTitle
1475 highlight default link TagListTitle Title
1477 if hlexists('MyTagListFileName')
1478 highlight link TagListFileName MyTagListFileName
1480 highlight clear TagListFileName
1481 highlight default TagListFileName guibg=Grey ctermbg=darkgray
1482 \ guifg=white ctermfg=white
1484 if hlexists('MyTagListTagScope')
1485 highlight link TagListTagScope1 MyTagListTagScope
1487 highlight clear TagListTagScope1
1488 highlight clear TagListTagScope2
1489 highlight default link TagListTagScope1 Identifier
1490 highlight default link TagListTagScope2 Keyword
1493 highlight default TagListTagName term=reverse cterm=reverse
1496 " Folding related settings
1498 setlocal foldminlines=0
1499 setlocal foldmethod=manual
1500 setlocal foldlevel=9999
1501 if g:Tlist_Enable_Fold_Column
1502 setlocal foldcolumn=3
1504 setlocal foldcolumn=0
1506 setlocal foldtext=v:folddashes.getline(v:foldstart)
1508 if s:tlist_app_name != "winmanager"
1509 " Mark buffer as scratch
1510 silent! setlocal buftype=nofile
1511 if s:tlist_app_name == "none"
1512 silent! setlocal bufhidden=delete
1514 silent! setlocal noswapfile
1515 " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted
1516 " buffers. So if the taglist buffer is unlisted, multiple taglist
1517 " windows will be opened. This bug is fixed in Vim 6.1 and above
1519 silent! setlocal nobuflisted
1523 silent! setlocal nowrap
1525 " If the 'number' option is set in the source window, it will affect the
1526 " taglist window. So forcefully disable 'number' option for the taglist
1528 silent! setlocal nonumber
1530 " Use fixed height when horizontally split window is used
1531 if g:Tlist_Use_Horiz_Window
1536 if !g:Tlist_Use_Horiz_Window && v:version >= 700
1540 " Setup balloon evaluation to display tag prototype
1541 if v:version >= 700 && has('balloon_eval')
1542 setlocal balloonexpr=Tlist_Ballon_Expr()
1546 " Setup the cpoptions properly for the maps to work
1547 let old_cpoptions = &cpoptions
1550 " Create buffer local mappings for jumping to the tags and sorting the list
1551 nnoremap <buffer> <silent> <CR>
1552 \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1553 " If more languages are required, generate this from a list of options
1554 nnoremap <buffer> <silent> m
1555 \ :call <SID>Tlist_Window_Toggle_Extra('javascript', 'type')<CR>
1556 nnoremap <buffer> <silent> o
1557 \ :call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
1558 nnoremap <buffer> <silent> p
1559 \ :call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
1560 nnoremap <buffer> <silent> P
1561 \ :call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
1563 nnoremap <buffer> <silent> t
1564 \ :call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
1565 nnoremap <buffer> <silent> <C-t>
1566 \ :call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
1568 nnoremap <buffer> <silent> <2-LeftMouse>
1569 \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1570 nnoremap <buffer> <silent> s
1571 \ :call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
1572 nnoremap <buffer> <silent> + :silent! foldopen<CR>
1573 nnoremap <buffer> <silent> - :silent! foldclose<CR>
1574 nnoremap <buffer> <silent> * :silent! %foldopen!<CR>
1575 nnoremap <buffer> <silent> = :silent! %foldclose<CR>
1576 nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR>
1577 nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR>
1578 nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR>
1579 nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Window_Show_Info()<CR>
1580 nnoremap <buffer> <silent> u :call <SID>Tlist_Window_Update_File()<CR>
1581 nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1, 1)<CR>
1582 nnoremap <buffer> <silent> x :call <SID>Tlist_Window_Zoom()<CR>
1583 nnoremap <buffer> <silent> [[ :call <SID>Tlist_Window_Move_To_File(-1)<CR>
1584 nnoremap <buffer> <silent> <BS> :call <SID>Tlist_Window_Move_To_File(-1)<CR>
1585 nnoremap <buffer> <silent> ]] :call <SID>Tlist_Window_Move_To_File(1)<CR>
1586 nnoremap <buffer> <silent> <Tab> :call <SID>Tlist_Window_Move_To_File(1)<CR>
1587 nnoremap <buffer> <silent> <F1> :call <SID>Tlist_Window_Toggle_Help_Text()<CR>
1588 nnoremap <buffer> <silent> q :close<CR>
1590 " Insert mode mappings
1591 inoremap <buffer> <silent> <CR>
1592 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1593 " Windows needs return
1594 inoremap <buffer> <silent> <Return>
1595 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1596 inoremap <buffer> <silent> o
1597 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
1598 inoremap <buffer> <silent> p
1599 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
1600 inoremap <buffer> <silent> P
1601 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
1603 inoremap <buffer> <silent> t
1604 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
1605 inoremap <buffer> <silent> <C-t>
1606 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
1608 inoremap <buffer> <silent> <2-LeftMouse>
1609 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1610 inoremap <buffer> <silent> s
1611 \ <C-o>:call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
1612 inoremap <buffer> <silent> + <C-o>:silent! foldopen<CR>
1613 inoremap <buffer> <silent> - <C-o>:silent! foldclose<CR>
1614 inoremap <buffer> <silent> * <C-o>:silent! %foldopen!<CR>
1615 inoremap <buffer> <silent> = <C-o>:silent! %foldclose<CR>
1616 inoremap <buffer> <silent> <kPlus> <C-o>:silent! foldopen<CR>
1617 inoremap <buffer> <silent> <kMinus> <C-o>:silent! foldclose<CR>
1618 inoremap <buffer> <silent> <kMultiply> <C-o>:silent! %foldopen!<CR>
1619 inoremap <buffer> <silent> <Space> <C-o>:call
1620 \ <SID>Tlist_Window_Show_Info()<CR>
1621 inoremap <buffer> <silent> u
1622 \ <C-o>:call <SID>Tlist_Window_Update_File()<CR>
1623 inoremap <buffer> <silent> d <C-o>:call <SID>Tlist_Remove_File(-1, 1)<CR>
1624 inoremap <buffer> <silent> x <C-o>:call <SID>Tlist_Window_Zoom()<CR>
1625 inoremap <buffer> <silent> [[ <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
1626 inoremap <buffer> <silent> <BS> <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
1627 inoremap <buffer> <silent> ]] <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
1628 inoremap <buffer> <silent> <Tab> <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
1629 inoremap <buffer> <silent> <F1> <C-o>:call <SID>Tlist_Window_Toggle_Help_Text()<CR>
1630 inoremap <buffer> <silent> q <C-o>:close<CR>
1632 " Map single left mouse click if the user wants this functionality
1633 if g:Tlist_Use_SingleClick == 1
1634 " Contributed by Bindu Wavell
1635 " attempt to perform single click mapping, it would be much
1636 " nicer if we could nnoremap <buffer> ... however vim does
1637 " not fire the <buffer> <leftmouse> when you use the mouse
1638 " to enter a buffer.
1639 let clickmap = ':if bufname("%") =~ "__Tag_List__" <bar> ' .
1640 \ 'call <SID>Tlist_Window_Jump_To_Tag("useopen") ' .
1641 \ '<bar> endif <CR>'
1642 if maparg('<leftmouse>', 'n') == ''
1643 " no mapping for leftmouse
1644 exe ':nnoremap <silent> <leftmouse> <leftmouse>' . clickmap
1647 let mapcmd = ':nnoremap <silent> <leftmouse> <leftmouse>'
1648 let mapcmd = mapcmd . substitute(substitute(
1649 \ maparg('<leftmouse>', 'n'), '|', '<bar>', 'g'),
1650 \ '\c^<leftmouse>', '', '')
1651 let mapcmd = mapcmd . clickmap
1656 " Define the taglist autocommands
1657 augroup TagListAutoCmds
1659 " Display the tag prototype for the tag under the cursor.
1660 autocmd CursorHold __Tag_List__ call s:Tlist_Window_Show_Info()
1661 " Highlight the current tag periodically
1662 autocmd CursorHold * silent call s:Tlist_Window_Highlight_Tag(
1663 \ fnamemodify(bufname('%'), ':p'), line('.'), 1, 0)
1665 " Adjust the Vim window width when taglist window is closed
1666 autocmd BufUnload __Tag_List__ call s:Tlist_Post_Close_Cleanup()
1667 " Close the fold for this buffer when leaving the buffer
1668 if g:Tlist_File_Fold_Auto_Close
1669 autocmd BufEnter * silent
1670 \ call s:Tlist_Window_Open_File_Fold(expand('<abuf>'))
1672 " Exit Vim itself if only the taglist window is present (optional)
1673 if g:Tlist_Exit_OnlyWindow
1674 autocmd BufEnter __Tag_List__ nested
1675 \ call s:Tlist_Window_Exit_Only_Window()
1677 if s:tlist_app_name != "winmanager" &&
1678 \ !g:Tlist_Process_File_Always &&
1679 \ (!has('gui_running') || !g:Tlist_Show_Menu)
1680 " Auto refresh the taglist window
1681 autocmd BufEnter * call s:Tlist_Refresh()
1684 if !g:Tlist_Use_Horiz_Window
1686 autocmd WinEnter * call s:Tlist_Window_Check_Width()
1690 autocmd TabEnter * silent call s:Tlist_Refresh_Folds()
1694 " Restore the previous cpoptions settings
1695 let &cpoptions = old_cpoptions
1698 " Tlist_Window_Refresh
1699 " Display the tags for all the files in the taglist window
1700 function! s:Tlist_Window_Refresh()
1701 call s:Tlist_Log_Msg('Tlist_Window_Refresh()')
1702 " Set report option to a huge value to prevent informational messages
1703 " while deleting the lines
1704 let old_report = &report
1707 " Mark the buffer as modifiable
1710 " Delete the contents of the buffer to the black-hole register
1713 " As we have cleared the taglist window, mark all the files
1716 while i < s:tlist_file_count
1717 let s:tlist_{i}_visible = 0
1721 if g:Tlist_Compact_Format == 0
1722 " Display help in non-compact mode
1723 call s:Tlist_Window_Display_Help()
1726 " Mark the buffer as not modifiable
1727 setlocal nomodifiable
1729 " Restore the report option
1730 let &report = old_report
1732 " If the tags for only one file should be displayed in the taglist
1733 " window, then no need to add the tags here. The bufenter autocommand
1734 " will add the tags for that file.
1735 if g:Tlist_Show_One_File
1739 " List all the tags for the previously processed files
1740 " Do this only if taglist is configured to display tags for more than
1741 " one file. Otherwise, when Tlist_Show_One_File is configured,
1742 " tags for the wrong file will be displayed.
1744 while i < s:tlist_file_count
1745 call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename,
1746 \ s:tlist_{i}_filetype)
1750 if g:Tlist_Auto_Update
1751 " Add and list the tags for all buffers in the Vim buffer list
1753 let last_bufnum = bufnr('$')
1754 while i <= last_bufnum
1756 let fname = fnamemodify(bufname(i), ':p')
1757 let ftype = s:Tlist_Get_Buffer_Filetype(i)
1758 " If the file doesn't support tag listing, skip it
1759 if !s:Tlist_Skip_File(fname, ftype)
1760 call s:Tlist_Window_Refresh_File(fname, ftype)
1767 " If Tlist_File_Fold_Auto_Close option is set, then close all the folds
1768 if g:Tlist_File_Fold_Auto_Close
1769 " Close all the folds
1773 if !g:Tlist_Use_Horiz_Window && s:auto_width
1774 exe 'vertical resize '.g:Tlist_WinWidth
1777 " Move the cursor to the top of the taglist window
1781 " Tlist_Post_Close_Cleanup()
1782 " Close the taglist window and adjust the Vim window width
1783 function! s:Tlist_Post_Close_Cleanup()
1784 call s:Tlist_Log_Msg('Tlist_Post_Close_Cleanup()')
1785 " Mark all the files as not visible
1787 while i < s:tlist_file_count
1788 let s:tlist_{i}_visible = 0
1792 " Remove the taglist autocommands
1793 silent! autocmd! TagListAutoCmds
1795 " Clear all the highlights
1798 silent! syntax clear TagListTitle
1799 silent! syntax clear TagListComment
1800 silent! syntax clear TagListTagScope
1802 " Remove the left mouse click mapping if it was setup initially
1803 if g:Tlist_Use_SingleClick
1804 if hasmapto('<LeftMouse>')
1809 if s:tlist_app_name != "winmanager"
1810 if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 ||
1811 \ s:tlist_winsize_chgd != 1 ||
1812 \ &columns < (80 + g:Tlist_WinWidth)
1813 " No need to adjust window width if using horizontally split taglist
1814 " window or if columns is less than 101 or if the user chose not to
1815 " adjust the window width
1817 " If the user didn't manually move the window, then restore the window
1818 " position to the pre-taglist position
1819 if s:tlist_pre_winx != -1 && s:tlist_pre_winy != -1 &&
1820 \ getwinposx() == s:tlist_winx &&
1821 \ getwinposy() == s:tlist_winy
1822 exe 'winpos ' . s:tlist_pre_winx . ' ' . s:tlist_pre_winy
1825 " Adjust the Vim window width
1826 let &columns= &columns - (g:Tlist_WinWidth + 1)
1830 let s:tlist_winsize_chgd = -1
1832 " Reset taglist state variables
1833 if s:tlist_app_name == "winmanager"
1834 let s:tlist_app_name = "none"
1836 let s:tlist_window_initialized = 0
1839 " Tlist_Window_Refresh_File()
1840 " List the tags defined in the specified file in a Vim window
1841 function! s:Tlist_Window_Refresh_File(filename, ftype)
1842 call s:Tlist_Log_Msg('Tlist_Window_Refresh_File (' . a:filename . ')')
1843 " First check whether the file already exists
1844 let fidx = s:Tlist_Get_File_Index(a:filename)
1852 " Check whether this file is removed based on user request
1853 " If it is, then don't display the tags for this file
1854 if s:Tlist_User_Removed_File(a:filename)
1859 if file_listed && s:tlist_{fidx}_visible
1860 " Check whether the file tags are currently valid
1861 if s:tlist_{fidx}_valid
1862 " Goto the first line in the file
1863 exe s:tlist_{fidx}_start
1865 " If the line is inside a fold, open the fold
1866 if foldclosed('.') != -1
1867 exe "silent! " . s:tlist_{fidx}_start . "," .
1868 \ s:tlist_{fidx}_end . "foldopen!"
1873 " Discard and remove the tags for this file from display
1874 call s:Tlist_Discard_TagInfo(fidx)
1875 call s:Tlist_Window_Remove_File_From_Display(fidx)
1878 " Process and generate a list of tags defined in the file
1879 if !file_listed || !s:tlist_{fidx}_valid
1880 let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype)
1887 " Set report option to a huge value to prevent informational messages
1888 " while adding lines to the taglist window
1889 let old_report = &report
1892 if g:Tlist_Show_One_File
1893 " Remove the previous file
1894 if s:tlist_cur_file_idx != -1
1895 call s:Tlist_Window_Remove_File_From_Display(s:tlist_cur_file_idx)
1896 let s:tlist_{s:tlist_cur_file_idx}_visible = 0
1897 let s:tlist_{s:tlist_cur_file_idx}_start = 0
1898 let s:tlist_{s:tlist_cur_file_idx}_end = 0
1900 let s:tlist_cur_file_idx = fidx
1903 " Mark the buffer as modifiable
1906 " Add new files to the end of the window. For existing files, add them at
1907 " the same line where they were previously present. If the file is not
1908 " visible, then add it at the end
1909 if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible
1910 if g:Tlist_Compact_Format
1911 let s:tlist_{fidx}_start = line('$')
1913 let s:tlist_{fidx}_start = line('$') + 1
1917 let s:tlist_{fidx}_visible = 1
1919 " Goto the line where this file should be placed
1920 if g:Tlist_Compact_Format
1921 exe s:tlist_{fidx}_start
1923 exe s:tlist_{fidx}_start - 1
1926 let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' .
1927 \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')'
1928 if g:Tlist_Compact_Format == 0
1932 " Move to the next line
1935 let file_start = s:tlist_{fidx}_start
1937 " Add the tag names grouped by tag type to the buffer with a title
1939 let ttype_cnt = s:tlist_{a:ftype}_count
1940 while i <= ttype_cnt
1941 let ttype = s:tlist_{a:ftype}_{i}_name
1942 " Add the tag type only if there are tags for that type
1943 let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
1944 let ttype_txt = {fidx_ttype}
1946 let txt = ' ' . s:tlist_{a:ftype}_{i}_fullname
1947 if g:Tlist_Compact_Format == 0
1948 let ttype_start_lnum = line('.') + 1
1951 let ttype_start_lnum = line('.')
1954 silent! put =ttype_txt
1956 let {fidx_ttype}_offset = ttype_start_lnum - file_start
1958 " create a fold for this tag type
1959 let fold_start = ttype_start_lnum
1960 let fold_end = fold_start + {fidx_ttype}_count
1961 exe fold_start . ',' . fold_end . 'fold'
1963 " Adjust the cursor position
1964 if g:Tlist_Compact_Format == 0
1965 exe ttype_start_lnum + {fidx_ttype}_count
1967 exe ttype_start_lnum + {fidx_ttype}_count + 1
1970 if g:Tlist_Compact_Format == 0
1971 " Separate the tag types by a empty line
1978 if s:tlist_{fidx}_tag_count == 0
1979 if g:Tlist_Compact_Format == 0
1984 let s:tlist_{fidx}_end = line('.') - 1
1986 " Create a fold for the entire file
1987 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
1988 exe 'silent! ' . s:tlist_{fidx}_start . ',' .
1989 \ s:tlist_{fidx}_end . 'foldopen!'
1991 " Goto the starting line for this file,
1992 exe s:tlist_{fidx}_start
1994 if s:tlist_app_name == "winmanager"
1995 " To handle a bug in the winmanager plugin, add a space at the
1997 call setline('$', ' ')
2000 " Mark the buffer as not modifiable
2001 setlocal nomodifiable
2003 " Restore the report option
2004 let &report = old_report
2006 " Update the start and end line numbers for all the files following this
2008 let start = s:tlist_{fidx}_start
2009 " include the empty line after the last line
2010 if g:Tlist_Compact_Format
2011 let end = s:tlist_{fidx}_end
2013 let end = s:tlist_{fidx}_end + 1
2015 call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1)
2017 if !g:Tlist_Use_Horiz_Window && s:auto_width
2018 exe 'vertical resize '.g:Tlist_WinWidth
2021 " Now that we have updated the taglist window, update the tags
2023 if g:Tlist_Show_Menu
2024 call s:Tlist_Menu_Update_File(1)
2029 " Initialize the variables for a new file
2030 function! s:Tlist_Init_File(filename, ftype)
2031 call s:Tlist_Log_Msg('Tlist_Init_File (' . a:filename . ')')
2032 " Add new files at the end of the list
2033 let fidx = s:tlist_file_count
2034 let s:tlist_file_count = s:tlist_file_count + 1
2035 " Add the new file name to the taglist list of file names
2036 let s:tlist_file_names = s:tlist_file_names . a:filename . "\n"
2038 " Initialize the file variables
2039 let s:tlist_{fidx}_filename = a:filename
2040 let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type
2041 let s:tlist_{fidx}_filetype = a:ftype
2042 let s:tlist_{fidx}_mtime = -1
2043 let s:tlist_{fidx}_start = 0
2044 let s:tlist_{fidx}_end = 0
2045 let s:tlist_{fidx}_valid = 0
2046 let s:tlist_{fidx}_visible = 0
2047 let s:tlist_{fidx}_tag_count = 0
2048 let s:tlist_{fidx}_menu_cmd = ''
2050 " Initialize the tag type variables
2052 while i <= s:tlist_{a:ftype}_count
2053 let ttype = s:tlist_{a:ftype}_{i}_name
2054 let s:tlist_{fidx}_{ttype} = ''
2055 let s:tlist_{fidx}_{ttype}_offset = 0
2056 let s:tlist_{fidx}_{ttype}_count = 0
2063 " Tlist_Get_Tag_Type_By_Tag
2064 " Return the tag type for the specified tag index
2065 function! s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
2066 let ttype_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_type'
2068 " Already parsed and have the tag name
2069 if exists(ttype_var)
2073 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2074 let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line)
2079 " Tlist_Get_Tag_Prototype
2080 function! s:Tlist_Get_Tag_Prototype(fidx, tidx)
2081 let tproto_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_proto'
2083 " Already parsed and have the tag prototype
2084 if exists(tproto_var)
2088 " Parse and extract the tag prototype
2089 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2090 let start = stridx(tag_line, '/^') + 2
2091 let end = stridx(tag_line, '/;"' . "\t")
2092 if tag_line[end - 1] == '$'
2095 let tag_proto = strpart(tag_line, start, end - start)
2096 let {tproto_var} = substitute(tag_proto, '\s*', '', '')
2101 " Tlist_Get_Tag_SearchPat
2102 function! s:Tlist_Get_Tag_SearchPat(fidx, tidx)
2103 let tpat_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_searchpat'
2105 " Already parsed and have the tag search pattern
2110 " Parse and extract the tag search pattern
2111 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2112 let start = stridx(tag_line, '/^') + 2
2113 let end = stridx(tag_line, '/;"' . "\t")
2114 if tag_line[end - 1] == '$'
2117 let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) .
2118 \ (tag_line[end] == '$' ? '\$' : '')
2123 " Tlist_Get_Tag_Linenum
2124 " Return the tag line number, given the tag index
2125 function! s:Tlist_Get_Tag_Linenum(fidx, tidx)
2126 let tline_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_linenum'
2128 " Already parsed and have the tag line number
2129 if exists(tline_var)
2133 " Parse and extract the tag line number
2134 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2135 let start = match(tag_line, 'line\(no\)\?:')
2136 let start = stridx(tag_line, ':', start) + 1
2137 let end = stridx(tag_line, "\t", start)
2140 let {tline_var} = strpart(tag_line, start) + 0
2142 let {tline_var} = strpart(tag_line, start, end - start) + 0
2148 " Tlist_Parse_Tagline
2149 " Parse a tag line from the ctags output. Separate the tag output based on the
2150 " tag type and store it in the tag type variable.
2151 " The format of each line in the ctags output is:
2153 " tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields
2155 function! s:Tlist_Parse_Tagline(tag_line,ftype)
2161 " Extract the tag type
2162 let ttype = s:Tlist_Extract_Tagtype(a:tag_line)
2164 " Make sure the tag type is a valid and supported one
2165 if ttype == '' || stridx(s:ctags_flags, ttype) == -1
2166 " Line is not in proper tags format or Tag type is not supported
2170 " Update the total tag count
2171 let s:tidx = s:tidx + 1
2173 " The following variables are used to optimize this code. Vim is slow in
2174 " using curly brace names. To reduce the amount of processing needed, the
2175 " curly brace variables are pre-processed here
2176 let fidx_tidx = 's:tlist_' . s:fidx . '_' . s:tidx
2177 let fidx_ttype = 's:tlist_' . s:fidx . '_' . ttype
2179 " Update the count of this tag type
2180 let ttype_idx = {fidx_ttype}_count + 1
2181 let {fidx_ttype}_count = ttype_idx
2183 " Store the ctags output for this tag
2184 let {fidx_tidx}_tag = a:tag_line
2186 " Store the tag index and the tag type index (back pointers)
2187 let {fidx_ttype}_{ttype_idx} = s:tidx
2188 let {fidx_tidx}_ttype_idx = ttype_idx
2190 " Extract the tag name
2191 let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t"))
2193 " Extract the tag scope/prototype
2194 if g:Tlist_Display_Prototype
2195 let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx)
2197 let ttxt = ' ' . tag_name
2199 " Add the tag scope, if it is available and is configured. Tag
2200 " scope is the last field after the 'line:<num>\t' field
2201 if g:Tlist_Display_Tag_Scope
2202 let ttxt .= s:Tlist_Get_Scope_String(a:tag_line, a:ftype)
2206 if !g:Tlist_Use_Horiz_Window && s:auto_width
2207 " Add 3 for the fold columns
2208 let g:Tlist_WinWidth = max([g:Tlist_WinWidth, strlen(ttxt)+3])
2211 " Add this tag to the tag type variable
2212 let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
2215 let {fidx_tidx}_tag_name = tag_name
2218 function! s:Tlist_Get_Scope_String(tag_line, ftype)
2220 let tag_scopes = s:Tlist_Extract_Tag_Scope(a:tag_line)
2221 for [extradata_name, extradata_content] in items(tag_scopes)
2222 if !exists('g:Tlist_{a:ftype}_Hide_Extras') || match(g:Tlist_{a:ftype}_Hide_Extras, extradata_name) == -1
2223 let ttxt = ttxt . ' [' . extradata_content . ']'
2229 " Tlist_Process_File
2230 " Get the list of tags defined in the specified file and store them
2231 " in Vim variables. Returns the file index where the tags are stored.
2232 function! s:Tlist_Process_File(filename, ftype)
2233 call s:Tlist_Log_Msg('Tlist_Process_File (' . a:filename . ', ' .
2235 " Check whether this file is supported
2236 if s:Tlist_Skip_File(a:filename, a:ftype)
2240 " If the tag types for this filetype are not yet created, then create
2242 let var = 's:tlist_' . a:ftype . '_count'
2244 if s:Tlist_FileType_Init(a:ftype) == 0
2249 " If this file is already processed, then use the cached values
2250 let fidx = s:Tlist_Get_File_Index(a:filename)
2252 " First time, this file is loaded
2253 let fidx = s:Tlist_Init_File(a:filename, a:ftype)
2255 " File was previously processed. Discard the tag information
2256 call s:Tlist_Discard_TagInfo(fidx)
2259 let s:tlist_{fidx}_valid = 1
2261 " Exuberant ctags arguments to generate a tag list
2262 let ctags_args = { '-f': ' -', '--format=': '2', '--excmd=': 'pattern', '--fields=': 'nks' }
2264 " Form the ctags argument depending on the sort type
2265 if s:tlist_{fidx}_sort_type == 'name'
2266 let ctags_args['--sort'] = '=yes'
2268 let ctags_args['--sort'] = '=no'
2271 " Add the filetype specific arguments
2272 call extend(ctags_args, s:tlist_{a:ftype}_ctags_args)
2274 " Ctags command to produce output with regexp for locating the tags
2275 if exists('g:Tlist_{a:ftype}_Ctags_Cmd')
2276 let ctags_cmd = g:Tlist_{a:ftype}_Ctags_Cmd
2277 let ctags_args = filter(ctags_args, 'match(g:Tlist_javascript_Ctags_Allowed_Flags, "^".v:key."$") != -1')
2279 let ctags_cmd = g:Tlist_Ctags_Cmd
2281 let ctags_cmd = ctags_cmd . ' ' . join(values(map(ctags_args, 'v:key . v:val')))
2282 let ctags_cmd = ctags_cmd . ' "' . a:filename . '"'
2284 if &shellxquote == '"'
2285 " Double-quotes within double-quotes will not work in the
2286 " command-line.If the 'shellxquote' option is set to double-quotes,
2287 " then escape the double-quotes in the ctags command-line.
2288 let ctags_cmd = escape(ctags_cmd, '"')
2291 " In Windows 95, if not using cygwin, disable the 'shellslash'
2292 " option. Otherwise, this will cause problems when running the
2294 if has('win95') && !has('win32unix')
2295 let old_shellslash = &shellslash
2299 if has('win32') && !has('win32unix') && !has('win95')
2300 \ && (&shell =~ 'cmd.exe')
2301 " Windows does not correctly deal with commands that have more than 1
2302 " set of double quotes. It will strip them all resulting in:
2303 " 'C:\Program' is not recognized as an internal or external command
2304 " operable program or batch file. To work around this, place the
2305 " command inside a batch file and call the batch file.
2306 " Do this only on Win2K, WinXP and above.
2307 " Contributed by: David Fishburn.
2308 let s:taglist_tempfile = fnamemodify(tempname(), ':h') .
2310 exe 'redir! > ' . s:taglist_tempfile
2311 silent echo ctags_cmd
2314 call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd)
2315 let ctags_cmd = '"' . s:taglist_tempfile . '"'
2318 call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd)
2320 " Run ctags and get the tag list
2321 let cmd_output = system(ctags_cmd)
2323 " Restore the value of the 'shellslash' option.
2324 if has('win95') && !has('win32unix')
2325 let &shellslash = old_shellslash
2328 if exists('s:taglist_tempfile')
2329 " Delete the temporary cmd file created on MS-Windows
2330 call delete(s:taglist_tempfile)
2335 let msg = "Taglist: Failed to generate tags for " . a:filename
2336 call s:Tlist_Warning_Msg(msg)
2338 call s:Tlist_Warning_Msg(cmd_output)
2343 " Store the modification time for the file
2344 let s:tlist_{fidx}_mtime = getftime(a:filename)
2346 " No tags for current file
2348 call s:Tlist_Log_Msg('No tags defined in ' . a:filename)
2352 call s:Tlist_Log_Msg('Generated tags information for ' . a:filename)
2355 " The following script local variables are used by the
2356 " Tlist_Parse_Tagline() function.
2357 let s:ctags_flags = s:tlist_{a:ftype}_ctags_flags
2361 " Tlist_Parse_Tagline will adjust this accordingly
2362 if !g:Tlist_Use_Horiz_Window && s:auto_width
2363 let g:Tlist_WinWidth = 0
2366 " Process the ctags output one line at a time. The substitute()
2367 " command is used to parse the tag lines instead of using the
2368 " matchstr()/stridx()/strpart() functions for performance reason
2369 call substitute(cmd_output, "\\([^\n]\\+\\)\n",
2370 \ '\=s:Tlist_Parse_Tagline(submatch(1),a:ftype)', 'g')
2372 " Save the number of tags for this file
2373 let s:tlist_{fidx}_tag_count = s:tidx
2375 " The following script local variables are no longer needed
2376 unlet! s:ctags_flags
2380 " Due to a bug in Vim earlier than version 6.1,
2381 " we cannot use substitute() to parse the ctags output.
2382 " Instead the slow str*() functions are used
2383 let ctags_flags = s:tlist_{a:ftype}_ctags_flags
2386 while cmd_output != ''
2387 " Extract one line at a time
2388 let idx = stridx(cmd_output, "\n")
2389 let one_line = strpart(cmd_output, 0, idx)
2390 " Remove the line from the tags output
2391 let cmd_output = strpart(cmd_output, idx + 1)
2394 " Line is not in proper tags format
2398 " Extract the tag type
2399 let ttype = s:Tlist_Extract_Tagtype(one_line)
2401 " Make sure the tag type is a valid and supported one
2402 if ttype == '' || stridx(ctags_flags, ttype) == -1
2403 " Line is not in proper tags format or Tag type is not
2408 " Update the total tag count
2411 " The following variables are used to optimize this code. Vim is
2412 " slow in using curly brace names. To reduce the amount of
2413 " processing needed, the curly brace variables are pre-processed
2415 let fidx_tidx = 's:tlist_' . fidx . '_' . tidx
2416 let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
2418 " Update the count of this tag type
2419 let ttype_idx = {fidx_ttype}_count + 1
2420 let {fidx_ttype}_count = ttype_idx
2422 " Store the ctags output for this tag
2423 let {fidx_tidx}_tag = one_line
2425 " Store the tag index and the tag type index (back pointers)
2426 let {fidx_ttype}_{ttype_idx} = tidx
2427 let {fidx_tidx}_ttype_idx = ttype_idx
2429 " Extract the tag name
2430 let tag_name = strpart(one_line, 0, stridx(one_line, "\t"))
2432 " Extract the tag scope/prototype
2433 if g:Tlist_Display_Prototype
2434 let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(fidx, tidx)
2436 let ttxt = ' ' . tag_name
2438 " Add the tag scope, if it is available and is configured. Tag
2439 " scope is the last field after the 'line:<num>\t' field
2440 if g:Tlist_Display_Tag_Scope
2441 let ttxt .= s:Tlist_Get_Scope_String(a:tag_line, a:ftype)
2445 " Add this tag to the tag type variable
2446 let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
2449 let {fidx_tidx}_tag_name = tag_name
2452 " Save the number of tags for this file
2453 let s:tlist_{fidx}_tag_count = tidx
2456 call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count .
2457 \ ' tags in ' . a:filename)
2463 " Update the tags for a file (if needed)
2464 function! Tlist_Update_File(filename, ftype)
2465 call s:Tlist_Log_Msg('Tlist_Update_File (' . a:filename . ')')
2466 " If the file doesn't support tag listing, skip it
2467 if s:Tlist_Skip_File(a:filename, a:ftype)
2471 " Convert the file name to a full path
2472 let fname = fnamemodify(a:filename, ':p')
2474 " First check whether the file already exists
2475 let fidx = s:Tlist_Get_File_Index(fname)
2477 if fidx != -1 && s:tlist_{fidx}_valid
2478 " File exists and the tags are valid
2479 " Check whether the file was modified after the last tags update
2480 " If it is modified, then update the tags
2481 if s:tlist_{fidx}_mtime == getftime(fname)
2485 " If the tags were removed previously based on a user request,
2486 " as we are going to update the tags (based on the user request),
2487 " remove the filename from the deleted list
2488 call s:Tlist_Update_Remove_List(fname, 0)
2491 " If the taglist window is opened, update it
2492 let winnum = bufwinnr(g:TagList_title)
2494 " Taglist window is not present. Just update the taglist
2496 call s:Tlist_Process_File(fname, a:ftype)
2498 if g:Tlist_Show_One_File && s:tlist_cur_file_idx != -1
2499 " If tags for only one file are displayed and we are not
2500 " updating the tags for that file, then no need to
2501 " refresh the taglist window. Otherwise, the taglist
2502 " window should be updated.
2503 if s:tlist_{s:tlist_cur_file_idx}_filename != fname
2504 call s:Tlist_Process_File(fname, a:ftype)
2509 " Save the current window number
2510 let save_winnr = winnr()
2512 " Goto the taglist window
2513 call s:Tlist_Window_Goto_Window()
2515 " Save the cursor position
2516 let save_line = line('.')
2517 let save_col = col('.')
2519 " Update the taglist window
2520 call s:Tlist_Window_Refresh_File(fname, a:ftype)
2522 " Restore the cursor position
2524 call cursor(save_line, save_col)
2527 exe 'normal! ' . save_col . '|'
2530 if winnr() != save_winnr
2531 " Go back to the original window
2532 call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
2536 " Update the taglist menu
2537 if g:Tlist_Show_Menu
2538 call s:Tlist_Menu_Update_File(1)
2542 " Tlist_Window_Close
2543 " Close the taglist window
2544 function! s:Tlist_Window_Close()
2545 call s:Tlist_Log_Msg('Tlist_Window_Close()')
2546 " Make sure the taglist window exists
2547 let winnum = bufwinnr(g:TagList_title)
2549 call s:Tlist_Warning_Msg('Error: Taglist window is not open')
2553 if winnr() == winnum
2554 " Already in the taglist window. Close it and return.
2555 " Store the buffer that was selected prior to the taglist buffer
2556 let prev_buf = bufnr('#')
2557 if winbufnr(2) != -1
2558 " If a window other than the taglist window is open,
2559 " then only close the taglist window.
2561 call s:Tlist_Exe_Cmd_No_Acmds(bufwinnr(prev_buf) . 'wincmd w')
2564 " Goto the taglist window, close it and then come back to the
2566 let curbufnr = bufnr('%')
2567 exe winnum . 'wincmd w'
2569 " Need to jump back to the original window only if we are not
2570 " already in that window
2571 let winnum = bufwinnr(curbufnr)
2572 if winnr() != winnum
2573 exe winnum . 'wincmd w'
2578 " Tlist_Window_Mark_File_Window
2579 " Mark the current window as the file window to use when jumping to a tag.
2580 " Only if the current window is a non-plugin, non-preview and non-taglist
2582 function! s:Tlist_Window_Mark_File_Window()
2583 if getbufvar('%', '&buftype') == '' && !&previewwindow
2584 let w:tlist_file_window = "yes"
2589 " Open and refresh the taglist window
2590 function! s:Tlist_Window_Open()
2591 call s:Tlist_Log_Msg('Tlist_Window_Open()')
2592 " If the window is open, jump to it
2593 let winnum = bufwinnr(g:TagList_title)
2595 " Jump to the existing window
2596 if winnr() != winnum
2597 exe winnum . 'wincmd w'
2602 if s:tlist_app_name == "winmanager"
2603 " Taglist plugin is no longer part of the winmanager app
2604 let s:tlist_app_name = "none"
2607 " Get the filename and filetype for the specified buffer
2608 let curbuf_name = fnamemodify(bufname('%'), ':p')
2609 let curbuf_ftype = s:Tlist_Get_Buffer_Filetype('%')
2610 let cur_lnum = line('.')
2612 " Mark the current window as the desired window to open a file when a tag
2614 call s:Tlist_Window_Mark_File_Window()
2616 " Open the taglist window
2617 call s:Tlist_Window_Create()
2619 call s:Tlist_Window_Refresh()
2621 if g:Tlist_Show_One_File
2622 " Add only the current buffer and file
2624 " If the file doesn't support tag listing, skip it
2625 if !s:Tlist_Skip_File(curbuf_name, curbuf_ftype)
2626 call s:Tlist_Window_Refresh_File(curbuf_name, curbuf_ftype)
2630 if g:Tlist_File_Fold_Auto_Close
2631 " Open the fold for the current file, as all the folds in
2632 " the taglist window are closed
2633 let fidx = s:Tlist_Get_File_Index(curbuf_name)
2635 exe "silent! " . s:tlist_{fidx}_start . "," .
2636 \ s:tlist_{fidx}_end . "foldopen!"
2640 " Highlight the current tag
2641 call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1)
2644 " Tlist_Window_Toggle()
2645 " Open or close a taglist window
2646 function! s:Tlist_Window_Toggle()
2647 call s:Tlist_Log_Msg('Tlist_Window_Toggle()')
2648 " If taglist window is open then close it.
2649 let winnum = bufwinnr(g:TagList_title)
2651 call s:Tlist_Window_Close()
2655 " Store the current buffer
2656 let current_buf = winbufnr(0)
2657 call s:Tlist_Window_Open()
2659 " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not
2661 if !g:Tlist_GainFocus_On_ToggleOpen
2662 let prev_win = bufwinnr(current_buf)
2663 call s:Tlist_Exe_Cmd_No_Acmds(prev_win . 'wincmd w')
2666 " Update the taglist menu
2667 if g:Tlist_Show_Menu
2668 call s:Tlist_Menu_Update_File(0)
2672 " Tlist_Process_Filelist
2673 " Process multiple files. Each filename is separated by "\n"
2674 " Returns the number of processed files
2675 function! s:Tlist_Process_Filelist(file_names)
2676 let flist = a:file_names
2678 " Enable lazy screen updates
2679 let old_lazyredraw = &lazyredraw
2682 " Keep track of the number of processed files
2685 " Process one file at a time
2687 let nl_idx = stridx(flist, "\n")
2688 let one_file = strpart(flist, 0, nl_idx)
2690 " Remove the filename from the list
2691 let flist = strpart(flist, nl_idx + 1)
2698 if isdirectory(one_file)
2702 let ftype = s:Tlist_Detect_Filetype(one_file)
2705 echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t')
2709 call Tlist_Update_File(one_file, ftype)
2712 " Clear the displayed informational messages
2715 " Restore the previous state
2716 let &lazyredraw = old_lazyredraw
2722 " Process the files in a directory matching the specified pattern
2723 function! s:Tlist_Process_Dir(dir_name, pat)
2724 let flist = glob(a:dir_name . '/' . a:pat) . "\n"
2726 let fcnt = s:Tlist_Process_Filelist(flist)
2728 let len = strlen(a:dir_name)
2729 if a:dir_name[len - 1] == '\' || a:dir_name[len - 1] == '/'
2730 let glob_expr = a:dir_name . '*'
2732 let glob_expr = a:dir_name . '/*'
2734 let all_files = glob(glob_expr) . "\n"
2736 while all_files != ''
2737 let nl_idx = stridx(all_files, "\n")
2738 let one_file = strpart(all_files, 0, nl_idx)
2740 let all_files = strpart(all_files, nl_idx + 1)
2745 " Skip non-directory names
2746 if !isdirectory(one_file)
2751 echon "\rProcessing files in directory " . fnamemodify(one_file, ':t')
2752 let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat)
2758 " Tlist_Add_Files_Recursive
2759 " Add files recursively from a directory
2760 function! s:Tlist_Add_Files_Recursive(dir, ...)
2761 let dir_name = fnamemodify(a:dir, ':p')
2762 if !isdirectory(dir_name)
2763 call s:Tlist_Warning_Msg('Error: ' . dir_name . ' is not a directory')
2768 " User specified file pattern
2771 " Default file pattern
2776 echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t')
2777 let fcnt = s:Tlist_Process_Dir(dir_name, pat)
2779 echon "\rAdded " . fcnt . " files to the taglist"
2783 " Add the specified list of files to the taglist
2784 function! s:Tlist_Add_Files(...)
2788 " Get all the files matching the file patterns supplied as argument
2790 let flist = flist . glob(a:{i}) . "\n"
2795 call s:Tlist_Warning_Msg('Error: No matching files are found')
2799 let fcnt = s:Tlist_Process_Filelist(flist)
2800 echon "\rAdded " . fcnt . " files to the taglist"
2803 " Tlist_Extract_Tagtype
2804 " Extract the tag type from the tag text
2805 function! s:Tlist_Extract_Tagtype(tag_line)
2806 " The tag type is after the tag prototype field. The prototype field
2807 " ends with the /;"\t string. We add 4 at the end to skip the characters
2808 " in this special string..
2809 let start = strridx(a:tag_line, '/;"' . "\t") + 4
2810 let end = match(a:tag_line, 'line\(no\)\?:') - 1
2811 let ttype = strpart(a:tag_line, start, end - start)
2816 " Tlist_Extract_Tag_Scope
2817 " Extract the tag scope from the tag text
2818 function! s:Tlist_Extract_Tag_Scope(tag_line)
2819 let start = match(a:tag_line, 'line\(no\)\?:')
2820 let end = stridx(a:tag_line, "\t", start)
2827 let tag_extra = strpart(a:tag_line, end + 1)
2828 while tag_extra != ''
2829 let tag_extra_separator_start = stridx(tag_extra, ':')
2830 let tag_extra_content_start = tag_extra_separator_start + 1
2831 let tag_extra_content_end = stridx(tag_extra, "\t")
2832 if tag_extra_content_end == -1
2833 let tag_extra_content_end = strlen(tag_extra)
2835 let tag_extra_name = strpart(tag_extra, 0, tag_extra_separator_start)
2836 let tag_extra_content = strpart(tag_extra, tag_extra_content_start, tag_extra_content_end - tag_extra_content_start)
2837 let tag_extras[tag_extra_name] = tag_extra_content
2838 let tag_extra = strpart(tag_extra, tag_extra_content_end + 1)
2844 function! s:Tlist_Window_Toggle_Extra(ftype, extra_name)
2845 if !exists('g:Tlist_{a:ftype}_Hide_Extras')
2848 let index = index(g:Tlist_{a:ftype}_Hide_Extras, a:extra_name)
2850 call add(g:Tlist_{a:ftype}_Hide_Extras, a:extra_name)
2852 unlet g:Tlist_{a:ftype}_Hide_Extras[index]
2855 let g:Tlist_WinWidth = 30
2858 let cur_lnum = line('.')
2859 let cur_col = col('.')
2860 call s:Tlist_Window_Update_File()
2861 call s:Tlist_Window_Check_Width()
2862 call cursor(cur_lnum, cur_col)
2866 " Refresh the taglist
2867 function! s:Tlist_Refresh()
2868 call s:Tlist_Log_Msg('Tlist_Refresh (Skip_Refresh = ' .
2869 \ s:Tlist_Skip_Refresh . ', ' . bufname('%') . ')')
2870 " If we are entering the buffer from one of the taglist functions, then
2871 " no need to refresh the taglist window again.
2872 if s:Tlist_Skip_Refresh
2873 " We still need to update the taglist menu
2874 if g:Tlist_Show_Menu
2875 call s:Tlist_Menu_Update_File(0)
2880 " If part of the winmanager plugin and not configured to process
2881 " tags always and not configured to display the tags menu, then return
2882 if (s:tlist_app_name == 'winmanager') && !g:Tlist_Process_File_Always
2883 \ && !g:Tlist_Show_Menu
2887 " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
2892 let filename = fnamemodify(bufname('%'), ':p')
2893 let ftype = s:Tlist_Get_Buffer_Filetype('%')
2895 " If the file doesn't support tag listing, skip it
2896 if s:Tlist_Skip_File(filename, ftype)
2900 let tlist_win = bufwinnr(g:TagList_title)
2902 " If the taglist window is not opened and not configured to process
2903 " tags always and not displaying the tags menu, then return
2904 if tlist_win == -1 && !g:Tlist_Process_File_Always && !g:Tlist_Show_Menu
2908 let fidx = s:Tlist_Get_File_Index(filename)
2910 " Check whether this file is removed based on user request
2911 " If it is, then don't display the tags for this file
2912 if s:Tlist_User_Removed_File(filename)
2916 " If the taglist should not be auto updated, then return
2917 if !g:Tlist_Auto_Update
2922 let cur_lnum = line('.')
2925 " Update the tags for the file
2926 let fidx = s:Tlist_Process_File(filename, ftype)
2928 let mtime = getftime(filename)
2929 if s:tlist_{fidx}_mtime != mtime
2930 " Invalidate the tags listed for this file
2931 let s:tlist_{fidx}_valid = 0
2933 " Update the taglist and the window
2934 call Tlist_Update_File(filename, ftype)
2936 " Store the new file modification time
2937 let s:tlist_{fidx}_mtime = mtime
2941 " Update the taglist window
2943 " Disable screen updates
2944 let old_lazyredraw = &lazyredraw
2947 " Save the current window number
2948 let save_winnr = winnr()
2950 " Goto the taglist window
2951 call s:Tlist_Window_Goto_Window()
2953 if !g:Tlist_Auto_Highlight_Tag || !g:Tlist_Highlight_Tag_On_BufEnter
2954 " Save the cursor position
2955 let save_line = line('.')
2956 let save_col = col('.')
2959 " Update the taglist window
2960 call s:Tlist_Window_Refresh_File(filename, ftype)
2962 " Open the fold for the file
2963 exe "silent! " . s:tlist_{fidx}_start . "," .
2964 \ s:tlist_{fidx}_end . "foldopen!"
2966 if g:Tlist_Highlight_Tag_On_BufEnter && g:Tlist_Auto_Highlight_Tag
2967 if g:Tlist_Show_One_File && s:tlist_cur_file_idx != fidx
2968 " If displaying tags for only one file in the taglist
2969 " window and about to display the tags for a new file,
2970 " then center the current tag line for the new file
2971 let center_tag_line = 1
2973 let center_tag_line = 0
2976 " Highlight the current tag
2977 call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line)
2979 " Restore the cursor position
2981 call cursor(save_line, save_col)
2984 exe 'normal! ' . save_col . '|'
2988 " Jump back to the original window
2989 if save_winnr != winnr()
2990 call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
2993 " Restore screen updates
2994 let &lazyredraw = old_lazyredraw
2997 " Update the taglist menu
2998 if g:Tlist_Show_Menu
2999 call s:Tlist_Menu_Update_File(0)
3003 " Tlist_Change_Sort()
3004 " Change the sort order of the tag listing
3005 " caller == 'cmd', command used in the taglist window
3006 " caller == 'menu', taglist menu
3007 " action == 'toggle', toggle sort from name to order and vice versa
3008 " action == 'set', set the sort order to sort_type
3009 function! s:Tlist_Change_Sort(caller, action, sort_type)
3010 call s:Tlist_Log_Msg('Tlist_Change_Sort (caller = ' . a:caller .
3011 \ ', action = ' . a:action . ', sort_type = ' . a:sort_type . ')')
3012 if a:caller == 'cmd'
3013 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
3018 " Remove the previous highlighting
3020 elseif a:caller == 'menu'
3021 let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
3027 if a:action == 'toggle'
3028 let sort_type = s:tlist_{fidx}_sort_type
3030 " Toggle the sort order from 'name' to 'order' and vice versa
3031 if sort_type == 'name'
3032 let s:tlist_{fidx}_sort_type = 'order'
3034 let s:tlist_{fidx}_sort_type = 'name'
3037 let s:tlist_{fidx}_sort_type = a:sort_type
3040 " Invalidate the tags listed for this file
3041 let s:tlist_{fidx}_valid = 0
3043 if a:caller == 'cmd'
3044 " Save the current line for later restoration
3045 let curline = '\V\^' . getline('.') . '\$'
3047 call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
3048 \ s:tlist_{fidx}_filetype)
3050 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
3052 " Go back to the cursor line before the tag list is sorted
3053 call search(curline, 'w')
3055 call s:Tlist_Menu_Update_File(1)
3057 call s:Tlist_Menu_Remove_File()
3059 call s:Tlist_Refresh()
3063 " Tlist_Update_Current_File()
3064 " Update taglist for the current buffer by regenerating the tag list
3065 " Contributed by WEN Guopeng.
3066 function! s:Tlist_Update_Current_File()
3067 call s:Tlist_Log_Msg('Tlist_Update_Current_File()')
3068 if winnr() == bufwinnr(g:TagList_title)
3069 " In the taglist window. Update the current file
3070 call s:Tlist_Window_Update_File()
3072 " Not in the taglist window. Update the current buffer
3073 let filename = fnamemodify(bufname('%'), ':p')
3074 let fidx = s:Tlist_Get_File_Index(filename)
3076 let s:tlist_{fidx}_valid = 0
3078 let ft = s:Tlist_Get_Buffer_Filetype('%')
3079 call Tlist_Update_File(filename, ft)
3083 " Tlist_Window_Update_File()
3084 " Update the tags displayed in the taglist window
3085 function! s:Tlist_Window_Update_File()
3086 call s:Tlist_Log_Msg('Tlist_Window_Update_File()')
3087 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
3092 " Remove the previous highlighting
3095 " Save the current line for later restoration
3096 let curline = '\V\^' . getline('.') . '\$'
3098 let s:tlist_{fidx}_valid = 0
3100 " Update the taglist window
3101 call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
3102 \ s:tlist_{fidx}_filetype)
3104 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
3106 " Go back to the tag line before the list is updated
3107 call search(curline, 'w')
3110 " Tlist_Window_Get_Tag_Type_By_Linenum()
3111 " Return the tag type index for the specified line in the taglist window
3112 function! s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
3113 let ftype = s:tlist_{a:fidx}_filetype
3115 " Determine to which tag type the current line number belongs to using the
3116 " tag type start line number and the number of tags in a tag type
3118 while i <= s:tlist_{ftype}_count
3119 let ttype = s:tlist_{ftype}_{i}_name
3121 \ s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
3122 let end = start_lnum + s:tlist_{a:fidx}_{ttype}_count
3123 if a:lnum >= start_lnum && a:lnum <= end
3129 " Current line doesn't belong to any of the displayed tag types
3130 if i > s:tlist_{ftype}_count
3137 " Tlist_Window_Get_Tag_Index()
3138 " Return the tag index for the specified line in the taglist window
3139 function! s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3140 let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(a:fidx, a:lnum)
3142 " Current line doesn't belong to any of the displayed tag types
3147 " Compute the index into the displayed tags for the tag type
3148 let ttype_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
3149 let tidx = a:lnum - ttype_lnum
3154 " Get the corresponding tag line and return it
3155 return s:tlist_{a:fidx}_{ttype}_{tidx}
3158 " Tlist_Window_Highlight_Line
3159 " Highlight the current line
3160 function! s:Tlist_Window_Highlight_Line()
3161 " Clear previously selected name
3164 " Highlight the current line
3165 if g:Tlist_Display_Prototype == 0
3166 let pat = '/\%' . line('.') . 'l\s\+\zs.*/'
3168 let pat = '/\%' . line('.') . 'l.*/'
3171 exe 'match TagListTagName ' . pat
3174 " Tlist_Window_Open_File
3175 " Open the specified file in either a new window or an existing window
3176 " and place the cursor at the specified tag pattern
3177 function! s:Tlist_Window_Open_File(win_ctrl, filename, tagpat)
3178 call s:Tlist_Log_Msg('Tlist_Window_Open_File (' . a:filename . ',' .
3180 let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh
3181 let s:Tlist_Skip_Refresh = 1
3183 if s:tlist_app_name == "winmanager"
3184 " Let the winmanager edit the file
3185 call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin')
3188 if a:win_ctrl == 'newtab'
3190 exe 'tabnew ' . escape(a:filename, ' ')
3191 " Open the taglist window in the new tab
3192 call s:Tlist_Window_Open()
3195 if a:win_ctrl == 'checktab'
3196 " Check whether the file is present in any of the tabs.
3197 " If the file is present in the current tab, then use the
3199 if bufwinnr(a:filename) != -1
3200 let file_present_in_tab = 1
3204 let bnum = bufnr(a:filename)
3205 let file_present_in_tab = 0
3206 while i <= tabpagenr('$')
3207 if index(tabpagebuflist(i), bnum) != -1
3208 let file_present_in_tab = 1
3215 if file_present_in_tab
3216 " Goto the tab containing the file
3220 exe 'tabnew ' . escape(a:filename, ' ')
3222 " Open the taglist window
3223 call s:Tlist_Window_Open()
3228 if a:win_ctrl == 'prevwin'
3229 " Open the file in the previous window, if it is usable
3230 let cur_win = winnr()
3232 if &buftype == '' && !&previewwindow
3233 exe "edit " . escape(a:filename, ' ')
3234 let winnum = winnr()
3236 " Previous window is not usable
3237 exe cur_win . 'wincmd w'
3241 " Goto the window containing the file. If the window is not there, open a
3244 let winnum = bufwinnr(a:filename)
3248 " Locate the previously used window for opening a file
3250 let first_usable_win = 0
3253 let bnum = winbufnr(i)
3255 if getwinvar(i, 'tlist_file_window') == 'yes'
3259 if first_usable_win == 0 &&
3260 \ getbufvar(bnum, '&buftype') == '' &&
3261 \ !getwinvar(i, '&previewwindow')
3262 " First non-taglist, non-plugin and non-preview window
3263 let first_usable_win = i
3266 let bnum = winbufnr(i)
3269 " If a previously used window is not found, then use the first
3270 " non-taglist window
3272 let fwin_num = first_usable_win
3276 " Jump to the file window
3277 exe fwin_num . "wincmd w"
3279 " If the user asked to jump to the tag in a new window, then split
3280 " the existing window into two.
3281 if a:win_ctrl == 'newwin'
3284 exe "edit " . escape(a:filename, ' ')
3287 if g:Tlist_Use_Horiz_Window
3288 exe 'leftabove split ' . escape(a:filename, ' ')
3290 if winbufnr(2) == -1
3291 " Only the taglist window is present
3292 if g:Tlist_Use_Right_Window
3293 exe 'leftabove vertical split ' .
3294 \ escape(a:filename, ' ')
3296 exe 'rightbelow vertical split ' .
3297 \ escape(a:filename, ' ')
3300 " Go to the taglist window to change the window size to
3301 " the user configured value
3302 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3303 if g:Tlist_Use_Horiz_Window
3304 exe 'resize ' . g:Tlist_WinHeight
3306 exe 'vertical resize ' . g:Tlist_WinWidth
3308 " Go back to the file window
3309 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3311 " A plugin or help window is also present
3313 exe 'leftabove split ' . escape(a:filename, ' ')
3317 " Mark the window, so that it can be reused.
3318 call s:Tlist_Window_Mark_File_Window()
3321 " If the file is opened in more than one window, then check
3322 " whether the last accessed window has the selected file.
3323 " If it does, then use that window.
3324 let lastwin_bufnum = winbufnr(winnr('#'))
3325 if bufnr(a:filename) == lastwin_bufnum
3326 let winnum = winnr('#')
3329 exe winnum . 'wincmd w'
3331 " If the user asked to jump to the tag in a new window, then split the
3332 " existing window into two.
3333 if a:win_ctrl == 'newwin'
3341 " Add the current cursor position to the jump list, so that user can
3342 " jump back using the ' and ` marks.
3344 silent call search(a:tagpat, 'w')
3346 " Bring the line to the middle of the window
3349 " If the line is inside a fold, open the fold
3350 if foldclosed('.') != -1
3355 " If the user selects to preview the tag then jump back to the
3357 if a:win_ctrl == 'preview'
3358 " Go back to the taglist window
3359 let winnum = bufwinnr(g:TagList_title)
3360 exe winnum . 'wincmd w'
3362 " If the user has selected to close the taglist window, when a
3363 " tag is selected, close the taglist window
3364 if g:Tlist_Close_On_Select
3365 call s:Tlist_Window_Goto_Window()
3368 " Go back to the window displaying the selected file
3369 let wnum = bufwinnr(a:filename)
3370 if wnum != -1 && wnum != winnr()
3371 call s:Tlist_Exe_Cmd_No_Acmds(wnum . 'wincmd w')
3376 let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh
3379 " Tlist_Window_Jump_To_Tag()
3380 " Jump to the location of the current tag
3381 " win_ctrl == useopen - Reuse the existing file window
3382 " win_ctrl == newwin - Open a new window
3383 " win_ctrl == preview - Preview the tag
3384 " win_ctrl == prevwin - Open in previous window
3385 " win_ctrl == newtab - Open in new tab
3386 function! s:Tlist_Window_Jump_To_Tag(win_ctrl)
3387 call s:Tlist_Log_Msg('Tlist_Window_Jump_To_Tag(' . a:win_ctrl . ')')
3388 " Do not process comment lines and empty lines
3389 let curline = getline('.')
3390 if curline =~ '^\s*$' || curline[0] == '"'
3394 " If inside a closed fold, then use the first line of the fold
3395 " and jump to the file.
3396 let lnum = foldclosed('.')
3398 " Jump to the selected tag or file
3399 let lnum = line('.')
3401 " Open the closed fold
3405 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
3410 " Get the tag output for the current tag
3411 let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3413 let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx)
3415 " Highlight the tagline
3416 call s:Tlist_Window_Highlight_Line()
3418 " Selected a line which is not a tag name. Just edit the file
3422 call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat)
3425 " Tlist_Window_Show_Info()
3426 " Display information about the entry under the cursor
3427 function! s:Tlist_Window_Show_Info()
3428 call s:Tlist_Log_Msg('Tlist_Window_Show_Info()')
3430 " Clear the previously displayed line
3433 " Do not process comment lines and empty lines
3434 let curline = getline('.')
3435 if curline =~ '^\s*$' || curline[0] == '"'
3439 " If inside a fold, then don't display the prototype
3440 if foldclosed('.') != -1
3444 let lnum = line('.')
3446 " Get the file index
3447 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
3452 if lnum == s:tlist_{fidx}_start
3453 " Cursor is on a file name
3454 let fname = s:tlist_{fidx}_filename
3455 if strlen(fname) > 50
3456 let fname = fnamemodify(fname, ':t')
3458 echo fname . ', Filetype=' . s:tlist_{fidx}_filetype .
3459 \ ', Tag count=' . s:tlist_{fidx}_tag_count
3463 " Get the tag output line for the current tag
3464 let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3466 " Cursor is on a tag type
3467 let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
3474 let ftype = s:tlist_{fidx}_filetype
3476 while i <= s:tlist_{ftype}_count
3477 if ttype == s:tlist_{ftype}_{i}_name
3478 let ttype_name = s:tlist_{ftype}_{i}_fullname
3484 echo 'Tag type=' . ttype_name .
3485 \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count
3489 " Get the tag search pattern and display it
3490 echo s:Tlist_Get_Tag_Prototype(fidx, tidx)
3493 " Tlist_Find_Nearest_Tag_Idx
3494 " Find the tag idx nearest to the supplied line number
3495 " Returns -1, if a tag couldn't be found for the specified line number
3496 function! s:Tlist_Find_Nearest_Tag_Idx(fidx, linenum)
3497 let sort_type = s:tlist_{a:fidx}_sort_type
3500 let right = s:tlist_{a:fidx}_tag_count
3502 if sort_type == 'order'
3503 " Tags sorted by order, use a binary search.
3504 " The idea behind this function is taken from the ctags.vim script (by
3505 " Alexey Marinichev) available at the Vim online website.
3507 " If the current line is the less than the first tag, then no need to
3509 let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1)
3511 if a:linenum < first_lnum
3516 let middle = (right + left + 1) / 2
3517 let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle)
3519 if middle_lnum == a:linenum
3524 if middle_lnum > a:linenum
3525 let right = middle - 1
3531 " Tags sorted by name, use a linear search. (contributed by Dave
3533 " Look for a tag with a line number less than or equal to the supplied
3534 " line number. If multiple tags are found, then use the tag with the
3535 " line number closest to the supplied line number. IOW, use the tag
3536 " with the highest line number.
3537 let closest_lnum = 0
3540 let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left)
3542 if lnum < a:linenum && lnum > closest_lnum
3543 let closest_lnum = lnum
3544 let final_left = left
3545 elseif lnum == a:linenum
3546 let closest_lnum = lnum
3547 let final_left = left
3553 if closest_lnum == 0
3557 let left = final_left
3564 " Tlist_Window_Highlight_Tag()
3565 " Highlight the current tag
3566 " cntx == 1, Called by the taglist plugin itself
3567 " cntx == 2, Forced by the user through the TlistHighlightTag command
3568 " center = 1, move the tag line to the center of the taglist window
3569 function! s:Tlist_Window_Highlight_Tag(filename, cur_lnum, cntx, center)
3570 " Highlight the current tag only if the user configured the
3571 " taglist plugin to do so or if the user explictly invoked the
3572 " command to highlight the current tag.
3573 if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1
3581 " Make sure the taglist window is present
3582 let winnum = bufwinnr(g:TagList_title)
3584 call s:Tlist_Warning_Msg('Error: Taglist window is not open')
3588 let fidx = s:Tlist_Get_File_Index(a:filename)
3593 " If the file is currently not displayed in the taglist window, then retrn
3594 if !s:tlist_{fidx}_visible
3598 " If there are no tags for this file, then no need to proceed further
3599 if s:tlist_{fidx}_tag_count == 0
3603 " Ignore all autocommands
3604 let old_ei = &eventignore
3607 " Save the original window number
3608 let org_winnr = winnr()
3610 if org_winnr == winnum
3611 let in_taglist_window = 1
3613 let in_taglist_window = 0
3616 " Go to the taglist window
3617 if !in_taglist_window
3618 exe winnum . 'wincmd w'
3621 " Clear previously selected name
3624 let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum)
3626 " Make sure the current tag line is visible in the taglist window.
3627 " Calling the winline() function makes the line visible. Don't know
3628 " of a better way to achieve this.
3629 let lnum = line('.')
3631 if lnum < s:tlist_{fidx}_start || lnum > s:tlist_{fidx}_end
3632 " Move the cursor to the beginning of the file
3633 exe s:tlist_{fidx}_start
3636 if foldclosed('.') != -1
3642 if !in_taglist_window
3643 exe org_winnr . 'wincmd w'
3646 " Restore the autocommands
3647 let &eventignore = old_ei
3651 " Extract the tag type
3652 let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
3654 " Compute the line number
3655 " Start of file + Start of tag type + offset
3656 let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset +
3657 \ s:tlist_{fidx}_{tidx}_ttype_idx
3659 " Goto the line containing the tag
3663 if foldclosed('.') != -1
3668 " Move the tag line to the center of the taglist window
3671 " Make sure the current tag line is visible in the taglist window.
3672 " Calling the winline() function makes the line visible. Don't know
3673 " of a better way to achieve this.
3677 " Highlight the tag name
3678 call s:Tlist_Window_Highlight_Line()
3680 " Go back to the original window
3681 if !in_taglist_window
3682 exe org_winnr . 'wincmd w'
3685 " Restore the autocommands
3686 let &eventignore = old_ei
3690 " Tlist_Get_Tag_Prototype_By_Line
3691 " Get the prototype for the tag on or before the specified line number in the
3693 function! Tlist_Get_Tag_Prototype_By_Line(...)
3695 " Arguments are not supplied. Use the current buffer name
3697 let filename = bufname('%')
3698 let linenr = line('.')
3700 " Filename and line number are specified
3704 " Invalid line number
3708 " Sufficient arguments are not supplied
3709 let msg = 'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' .
3711 call s:Tlist_Warning_Msg(msg)
3715 " Expand the file to a fully qualified name
3716 let filename = fnamemodify(filename, ':p')
3721 let fidx = s:Tlist_Get_File_Index(filename)
3726 " If there are no tags for this file, then no need to proceed further
3727 if s:tlist_{fidx}_tag_count == 0
3731 " Get the tag text using the line number
3732 let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
3737 return s:Tlist_Get_Tag_Prototype(fidx, tidx)
3740 " Tlist_Get_Tagname_By_Line
3741 " Get the tag name on or before the specified line number in the
3743 function! Tlist_Get_Tagname_By_Line(...)
3745 " Arguments are not supplied. Use the current buffer name
3747 let filename = bufname('%')
3748 let linenr = line('.')
3750 " Filename and line number are specified
3754 " Invalid line number
3758 " Sufficient arguments are not supplied
3759 let msg = 'Usage: Tlist_Get_Tagname_By_Line <filename> <line_number>'
3760 call s:Tlist_Warning_Msg(msg)
3764 " Make sure the current file has a name
3765 let filename = fnamemodify(filename, ':p')
3770 let fidx = s:Tlist_Get_File_Index(filename)
3775 " If there are no tags for this file, then no need to proceed further
3776 if s:tlist_{fidx}_tag_count == 0
3780 " Get the tag name using the line number
3781 let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
3786 return s:tlist_{fidx}_{tidx}_tag_name
3789 " Tlist_Window_Move_To_File
3790 " Move the cursor to the beginning of the current file or the next file
3791 " or the previous file in the taglist window
3792 " dir == -1, move to start of current or previous function
3793 " dir == 1, move to start of next function
3794 function! s:Tlist_Window_Move_To_File(dir)
3795 if foldlevel('.') == 0
3796 " Cursor is on a non-folded line (it is not in any of the files)
3797 " Move it to a folded line
3801 " While moving down to the start of the next fold,
3802 " no need to do go to the start of the next file.
3808 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
3813 let cur_lnum = line('.')
3816 if cur_lnum > s:tlist_{fidx}_start
3817 " Move to the beginning of the current file
3818 exe s:tlist_{fidx}_start
3823 " Move to the beginning of the previous file
3826 " Cursor is at the first file, wrap around to the last file
3827 let fidx = s:tlist_file_count - 1
3830 exe s:tlist_{fidx}_start
3833 " Move to the beginning of the next file
3836 if fidx >= s:tlist_file_count
3837 " Cursor is at the last file, wrap around to the first file
3841 if s:tlist_{fidx}_start != 0
3842 exe s:tlist_{fidx}_start
3848 " Tlist_Session_Load
3849 " Load a taglist session (information about all the displayed files
3850 " and the tags) from the specified file
3851 function! s:Tlist_Session_Load(...)
3852 if a:0 == 0 || a:1 == ''
3853 call s:Tlist_Warning_Msg('Usage: TlistSessionLoad <filename>')
3857 let sessionfile = a:1
3859 if !filereadable(sessionfile)
3860 let msg = 'Taglist: Error - Unable to open file ' . sessionfile
3861 call s:Tlist_Warning_Msg(msg)
3865 " Mark the current window as the file window
3866 call s:Tlist_Window_Mark_File_Window()
3868 " Source the session file
3869 exe 'source ' . sessionfile
3871 let new_file_count = g:tlist_file_count
3872 unlet! g:tlist_file_count
3875 while i < new_file_count
3876 let ftype = g:tlist_{i}_filetype
3877 unlet! g:tlist_{i}_filetype
3879 if !exists('s:tlist_' . ftype . '_count')
3880 if s:Tlist_FileType_Init(ftype) == 0
3886 let fname = g:tlist_{i}_filename
3887 unlet! g:tlist_{i}_filename
3889 let fidx = s:Tlist_Get_File_Index(fname)
3891 let s:tlist_{fidx}_visible = 0
3895 " As we are loading the tags from the session file, if this
3896 " file was previously deleted by the user, now we need to
3897 " add it back. So remove the file from the deleted list.
3898 call s:Tlist_Update_Remove_List(fname, 0)
3901 let fidx = s:Tlist_Init_File(fname, ftype)
3903 let s:tlist_{fidx}_filename = fname
3905 let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type
3906 unlet! g:tlist_{i}_sort_type
3908 let s:tlist_{fidx}_filetype = ftype
3909 let s:tlist_{fidx}_mtime = getftime(fname)
3911 let s:tlist_{fidx}_start = 0
3912 let s:tlist_{fidx}_end = 0
3914 let s:tlist_{fidx}_valid = 1
3916 let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count
3917 unlet! g:tlist_{i}_tag_count
3920 while j <= s:tlist_{fidx}_tag_count
3921 let s:tlist_{fidx}_{j}_tag = g:tlist_{i}_{j}_tag
3922 let s:tlist_{fidx}_{j}_tag_name = g:tlist_{i}_{j}_tag_name
3923 let s:tlist_{fidx}_{j}_ttype_idx = g:tlist_{i}_{j}_ttype_idx
3924 unlet! g:tlist_{i}_{j}_tag
3925 unlet! g:tlist_{i}_{j}_tag_name
3926 unlet! g:tlist_{i}_{j}_ttype_idx
3931 while j <= s:tlist_{ftype}_count
3932 let ttype = s:tlist_{ftype}_{j}_name
3934 if exists('g:tlist_' . i . '_' . ttype)
3935 let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype}
3936 unlet! g:tlist_{i}_{ttype}
3937 let s:tlist_{fidx}_{ttype}_offset = 0
3938 let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count
3939 unlet! g:tlist_{i}_{ttype}_count
3942 while k <= s:tlist_{fidx}_{ttype}_count
3943 let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k}
3944 unlet! g:tlist_{i}_{ttype}_{k}
3948 let s:tlist_{fidx}_{ttype} = ''
3949 let s:tlist_{fidx}_{ttype}_offset = 0
3950 let s:tlist_{fidx}_{ttype}_count = 0
3959 " If the taglist window is open, then update it
3960 let winnum = bufwinnr(g:TagList_title)
3962 let save_winnr = winnr()
3964 " Goto the taglist window
3965 call s:Tlist_Window_Goto_Window()
3967 " Refresh the taglist window
3968 call s:Tlist_Window_Refresh()
3970 " Go back to the original window
3971 if save_winnr != winnr()
3972 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3977 " Tlist_Session_Save
3978 " Save a taglist session (information about all the displayed files
3979 " and the tags) into the specified file
3980 function! s:Tlist_Session_Save(...)
3981 if a:0 == 0 || a:1 == ''
3982 call s:Tlist_Warning_Msg('Usage: TlistSessionSave <filename>')
3986 let sessionfile = a:1
3988 if s:tlist_file_count == 0
3989 " There is nothing to save
3990 call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.')
3994 if filereadable(sessionfile)
3995 let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?')
4003 let old_verbose = &verbose
4006 exe 'redir! > ' . sessionfile
4008 silent! echo '" Taglist session file. This file is auto-generated.'
4009 silent! echo '" File information'
4010 silent! echo 'let tlist_file_count = ' . s:tlist_file_count
4014 while i < s:tlist_file_count
4015 " Store information about the file
4016 silent! echo 'let tlist_' . i . "_filename = '" .
4017 \ s:tlist_{i}_filename . "'"
4018 silent! echo 'let tlist_' . i . '_sort_type = "' .
4019 \ s:tlist_{i}_sort_type . '"'
4020 silent! echo 'let tlist_' . i . '_filetype = "' .
4021 \ s:tlist_{i}_filetype . '"'
4022 silent! echo 'let tlist_' . i . '_tag_count = ' .
4023 \ s:tlist_{i}_tag_count
4024 " Store information about all the tags
4026 while j <= s:tlist_{i}_tag_count
4027 let txt = escape(s:tlist_{i}_{j}_tag, '"\\')
4028 silent! echo 'let tlist_' . i . '_' . j . '_tag = "' . txt . '"'
4029 silent! echo 'let tlist_' . i . '_' . j . '_tag_name = "' .
4030 \ s:tlist_{i}_{j}_tag_name . '"'
4031 silent! echo 'let tlist_' . i . '_' . j . '_ttype_idx' . ' = ' .
4032 \ s:tlist_{i}_{j}_ttype_idx
4036 " Store information about all the tags grouped by their type
4037 let ftype = s:tlist_{i}_filetype
4039 while j <= s:tlist_{ftype}_count
4040 let ttype = s:tlist_{ftype}_{j}_name
4041 if s:tlist_{i}_{ttype}_count != 0
4042 let txt = escape(s:tlist_{i}_{ttype}, '"\')
4043 let txt = substitute(txt, "\n", "\\\\n", 'g')
4044 silent! echo 'let tlist_' . i . '_' . ttype . ' = "' .
4046 silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' .
4047 \ s:tlist_{i}_{ttype}_count
4049 while k <= s:tlist_{i}_{ttype}_count
4050 silent! echo 'let tlist_' . i . '_' . ttype . '_' . k .
4051 \ ' = ' . s:tlist_{i}_{ttype}_{k}
4065 let &verbose = old_verbose
4068 " Tlist_Buffer_Removed
4069 " A buffer is removed from the Vim buffer list. Remove the tags defined
4071 function! s:Tlist_Buffer_Removed(filename)
4072 call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename . ')')
4074 " Make sure a valid filename is supplied
4079 " Get tag list index of the specified file
4080 let fidx = s:Tlist_Get_File_Index(a:filename)
4082 " File not present in the taglist
4086 " Remove the file from the list
4087 call s:Tlist_Remove_File(fidx, 0)
4090 " When a buffer is deleted, remove the file from the taglist
4091 autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand('<afile>:p'))
4093 " Tlist_Window_Open_File_Fold
4094 " Open the fold for the specified file and close the fold for all the
4096 function! s:Tlist_Window_Open_File_Fold(acmd_bufnr)
4097 call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')')
4099 " Make sure the taglist window is present
4100 let winnum = bufwinnr(g:TagList_title)
4102 call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open')
4106 " Save the original window number
4107 let org_winnr = winnr()
4108 if org_winnr == winnum
4109 let in_taglist_window = 1
4111 let in_taglist_window = 0
4114 if in_taglist_window
4115 " When entering the taglist window, no need to update the folds
4119 " Go to the taglist window
4120 if !in_taglist_window
4121 call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
4124 " Close all the folds
4127 " Get tag list index of the specified file
4128 let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p')
4129 if filereadable(fname)
4130 let fidx = s:Tlist_Get_File_Index(fname)
4132 " Open the fold for the file
4133 exe "silent! " . s:tlist_{fidx}_start . "," .
4134 \ s:tlist_{fidx}_end . "foldopen"
4138 " Go back to the original window
4139 if !in_taglist_window
4140 call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w')
4144 " Tlist_Window_Check_Auto_Open
4145 " Open the taglist window automatically on Vim startup.
4146 " Open the window only when files present in any of the Vim windows support
4148 function! s:Tlist_Window_Check_Auto_Open()
4152 let buf_num = winbufnr(i)
4154 let filename = fnamemodify(bufname(buf_num), ':p')
4155 let ft = s:Tlist_Get_Buffer_Filetype(buf_num)
4156 if !s:Tlist_Skip_File(filename, ft)
4161 let buf_num = winbufnr(i)
4165 call s:Tlist_Window_Toggle()
4169 " Tlist_Refresh_Folds
4170 " Remove and create the folds for all the files displayed in the taglist
4171 " window. Used after entering a tab. If this is not done, then the folds
4172 " are not properly created for taglist windows displayed in multiple tabs.
4173 function! s:Tlist_Refresh_Folds()
4174 let winnum = bufwinnr(g:TagList_title)
4179 let save_wnum = winnr()
4180 exe winnum . 'wincmd w'
4182 " First remove all the existing folds
4185 " Create the folds for each in the tag list
4187 while fidx < s:tlist_file_count
4188 let ftype = s:tlist_{fidx}_filetype
4190 " Create the folds for each tag type in a file
4192 while j <= s:tlist_{ftype}_count
4193 let ttype = s:tlist_{ftype}_{j}_name
4194 if s:tlist_{fidx}_{ttype}_count
4195 let s = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset
4196 let e = s + s:tlist_{fidx}_{ttype}_count
4197 exe s . ',' . e . 'fold'
4202 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
4203 exe 'silent! ' . s:tlist_{fidx}_start . ',' .
4204 \ s:tlist_{fidx}_end . 'foldopen!'
4208 exe save_wnum . 'wincmd w'
4211 function! s:Tlist_Menu_Add_Base_Menu()
4212 call s:Tlist_Log_Msg('Adding the base menu')
4215 anoremenu <silent> T&ags.Refresh\ menu :call <SID>Tlist_Menu_Refresh()<CR>
4216 anoremenu <silent> T&ags.Sort\ menu\ by.Name
4217 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
4218 anoremenu <silent> T&ags.Sort\ menu\ by.Order
4219 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
4220 anoremenu T&ags.-SEP1- :
4222 if &mousemodel =~ 'popup'
4223 anoremenu <silent> PopUp.T&ags.Refresh\ menu
4224 \ :call <SID>Tlist_Menu_Refresh()<CR>
4225 anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Name
4226 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
4227 anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Order
4228 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
4229 anoremenu PopUp.T&ags.-SEP1- :
4233 let s:menu_char_prefix =
4234 \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
4236 " Tlist_Menu_Get_Tag_Type_Cmd
4237 " Get the menu command for the specified tag type
4238 " fidx - File type index
4240 " add_ttype_name - To add or not to add the tag type name to the menu entries
4241 " ttype_idx - Tag type index
4242 function! s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, ttype_idx)
4243 " Curly brace variable name optimization
4244 let ftype_ttype_idx = a:ftype . '_' . a:ttype_idx
4246 let ttype = s:tlist_{ftype_ttype_idx}_name
4248 " If the tag type name contains space characters, escape it. This
4249 " will be used to create the menu entries.
4250 let ttype_fullname = escape(s:tlist_{ftype_ttype_idx}_fullname, ' ')
4253 " Curly brace variable name optimization
4254 let fidx_ttype = a:fidx . '_' . ttype
4256 " Number of tag entries for this tag type
4257 let tcnt = s:tlist_{fidx_ttype}_count
4258 if tcnt == 0 " No entries for this tag type
4264 " Create the menu items for the tags.
4265 " Depending on the number of tags of this type, split the menu into
4266 " multiple sub-menus, if needed.
4267 if tcnt > g:Tlist_Max_Submenu_Items
4270 let final_index = j + g:Tlist_Max_Submenu_Items - 1
4271 if final_index > tcnt
4272 let final_index = tcnt
4275 " Extract the first and last tag name and form the
4277 let tidx = s:tlist_{fidx_ttype}_{j}
4278 let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name
4280 let tidx = s:tlist_{fidx_ttype}_{final_index}
4281 let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name
4283 " Truncate the names, if they are greater than the
4285 let first_tag = strpart(first_tag, 0, g:Tlist_Max_Tag_Length)
4286 let last_tag = strpart(last_tag, 0, g:Tlist_Max_Tag_Length)
4288 " Form the menu command prefix
4289 let m_prefix = 'anoremenu <silent> T\&ags.'
4291 let m_prefix = m_prefix . ttype_fullname . '.'
4293 let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.'
4295 " Character prefix used to number the menu items (hotkey)
4296 let m_prefix_idx = 0
4298 while j <= final_index
4299 let tidx = s:tlist_{fidx_ttype}_{j}
4301 let tname = s:tlist_{a:fidx}_{tidx}_tag_name
4303 let mcmd = mcmd . m_prefix . '\&' .
4304 \ s:menu_char_prefix[m_prefix_idx] . '\.' .
4305 \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' .
4308 let m_prefix_idx = m_prefix_idx + 1
4313 " Character prefix used to number the menu items (hotkey)
4314 let m_prefix_idx = 0
4316 let m_prefix = 'anoremenu <silent> T\&ags.'
4318 let m_prefix = m_prefix . ttype_fullname . '.'
4322 let tidx = s:tlist_{fidx_ttype}_{j}
4324 let tname = s:tlist_{a:fidx}_{tidx}_tag_name
4326 let mcmd = mcmd . m_prefix . '\&' .
4327 \ s:menu_char_prefix[m_prefix_idx] . '\.' .
4328 \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . tidx
4331 let m_prefix_idx = m_prefix_idx + 1
4339 " Update the taglist menu with the tags for the specified file
4340 function! s:Tlist_Menu_File_Refresh(fidx)
4341 call s:Tlist_Log_Msg('Refreshing the tag menu for ' . s:tlist_{a:fidx}_filename)
4342 " The 'B' flag is needed in the 'cpoptions' option
4343 let old_cpoptions = &cpoptions
4346 exe s:tlist_{a:fidx}_menu_cmd
4348 " Update the popup menu (if enabled)
4349 if &mousemodel =~ 'popup'
4350 let cmd = substitute(s:tlist_{a:fidx}_menu_cmd, ' T\\&ags\.',
4351 \ ' PopUp.T\\\&ags.', "g")
4355 " The taglist menu is not empty now
4356 let s:tlist_menu_empty = 0
4358 " Restore the 'cpoptions' settings
4359 let &cpoptions = old_cpoptions
4362 " Tlist_Menu_Update_File
4363 " Add the taglist menu
4364 function! s:Tlist_Menu_Update_File(clear_menu)
4365 if !has('gui_running')
4366 " Not running in GUI mode
4370 call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu)
4372 " Remove the tags menu
4374 call s:Tlist_Menu_Remove_File()
4378 " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
4383 let filename = fnamemodify(bufname('%'), ':p')
4384 let ftype = s:Tlist_Get_Buffer_Filetype('%')
4386 " If the file doesn't support tag listing, skip it
4387 if s:Tlist_Skip_File(filename, ftype)
4391 let fidx = s:Tlist_Get_File_Index(filename)
4392 if fidx == -1 || !s:tlist_{fidx}_valid
4393 " Check whether this file is removed based on user request
4394 " If it is, then don't display the tags for this file
4395 if s:Tlist_User_Removed_File(filename)
4399 " Process the tags for the file
4400 let fidx = s:Tlist_Process_File(filename, ftype)
4406 let fname = escape(fnamemodify(bufname('%'), ':t'), '.')
4408 exe 'anoremenu T&ags.' . fname . ' <Nop>'
4409 anoremenu T&ags.-SEP2- :
4412 if !s:tlist_{fidx}_tag_count
4416 if s:tlist_{fidx}_menu_cmd != ''
4417 " Update the menu with the cached command
4418 call s:Tlist_Menu_File_Refresh(fidx)
4423 " We are going to add entries to the tags menu, so the menu won't be
4425 let s:tlist_menu_empty = 0
4429 " Determine whether the tag type name needs to be added to the menu
4430 " If more than one tag type is present in the taglisting for a file,
4431 " then the tag type name needs to be present
4432 let add_ttype_name = -1
4434 while i <= s:tlist_{ftype}_count && add_ttype_name < 1
4435 let ttype = s:tlist_{ftype}_{i}_name
4436 if s:tlist_{fidx}_{ttype}_count
4437 let add_ttype_name = add_ttype_name + 1
4442 " Process the tags by the tag type and get the menu command
4444 while i <= s:tlist_{ftype}_count
4445 let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i)
4447 let cmd = cmd . mcmd
4453 " Cache the menu command for reuse
4454 let s:tlist_{fidx}_menu_cmd = cmd
4457 call s:Tlist_Menu_File_Refresh(fidx)
4460 " Tlist_Menu_Remove_File
4461 " Remove the tags displayed in the tags menu
4462 function! s:Tlist_Menu_Remove_File()
4463 if !has('gui_running') || s:tlist_menu_empty
4467 call s:Tlist_Log_Msg('Removing the tags menu for a file')
4469 " Cleanup the Tags menu
4470 silent! unmenu T&ags
4471 if &mousemodel =~ 'popup'
4472 silent! unmenu PopUp.T&ags
4475 " Add a dummy menu item to retain teared off menu
4476 noremenu T&ags.Dummy l
4478 silent! unmenu! T&ags
4479 if &mousemodel =~ 'popup'
4480 silent! unmenu! PopUp.T&ags
4483 call s:Tlist_Menu_Add_Base_Menu()
4485 " Remove the dummy menu item
4488 let s:tlist_menu_empty = 1
4491 " Tlist_Menu_Refresh
4492 " Refresh the taglist menu
4493 function! s:Tlist_Menu_Refresh()
4494 call s:Tlist_Log_Msg('Refreshing the tags menu')
4495 let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
4497 " Invalidate the cached menu command
4498 let s:tlist_{fidx}_menu_cmd = ''
4501 " Update the taglist, menu and window
4502 call s:Tlist_Update_Current_File()
4505 " Tlist_Menu_Jump_To_Tag
4506 " Jump to the selected tag
4507 function! s:Tlist_Menu_Jump_To_Tag(tidx)
4508 let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
4513 let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx)
4518 " Add the current cursor position to the jump list, so that user can
4519 " jump back using the ' and ` marks.
4522 silent call search(tagpat, 'w')
4524 " Bring the line to the middle of the window
4527 " If the line is inside a fold, open the fold
4528 if foldclosed('.') != -1
4534 " Initialize the taglist menu
4535 function! s:Tlist_Menu_Init()
4536 call s:Tlist_Menu_Add_Base_Menu()
4538 " Automatically add the tags defined in the current file to the menu
4539 augroup TagListMenuCmds
4542 if !g:Tlist_Process_File_Always
4543 autocmd BufEnter * call s:Tlist_Refresh()
4545 autocmd BufLeave * call s:Tlist_Menu_Remove_File()
4548 call s:Tlist_Menu_Update_File(0)
4551 " Tlist_Vim_Session_Load
4552 " Initialize the taglist window/buffer, which is created when loading
4553 " a Vim session file.
4554 function! s:Tlist_Vim_Session_Load()
4555 call s:Tlist_Log_Msg('Tlist_Vim_Session_Load')
4557 " Initialize the taglist window
4558 call s:Tlist_Window_Init()
4560 " Refresh the taglist window
4561 call s:Tlist_Window_Refresh()
4565 " Set the name of the external plugin/application to which taglist
4567 " Taglist plugin is part of another plugin like cream or winmanager.
4568 function! Tlist_Set_App(name)
4573 let s:tlist_app_name = a:name
4576 " Winmanager integration
4578 " Initialization required for integration with winmanager
4579 function! TagList_Start()
4580 " If current buffer is not taglist buffer, then don't proceed
4581 if bufname('%') != '__Tag_List__'
4585 call Tlist_Set_App('winmanager')
4587 " Get the current filename from the winmanager plugin
4588 let bufnum = WinManagerGetLastEditedFile()
4590 let filename = fnamemodify(bufname(bufnum), ':p')
4591 let ftype = s:Tlist_Get_Buffer_Filetype(bufnum)
4594 " Initialize the taglist window, if it is not already initialized
4595 if !exists('s:tlist_window_initialized') || !s:tlist_window_initialized
4596 call s:Tlist_Window_Init()
4597 call s:Tlist_Window_Refresh()
4598 let s:tlist_window_initialized = 1
4601 " Update the taglist window
4603 if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update
4604 call s:Tlist_Window_Refresh_File(filename, ftype)
4609 function! TagList_IsValid()
4613 function! TagList_WrapUp()
4618 let &cpo = s:cpo_save