added submodules and default configuration
[stack/conf/vim.git] / addons / taglist-plus / plugin / taglist-plus.vim
1 " File: taglist-plus.vim
2 " Authors: Jezreel Ng (jezreel AT gmail DOT com)
3 "          Yegappan Lakshmanan (yegappan AT yahoo DOT com)
4 " Version: 1.0
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
14 "            software.
15 "
16 " For more information about using this plugin, after installing the
17 " taglist plugin, use the ":help taglist" command.
18 "
19 " Installation
20 " ------------
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
24 "    preserved):
25 "
26 "       plugin/taglist-plus.vim - main taglist plugin file
27 "       doc/taglist-plus.txt    - documentation (help) file
28 "
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.
40 " 5. Restart Vim.
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.
44 "
45 " ****************** Do not modify after this line ************************
46
47 " Line continuation used here
48 let s:cpo_save = &cpo
49 set cpo&vim
50
51 if !exists('loaded_taglist')
52     " First time loading the taglist plugin
53     "
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
58
59     " The taglist plugin requires the built-in Vim system() function. If this
60     " function is not available, then don't load the plugin.
61     if !exists('*system')
62         echomsg 'Taglist: Vim system() built-in function is not available. ' .
63                     \ 'Plugin is not loaded.'
64         let loaded_taglist = 'no'
65         let &cpo = s:cpo_save
66         finish
67     endif
68
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
73             " as exuberant-ctags
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'
84         else
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'
89             let &cpo = s:cpo_save
90             finish
91         endif
92     endif
93
94
95     " Automatically open the taglist window on Vim startup
96     if !exists('Tlist_Auto_Open')
97         let Tlist_Auto_Open = 0
98     endif
99
100     " When the taglist window is toggle opened, move the cursor to the
101     " taglist window
102     if !exists('Tlist_GainFocus_On_ToggleOpen')
103         let Tlist_GainFocus_On_ToggleOpen = 0
104     endif
105
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
109     endif
110
111     if !exists('Tlist_Show_Menu')
112         let Tlist_Show_Menu = 0
113     endif
114
115     " Tag listing sort type - 'name' or 'order'
116     if !exists('Tlist_Sort_Type')
117         let Tlist_Sort_Type = 'order'
118     endif
119
120     " Tag listing window split (horizontal/vertical) control
121     if !exists('Tlist_Use_Horiz_Window')
122         let Tlist_Use_Horiz_Window = 0
123     endif
124
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
130     endif
131
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
138         else
139             let Tlist_Inc_Winwidth = 1
140         endif
141     endif
142
143     " Vertically split taglist window width setting
144     if !exists('Tlist_WinWidth')
145         let Tlist_WinWidth = 30
146         let s:auto_width = 0
147     elseif Tlist_WinWidth == 'auto'
148         let Tlist_WinWidth = 30
149         let s:auto_width = 1
150     endif
151
152     " Horizontally split taglist window height setting
153     if !exists('Tlist_WinHeight')
154         let Tlist_WinHeight = 10
155     endif
156
157     " Display tag prototypes or tag names in the taglist window
158     if !exists('Tlist_Display_Prototype')
159         let Tlist_Display_Prototype = 0
160     endif
161
162     " Display tag scopes in the taglist window
163     if !exists('Tlist_Display_Tag_Scope')
164         let Tlist_Display_Tag_Scope = 1
165     endif
166
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
171     endif
172
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
175     " tree.
176     if !exists('Tlist_Compact_Format')
177         let Tlist_Compact_Format = 0
178     endif
179
180     " Exit Vim if only the taglist window is currently open. By default, this is
181     " set to zero.
182     if !exists('Tlist_Exit_OnlyWindow')
183         let Tlist_Exit_OnlyWindow = 0
184     endif
185
186     " Automatically close the folds for the non-active files in the taglist
187     " window
188     if !exists('Tlist_File_Fold_Auto_Close')
189         let Tlist_File_Fold_Auto_Close = 0
190     endif
191
192     " Close the taglist window when a tag is selected
193     if !exists('Tlist_Close_On_Select')
194         let Tlist_Close_On_Select = 0
195     endif
196
197     " Automatically update the taglist window to display tags for newly
198     " edited files
199     if !exists('Tlist_Auto_Update')
200         let Tlist_Auto_Update = 1
201     endif
202
203     " Automatically highlight the current tag
204     if !exists('Tlist_Auto_Highlight_Tag')
205         let Tlist_Auto_Highlight_Tag = 1
206     endif
207     
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
211     endif
212
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
216     endif
217
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
221     endif
222
223     if !exists('Tlist_Max_Submenu_Items')
224         let Tlist_Max_Submenu_Items = 20
225     endif
226
227     if !exists('Tlist_Max_Tag_Length')
228         let Tlist_Max_Tag_Length = 10
229     endif
230
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
233     " plugin.
234     let TagList_title = "__Tag_List__"
235
236     " Taglist debug messages
237     let s:tlist_msg = ''
238
239     " Define the taglist autocommand to automatically open the taglist window
240     " on Vim startup
241     if g:Tlist_Auto_Open
242         autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open()
243     endif
244
245     " Refresh the taglist
246     if g:Tlist_Process_File_Always
247         autocmd BufEnter * call s:Tlist_Refresh()
248     endif
249
250     if g:Tlist_Show_Menu
251         autocmd GUIEnter * call s:Tlist_Menu_Init()
252     endif
253
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()
258
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
284
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()
290
291     " Define autocommands to autoload the taglist plugin when needed.
292
293     " Trick to get the current script ID
294     map <SID>xx <SID>xx
295     let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$',
296                                 \ '\1', '')
297     unmap <SID>xx
298
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>'), ' ')
309
310     let loaded_taglist = 'fast_load_done'
311
312     if g:Tlist_Show_Menu && has('gui_running')
313         call s:Tlist_Menu_Init()
314     endif
315
316     " restore 'cpo'
317     let &cpo = s:cpo_save
318     finish
319 endif
320
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.
324     finish
325 endif
326
327 unlet! s:tlist_sid
328
329 if loaded_taglist != 'fast_load_done'
330     " restore 'cpo'
331     let &cpo = s:cpo_save
332     finish
333 endif
334
335 " Taglist plugin functionality is available
336 let loaded_taglist = 'available'
337
338 "------------------- end of user configurable options --------------------
339
340 " Default language specific settings for supported file types and tag types
341 "
342 " Variable name format:
343 "
344 "       s:tlist_def_{vim_ftype}_settings
345
346 " vim_ftype - Filetype detected by Vim
347 "
348 " Value format:
349 "
350 "       <ctags_ftype>;<flag>:<name>;<flag>:<name>;...
351 "
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
355 "               tags of this type
356 "
357
358 " assembly language
359 let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type'
360
361 " aspperl language
362 let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable'
363
364 " aspvbs language
365 let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable'
366
367 " awk language
368 let s:tlist_def_awk_settings = 'awk;f:function'
369
370 " beta language
371 let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern'
372
373 " c language
374 let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' .
375                            \ 'v:variable;f:function'
376
377 " c++ language
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'
380
381 " c# language
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'
385
386 " cobol language
387 let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
388                                \ 'P:program;s:section'
389
390 " eiffel language
391 let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature'
392
393 " erlang language
394 let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function'
395
396 " expect (same as tcl) language
397 let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure'
398
399 " fortran language
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'
403
404 " HTML language
405 let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function'
406
407 " java language
408 let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
409                               \ 'f:field;m:method'
410
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'
415 endif
416 let Tlist_javascript_Ctags_Allowed_Flags = ['-f', '--sort']
417
418 " lisp language
419 let s:tlist_def_lisp_settings = 'lisp;f:function'
420
421 " lua language
422 let s:tlist_def_lua_settings = 'lua;f:function'
423
424 " makefiles
425 let s:tlist_def_make_settings = 'make;m:macro'
426
427 " pascal language
428 let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure'
429
430 " perl language
431 let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine'
432
433 " php language
434 let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function'
435
436 " python language
437 let s:tlist_def_python_settings = 'python;c:class;m:member;f:function'
438
439 " rexx language
440 let s:tlist_def_rexx_settings = 'rexx;s:subroutine'
441
442 " ruby language
443 let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' .
444                               \ 'm:singleton method'
445
446 " scheme language
447 let s:tlist_def_scheme_settings = 'scheme;s:set;f:function'
448
449 " shell language
450 let s:tlist_def_sh_settings = 'sh;f:function'
451
452 " C shell language
453 let s:tlist_def_csh_settings = 'sh;f:function'
454
455 " Z shell language
456 let s:tlist_def_zsh_settings = 'sh;f:function'
457
458 " slang language
459 let s:tlist_def_slang_settings = 'slang;n:namespace;f:function'
460
461 " sml language
462 let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' .
463                              \ 'r:structure;t:type;v:value;f:function'
464
465 " sql language
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'
468
469 " tcl language
470 let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure'
471
472 " vera language
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;' .
476                                 \ 'x:externvar'
477
478 "verilog language
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'
481
482 " vim language
483 let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function'
484
485 " yacc language
486 let s:tlist_def_yacc_settings = 'yacc;l:label'
487
488 "------------------- end of language specific options --------------------
489
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
510
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
517
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
522         " last line
523         call setline('$', ' ')
524     endif
525
526     if s:tlist_brief_help
527         " Add the brief help
528         call append(0, '" Press <F1> to display help text')
529     else
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')
548     endif
549 endfunction
550
551 " Tlist_Window_Toggle_Help_Text()
552 " Toggle taglist plugin help text between the full version and the brief
553 " version
554 function! s:Tlist_Window_Toggle_Help_Text()
555     if g:Tlist_Compact_Format
556         " In compact display mode, do not display help
557         return
558     endif
559
560     " Include the empty line displayed after the help text
561     let brief_help_size = 1
562     let full_help_size = 16
563
564     setlocal modifiable
565
566     " Set report option to a huge value to prevent informational messages
567     " while deleting the lines
568     let old_report = &report
569     set report=99999
570
571     " Remove the currently highlighted tag. Otherwise, the help text
572     " might be highlighted by mistake
573     match none
574
575     " Toggle between brief and full help text
576     if s:tlist_brief_help
577         let s:tlist_brief_help = 0
578
579         " Remove the previous help
580         exe '1,' . brief_help_size . ' delete _'
581
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)
584     else
585         let s:tlist_brief_help = 1
586
587         " Remove the previous help
588         exe '1,' . full_help_size . ' delete _'
589
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)
592     endif
593
594     call s:Tlist_Window_Display_Help()
595
596     " Restore the report option
597     let &report = old_report
598
599     setlocal nomodifiable
600 endfunction
601
602 " Taglist debug support
603 let s:tlist_debug = 0
604
605 " File for storing the debug messages
606 let s:tlist_debug_file = ''
607
608 " Tlist_Debug_Enable
609 " Enable logging of taglist debug messages.
610 function! s:Tlist_Debug_Enable(...)
611     let s:tlist_debug = 1
612
613     " Check whether a valid file name is supplied.
614     if a:1 != ''
615         let s:tlist_debug_file = fnamemodify(a:1, ':p')
616
617         " Empty the log file
618         exe 'redir! > ' . s:tlist_debug_file
619         redir END
620
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 = ''
626         endif
627     endif
628 endfunction
629
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 = ''
635 endfunction
636
637 " Tlist_Debug_Show
638 " Display the taglist debug messages in a new window
639 function! s:Tlist_Debug_Show()
640     if s:tlist_msg == ''
641         call s:Tlist_Warning_Msg('Taglist: No debug messages')
642         return
643     endif
644
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)
648     silent! %delete _
649     " Add the messages
650     silent! put =s:tlist_msg
651     " Move the cursor to the first line
652     normal! gg
653 endfunction
654
655 " Tlist_Log_Msg
656 " Log the supplied debug message along with the time
657 function! s:Tlist_Log_Msg(msg)
658     if s:tlist_debug
659         if s:tlist_debug_file != ''
660             exe 'redir >> ' . s:tlist_debug_file
661             silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n"
662             redir END
663         else
664             " Log the message into a variable
665             " Retain only the last 3000 characters
666             let len = strlen(s:tlist_msg)
667             if len > 3000
668                 let s:tlist_msg = strpart(s:tlist_msg, len - 3000)
669             endif
670             let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' . 
671                         \ a:msg . "\n"
672         endif
673     endif
674 endfunction
675
676 " Tlist_Warning_Msg()
677 " Display a message using WarningMsg highlight group
678 function! s:Tlist_Warning_Msg(msg)
679     echohl WarningMsg
680     echomsg a:msg
681     echohl None
682 endfunction
683
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
687
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 == ''
692         return -1
693     endif
694
695     " If the new filename is same as the last accessed filename, then
696     " return that index
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
702         endif
703     endif
704
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)
708     if i == -1
709         let s:tlist_file_name_idx_cache = -1
710         return -1
711     endif
712
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
717 endfunction
718
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
722
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 . ')')
728
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
736         endif
737     endif
738
739     let fidx = -1
740
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
748             endif
749
750         endif
751     else
752         " Do a binary search in the taglist
753         let left = 0
754         let right = s:tlist_file_count - 1
755
756         while left < right
757             let mid = (left + right) / 2
758
759             if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end
760                 let s:tlist_file_lnum_idx_cache = mid
761                 return mid
762             endif
763
764             if a:lnum < s:tlist_{mid}_start
765                 let right = mid - 1
766             else
767                 let left = mid + 1
768             endif
769         endwhile
770
771         if left >= 0 && left < s:tlist_file_count
772                     \ && a:lnum >= s:tlist_{left}_start
773                     \ && a:lnum <= s:tlist_{left}_end
774             let fidx = left
775         endif
776     endif
777
778     let s:tlist_file_lnum_idx_cache = fidx
779
780     return fidx
781 endfunction
782
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
787     set eventignore=all
788     exe a:cmd
789     let &eventignore = old_eventignore
790 endfunction
791
792 " Tlist_Skip_File()
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 == ''
797         return 1
798     endif
799
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
804     " filetype
805     let var = 's:tlist_def_' . a:ftype . '_settings'
806     if !exists(var)
807         let var = 'g:tlist_' . a:ftype . '_settings'
808         if !exists(var)
809             return 1
810         endif
811     endif
812
813     " Skip files which are not readable or files which are not yet stored
814     " to the disk
815     if !filereadable(a:filename)
816         return 1
817     endif
818
819     return 0
820 endfunction
821
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
826 endfunction
827
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)
833     if a:add
834         let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n"
835     else
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)
841
842         let s:tlist_removed_flist = text_before . text_after
843     endif
844 endfunction
845
846 " Tlist_FileType_Init
847 " Initialize the ctags arguments and tag variable for the specified
848 " file type
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'
854     if exists(var)
855         " User specified ctags arguments
856         let settings = {var} . ';'
857     else
858         " Default ctags arguments
859         let var = 's:tlist_def_' . a:ftype . '_settings'
860         if !exists(var)
861             " No default settings for this file type. This filetype is
862             " not supported
863             return 0
864         endif
865         let settings = s:tlist_def_{a:ftype}_settings . ';'
866     endif
867
868     let msg = 'Taglist: Invalid ctags option setting - ' . settings
869
870     " Format of the option that specifies the filetype and ctags arugments:
871     "
872     "       <language_name>;flag1:name1;flag2:name2;flag3:name3
873     "
874
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, ';')
878     if pos == -1
879         call s:Tlist_Warning_Msg(msg)
880         return 0
881     endif
882     let ctags_ftype = strpart(settings, 0, pos)
883     if ctags_ftype == ''
884         call s:Tlist_Warning_Msg(msg)
885         return 0
886     endif
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
889     " filetype
890     if ctags_ftype =~ ':'
891         call s:Tlist_Warning_Msg(msg)
892         return 0
893     endif
894
895     " Remove the file type from settings
896     let settings = strpart(settings, pos + 1)
897     if settings == ''
898         call s:Tlist_Warning_Msg(msg)
899         return 0
900     endif
901
902     " Process all the specified ctags flags. The format is
903     " flag1:name1;flag2:name2;flag3:name3
904     let ctags_flags = ''
905     let cnt = 0
906     while settings != ''
907         " Extract the flag
908         let pos = stridx(settings, ':')
909         if pos == -1
910             call s:Tlist_Warning_Msg(msg)
911             return 0
912         endif
913         let flag = strpart(settings, 0, pos)
914         if flag == ''
915             call s:Tlist_Warning_Msg(msg)
916             return 0
917         endif
918         " Remove the flag from settings
919         let settings = strpart(settings, pos + 1)
920
921         " Extract the tag type name
922         let pos = stridx(settings, ';')
923         if pos == -1
924             call s:Tlist_Warning_Msg(msg)
925             return 0
926         endif
927         let name = strpart(settings, 0, pos)
928         if name == ''
929             call s:Tlist_Warning_Msg(msg)
930             return 0
931         endif
932         let settings = strpart(settings, pos + 1)
933
934         let cnt = cnt + 1
935
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
939     endwhile
940
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
945
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
949
950     return 1
951 endfunction
952
953 " Tlist_Detect_Filetype
954 " Determine the filetype for the specified file using the filetypedetect
955 " autocmd.
956 function! s:Tlist_Detect_Filetype(fname)
957     " Ignore the filetype autocommands
958     let old_eventignore = &eventignore
959     set eventignore=FileType
960
961     " Save the 'filetype', as this will be changed temporarily
962     let old_filetype = &filetype
963
964     " Run the filetypedetect group of autocommands to determine
965     " the filetype
966     exe 'doautocmd filetypedetect BufRead ' . a:fname
967
968     " Save the detected filetype
969     let ftype = &filetype
970
971     " Restore the previous state
972     let &filetype = old_filetype
973     let &eventignore = old_eventignore
974
975     return ftype
976 endfunction
977
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')
982
983     if bufloaded(a:bnum)
984         " For loaded buffers, the 'filetype' is already determined
985         return buf_ft
986     endif
987
988     " For unloaded buffers, if the 'filetype' option is set, return it
989     if buf_ft != ''
990         return buf_ft
991     endif
992
993     " Skip non-existent buffers
994     if !bufexists(a:bnum)
995         return ''
996     endif
997
998     " For buffers whose filetype is not yet determined, try to determine
999     " the filetype
1000     let bname = bufname(a:bnum)
1001
1002     return s:Tlist_Detect_Filetype(bname)
1003 endfunction
1004
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
1011
1012     " Discard information about the tags defined in the file
1013     let i = 1
1014     while i <= s:tlist_{a:fidx}_tag_count
1015         let fidx_i = 's:tlist_' . a:fidx . '_' . i
1016         unlet! {fidx_i}_tag
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
1023         let i = i + 1
1024     endwhile
1025
1026     let s:tlist_{a:fidx}_tag_count = 0
1027
1028     " Discard information about tag type groups
1029     let i = 1
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
1038             let j = 1
1039             while j <= cnt
1040                 unlet! {fidx_ttype}_{j}
1041                 let j = j + 1
1042             endwhile
1043         endif
1044         let i = i + 1
1045     endwhile
1046
1047     " Discard the stored menu command also
1048     let s:tlist_{a:fidx}_menu_cmd = ''
1049 endfunction
1050
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)
1055     let i = a:start_idx
1056
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
1060             if a:increment
1061                 let s:tlist_{i}_start = s:tlist_{i}_start + a:offset
1062                 let s:tlist_{i}_end = s:tlist_{i}_end + a:offset
1063             else
1064                 let s:tlist_{i}_start = s:tlist_{i}_start - a:offset
1065                 let s:tlist_{i}_end = s:tlist_{i}_end - a:offset
1066             endif
1067         endif
1068         let i = i + 1
1069     endwhile
1070 endfunction
1071
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)
1078
1079     let ftype = s:tlist_{a:fidx}_filetype
1080
1081     let i = 1
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
1087         let i = i + 1
1088     endwhile
1089
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
1100 endfunction
1101
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
1109         return
1110     endif
1111
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
1117     else
1118         let end = s:tlist_{a:fidx}_end + 1
1119     endif
1120
1121     setlocal modifiable
1122     exe 'silent! ' . start . ',' . end . 'delete _'
1123     setlocal nomodifiable
1124
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)
1128 endfunction
1129
1130 " Tlist_Remove_File
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
1135
1136     if fidx == -1
1137         let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
1138         if fidx == -1
1139             return
1140         endif
1141     endif
1142     call s:Tlist_Log_Msg('Tlist_Remove_File (' .
1143                 \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')')
1144
1145     let save_winnr = winnr()
1146     let winnum = bufwinnr(g:TagList_title)
1147     if winnum != -1
1148         " Taglist window is open, remove the file from display
1149
1150         if save_winnr != winnum
1151             let old_eventignore = &eventignore
1152             set eventignore=all
1153             exe winnum . 'wincmd w'
1154         endif
1155
1156         call s:Tlist_Window_Remove_File_From_Display(fidx)
1157
1158         if save_winnr != winnum
1159             exe save_winnr . 'wincmd w'
1160             let &eventignore = old_eventignore
1161         endif
1162     endif
1163
1164     let fname = s:tlist_{fidx}_filename
1165
1166     if a:user_request
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)
1170     endif
1171
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
1179
1180     call s:Tlist_Discard_FileInfo(fidx)
1181
1182     " Shift all the file variables by one index
1183     let i = fidx + 1
1184
1185     while i < s:tlist_file_count
1186         let j = i - 1
1187
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
1198
1199         let k = 1
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)
1208             let k = k + 1
1209         endwhile
1210
1211         let ftype = s:tlist_{i}_filetype
1212
1213         let k = 1
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} != ''
1220                 let l = 1
1221                 while l <= s:tlist_{j}_{ttype}_count
1222                     let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l}
1223                     let l = l + 1
1224                 endwhile
1225             endif
1226             let k = k + 1
1227         endwhile
1228
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)
1232
1233         let i = i + 1
1234     endwhile
1235
1236     " Reduce the number of files displayed
1237     let s:tlist_file_count = s:tlist_file_count - 1
1238
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
1244         endif
1245     endif
1246 endfunction
1247
1248 " Tlist_Window_Goto_Window
1249 " Goto the taglist window
1250 function! s:Tlist_Window_Goto_Window()
1251     let winnum = bufwinnr(g:TagList_title)
1252     if winnum != -1
1253         if winnr() != winnum
1254             call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
1255         endif
1256     endif
1257 endfunction
1258
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)
1265     if winnum != -1
1266         " Jump to the existing window
1267         if winnr() != winnum
1268             exe winnum . 'wincmd w'
1269         endif
1270         return
1271     endif
1272
1273     " If used with winmanager don't open windows. Winmanager will handle
1274     " the window/buffer management
1275     if s:tlist_app_name == "winmanager"
1276         return
1277     endif
1278
1279     " Create a new window. If user prefers a horizontal window, then open
1280     " a horizontally split window. Otherwise open a vertically split
1281     " window
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
1287     else
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()
1296
1297                 " one extra column is needed to include the vertical split
1298                 let &columns= &columns + g:Tlist_WinWidth + 1
1299
1300                 let s:tlist_winsize_chgd = 1
1301             else
1302                 let s:tlist_winsize_chgd = 0
1303             endif
1304         endif
1305
1306         if g:Tlist_Use_Right_Window
1307             " Open the window at the rightmost place
1308             let win_dir = 'botright vertical'
1309         else
1310             " Open the window at the leftmost place
1311             let win_dir = 'topleft vertical'
1312         endif
1313         let win_size = g:Tlist_WinWidth
1314     endif
1315
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)
1319     if bufnum == -1
1320         " Create a new buffer
1321         let wcmd = g:TagList_title
1322     else
1323         " Edit the existing buffer
1324         let wcmd = '+buffer' . bufnum
1325     endif
1326
1327     " Create the taglist window
1328     exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
1329
1330     " Save the new window position
1331     let s:tlist_winx = getwinposx()
1332     let s:tlist_winy = getwinposy()
1333
1334     " Initialize the taglist window
1335     call s:Tlist_Window_Init()
1336 endfunction
1337
1338 " Tlist_Window_Zoom
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
1345         else
1346             exe 'vert resize ' . g:Tlist_WinWidth
1347         endif
1348         let s:tlist_win_maximized = 0
1349     else
1350         " Set the window size to the maximum possible without closing other
1351         " windows
1352         if g:Tlist_Use_Horiz_Window
1353             resize
1354         else
1355             vert resize
1356         endif
1357         let s:tlist_win_maximized = 1
1358     endif
1359 endfunction
1360
1361 " Tlist_Ballon_Expr
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)
1367     if fidx == -1
1368         return ''
1369     endif
1370
1371     " Get the tag output line for the current tag
1372     let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum)
1373     if tidx == 0
1374         return ''
1375     endif
1376
1377     " Get the tag search pattern and display it
1378     return s:Tlist_Get_Tag_Prototype(fidx, tidx)
1379 endfunction
1380
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
1389         return
1390     endif
1391
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')
1399         endif
1400         exe 'vert resize ' . g:Tlist_WinWidth
1401         if save_winnr != tlist_winnr
1402             call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
1403         endif
1404     endif
1405 endfunction
1406
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.
1413     if v:version < 700
1414         if winbufnr(2) == -1
1415             bdelete
1416             quit
1417         endif
1418     else
1419         if winbufnr(2) == -1
1420             if tabpagenr('$') == 1
1421                 " Only one tag page is present
1422                 bdelete
1423                 quit
1424             else
1425                 " More than one tab page is present. Close only the current
1426                 " tab page
1427                 close
1428             endif
1429         endif
1430     endif
1431 endfunction
1432
1433 " Tlist_Window_Init
1434 " Set the default options for the taglist window
1435 function! s:Tlist_Window_Init()
1436     call s:Tlist_Log_Msg('Tlist_Window_Init()')
1437
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
1442     setlocal noreadonly
1443
1444     " Set the taglist buffer filetype to taglist
1445     setlocal filetype=taglist
1446
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
1453
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
1461         else
1462             highlight default link TagListTagName Search
1463         endif
1464         " Colors to highlight comments and titles
1465         if hlexists('MyTagListComment')
1466             highlight link TagListComment MyTagListComment
1467         else
1468             highlight clear TagListComment
1469             highlight default link TagListComment Comment
1470         endif
1471         if hlexists('MyTagListTitle')
1472             highlight link TagListTitle MyTagListTitle
1473         else
1474             highlight clear TagListTitle
1475             highlight default link TagListTitle Title
1476         endif
1477         if hlexists('MyTagListFileName')
1478             highlight link TagListFileName MyTagListFileName
1479         else
1480             highlight clear TagListFileName
1481             highlight default TagListFileName guibg=Grey ctermbg=darkgray
1482                         \ guifg=white ctermfg=white
1483         endif
1484         if hlexists('MyTagListTagScope')
1485             highlight link TagListTagScope1 MyTagListTagScope
1486         else
1487             highlight clear TagListTagScope1
1488             highlight clear TagListTagScope2
1489             highlight default link TagListTagScope1 Identifier
1490             highlight default link TagListTagScope2 Keyword
1491         endif
1492     else
1493         highlight default TagListTagName term=reverse cterm=reverse
1494     endif
1495
1496     " Folding related settings
1497     setlocal foldenable
1498     setlocal foldminlines=0
1499     setlocal foldmethod=manual
1500     setlocal foldlevel=9999
1501     if g:Tlist_Enable_Fold_Column
1502         setlocal foldcolumn=3
1503     else
1504         setlocal foldcolumn=0
1505     endif
1506     setlocal foldtext=v:folddashes.getline(v:foldstart)
1507
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
1513         endif
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
1518         if v:version >= 601
1519             silent! setlocal nobuflisted
1520         endif
1521     endif
1522
1523     silent! setlocal nowrap
1524
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
1527     " window
1528     silent! setlocal nonumber
1529
1530     " Use fixed height when horizontally split window is used
1531     if g:Tlist_Use_Horiz_Window
1532         if v:version >= 602
1533             set winfixheight
1534         endif
1535     endif
1536     if !g:Tlist_Use_Horiz_Window && v:version >= 700
1537         set winfixwidth
1538     endif
1539
1540     " Setup balloon evaluation to display tag prototype
1541     if v:version >= 700 && has('balloon_eval')
1542         setlocal balloonexpr=Tlist_Ballon_Expr()
1543         set ballooneval
1544     endif
1545
1546     " Setup the cpoptions properly for the maps to work
1547     let old_cpoptions = &cpoptions
1548     set cpoptions&vim
1549
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>
1562     if v:version >= 700
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>
1567     endif
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>
1589
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>
1602     if v:version >= 700
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>
1607     endif
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>
1631
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
1645         else
1646             " we have a mapping
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
1652             exe mapcmd
1653         endif
1654     endif
1655
1656     " Define the taglist autocommands
1657     augroup TagListAutoCmds
1658         autocmd!
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)
1664
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>'))
1671         endif
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()
1676         endif
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()
1682         endif
1683
1684         if !g:Tlist_Use_Horiz_Window
1685             if v:version < 700
1686                 autocmd WinEnter * call s:Tlist_Window_Check_Width()
1687             endif
1688         endif
1689         if v:version >= 700
1690             autocmd TabEnter * silent call s:Tlist_Refresh_Folds()
1691         endif
1692     augroup end
1693
1694     " Restore the previous cpoptions settings
1695     let &cpoptions = old_cpoptions
1696 endfunction
1697
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
1705     set report=99999
1706
1707     " Mark the buffer as modifiable
1708     setlocal modifiable
1709
1710     " Delete the contents of the buffer to the black-hole register
1711     silent! %delete _
1712
1713     " As we have cleared the taglist window, mark all the files
1714     " as not visible
1715     let i = 0
1716     while i < s:tlist_file_count
1717         let s:tlist_{i}_visible = 0
1718         let i = i + 1
1719     endwhile
1720
1721     if g:Tlist_Compact_Format == 0
1722         " Display help in non-compact mode
1723         call s:Tlist_Window_Display_Help()
1724     endif
1725
1726     " Mark the buffer as not modifiable
1727     setlocal nomodifiable
1728
1729     " Restore the report option
1730     let &report = old_report
1731
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
1736         return
1737     endif
1738
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.
1743     let i = 0
1744     while i < s:tlist_file_count
1745         call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename,
1746                     \ s:tlist_{i}_filetype)
1747         let i = i + 1
1748     endwhile
1749
1750     if g:Tlist_Auto_Update
1751         " Add and list the tags for all buffers in the Vim buffer list
1752         let i = 1
1753         let last_bufnum = bufnr('$')
1754         while i <= last_bufnum
1755             if buflisted(i)
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)
1761                 endif
1762             endif
1763             let i = i + 1
1764         endwhile
1765     endif
1766
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
1770         silent! %foldclose
1771     endif
1772
1773     if !g:Tlist_Use_Horiz_Window && s:auto_width
1774         exe 'vertical resize '.g:Tlist_WinWidth
1775     endif
1776
1777     " Move the cursor to the top of the taglist window
1778     normal! gg
1779 endfunction
1780
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
1786     let i = 0
1787     while i < s:tlist_file_count
1788         let s:tlist_{i}_visible = 0
1789         let i = i + 1
1790     endwhile
1791
1792     " Remove the taglist autocommands
1793     silent! autocmd! TagListAutoCmds
1794
1795     " Clear all the highlights
1796     match none
1797
1798     silent! syntax clear TagListTitle
1799     silent! syntax clear TagListComment
1800     silent! syntax clear TagListTagScope
1801
1802     " Remove the left mouse click mapping if it was setup initially
1803     if g:Tlist_Use_SingleClick
1804         if hasmapto('<LeftMouse>')
1805             nunmap <LeftMouse>
1806         endif
1807     endif
1808
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
1816     else
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
1823         endif
1824
1825         " Adjust the Vim window width
1826         let &columns= &columns - (g:Tlist_WinWidth + 1)
1827     endif
1828     endif
1829
1830     let s:tlist_winsize_chgd = -1
1831
1832     " Reset taglist state variables
1833     if s:tlist_app_name == "winmanager"
1834         let s:tlist_app_name = "none"
1835     endif
1836     let s:tlist_window_initialized = 0
1837 endfunction
1838
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)
1845     if fidx != -1
1846         let file_listed = 1
1847     else
1848         let file_listed = 0
1849     endif
1850
1851     if !file_listed
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)
1855             return
1856         endif
1857     endif
1858
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
1864
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!"
1869             endif
1870             return
1871         endif
1872
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)
1876     endif
1877
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)
1881         if ret_fidx == -1
1882             return
1883         endif
1884         let fidx = ret_fidx
1885     endif
1886
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
1890     set report=99999
1891
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
1899         endif
1900         let s:tlist_cur_file_idx = fidx
1901     endif
1902
1903     " Mark the buffer as modifiable
1904     setlocal modifiable
1905
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('$')
1912         else
1913             let s:tlist_{fidx}_start = line('$') + 1
1914         endif
1915     endif
1916
1917     let s:tlist_{fidx}_visible = 1
1918
1919     " Goto the line where this file should be placed
1920     if g:Tlist_Compact_Format
1921         exe s:tlist_{fidx}_start
1922     else
1923         exe s:tlist_{fidx}_start - 1
1924     endif
1925
1926     let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' .
1927                 \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')'
1928     if g:Tlist_Compact_Format == 0
1929         silent! put =txt
1930     else
1931         silent! put! =txt
1932         " Move to the next line
1933         exe line('.') + 1
1934     endif
1935     let file_start = s:tlist_{fidx}_start
1936
1937     " Add the tag names grouped by tag type to the buffer with a title
1938     let i = 1
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}
1945         if ttype_txt != ''
1946             let txt = '  ' . s:tlist_{a:ftype}_{i}_fullname
1947             if g:Tlist_Compact_Format == 0
1948                 let ttype_start_lnum = line('.') + 1
1949                 silent! put =txt
1950             else
1951                 let ttype_start_lnum = line('.')
1952                 silent! put! =txt
1953             endif
1954             silent! put =ttype_txt
1955
1956             let {fidx_ttype}_offset = ttype_start_lnum - file_start
1957
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'
1962
1963             " Adjust the cursor position
1964             if g:Tlist_Compact_Format == 0
1965                 exe ttype_start_lnum + {fidx_ttype}_count
1966             else
1967                 exe ttype_start_lnum + {fidx_ttype}_count + 1
1968             endif
1969
1970             if g:Tlist_Compact_Format == 0
1971                 " Separate the tag types by a empty line
1972                 silent! put =''
1973             endif
1974         endif
1975         let i = i + 1
1976     endwhile
1977
1978     if s:tlist_{fidx}_tag_count == 0
1979         if g:Tlist_Compact_Format == 0
1980             silent! put =''
1981         endif
1982     endif
1983
1984     let s:tlist_{fidx}_end = line('.') - 1
1985
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!'
1990
1991     " Goto the starting line for this file,
1992     exe s:tlist_{fidx}_start
1993
1994     if s:tlist_app_name == "winmanager"
1995         " To handle a bug in the winmanager plugin, add a space at the
1996         " last line
1997         call setline('$', ' ')
1998     endif
1999
2000     " Mark the buffer as not modifiable
2001     setlocal nomodifiable
2002
2003     " Restore the report option
2004     let &report = old_report
2005
2006     " Update the start and end line numbers for all the files following this
2007     " file
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
2012     else
2013         let end = s:tlist_{fidx}_end + 1
2014     endif
2015     call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1)
2016
2017     if !g:Tlist_Use_Horiz_Window && s:auto_width
2018         exe 'vertical resize '.g:Tlist_WinWidth
2019     endif
2020
2021     " Now that we have updated the taglist window, update the tags
2022     " menu (if present)
2023     if g:Tlist_Show_Menu
2024         call s:Tlist_Menu_Update_File(1)
2025     endif
2026 endfunction
2027
2028 " Tlist_Init_File
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"
2037
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 = ''
2049
2050     " Initialize the tag type variables
2051     let i = 1
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
2057         let i = i + 1
2058     endwhile
2059
2060     return fidx
2061 endfunction
2062
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'
2067
2068     " Already parsed and have the tag name
2069     if exists(ttype_var)
2070         return {ttype_var}
2071     endif
2072
2073     let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2074     let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line)
2075
2076     return {ttype_var}
2077 endfunction
2078
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'
2082
2083     " Already parsed and have the tag prototype
2084     if exists(tproto_var)
2085         return {tproto_var}
2086     endif
2087
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] == '$'
2093         let end = end -1
2094     endif
2095     let tag_proto = strpart(tag_line, start, end - start)
2096     let {tproto_var} = substitute(tag_proto, '\s*', '', '')
2097
2098     return {tproto_var}
2099 endfunction
2100
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'
2104
2105     " Already parsed and have the tag search pattern
2106     if exists(tpat_var)
2107         return {tpat_var}
2108     endif
2109
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] == '$'
2115         let end = end -1
2116     endif
2117     let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) .
2118                         \ (tag_line[end] == '$' ? '\$' : '')
2119
2120     return {tpat_var}
2121 endfunction
2122
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'
2127
2128     " Already parsed and have the tag line number
2129     if exists(tline_var)
2130         return {tline_var}
2131     endif
2132
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)
2138
2139     if end < start
2140         let {tline_var} = strpart(tag_line, start) + 0
2141     else
2142         let {tline_var} = strpart(tag_line, start, end - start) + 0
2143     endif
2144
2145     return {tline_var}
2146 endfunction
2147
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:
2152 "
2153 "     tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields
2154 "
2155 function! s:Tlist_Parse_Tagline(tag_line,ftype)
2156     if a:tag_line == ''
2157         " Skip empty lines
2158         return
2159     endif
2160
2161     " Extract the tag type
2162     let ttype = s:Tlist_Extract_Tagtype(a:tag_line)
2163
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
2167         return
2168     endif
2169
2170     " Update the total tag count
2171     let s:tidx = s:tidx + 1
2172
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
2178
2179     " Update the count of this tag type
2180     let ttype_idx = {fidx_ttype}_count + 1
2181     let {fidx_ttype}_count = ttype_idx
2182
2183     " Store the ctags output for this tag
2184     let {fidx_tidx}_tag = a:tag_line
2185
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
2189
2190     " Extract the tag name
2191     let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t"))
2192
2193     " Extract the tag scope/prototype
2194     if g:Tlist_Display_Prototype
2195         let ttxt = '    ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx)
2196     else
2197         let ttxt = '    ' . tag_name
2198
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)
2203         endif
2204     endif
2205
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])
2209     endif
2210
2211     " Add this tag to the tag type variable
2212     let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
2213
2214     " Save the tag name
2215     let {fidx_tidx}_tag_name = tag_name
2216 endfunction
2217
2218 function! s:Tlist_Get_Scope_String(tag_line, ftype)
2219     let ttxt = ''
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 . ']'
2224         endif
2225     endfor
2226     return ttxt
2227 endfunction
2228
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 . ', ' .
2234                 \ a:ftype . ')')
2235     " Check whether this file is supported
2236     if s:Tlist_Skip_File(a:filename, a:ftype)
2237         return -1
2238     endif
2239
2240     " If the tag types for this filetype are not yet created, then create
2241     " them now
2242     let var = 's:tlist_' . a:ftype . '_count'
2243     if !exists(var)
2244         if s:Tlist_FileType_Init(a:ftype) == 0
2245             return -1
2246         endif
2247     endif
2248
2249     " If this file is already processed, then use the cached values
2250     let fidx = s:Tlist_Get_File_Index(a:filename)
2251     if fidx == -1
2252         " First time, this file is loaded
2253         let fidx = s:Tlist_Init_File(a:filename, a:ftype)
2254     else
2255         " File was previously processed. Discard the tag information
2256         call s:Tlist_Discard_TagInfo(fidx)
2257     endif
2258
2259     let s:tlist_{fidx}_valid = 1
2260
2261     " Exuberant ctags arguments to generate a tag list
2262     let ctags_args = { '-f': ' -', '--format=': '2', '--excmd=': 'pattern', '--fields=': 'nks' }
2263
2264     " Form the ctags argument depending on the sort type
2265     if s:tlist_{fidx}_sort_type == 'name'
2266         let ctags_args['--sort'] = '=yes'
2267     else
2268         let ctags_args['--sort'] = '=no'
2269     endif
2270
2271     " Add the filetype specific arguments
2272     call extend(ctags_args, s:tlist_{a:ftype}_ctags_args)
2273
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')
2278     else
2279         let ctags_cmd = g:Tlist_Ctags_Cmd
2280     endif
2281     let ctags_cmd = ctags_cmd . ' ' . join(values(map(ctags_args, 'v:key . v:val')))
2282     let ctags_cmd = ctags_cmd . ' "' . a:filename . '"'
2283
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, '"')
2289     endif
2290
2291     " In Windows 95, if not using cygwin, disable the 'shellslash'
2292     " option. Otherwise, this will cause problems when running the
2293     " ctags command.
2294     if has('win95') && !has('win32unix')
2295         let old_shellslash = &shellslash
2296         set noshellslash
2297     endif
2298
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') .
2309                     \ '\taglist.cmd'
2310         exe 'redir! > ' . s:taglist_tempfile
2311         silent echo ctags_cmd
2312         redir END
2313
2314         call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd)
2315         let ctags_cmd = '"' . s:taglist_tempfile . '"'
2316     endif
2317
2318     call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd)
2319
2320     " Run ctags and get the tag list
2321     let cmd_output = system(ctags_cmd)
2322
2323     " Restore the value of the 'shellslash' option.
2324     if has('win95') && !has('win32unix')
2325         let &shellslash = old_shellslash
2326     endif
2327
2328     if exists('s:taglist_tempfile')
2329         " Delete the temporary cmd file created on MS-Windows
2330         call delete(s:taglist_tempfile)
2331     endif
2332
2333     " Handle errors
2334     if v:shell_error
2335         let msg = "Taglist: Failed to generate tags for " . a:filename
2336         call s:Tlist_Warning_Msg(msg)
2337         if cmd_output != ''
2338             call s:Tlist_Warning_Msg(cmd_output)
2339         endif
2340         return fidx
2341     endif
2342
2343     " Store the modification time for the file
2344     let s:tlist_{fidx}_mtime = getftime(a:filename)
2345
2346     " No tags for current file
2347     if cmd_output == ''
2348         call s:Tlist_Log_Msg('No tags defined in ' . a:filename)
2349         return fidx
2350     endif
2351
2352     call s:Tlist_Log_Msg('Generated tags information for ' . a:filename)
2353
2354     if v:version > 601
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
2358         let s:fidx = fidx
2359         let s:tidx = 0
2360
2361         " Tlist_Parse_Tagline will adjust this accordingly
2362         if !g:Tlist_Use_Horiz_Window && s:auto_width
2363             let g:Tlist_WinWidth = 0
2364         endif
2365
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')
2371
2372         " Save the number of tags for this file
2373         let s:tlist_{fidx}_tag_count = s:tidx
2374
2375         " The following script local variables are no longer needed
2376         unlet! s:ctags_flags
2377         unlet! s:tidx
2378         unlet! s:fidx
2379     else
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
2384         let tidx = 0
2385
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)
2392
2393             if one_line == ''
2394                 " Line is not in proper tags format
2395                 continue
2396             endif
2397
2398             " Extract the tag type
2399             let ttype = s:Tlist_Extract_Tagtype(one_line)
2400
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
2404                 " supported
2405                 continue
2406             endif
2407
2408             " Update the total tag count
2409             let tidx = tidx + 1
2410
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
2414             " here
2415             let fidx_tidx = 's:tlist_' . fidx . '_' . tidx
2416             let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
2417
2418             " Update the count of this tag type
2419             let ttype_idx = {fidx_ttype}_count + 1
2420             let {fidx_ttype}_count = ttype_idx
2421
2422             " Store the ctags output for this tag
2423             let {fidx_tidx}_tag = one_line
2424
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
2428
2429             " Extract the tag name
2430             let tag_name = strpart(one_line, 0, stridx(one_line, "\t"))
2431
2432             " Extract the tag scope/prototype
2433             if g:Tlist_Display_Prototype
2434                 let ttxt = '    ' . s:Tlist_Get_Tag_Prototype(fidx, tidx)
2435             else
2436                 let ttxt = '    ' . tag_name
2437
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)
2442                 endif
2443             endif
2444
2445             " Add this tag to the tag type variable
2446             let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
2447
2448             " Save the tag name
2449             let {fidx_tidx}_tag_name = tag_name
2450         endwhile
2451
2452         " Save the number of tags for this file
2453         let s:tlist_{fidx}_tag_count = tidx
2454     endif
2455
2456     call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count . 
2457                 \ ' tags in ' . a:filename)
2458
2459     return fidx
2460 endfunction
2461
2462 " Tlist_Update_File
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)
2468         return
2469     endif
2470
2471     " Convert the file name to a full path
2472     let fname = fnamemodify(a:filename, ':p')
2473
2474     " First check whether the file already exists
2475     let fidx = s:Tlist_Get_File_Index(fname)
2476
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)
2482             return
2483         endif
2484     else
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)
2489     endif
2490
2491     " If the taglist window is opened, update it
2492     let winnum = bufwinnr(g:TagList_title)
2493     if winnum == -1
2494         " Taglist window is not present. Just update the taglist
2495         " and return
2496         call s:Tlist_Process_File(fname, a:ftype)
2497     else
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)
2505                 return
2506             endif
2507         endif
2508
2509         " Save the current window number
2510         let save_winnr = winnr()
2511
2512         " Goto the taglist window
2513         call s:Tlist_Window_Goto_Window()
2514
2515         " Save the cursor position
2516         let save_line = line('.')
2517         let save_col = col('.')
2518
2519         " Update the taglist window
2520         call s:Tlist_Window_Refresh_File(fname, a:ftype)
2521
2522         " Restore the cursor position
2523         if v:version >= 601
2524             call cursor(save_line, save_col)
2525         else
2526             exe save_line
2527             exe 'normal! ' . save_col . '|'
2528         endif
2529
2530         if winnr() != save_winnr
2531             " Go back to the original window
2532             call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
2533         endif
2534     endif
2535
2536     " Update the taglist menu
2537     if g:Tlist_Show_Menu
2538         call s:Tlist_Menu_Update_File(1)
2539     endif
2540 endfunction
2541
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)
2548     if winnum == -1
2549         call s:Tlist_Warning_Msg('Error: Taglist window is not open')
2550         return
2551     endif
2552
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.
2560             close
2561             call s:Tlist_Exe_Cmd_No_Acmds(bufwinnr(prev_buf) . 'wincmd w')
2562         endif
2563     else
2564         " Goto the taglist window, close it and then come back to the
2565         " original window
2566         let curbufnr = bufnr('%')
2567         exe winnum . 'wincmd w'
2568         close
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'
2574         endif
2575     endif
2576 endfunction
2577
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
2581 " window
2582 function! s:Tlist_Window_Mark_File_Window()
2583     if getbufvar('%', '&buftype') == '' && !&previewwindow
2584         let w:tlist_file_window = "yes"
2585     endif
2586 endfunction
2587
2588 " Tlist_Window_Open
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)
2594     if winnum != -1
2595         " Jump to the existing window
2596         if winnr() != winnum
2597             exe winnum . 'wincmd w'
2598         endif
2599         return
2600     endif
2601
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"
2605     endif
2606
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('.')
2611
2612     " Mark the current window as the desired window to open a file when a tag
2613     " is selected.
2614     call s:Tlist_Window_Mark_File_Window()
2615
2616     " Open the taglist window
2617     call s:Tlist_Window_Create()
2618
2619     call s:Tlist_Window_Refresh()
2620
2621     if g:Tlist_Show_One_File
2622         " Add only the current buffer and file
2623         "
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)
2627         endif
2628     endif
2629
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)
2634         if fidx != -1
2635             exe "silent! " . s:tlist_{fidx}_start . "," .
2636                         \ s:tlist_{fidx}_end . "foldopen!"
2637         endif
2638     endif
2639
2640     " Highlight the current tag
2641     call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1)
2642 endfunction
2643
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)
2650     if winnum != -1
2651         call s:Tlist_Window_Close()
2652         return
2653     endif
2654
2655     " Store the current buffer
2656     let current_buf = winbufnr(0)
2657     call s:Tlist_Window_Open()
2658
2659     " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not
2660     " set
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')
2664     endif
2665
2666     " Update the taglist menu
2667     if g:Tlist_Show_Menu
2668         call s:Tlist_Menu_Update_File(0)
2669     endif
2670 endfunction
2671
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
2677
2678     " Enable lazy screen updates
2679     let old_lazyredraw = &lazyredraw
2680     set lazyredraw
2681
2682     " Keep track of the number of processed files
2683     let fcnt = 0
2684
2685     " Process one file at a time
2686     while flist != ''
2687         let nl_idx = stridx(flist, "\n")
2688         let one_file = strpart(flist, 0, nl_idx)
2689
2690         " Remove the filename from the list
2691         let flist = strpart(flist, nl_idx + 1)
2692
2693         if one_file == ''
2694             continue
2695         endif
2696
2697         " Skip directories
2698         if isdirectory(one_file)
2699             continue
2700         endif
2701
2702         let ftype = s:Tlist_Detect_Filetype(one_file)
2703
2704         echon "\r                                                              "
2705         echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t')
2706
2707         let fcnt = fcnt + 1
2708
2709         call Tlist_Update_File(one_file, ftype)
2710     endwhile
2711
2712     " Clear the displayed informational messages
2713     echon "\r                                                            "
2714
2715     " Restore the previous state
2716     let &lazyredraw = old_lazyredraw
2717
2718     return fcnt
2719 endfunction
2720
2721 " Tlist_Process_Dir
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"
2725
2726     let fcnt = s:Tlist_Process_Filelist(flist)
2727
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 . '*'
2731     else
2732         let glob_expr = a:dir_name . '/*'
2733     endif
2734     let all_files = glob(glob_expr) . "\n"
2735
2736     while all_files != ''
2737         let nl_idx = stridx(all_files, "\n")
2738         let one_file = strpart(all_files, 0, nl_idx)
2739
2740         let all_files = strpart(all_files, nl_idx + 1)
2741         if one_file == ''
2742             continue
2743         endif
2744
2745         " Skip non-directory names
2746         if !isdirectory(one_file)
2747             continue
2748         endif
2749
2750         echon "\r                                                              "
2751         echon "\rProcessing files in directory " . fnamemodify(one_file, ':t')
2752         let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat)
2753     endwhile
2754
2755     return fcnt
2756 endfunction
2757
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')
2764         return
2765     endif
2766
2767     if a:0 == 1
2768         " User specified file pattern
2769         let pat = a:1
2770     else
2771         " Default file pattern
2772         let pat = '*'
2773     endif
2774
2775     echon "\r                                                              "
2776     echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t')
2777     let fcnt = s:Tlist_Process_Dir(dir_name, pat)
2778
2779     echon "\rAdded " . fcnt . " files to the taglist"
2780 endfunction
2781
2782 " Tlist_Add_Files
2783 " Add the specified list of files to the taglist
2784 function! s:Tlist_Add_Files(...)
2785     let flist = ''
2786     let i = 1
2787
2788     " Get all the files matching the file patterns supplied as argument
2789     while i <= a:0
2790         let flist = flist . glob(a:{i}) . "\n"
2791         let i = i + 1
2792     endwhile
2793
2794     if flist == ''
2795         call s:Tlist_Warning_Msg('Error: No matching files are found')
2796         return
2797     endif
2798
2799     let fcnt = s:Tlist_Process_Filelist(flist)
2800     echon "\rAdded " . fcnt . " files to the taglist"
2801 endfunction
2802
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)
2812
2813     return ttype
2814 endfunction
2815
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)
2821     if end <= start
2822         return {}
2823     endif
2824
2825     let tag_extras = {}
2826
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)
2834         endif
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)
2839     endwhile
2840
2841     return tag_extras
2842 endfunction
2843
2844 function! s:Tlist_Window_Toggle_Extra(ftype, extra_name)
2845     if !exists('g:Tlist_{a:ftype}_Hide_Extras')
2846         return
2847     endif
2848     let index = index(g:Tlist_{a:ftype}_Hide_Extras, a:extra_name)
2849     if index == -1
2850         call add(g:Tlist_{a:ftype}_Hide_Extras, a:extra_name)
2851     else
2852         unlet g:Tlist_{a:ftype}_Hide_Extras[index]
2853     endif
2854     if s:auto_width
2855         let g:Tlist_WinWidth = 30
2856     endif
2857
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)
2863 endfunction
2864
2865 " Tlist_Refresh()
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)
2876         endif
2877         return
2878     endif
2879
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
2884         return
2885     endif
2886
2887     " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
2888     if &buftype != ''
2889         return
2890     endif
2891
2892     let filename = fnamemodify(bufname('%'), ':p')
2893     let ftype = s:Tlist_Get_Buffer_Filetype('%')
2894
2895     " If the file doesn't support tag listing, skip it
2896     if s:Tlist_Skip_File(filename, ftype)
2897         return
2898     endif
2899
2900     let tlist_win = bufwinnr(g:TagList_title)
2901
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
2905         return
2906     endif
2907
2908     let fidx = s:Tlist_Get_File_Index(filename)
2909     if fidx == -1
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)
2913             return
2914         endif
2915
2916         " If the taglist should not be auto updated, then return
2917         if !g:Tlist_Auto_Update
2918             return
2919         endif
2920     endif
2921
2922     let cur_lnum = line('.')
2923
2924     if fidx == -1
2925         " Update the tags for the file
2926         let fidx = s:Tlist_Process_File(filename, ftype)
2927     else
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
2932
2933             " Update the taglist and the window
2934             call Tlist_Update_File(filename, ftype)
2935
2936             " Store the new file modification time
2937             let s:tlist_{fidx}_mtime = mtime
2938         endif
2939     endif
2940
2941     " Update the taglist window
2942     if tlist_win != -1
2943         " Disable screen updates
2944         let old_lazyredraw = &lazyredraw
2945         set nolazyredraw
2946
2947         " Save the current window number
2948         let save_winnr = winnr()
2949
2950         " Goto the taglist window
2951         call s:Tlist_Window_Goto_Window()
2952
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('.')
2957         endif
2958
2959         " Update the taglist window
2960         call s:Tlist_Window_Refresh_File(filename, ftype)
2961
2962         " Open the fold for the file
2963         exe "silent! " . s:tlist_{fidx}_start . "," .
2964                     \ s:tlist_{fidx}_end . "foldopen!"
2965
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
2972             else
2973                 let center_tag_line = 0
2974             endif
2975
2976             " Highlight the current tag
2977             call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line)
2978         else
2979             " Restore the cursor position
2980             if v:version >= 601
2981                 call cursor(save_line, save_col)
2982             else
2983                 exe save_line
2984                 exe 'normal! ' . save_col . '|'
2985             endif
2986         endif
2987
2988         " Jump back to the original window
2989         if save_winnr != winnr()
2990             call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
2991         endif
2992
2993         " Restore screen updates
2994         let &lazyredraw = old_lazyredraw
2995     endif
2996
2997     " Update the taglist menu
2998     if g:Tlist_Show_Menu
2999         call s:Tlist_Menu_Update_File(0)
3000     endif
3001 endfunction
3002
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('.'))
3014         if fidx == -1
3015             return
3016         endif
3017
3018         " Remove the previous highlighting
3019         match none
3020     elseif a:caller == 'menu'
3021         let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
3022         if fidx == -1
3023             return
3024         endif
3025     endif
3026
3027     if a:action == 'toggle'
3028         let sort_type = s:tlist_{fidx}_sort_type
3029
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'
3033         else
3034             let s:tlist_{fidx}_sort_type = 'name'
3035         endif
3036     else
3037         let s:tlist_{fidx}_sort_type = a:sort_type
3038     endif
3039
3040     " Invalidate the tags listed for this file
3041     let s:tlist_{fidx}_valid = 0
3042
3043     if a:caller  == 'cmd'
3044         " Save the current line for later restoration
3045         let curline = '\V\^' . getline('.') . '\$'
3046
3047         call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
3048                     \   s:tlist_{fidx}_filetype)
3049
3050         exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
3051
3052         " Go back to the cursor line before the tag list is sorted
3053         call search(curline, 'w')
3054
3055         call s:Tlist_Menu_Update_File(1)
3056     else
3057         call s:Tlist_Menu_Remove_File()
3058
3059         call s:Tlist_Refresh()
3060     endif
3061 endfunction
3062
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()
3071     else
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)
3075         if fidx != -1
3076             let s:tlist_{fidx}_valid = 0
3077         endif
3078         let ft = s:Tlist_Get_Buffer_Filetype('%')
3079         call Tlist_Update_File(filename, ft)
3080     endif
3081 endfunction
3082
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('.'))
3088     if fidx == -1
3089         return
3090     endif
3091
3092     " Remove the previous highlighting
3093     match none
3094
3095     " Save the current line for later restoration
3096     let curline = '\V\^' . getline('.') . '\$'
3097
3098     let s:tlist_{fidx}_valid = 0
3099
3100     " Update the taglist window
3101     call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
3102                 \ s:tlist_{fidx}_filetype)
3103
3104     exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
3105
3106     " Go back to the tag line before the list is updated
3107     call search(curline, 'w')
3108 endfunction
3109
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
3114
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
3117     let i = 1
3118     while i <= s:tlist_{ftype}_count
3119         let ttype = s:tlist_{ftype}_{i}_name
3120         let start_lnum =
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
3124             break
3125         endif
3126         let i = i + 1
3127     endwhile
3128
3129     " Current line doesn't belong to any of the displayed tag types
3130     if i > s:tlist_{ftype}_count
3131         return ''
3132     endif
3133
3134     return ttype
3135 endfunction
3136
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)
3141
3142     " Current line doesn't belong to any of the displayed tag types
3143     if ttype == ''
3144         return 0
3145     endif
3146
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
3150     if tidx == 0
3151         return 0
3152     endif
3153
3154     " Get the corresponding tag line and return it
3155     return s:tlist_{a:fidx}_{ttype}_{tidx}
3156 endfunction
3157
3158 " Tlist_Window_Highlight_Line
3159 " Highlight the current line
3160 function! s:Tlist_Window_Highlight_Line()
3161     " Clear previously selected name
3162     match none
3163
3164     " Highlight the current line
3165     if g:Tlist_Display_Prototype == 0
3166         let pat = '/\%' . line('.') . 'l\s\+\zs.*/'
3167     else
3168         let pat = '/\%' . line('.') . 'l.*/'
3169     endif
3170
3171     exe 'match TagListTagName ' . pat
3172 endfunction
3173
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 . ',' .
3179                 \ a:win_ctrl . ')')
3180     let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh
3181     let s:Tlist_Skip_Refresh = 1
3182
3183     if s:tlist_app_name == "winmanager"
3184         " Let the winmanager edit the file
3185         call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin')
3186     else
3187
3188     if a:win_ctrl == 'newtab'
3189         " Create a new tab
3190         exe 'tabnew ' . escape(a:filename, ' ')
3191         " Open the taglist window in the new tab
3192         call s:Tlist_Window_Open()
3193     endif
3194
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
3198         " current tab.
3199         if bufwinnr(a:filename) != -1
3200             let file_present_in_tab = 1
3201             let i = tabpagenr()
3202         else
3203             let i = 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
3209                     break
3210                 endif
3211                 let i += 1
3212             endwhile
3213         endif
3214
3215         if file_present_in_tab
3216             " Goto the tab containing the file
3217             exe 'tabnext ' . i
3218         else
3219             " Open a new tab
3220             exe 'tabnew ' . escape(a:filename, ' ')
3221
3222             " Open the taglist window
3223             call s:Tlist_Window_Open()
3224         endif
3225     endif
3226
3227     let winnum = -1
3228     if a:win_ctrl == 'prevwin'
3229         " Open the file in the previous window, if it is usable
3230         let cur_win = winnr()
3231         wincmd p
3232         if &buftype == '' && !&previewwindow
3233             exe "edit " . escape(a:filename, ' ')
3234             let winnum = winnr()
3235         else
3236             " Previous window is not usable
3237             exe cur_win . 'wincmd w'
3238         endif
3239     endif
3240
3241     " Goto the window containing the file.  If the window is not there, open a
3242     " new window
3243     if winnum == -1
3244         let winnum = bufwinnr(a:filename)
3245     endif
3246
3247     if winnum == -1
3248         " Locate the previously used window for opening a file
3249         let fwin_num = 0
3250         let first_usable_win = 0
3251
3252         let i = 1
3253         let bnum = winbufnr(i)
3254         while bnum != -1
3255             if getwinvar(i, 'tlist_file_window') == 'yes'
3256                 let fwin_num = i
3257                 break
3258             endif
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
3264             endif
3265             let i = i + 1
3266             let bnum = winbufnr(i)
3267         endwhile
3268
3269         " If a previously used window is not found, then use the first
3270         " non-taglist window
3271         if fwin_num == 0
3272             let fwin_num = first_usable_win
3273         endif
3274
3275         if fwin_num != 0
3276             " Jump to the file window
3277             exe fwin_num . "wincmd w"
3278
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'
3282                 split
3283             endif
3284             exe "edit " . escape(a:filename, ' ')
3285         else
3286             " Open a new window
3287             if g:Tlist_Use_Horiz_Window
3288                 exe 'leftabove split ' . escape(a:filename, ' ')
3289             else
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, ' ')
3295                     else
3296                         exe 'rightbelow vertical split ' .
3297                                     \ escape(a:filename, ' ')
3298                     endif
3299
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
3305                     else
3306                         exe 'vertical resize ' . g:Tlist_WinWidth
3307                     endif
3308                     " Go back to the file window
3309                     call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3310                 else
3311                     " A plugin or help window is also present
3312                     wincmd w
3313                     exe 'leftabove split ' . escape(a:filename, ' ')
3314                 endif
3315             endif
3316         endif
3317         " Mark the window, so that it can be reused.
3318         call s:Tlist_Window_Mark_File_Window()
3319     else
3320         if v:version >= 700
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('#')
3327             endif
3328         endif
3329         exe winnum . 'wincmd w'
3330
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'
3334             split
3335         endif
3336     endif
3337     endif
3338
3339     " Jump to the tag
3340     if a:tagpat != ''
3341         " Add the current cursor position to the jump list, so that user can
3342         " jump back using the ' and ` marks.
3343         mark '
3344         silent call search(a:tagpat, 'w')
3345
3346         " Bring the line to the middle of the window
3347         normal! z.
3348
3349         " If the line is inside a fold, open the fold
3350         if foldclosed('.') != -1
3351             .foldopen
3352         endif
3353     endif
3354
3355     " If the user selects to preview the tag then jump back to the
3356     " taglist window
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'
3361     else
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()
3366             close
3367
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')
3372             endif
3373         endif
3374     endif
3375
3376     let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh
3377 endfunction
3378
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] == '"'
3391         return
3392     endif
3393
3394     " If inside a closed fold, then use the first line of the fold
3395     " and jump to the file.
3396     let lnum = foldclosed('.')
3397     if lnum == -1
3398         " Jump to the selected tag or file
3399         let lnum = line('.')
3400     else
3401         " Open the closed fold
3402         .foldopen!
3403     endif
3404
3405     let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
3406     if fidx == -1
3407         return
3408     endif
3409
3410     " Get the tag output for the current tag
3411     let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3412     if tidx != 0
3413         let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx)
3414
3415         " Highlight the tagline
3416         call s:Tlist_Window_Highlight_Line()
3417     else
3418         " Selected a line which is not a tag name. Just edit the file
3419         let tagpat = ''
3420     endif
3421
3422     call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat)
3423 endfunction
3424
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()')
3429
3430     " Clear the previously displayed line
3431     echo
3432
3433     " Do not process comment lines and empty lines
3434     let curline = getline('.')
3435     if curline =~ '^\s*$' || curline[0] == '"'
3436         return
3437     endif
3438
3439     " If inside a fold, then don't display the prototype
3440     if foldclosed('.') != -1
3441         return
3442     endif
3443
3444     let lnum = line('.')
3445
3446     " Get the file index
3447     let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
3448     if fidx == -1
3449         return
3450     endif
3451
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')
3457         endif
3458         echo fname . ', Filetype=' . s:tlist_{fidx}_filetype .
3459                     \  ', Tag count=' . s:tlist_{fidx}_tag_count
3460         return
3461     endif
3462
3463     " Get the tag output line for the current tag
3464     let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3465     if tidx == 0
3466         " Cursor is on a tag type
3467         let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
3468         if ttype == ''
3469             return
3470         endif
3471
3472         let ttype_name = ''
3473
3474         let ftype = s:tlist_{fidx}_filetype
3475         let i = 1
3476         while i <= s:tlist_{ftype}_count
3477             if ttype == s:tlist_{ftype}_{i}_name
3478                 let ttype_name = s:tlist_{ftype}_{i}_fullname
3479                 break
3480             endif
3481             let i = i + 1
3482         endwhile
3483
3484         echo 'Tag type=' . ttype_name .
3485                     \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count
3486         return
3487     endif
3488
3489     " Get the tag search pattern and display it
3490     echo s:Tlist_Get_Tag_Prototype(fidx, tidx)
3491 endfunction
3492
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
3498
3499     let left = 1
3500     let right = s:tlist_{a:fidx}_tag_count
3501
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.
3506
3507         " If the current line is the less than the first tag, then no need to
3508         " search
3509         let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1)
3510
3511         if a:linenum < first_lnum
3512             return -1
3513         endif
3514
3515         while left < right
3516             let middle = (right + left + 1) / 2
3517             let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle)
3518
3519             if middle_lnum == a:linenum
3520                 let left = middle
3521                 break
3522             endif
3523
3524             if middle_lnum > a:linenum
3525                 let right = middle - 1
3526             else
3527                 let left = middle
3528             endif
3529         endwhile
3530     else
3531         " Tags sorted by name, use a linear search. (contributed by Dave
3532         " Eggum).
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
3538         let final_left = 0
3539         while left <= right
3540             let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left)
3541
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
3548                 break
3549             else
3550                 let left = left + 1
3551             endif
3552         endwhile
3553         if closest_lnum == 0
3554             return -1
3555         endif
3556         if left >= right
3557             let left = final_left
3558         endif
3559     endif
3560
3561     return left
3562 endfunction
3563
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
3574         return
3575     endif
3576
3577     if a:filename == ''
3578         return
3579     endif
3580
3581     " Make sure the taglist window is present
3582     let winnum = bufwinnr(g:TagList_title)
3583     if winnum == -1
3584         call s:Tlist_Warning_Msg('Error: Taglist window is not open')
3585         return
3586     endif
3587
3588     let fidx = s:Tlist_Get_File_Index(a:filename)
3589     if fidx == -1
3590         return
3591     endif
3592
3593     " If the file is currently not displayed in the taglist window, then retrn
3594     if !s:tlist_{fidx}_visible
3595         return
3596     endif
3597
3598     " If there are no tags for this file, then no need to proceed further
3599     if s:tlist_{fidx}_tag_count == 0
3600         return
3601     endif
3602
3603     " Ignore all autocommands
3604     let old_ei = &eventignore
3605     set eventignore=all
3606
3607     " Save the original window number
3608     let org_winnr = winnr()
3609
3610     if org_winnr == winnum
3611         let in_taglist_window = 1
3612     else
3613         let in_taglist_window = 0
3614     endif
3615
3616     " Go to the taglist window
3617     if !in_taglist_window
3618         exe winnum . 'wincmd w'
3619     endif
3620
3621     " Clear previously selected name
3622     match none
3623
3624     let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum)
3625     if tidx == -1
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('.')
3630
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
3634         endif
3635
3636         if foldclosed('.') != -1
3637             .foldopen
3638         endif
3639
3640         call winline()
3641
3642         if !in_taglist_window
3643             exe org_winnr . 'wincmd w'
3644         endif
3645
3646         " Restore the autocommands
3647         let &eventignore = old_ei
3648         return
3649     endif
3650
3651     " Extract the tag type
3652     let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
3653
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
3658
3659     " Goto the line containing the tag
3660     exe lnum
3661
3662     " Open the fold
3663     if foldclosed('.') != -1
3664         .foldopen
3665     endif
3666
3667     if a:center
3668         " Move the tag line to the center of the taglist window
3669         normal! z.
3670     else
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.
3674         call winline()
3675     endif
3676
3677     " Highlight the tag name
3678     call s:Tlist_Window_Highlight_Line()
3679
3680     " Go back to the original window
3681     if !in_taglist_window
3682         exe org_winnr . 'wincmd w'
3683     endif
3684
3685     " Restore the autocommands
3686     let &eventignore = old_ei
3687     return
3688 endfunction
3689
3690 " Tlist_Get_Tag_Prototype_By_Line
3691 " Get the prototype for the tag on or before the specified line number in the
3692 " current buffer
3693 function! Tlist_Get_Tag_Prototype_By_Line(...)
3694     if a:0 == 0
3695         " Arguments are not supplied. Use the current buffer name
3696         " and line number
3697         let filename = bufname('%')
3698         let linenr = line('.')
3699     elseif a:0 == 2
3700         " Filename and line number are specified
3701         let filename = a:1
3702         let linenr = a:2
3703         if linenr !~ '\d\+'
3704             " Invalid line number
3705             return ""
3706         endif
3707     else
3708         " Sufficient arguments are not supplied
3709         let msg =  'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' .
3710                                 \ '<line_number>'
3711         call s:Tlist_Warning_Msg(msg)
3712         return ""
3713     endif
3714
3715     " Expand the file to a fully qualified name
3716     let filename = fnamemodify(filename, ':p')
3717     if filename == ''
3718         return ""
3719     endif
3720
3721     let fidx = s:Tlist_Get_File_Index(filename)
3722     if fidx == -1
3723         return ""
3724     endif
3725
3726     " If there are no tags for this file, then no need to proceed further
3727     if s:tlist_{fidx}_tag_count == 0
3728         return ""
3729     endif
3730
3731     " Get the tag text using the line number
3732     let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
3733     if tidx == -1
3734         return ""
3735     endif
3736
3737     return s:Tlist_Get_Tag_Prototype(fidx, tidx)
3738 endfunction
3739
3740 " Tlist_Get_Tagname_By_Line
3741 " Get the tag name on or before the specified line number in the
3742 " current buffer
3743 function! Tlist_Get_Tagname_By_Line(...)
3744     if a:0 == 0
3745         " Arguments are not supplied. Use the current buffer name
3746         " and line number
3747         let filename = bufname('%')
3748         let linenr = line('.')
3749     elseif a:0 == 2
3750         " Filename and line number are specified
3751         let filename = a:1
3752         let linenr = a:2
3753         if linenr !~ '\d\+'
3754             " Invalid line number
3755             return ""
3756         endif
3757     else
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)
3761         return ""
3762     endif
3763
3764     " Make sure the current file has a name
3765     let filename = fnamemodify(filename, ':p')
3766     if filename == ''
3767         return ""
3768     endif
3769
3770     let fidx = s:Tlist_Get_File_Index(filename)
3771     if fidx == -1
3772         return ""
3773     endif
3774
3775     " If there are no tags for this file, then no need to proceed further
3776     if s:tlist_{fidx}_tag_count == 0
3777         return ""
3778     endif
3779
3780     " Get the tag name using the line number
3781     let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
3782     if tidx == -1
3783         return ""
3784     endif
3785
3786     return s:tlist_{fidx}_{tidx}_tag_name
3787 endfunction
3788
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
3798         if a:dir == -1
3799             normal! zk
3800         else
3801             " While moving down to the start of the next fold,
3802             " no need to do go to the start of the next file.
3803             normal! zj
3804             return
3805         endif
3806     endif
3807
3808     let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
3809     if fidx == -1
3810         return
3811     endif
3812
3813     let cur_lnum = line('.')
3814
3815     if a:dir == -1
3816         if cur_lnum > s:tlist_{fidx}_start
3817             " Move to the beginning of the current file
3818             exe s:tlist_{fidx}_start
3819             return
3820         endif
3821
3822         if fidx != 0
3823             " Move to the beginning of the previous file
3824             let fidx = fidx - 1
3825         else
3826             " Cursor is at the first file, wrap around to the last file
3827             let fidx = s:tlist_file_count - 1
3828         endif
3829
3830         exe s:tlist_{fidx}_start
3831         return
3832     else
3833         " Move to the beginning of the next file
3834         let fidx = fidx + 1
3835
3836         if fidx >= s:tlist_file_count
3837             " Cursor is at the last file, wrap around to the first file
3838             let fidx = 0
3839         endif
3840
3841         if s:tlist_{fidx}_start != 0
3842             exe s:tlist_{fidx}_start
3843         endif
3844         return
3845     endif
3846 endfunction
3847
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>')
3854         return
3855     endif
3856
3857     let sessionfile = a:1
3858
3859     if !filereadable(sessionfile)
3860         let msg = 'Taglist: Error - Unable to open file ' . sessionfile
3861         call s:Tlist_Warning_Msg(msg)
3862         return
3863     endif
3864
3865     " Mark the current window as the file window
3866     call s:Tlist_Window_Mark_File_Window()
3867
3868     " Source the session file
3869     exe 'source ' . sessionfile
3870
3871     let new_file_count = g:tlist_file_count
3872     unlet! g:tlist_file_count
3873
3874     let i = 0
3875     while i < new_file_count
3876         let ftype = g:tlist_{i}_filetype
3877         unlet! g:tlist_{i}_filetype
3878
3879         if !exists('s:tlist_' . ftype . '_count')
3880             if s:Tlist_FileType_Init(ftype) == 0
3881                 let i = i + 1
3882                 continue
3883             endif
3884         endif
3885
3886         let fname = g:tlist_{i}_filename
3887         unlet! g:tlist_{i}_filename
3888
3889         let fidx = s:Tlist_Get_File_Index(fname)
3890         if fidx != -1
3891             let s:tlist_{fidx}_visible = 0
3892             let i = i + 1
3893             continue
3894         else
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)
3899         endif
3900
3901         let fidx = s:Tlist_Init_File(fname, ftype)
3902
3903         let s:tlist_{fidx}_filename = fname
3904
3905         let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type
3906         unlet! g:tlist_{i}_sort_type
3907
3908         let s:tlist_{fidx}_filetype = ftype
3909         let s:tlist_{fidx}_mtime = getftime(fname)
3910
3911         let s:tlist_{fidx}_start = 0
3912         let s:tlist_{fidx}_end = 0
3913
3914         let s:tlist_{fidx}_valid = 1
3915
3916         let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count
3917         unlet! g:tlist_{i}_tag_count
3918
3919         let j = 1
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
3927             let j = j + 1
3928         endwhile
3929
3930         let j = 1
3931         while j <= s:tlist_{ftype}_count
3932             let ttype = s:tlist_{ftype}_{j}_name
3933
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
3940
3941                 let k = 1
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}
3945                     let k = k + 1
3946                 endwhile
3947             else
3948                 let s:tlist_{fidx}_{ttype} = ''
3949                 let s:tlist_{fidx}_{ttype}_offset = 0
3950                 let s:tlist_{fidx}_{ttype}_count = 0
3951             endif
3952
3953             let j = j + 1
3954         endwhile
3955
3956         let i = i + 1
3957     endwhile
3958
3959     " If the taglist window is open, then update it
3960     let winnum = bufwinnr(g:TagList_title)
3961     if winnum != -1
3962         let save_winnr = winnr()
3963
3964         " Goto the taglist window
3965         call s:Tlist_Window_Goto_Window()
3966
3967         " Refresh the taglist window
3968         call s:Tlist_Window_Refresh()
3969
3970         " Go back to the original window
3971         if save_winnr != winnr()
3972             call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3973         endif
3974     endif
3975 endfunction
3976
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>')
3983         return
3984     endif
3985
3986     let sessionfile = a:1
3987
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.')
3991         return
3992     endif
3993
3994     if filereadable(sessionfile)
3995         let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?')
3996         if ans !=? 'y'
3997             return
3998         endif
3999
4000         echo "\n"
4001     endif
4002
4003     let old_verbose = &verbose
4004     set verbose&vim
4005
4006     exe 'redir! > ' . sessionfile
4007
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
4011
4012     let i = 0
4013
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
4025         let j = 1
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
4033             let j = j + 1
4034         endwhile
4035
4036         " Store information about all the tags grouped by their type
4037         let ftype = s:tlist_{i}_filetype
4038         let j = 1
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 . ' = "' .
4045                                                 \ txt . '"'
4046                 silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' .
4047                                                      \ s:tlist_{i}_{ttype}_count
4048                 let k = 1
4049                 while k <= s:tlist_{i}_{ttype}_count
4050                     silent! echo 'let tlist_' . i . '_' . ttype . '_' . k .
4051                                 \ ' = ' . s:tlist_{i}_{ttype}_{k}
4052                     let k = k + 1
4053                 endwhile
4054             endif
4055             let j = j + 1
4056         endwhile
4057
4058         silent! echo
4059
4060         let i = i + 1
4061     endwhile
4062
4063     redir END
4064
4065     let &verbose = old_verbose
4066 endfunction
4067
4068 " Tlist_Buffer_Removed
4069 " A buffer is removed from the Vim buffer list. Remove the tags defined
4070 " for that file
4071 function! s:Tlist_Buffer_Removed(filename)
4072     call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename .  ')')
4073
4074     " Make sure a valid filename is supplied
4075     if a:filename == ''
4076         return
4077     endif
4078
4079     " Get tag list index of the specified file
4080     let fidx = s:Tlist_Get_File_Index(a:filename)
4081     if fidx == -1
4082         " File not present in the taglist
4083         return
4084     endif
4085
4086     " Remove the file from the list
4087     call s:Tlist_Remove_File(fidx, 0)
4088 endfunction
4089
4090 " When a buffer is deleted, remove the file from the taglist
4091 autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand('<afile>:p'))
4092
4093 " Tlist_Window_Open_File_Fold
4094 " Open the fold for the specified file and close the fold for all the
4095 " other files
4096 function! s:Tlist_Window_Open_File_Fold(acmd_bufnr)
4097     call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')')
4098
4099     " Make sure the taglist window is present
4100     let winnum = bufwinnr(g:TagList_title)
4101     if winnum == -1
4102         call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open')
4103         return
4104     endif
4105
4106     " Save the original window number
4107     let org_winnr = winnr()
4108     if org_winnr == winnum
4109         let in_taglist_window = 1
4110     else
4111         let in_taglist_window = 0
4112     endif
4113
4114     if in_taglist_window
4115         " When entering the taglist window, no need to update the folds
4116         return
4117     endif
4118
4119     " Go to the taglist window
4120     if !in_taglist_window
4121         call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
4122     endif
4123
4124     " Close all the folds
4125     silent! %foldclose
4126
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)
4131         if fidx != -1
4132             " Open the fold for the file
4133             exe "silent! " . s:tlist_{fidx}_start . "," .
4134                         \ s:tlist_{fidx}_end . "foldopen"
4135         endif
4136     endif
4137
4138     " Go back to the original window
4139     if !in_taglist_window
4140         call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w')
4141     endif
4142 endfunction
4143
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
4147 " tags.
4148 function! s:Tlist_Window_Check_Auto_Open()
4149     let open_window = 0
4150
4151     let i = 1
4152     let buf_num = winbufnr(i)
4153     while buf_num != -1
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)
4157             let open_window = 1
4158             break
4159         endif
4160         let i = i + 1
4161         let buf_num = winbufnr(i)
4162     endwhile
4163
4164     if open_window
4165         call s:Tlist_Window_Toggle()
4166     endif
4167 endfunction
4168
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)
4175     if winnum == -1
4176         return
4177     endif
4178
4179     let save_wnum = winnr()
4180     exe winnum . 'wincmd w'
4181
4182     " First remove all the existing folds
4183     normal! zE
4184
4185     " Create the folds for each in the tag list
4186     let fidx = 0
4187     while fidx < s:tlist_file_count
4188         let ftype = s:tlist_{fidx}_filetype
4189
4190         " Create the folds for each tag type in a file
4191         let j = 1
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'
4198             endif
4199             let j = j + 1
4200         endwhile
4201
4202         exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
4203         exe 'silent! ' . s:tlist_{fidx}_start . ',' .
4204                     \ s:tlist_{fidx}_end . 'foldopen!'
4205         let fidx = fidx + 1
4206     endwhile
4207
4208     exe save_wnum . 'wincmd w'
4209 endfunction
4210
4211 function! s:Tlist_Menu_Add_Base_Menu()
4212     call s:Tlist_Log_Msg('Adding the base menu')
4213
4214     " Add the 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-           :
4221
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-           :
4230     endif
4231 endfunction
4232
4233 let s:menu_char_prefix =
4234             \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
4235
4236 " Tlist_Menu_Get_Tag_Type_Cmd
4237 " Get the menu command for the specified tag type
4238 " fidx - File type index
4239 " ftype - File Type
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
4245
4246     let ttype = s:tlist_{ftype_ttype_idx}_name
4247     if a:add_ttype_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, ' ')
4251     endif
4252
4253     " Curly brace variable name optimization
4254     let fidx_ttype = a:fidx . '_' . ttype
4255
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
4259         return ''
4260     endif
4261
4262     let mcmd = ''
4263
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
4268         let j = 1
4269         while j <= tcnt
4270             let final_index = j + g:Tlist_Max_Submenu_Items - 1
4271             if final_index > tcnt
4272                 let final_index = tcnt
4273             endif
4274
4275             " Extract the first and last tag name and form the
4276             " sub-menu name
4277             let tidx = s:tlist_{fidx_ttype}_{j}
4278             let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name
4279
4280             let tidx = s:tlist_{fidx_ttype}_{final_index}
4281             let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name
4282
4283             " Truncate the names, if they are greater than the
4284             " max length
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)
4287
4288             " Form the menu command prefix
4289             let m_prefix = 'anoremenu <silent> T\&ags.'
4290             if a:add_ttype_name
4291                 let m_prefix = m_prefix . ttype_fullname . '.'
4292             endif
4293             let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.'
4294
4295             " Character prefix used to number the menu items (hotkey)
4296             let m_prefix_idx = 0
4297
4298             while j <= final_index
4299                 let tidx = s:tlist_{fidx_ttype}_{j}
4300
4301                 let tname = s:tlist_{a:fidx}_{tidx}_tag_name
4302
4303                 let mcmd = mcmd . m_prefix . '\&' .
4304                             \ s:menu_char_prefix[m_prefix_idx] . '\.' .
4305                             \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' .
4306                             \ tidx . ')<CR>|'
4307
4308                 let m_prefix_idx = m_prefix_idx + 1
4309                 let j = j + 1
4310             endwhile
4311         endwhile
4312     else
4313         " Character prefix used to number the menu items (hotkey)
4314         let m_prefix_idx = 0
4315
4316         let m_prefix = 'anoremenu <silent> T\&ags.'
4317         if a:add_ttype_name
4318             let m_prefix = m_prefix . ttype_fullname . '.'
4319         endif
4320         let j = 1
4321         while j <= tcnt
4322             let tidx = s:tlist_{fidx_ttype}_{j}
4323
4324             let tname = s:tlist_{a:fidx}_{tidx}_tag_name
4325
4326             let mcmd = mcmd . m_prefix . '\&' .
4327                         \ s:menu_char_prefix[m_prefix_idx] . '\.' .
4328                         \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . tidx
4329                         \ . ')<CR>|'
4330
4331             let m_prefix_idx = m_prefix_idx + 1
4332             let j = j + 1
4333         endwhile
4334     endif
4335
4336     return mcmd
4337 endfunction
4338
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
4344     set cpoptions&vim
4345
4346     exe s:tlist_{a:fidx}_menu_cmd
4347
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")
4352         exe cmd
4353     endif
4354
4355     " The taglist menu is not empty now
4356     let s:tlist_menu_empty = 0
4357
4358     " Restore the 'cpoptions' settings
4359     let &cpoptions = old_cpoptions
4360 endfunction
4361
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
4367         return
4368     endif
4369
4370     call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu)
4371
4372     " Remove the tags menu
4373     if a:clear_menu
4374         call s:Tlist_Menu_Remove_File()
4375
4376     endif
4377
4378     " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
4379     if &buftype != ''
4380         return
4381     endif
4382
4383     let filename = fnamemodify(bufname('%'), ':p')
4384     let ftype = s:Tlist_Get_Buffer_Filetype('%')
4385
4386     " If the file doesn't support tag listing, skip it
4387     if s:Tlist_Skip_File(filename, ftype)
4388         return
4389     endif
4390
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)
4396             return
4397         endif
4398
4399         " Process the tags for the file
4400         let fidx = s:Tlist_Process_File(filename, ftype)
4401         if fidx == -1
4402             return
4403         endif
4404     endif
4405
4406     let fname = escape(fnamemodify(bufname('%'), ':t'), '.')
4407     if fname != ''
4408         exe 'anoremenu T&ags.' .  fname . ' <Nop>'
4409         anoremenu T&ags.-SEP2-           :
4410     endif
4411
4412     if !s:tlist_{fidx}_tag_count
4413         return
4414     endif
4415
4416     if s:tlist_{fidx}_menu_cmd != ''
4417         " Update the menu with the cached command
4418         call s:Tlist_Menu_File_Refresh(fidx)
4419
4420         return
4421     endif
4422
4423     " We are going to add entries to the tags menu, so the menu won't be
4424     " empty
4425     let s:tlist_menu_empty = 0
4426
4427     let cmd = ''
4428
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
4433     let i = 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
4438         endif
4439         let i = i + 1
4440     endwhile
4441
4442     " Process the tags by the tag type and get the menu command
4443     let i = 1
4444     while i <= s:tlist_{ftype}_count
4445         let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i)
4446         if mcmd != ''
4447             let cmd = cmd . mcmd
4448         endif
4449
4450         let i = i + 1
4451     endwhile
4452
4453     " Cache the menu command for reuse
4454     let s:tlist_{fidx}_menu_cmd = cmd
4455
4456     " Update the menu
4457     call s:Tlist_Menu_File_Refresh(fidx)
4458 endfunction
4459
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
4464         return
4465     endif
4466
4467     call s:Tlist_Log_Msg('Removing the tags menu for a file')
4468
4469     " Cleanup the Tags menu
4470     silent! unmenu T&ags
4471     if &mousemodel =~ 'popup'
4472         silent! unmenu PopUp.T&ags
4473     endif
4474
4475     " Add a dummy menu item to retain teared off menu
4476     noremenu T&ags.Dummy l
4477
4478     silent! unmenu! T&ags
4479     if &mousemodel =~ 'popup'
4480         silent! unmenu! PopUp.T&ags
4481     endif
4482
4483     call s:Tlist_Menu_Add_Base_Menu()
4484
4485     " Remove the dummy menu item
4486     unmenu T&ags.Dummy
4487
4488     let s:tlist_menu_empty = 1
4489 endfunction
4490
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'))
4496     if fidx != -1
4497         " Invalidate the cached menu command
4498         let s:tlist_{fidx}_menu_cmd = ''
4499     endif
4500
4501     " Update the taglist, menu and window
4502     call s:Tlist_Update_Current_File()
4503 endfunction
4504
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'))
4509     if fidx == -1
4510         return
4511     endif
4512
4513     let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx)
4514     if tagpat == ''
4515         return
4516     endif
4517
4518     " Add the current cursor position to the jump list, so that user can
4519     " jump back using the ' and ` marks.
4520     mark '
4521
4522     silent call search(tagpat, 'w')
4523
4524     " Bring the line to the middle of the window
4525     normal! z.
4526
4527     " If the line is inside a fold, open the fold
4528     if foldclosed('.') != -1
4529         .foldopen
4530     endif
4531 endfunction
4532
4533 " Tlist_Menu_Init
4534 " Initialize the taglist menu
4535 function! s:Tlist_Menu_Init()
4536     call s:Tlist_Menu_Add_Base_Menu()
4537
4538     " Automatically add the tags defined in the current file to the menu
4539     augroup TagListMenuCmds
4540         autocmd!
4541
4542         if !g:Tlist_Process_File_Always
4543             autocmd BufEnter * call s:Tlist_Refresh()
4544         endif
4545         autocmd BufLeave * call s:Tlist_Menu_Remove_File()
4546     augroup end
4547
4548     call s:Tlist_Menu_Update_File(0)
4549 endfunction
4550
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')
4556
4557     " Initialize the taglist window
4558     call s:Tlist_Window_Init()
4559
4560     " Refresh the taglist window
4561     call s:Tlist_Window_Refresh()
4562 endfunction
4563
4564 " Tlist_Set_App
4565 " Set the name of the external plugin/application to which taglist
4566 " belongs.
4567 " Taglist plugin is part of another plugin like cream or winmanager.
4568 function! Tlist_Set_App(name)
4569     if a:name == ""
4570         return
4571     endif
4572
4573     let s:tlist_app_name = a:name
4574 endfunction
4575
4576 " Winmanager integration
4577
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__'
4582         return
4583     endif
4584
4585     call Tlist_Set_App('winmanager')
4586
4587     " Get the current filename from the winmanager plugin
4588     let bufnum = WinManagerGetLastEditedFile()
4589     if bufnum != -1
4590         let filename = fnamemodify(bufname(bufnum), ':p')
4591         let ftype = s:Tlist_Get_Buffer_Filetype(bufnum)
4592     endif
4593
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
4599     endif
4600
4601     " Update the taglist window
4602     if bufnum != -1
4603         if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update
4604             call s:Tlist_Window_Refresh_File(filename, ftype)
4605         endif
4606     endif
4607 endfunction
4608
4609 function! TagList_IsValid()
4610     return 0
4611 endfunction
4612
4613 function! TagList_WrapUp()
4614     return 0
4615 endfunction
4616
4617 " restore 'cpo'
4618 let &cpo = s:cpo_save
4619 unlet s:cpo_save
4620