Added taglist support.
[profile.git] / .vim / plugin / taglist.vim
1 " File: taglist.vim
2 " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
3 " Version: 2.3
4 " Last Modified: Feb 10, 2003
5 "
6 " Overview
7 " --------
8 " The "Tag List" plugin can be used to efficiently browse through your
9 " source files. The "Tag List" plugin provides the following features:
10 "
11 " 1. Opens a vertically/horizontally split Vim window with a list of tags
12 "    (functions, classes, structures, variables, etc) defined in the current
13 "    file.
14 " 2. Groups the tags by their type and displays them in a foldable tree.
15 " 3. Automatically updates the taglist window as you switch between
16 "    files/buffers.
17 " 4. When a tag name is selected from the taglist window, positions the cursor
18 "    at the definition of the tag in the source file
19 " 5. Automatically highlights the current tag name.
20 " 6. Can display the prototype of a tag from the taglist window.
21 " 7. Displays the scope of a tag.
22 " 8. Can optionally use the tag prototype instead of the tag name.
23 " 9. The tag list can be sorted either by name or by line number.
24 " 10. Supports the following language files: Assembly, ASP, Awk, C, C++,
25 "     Cobol, Eiffel, Fortran, Java, Lisp, Lua, Make, Pascal, Perl, PHP,
26 "     Python, Rexx, Ruby, Scheme, Shell, Slang, Sql, TCL, Verilog, Vim and
27 "     Yacc.
28 " 11. Runs in all the platforms where the exuberant ctags utility and Vim are
29 "     supported (this includes MS-Windows and Unix based systems).
30 " 12. Runs in both console/terminal and GUI versions of Vim.
31 " 13. The ctags output for a file is cached to speed up displaying the taglist
32 "     window.
33 " 14. Works with the winmanager plugin. Using the winmanager plugin, you can
34 "     use multiple Vim plugins at the same time efficiently.
35 " 15. Can be easily extended to support new languages. Support for existing
36 "     languages can be modified easily.
37 "
38 " To see the screenshots of the taglist plugin in different environments,
39 " visit the following page:
40 "
41 "       http://www.geocities.com/yegappan/taglist/screenshots.html
42 "
43 " This plugin relies on the exuberant ctags utility to dynamically generate
44 " the tag listing. You can download the exuberant ctags utility from
45 "
46 "               http://ctags.sourceforge.net.
47 "
48 " The exuberant ctags utility must be installed in your system to use this
49 " plugin. You should use exuberant ctags version 5.0 and above.  This plugin
50 " doesn't use or create a tags file and there is no need to create a tags file
51 " to use this plugin.
52 "
53 " This script relies on the Vim "filetype" detection mechanism to determine
54 " the type of the current file. To turn on filetype detection use
55 "
56 "               :filetype on
57 "
58 " This plugin will not work in 'compatible' mode.  Make sure the 'compatible'
59 " option is not set. This plugin will not work if you run Vim in the
60 " restricted mode (using the -Z command-line argument). This plugin also
61 " assumes that the system() Vim function is supported.
62 "
63 " Installation
64 " ------------
65 " 1. Copy the taglist.vim script to the $HOME/.vim/plugin directory. Refer to
66 "    ':help add-plugin', ':help add-global-plugin' and ':help runtimepath' for
67 "    more details about Vim plugins.
68 " 2. Set the Tlist_Ctags_Cmd variable to point to the location of the
69 "    exuberant ctags utility (not to the directory).
70 " 3. If you are running a terminal/console version of Vim and the terminal
71 "    doesn't support changing the window width then set the Tlist_Inc_Winwidth
72 "    variable to 0.
73 " 4. Restart Vim.
74 " 5. You can use the ":Tlist" command to open/close the taglist window. 
75 "
76 " Usage
77 " -----
78 " You can open the taglist window by using the ":Tlist" command. Invoking this
79 " command will toggle (open or close) the taglist window. You can map a key to
80 " invoke this command:
81 "
82 "               nnoremap <silent> <F8> :Tlist<CR>
83 "
84 " Add the above mapping to your ~/.vimrc file.  You can also open the taglist
85 " window on startup using the following command line:
86 "
87 "               $ vim +Tlist
88 "
89 " You can close the taglist window from the taglist window by pressing 'q' or
90 " using the Vim ":q" command. You can also use any of the Vim window commands
91 " to close the taglist window. Invoking the ":Tlist" command when the taglist
92 " window is opened, will close the taglist window.
93 "
94 " As you switch between source files, the taglist window will be automatically
95 " updated with the tag listing for the current source file.  The tag names
96 " will grouped by their type (variable, function, class, etc). For tags with
97 " scope information (like class members, structures inside structures, etc),
98 " the scope information will be displayed in square brackets "[]" after the
99 " tagname.
100
101 " The tag names will be  displayed as a foldable tree using the Vim folding
102 " support. You can collapse the tree using the '-' key or using the Vim zc
103 " fold command. You can open the tree using the '+' key or using the Vim zo
104 " fold command. You can open all the fold using the '*' key or using the Vim
105 " zR fold command You can also use the mouse to open/close the folds.
106 "
107 " You can select a tag either by pressing the <Enter> key or by double
108 " clicking the tag name using the mouse. You can configure the taglist plugin
109 " by setting the 'Tlist_Use_SingleClick' variable to jump to a tag on a single
110 " mouse click.
111 "
112 " The script will automatically highlight the name of the current tag.  The
113 " tag name will be highlighted after 'updatetime' milliseconds. The default
114 " value for this Vim option is 4 seconds.  You can also use the ":TlistSync"
115 " command to force the highlighting of the current tag. You can map a key to
116 " invoke this command:
117 "
118 "               nnoremap <silent> <F9> :TlistSync<CR>
119 "
120 " Add the above mapping to your ~/.vimrc file.
121 "
122 " If you place the cursor on a tag name in the "Tag List" window, then the tag
123 " prototype will be displayed at the Vim status line after 'updatetime'
124 " milliseconds. The default value for the 'updatetime' Vim option is 4
125 " seconds. You can also press the space bar to display the prototype of the
126 " tag under the cursor.
127 "
128 " By default, the tag list will be sorted by the order in which the tags
129 " appear in the file. You can sort the tags either by name or by order by
130 " pressing the "s" key in the taglist window.
131 "
132 " You can press the 'x' key in the taglist window to maximize the taglist
133 " window width/height. The window will be maximized to the maximum possible
134 " width/height without closing the other existing windows. You can again press
135 " 'x' to restore the taglist window to the default width/height.
136 "
137 " You can press the '?' key to display help information about using the
138 " taglist window. If you again press the '?' key, the help information will be
139 " removed.
140 "
141 " The following table lists the description of the keys that you can use
142 " in the taglist window.
143 "
144 "       Key           Description
145 "
146 "       <CR>          Jump to the location where the tag under cursor is
147 "                     defined.
148 "       o             Jump to the location where the tag under cursor is
149 "                     defined in a new window.
150 "       <Space>       Display the prototype of the tag under the cursor.
151 "       u             Update the tags listed in the taglist window
152 "       s             Change the sort order of the tags (by name or by order)
153 "       x             Zoom-in or Zoom-out the taglist window
154 "       +             Open a fold
155 "       -             Close a fold
156 "       *             Open all folds
157 "       q             Close the taglist window
158 "       ?             Display help
159 "
160 "
161 " You can use the ":TlistShowPrototype" command to display the prototype of
162 " a function in the specified line number. For example,
163 "
164 "               :TlistShowPrototype 50
165 "
166 " If the line number is not supplied, this command will display the prototype
167 " of the current function.
168 "
169 " You can also use the taglist plugin with the winmanager plugin. This will
170 " allow you to use the file explorer, buffer explorer and the taglist plugin
171 " at the same time in different windows. To use the taglist plugin with the
172 " winmanager plugin, set 'TagList' in the 'winManagerWindowLayout' variable.
173 " For example, to use the file explorer plugin and the taglist plugin at the
174 " same time, use the following setting:
175 "
176 "               let winManagerWindowLayout = 'FileExplorer|TagList'
177 "
178 " Configuration
179 " -------------
180 " By changing the following variables you can configure the behavior of this
181 " script. Set the following variables in your .vimrc file using the 'let'
182 " command.
183 "
184 " The script uses the Tlist_Ctags_Cmd variable to locate the ctags utility.
185 " By default, this is set to ctags. Set this variable to point to the location
186 " of the ctags utility in your system. Note that this variable should point to
187 " the fully qualified exuberant ctags location and NOT to the directory in
188 " which exuberant ctags is installed.
189 "
190 "               let Tlist_Ctags_Cmd = 'd:\tools\ctags.exe'
191 "               let Tlist_Ctags_Cmd = '/usr/local/bin/ctags'
192 "
193 " By default, the tag names will be listed in the order in which they are
194 " defined in the file. You can alphabetically sort the tag names by pressing
195 " the "s" key in the taglist window. You can also change the default order by
196 " setting the variable Tlist_Sort_Type to "name" or "order":
197 "
198 "               let Tlist_Sort_Type = "name"
199 "
200 " Be default, the tag names will be listed in a vertically split window.  If
201 " you prefer a horizontally split window, then set the
202 " 'Tlist_Use_Horiz_Window' variable to 1. If you are running MS-Windows
203 " version of Vim in a MS-DOS command window, then you should use a
204 " horizontally split window instead of a vertically split window.  Also, if
205 " you are using an older version of xterm in a Unix system that doesn't
206 " support changing the xterm window width, you should use a horizontally split
207 " window.
208 "
209 "               let Tlist_Use_Horiz_Window = 1
210 "
211 " By default, the vertically split taglist window will appear on the left hand
212 " side. If you prefer to open the window on the right hand side, you can set
213 " the Tlist_Use_Right_Window variable to one:
214 "
215 "               let Tlist_Use_Right_Window = 1
216 "
217 " To automatically open the taglist window, when you start Vim, you can set
218 " the Tlist_Auto_Open variable to 1. By default, this variable is set to 0 and
219 " the taglist window will not be opened automatically on Vim startup.
220 "
221 "               let Tlist_Auto_Open = 1
222 "
223 " By default, only the tag name will be displayed in the taglist window. If
224 " you like to see tag prototypes instead of names, set the
225 " Tlist_Display_Prototype variable to 1. By default, this variable is set to 0
226 " and only tag names will be displayed.
227 "
228 "               let Tlist_Display_Prototype = 1
229 "
230 " The default width of the vertically split taglist window will be 30.  This
231 " can be changed by modifying the Tlist_WinWidth variable:
232 "
233 "               let Tlist_WinWidth = 20
234 "
235 " Note that the value of the 'winwidth' option setting determines the minimum
236 " width of the current window. If you set the 'Tlist_WinWidth' variable to a
237 " value less than that of the 'winwidth' option setting, then Vim will use the
238 " value of the 'winwidth' option.
239 "
240 " By default, when the width of the window is less than 100 and a new taglist
241 " window is opened vertically, then the window width will be increased by the
242 " value set in the Tlist_WinWidth variable to accommodate the new window.  The
243 " value of this variable is used only if you are using a vertically split
244 " taglist window.  If your terminal doesn't support changing the window width
245 " from Vim (older version of xterm running in a Unix system) or if you see any
246 " weird problems in the screen due to the change in the window width or if you
247 " prefer not to adjust the window width then set the 'Tlist_Inc_Winwidth'
248 " variable to 0.  CAUTION: If you are using the MS-Windows version of Vim in a
249 " MS-DOS command window then you must set this variable to 0, otherwise the
250 " system may hang due to a Vim limitation (explained in :help win32-problems)
251 "
252 "               let Tlist_Inc_Winwidth = 0
253 "
254 " By default, when you double click on the tag name using the left mouse 
255 " button, the cursor will be positioned at the definition of the tag. You 
256 " can set the Tlist_Use_SingleClick variable to one to jump to a tag when
257 " you single click on the tag name using the mouse. By default this variable
258 " is set to zero.
259 "
260 "               let Tlist_Use_SingleClick = 1
261 "
262 " Due to a bug in Vim, if you set Tlist_Use_SingleClick to one and try to
263 " resize the taglist window using the mouse, then Vim will crash. The fix for
264 " this bug will be available in the next version of Vim. In the meantime,
265 " instead of resizing the taglist window using the mouse, you can use normal
266 " Vim window resizing commands to resize the taglist window.
267 "
268 " By default, the taglist window will contain text that display the name of
269 " the file, sort order information and the key to press to get help. Also,
270 " empty lines will be used to separate different groups of tags. If you
271 " don't need these information, you can set the Tlist_Compact_Format variable
272 " to one to get a compact display.
273 "
274 "               let Tlist_Compact_Format = 1
275 "
276 " Extending
277 " ---------
278 " You can extend exuberant ctags to add support for new languages. For more
279 " information, visit the following page
280 "
281 "               http://ctags.sourceforge.net/EXTENDING.html
282 "
283 " You can extend the taglist plugin to add support for new languages or modify
284 " the support for an already supported language by setting the following
285 " variables in the .vimrc file.
286 "
287 " To modify the support for an already supported language, you have to set the
288 " tlist_xxx_settings variable. Replace xxx with the Vim filetype name.  To
289 " determine the filetype name used by Vim for a file, use the command
290 "
291 "               :set filetype
292 "
293 " The format of the value set in the tlist_xxx_settings variable is
294 "
295 "          <language_name>;flag1:name1;flag2:name2;flag3:name3
296 "
297 " The different fields are separated by the ';' character.  The first field
298 " 'language_name' is the name used by exuberant ctags. This name can be
299 " different from the file type name used by Vim. For example, for C++, the
300 " language name used by ctags is 'c++' but the filetype name used by Vim is
301 " 'cpp'. The remaining fields follow the format "flag:name". The sub-field
302 " 'flag' is the language specific flag used by exuberant ctags to generate the
303 " corresponding tags.  For example, for the C language, to list only the
304 " functions, the 'f' flag should be used. For more information about the flags
305 " supported by exuberant ctags for a particular language, read the help text
306 " from the 'ctags --help' comand. The sub-field 'name' specifies the title
307 " text to use for displaying the tags of a particular type. For example,
308 " 'name' can be set to 'functions'.
309 "
310 " For example, to list only the classes and functions defined in a C++
311 " language file, add the following lines to your .vimrc file
312 "
313 "       let tlist_cpp_settings = 'c++;c:class;f:function'
314 "
315 " In the above setting, 'cpp' is the Vim filetype name and 'c++' is the name
316 " used by the exuberant ctags tool. 'c' and 'f' are the flags passed to
317 " exuberant ctags to list classes and functions.
318 "
319 " For example, to display only functions defined in a C file and to use "My
320 " Functions" as the title for the function group, use 
321 "
322 "       let tlist_c_settings = 'c;f:My Functions'
323 "
324 " To add support for a new language, set the tlist_xxx_settings variable
325 " appropriately as described above.
326 "
327 " ****************** Do not modify after this line ************************
328 if exists('loaded_taglist') || &cp
329     finish
330 endif
331 let loaded_taglist=1
332
333 " Location of the exuberant ctags tool
334 if !exists('Tlist_Ctags_Cmd')
335     let Tlist_Ctags_Cmd = 'ctags'
336 endif
337
338 " Tag listing sort type - 'name' or 'order'
339 if !exists('Tlist_Sort_Type')
340     let Tlist_Sort_Type = 'order'
341 endif
342
343 " Tag listing window split (horizontal/vertical) control
344 if !exists('Tlist_Use_Horiz_Window')
345     let Tlist_Use_Horiz_Window = 0
346 endif
347
348 " Open the vertically split taglist window on the left or on the right side.
349 " This setting is relevant only if Tlist_Use_Horiz_Window is set to zero (i.e.
350 " only for vertically split windows)
351 if !exists('Tlist_Use_Right_Window')
352     let Tlist_Use_Right_Window = 0
353 endif
354
355 " Increase Vim window width to display vertically split taglist window.  For
356 " MS-Windows version of Vim running in a MS-DOS window, this must be set to 0
357 " otherwise the system may hang due to a Vim limitation.
358 if !exists('Tlist_Inc_Winwidth')
359     if (has('win16') || has('win95')) && !has('gui_running')
360         let Tlist_Inc_Winwidth = 0
361     else
362         let Tlist_Inc_Winwidth = 1
363     endif
364 endif
365
366 " Vertically split taglist window width setting
367 if !exists('Tlist_WinWidth')
368     let Tlist_WinWidth = 30
369 endif
370
371 " Horizontally split taglist window height setting
372 if !exists('Tlist_WinHeight')
373     let Tlist_WinHeight = 10
374 endif
375
376 " Automatically open the taglist window on Vim startup
377 if !exists('Tlist_Auto_Open')
378     let Tlist_Auto_Open = 0
379 endif
380
381 " Display tag prototypes or tag names in the taglist window
382 if !exists('Tlist_Display_Prototype')
383     let Tlist_Display_Prototype = 0
384 endif
385
386 " Use single left mouse click to jump to a tag. By default this is disabled.
387 " Only double click using the mouse will be processed.
388 if !exists('Tlist_Use_SingleClick')
389     let Tlist_Use_SingleClick = 0
390 endif
391
392 " Control whether additional help is displayed as part of the taglist or not.
393 " Also, controls whether empty lines are used to separate the tag tree.
394 if !exists('Tlist_Compact_Format')
395     let Tlist_Compact_Format = 0
396 endif
397
398 " assembly language
399 let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type'
400
401 " aspperl language
402 let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub'
403
404 " aspvbs language
405 let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub'
406
407 " awk language
408 let s:tlist_def_awk_settings = 'awk;f:function'
409
410 " beta language
411 let s:tlist_def_beta_settings = 'beta;f:fragment;s:pattern;v:virtual'
412
413 " c language
414 let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' .
415                            \ 'v:variable;f:function'
416
417 " c++ language
418 let s:tlist_def_cpp_settings = 'c++;v:variable;d:macro;t:typedef;c:class;' .
419                              \ 'g:enum;s:struct;u:union;f:function'
420
421 " cobol language
422 let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
423                                \ 'P:program;s:section'
424
425 " eiffel language
426 let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature'
427
428 " fortran language
429 let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' .
430                     \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' .
431                     \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine'
432
433 " java language
434 let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
435                               \ 'f:field;m:method'
436
437 " lisp language
438 let s:tlist_def_lisp_settings = 'lisp;f:function'
439
440 " lua language
441 let s:tlist_def_lua_settings = 'lua;f:function'
442
443 " makefiles
444 let s:tlist_def_make_settings = 'make;m:macro'
445
446 " pascal language
447 let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure'
448
449 " perl language
450 let s:tlist_def_perl_settings = 'perl;p:package;s:subroutine'
451
452 " php language
453 let s:tlist_def_php_settings = 'php;c:class;f:function'
454
455 " python language
456 let s:tlist_def_python_settings = 'python;c:class;m:member;f:function'
457
458 " rexx language
459 let s:tlist_def_rexx_settings = 'rexx;s:subroutine'
460
461 " ruby language
462 let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' .
463                               \ 'm:singleton method'
464
465 " scheme language
466 let s:tlist_def_scheme_settings = 'scheme;s:set;f:function'
467
468 " shell language
469 let s:tlist_def_sh_settings = 'sh;f:function'
470
471 " C shell language
472 let s:tlist_def_csh_settings = 'sh;f:function'
473
474 " Z shell language
475 let s:tlist_def_zsh_settings = 'sh;f:function'
476
477 " slang language
478 let s:tlist_def_slang_settings = 'slang;n:namespace;f:function'
479
480 " sql language
481 let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' .
482             \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure'
483
484 " tcl language
485 let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;p:procedure'
486
487 "verilog language
488 let s:tlist_def_verilog_settings = 'verilog;m:module;P:parameter;r:reg;' .
489                                  \ 't:task;w:write;p:port;v:variable;f:function'
490
491 " vim language
492 let s:tlist_def_vim_settings = 'vim;v:variable;f:function'
493
494 " yacc language
495 let s:tlist_def_yacc_settings = 'yacc;l:label'
496
497 " Initialize the taglist script local variables for the supported file types
498 " and tag types
499 let s:tlist_winsize_chgd = 0
500 let s:tlist_win_maximized = 0
501 let s:tlist_part_of_winmanager = 0
502 " Do not change the name of the taglist title variable. The winmanager plugin
503 " relies on this name to determine the title for the taglist plugin.
504 let TagList_title = "__Tag_List__"
505
506 function! s:Tlist_Show_Help()
507     if g:Tlist_Compact_Format == 1
508         " In compact display mode, do not display help
509         return
510     endif
511     if exists("s:tlist_show_help") && s:tlist_show_help == 1
512         let s:tlist_show_help = 0
513     else
514         let s:tlist_show_help = 1
515     endif
516
517     call s:Tlist_Open_Window()
518
519     call s:Tlist_Init_Window(b:tlist_bufnum)
520
521     " Update the taglist window
522     call s:Tlist_Explore_File(b:tlist_bufnum)
523 endfunction
524
525 " An autocommand is used to refresh the taglist window when entering any
526 " buffer. We don't want to refresh the taglist window if we are entering the
527 " file window from one of the taglist functions. The 'Tlist_Skip_Refresh'
528 " variable is used to skip the refresh of the taglist window
529 let s:Tlist_Skip_Refresh = 0
530
531 function! s:Tlist_Warning_Msg(msg)
532     echohl WarningMsg
533     echomsg a:msg
534     echohl None
535 endfunction
536
537 " Tlist_Skip_Buffer()
538 " Check whether tag listing is supported for the specified buffer.
539 function! s:Tlist_Skip_Buffer(bufnum)
540     " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
541     if getbufvar(a:bufnum, '&buftype') != ''
542         return 1
543     endif
544
545     let ftype = getbufvar(a:bufnum, '&filetype')
546
547     " Skip buffers with filetype not set
548     if ftype == ''
549         return 1
550     endif
551
552     " Skip files which are not supported by exuberant ctags
553     " First check whether default settings for this filetype are available.
554     " If it is not available, then check whether user specified settings are
555     " available. If both are not available, then don't list the tags for this
556     " filetype
557     let var = 's:tlist_def_' . ftype . '_settings'
558     if !exists(var)
559         let var = 'g:tlist_' . ftype . '_settings'
560         if !exists(var)
561             return 1
562         endif
563     endif
564
565     let filename = fnamemodify(bufname(a:bufnum), '%:p')
566
567     " Skip buffers with no names
568     if filename == ''
569         return 1
570     endif
571
572     " Skip files which are not readable or files which are not yet stored
573     " to the disk
574     if !filereadable(filename)
575         return 1
576     endif
577
578     return 0
579 endfunction
580
581 " Tlist_FileType_Init
582 " Initialize the ctags arguments and tag variable for the specified
583 " file type
584 function! s:Tlist_FileType_Init(ftype)
585     " If the user didn't specify any settings, then use the default
586     " ctags args. Otherwise, use the settings specified by the user
587     let var = 'g:tlist_' . a:ftype . '_settings'
588     if exists(var)
589         " User specified ctags arguments
590         let settings = {var} . ';'
591     else
592         " Default ctags arguments
593         let var = 's:tlist_def_' . a:ftype . '_settings'
594         if !exists(var)
595             " No default settings for this file type. This filetype is
596             " not supported
597             return 0
598         endif
599         let settings = s:tlist_def_{a:ftype}_settings . ';'
600     endif
601
602     let msg = 'Invalid ctags option setting - ' . settings
603
604     " Extract the file type to pass to ctags. This can be different from the
605     " file type detected by Vim
606     let pos = stridx(settings, ';')
607     if pos == -1
608         call s:Tlist_Warning_Msg(msg)
609         return 0
610     endif
611     let ctags_ftype = strpart(settings, 0, pos)
612     if ctags_ftype == ''
613         call s:Tlist_Warning_Msg(msg)
614         return 0
615     endif
616     " Make sure a valid filetype is supplied. If the user didn't specify a
617     " valid filetype, then the ctags option settings may be treated as the
618     " filetype
619     if ctags_ftype =~ ':'
620         call s:Tlist_Warning_Msg(msg)
621         return 0
622     endif
623
624     " Remove the file type from settings
625     let settings = strpart(settings, pos + 1)
626     if settings == ''
627         call s:Tlist_Warning_Msg(msg)
628         return 0
629     endif
630
631     " Process all the specified ctags flags. The format is
632     " flag1:name1;flag2:name2;flag3:name3
633     let ctags_flags = ''
634     let cnt = 0
635     while settings != ''
636         " Extract the flag
637         let pos = stridx(settings, ':')
638         if pos == -1
639             call s:Tlist_Warning_Msg(msg)
640             return 0
641         endif
642         let flag = strpart(settings, 0, pos) 
643         if flag == ''
644             call s:Tlist_Warning_Msg(msg)
645             return 0
646         endif
647         " Remove the flag from settings
648         let settings = strpart(settings, pos + 1)
649
650         " Extract the tag type name
651         let pos = stridx(settings, ';')
652         if pos == -1
653             call s:Tlist_Warning_Msg(msg)
654             return 0
655         endif
656         let name = strpart(settings, 0, pos)
657         if name == ''
658             call s:Tlist_Warning_Msg(msg)
659             return 0
660         endif
661         let settings = strpart(settings, pos + 1)
662
663         let cnt = cnt + 1
664
665         let s:tlist_{a:ftype}_{cnt}_name = flag
666         let s:tlist_{a:ftype}_{cnt}_fullname = name
667         let ctags_flags = ctags_flags . flag
668     endwhile
669
670     let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype .
671                             \ ' --' . ctags_ftype . '-types=' . ctags_flags
672     let s:tlist_{a:ftype}_count = cnt
673     let s:tlist_{a:ftype}_ctags_flags = ctags_flags
674
675     return 1
676 endfunction
677
678 " Tlist_Cleanup()
679 " Cleanup all the taglist window variables.
680 function! s:Tlist_Cleanup()
681     if has('syntax')
682         silent! syntax clear TagListTitle
683     endif
684     match none
685
686     if exists('b:tlist_ftype') && b:tlist_ftype != ''
687         let count_var_name = 's:tlist_' . b:tlist_ftype . '_count'
688         if exists(count_var_name)
689             let old_ftype = b:tlist_ftype
690             let i = 1
691             while i <= s:tlist_{old_ftype}_count
692                 let ttype = s:tlist_{old_ftype}_{i}_name
693                 let j = 1
694                 let var_name = 'b:tlist_' . old_ftype . '_' . ttype . '_count'
695                 if exists(var_name)
696                     let cnt = b:tlist_{old_ftype}_{ttype}_count
697                 else
698                     let cnt = 0
699                 endif
700                 while j <= cnt
701                     unlet! b:tlist_{old_ftype}_{ttype}_{j}
702                     let j = j + 1
703                 endwhile
704                 unlet! b:tlist_{old_ftype}_{ttype}_count
705                 unlet! b:tlist_{old_ftype}_{ttype}_start
706                 let i = i + 1
707             endwhile
708         endif
709     endif
710
711     " Clean up all the variables containing the tags output
712     if exists('b:tlist_tag_count')
713         while b:tlist_tag_count > 0
714             unlet! b:tlist_tag_{b:tlist_tag_count}
715             let b:tlist_tag_count = b:tlist_tag_count - 1
716         endwhile
717     endif
718
719     unlet! b:tlist_bufnum
720     unlet! b:tlist_bufname
721     unlet! b:tlist_ftype
722 endfunction
723
724 " Tlist_Open_Window
725 " Create a new taglist window. If it is already open, clear it
726 function! s:Tlist_Open_Window()
727     " If used with winmanager don't open windows. Winmanager will handle
728     " the window/buffer management
729     if s:tlist_part_of_winmanager
730         return
731     endif
732
733     " Cleanup the taglist window listing, if the window is open
734     let winnum = bufwinnr(g:TagList_title)
735     if winnum != -1
736         " Jump to the existing window
737         if winnr() != winnum
738             exe winnum . 'wincmd w'
739         endif
740     else
741         " Create a new window. If user prefers a horizontal window, then open
742         " a horizontally split window. Otherwise open a vertically split
743         " window
744         if g:Tlist_Use_Horiz_Window == 1
745             " If a single window is used for all files, then open the tag
746             " listing window at the very bottom
747             let win_dir = 'botright'
748             " Horizontal window height
749             let win_size = g:Tlist_WinHeight
750         else
751             " Increase the window size, if needed, to accomodate the new
752             " window
753             if g:Tlist_Inc_Winwidth == 1 &&
754                         \ &columns < (80 + g:Tlist_WinWidth)
755                 " one extra column is needed to include the vertical split
756                 let &columns= &columns + (g:Tlist_WinWidth + 1)
757                 let s:tlist_winsize_chgd = 1
758             else
759                 let s:tlist_winsize_chgd = 0
760             endif
761
762             " Open the window at the leftmost place
763             if g:Tlist_Use_Right_Window == 1
764                 let win_dir = 'botright vertical'
765             else
766                 let win_dir = 'topleft vertical'
767             endif
768             let win_size = g:Tlist_WinWidth
769         endif
770
771         " If the tag listing temporary buffer already exists, then reuse it.
772         " Otherwise create a new buffer
773         let bufnum = bufnr(g:TagList_title)
774         if bufnum == -1
775             " Create a new buffer
776             let wcmd = g:TagList_title
777         else
778             " Edit the existing buffer
779             let wcmd = '+buffer' . bufnum
780         endif
781
782         " Create the taglist window
783         exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
784     endif
785 endfunction
786
787 " Tlist_Zoom_Window
788 " Zoom (maximize/minimize) the taglist window
789 function! s:Tlist_Zoom_Window()
790     if s:tlist_win_maximized == 1
791         if g:Tlist_Use_Horiz_Window == 1
792             exe 'resize ' . g:Tlist_WinHeight
793         else
794             exe 'vert resize ' . g:Tlist_WinWidth
795         endif
796         let s:tlist_win_maximized = 0
797     else
798         " Set the window size to the maximum possible without closing other
799         " windows
800         if g:Tlist_Use_Horiz_Window == 1
801             resize
802         else
803             vert resize
804         endif
805         let s:tlist_win_maximized = 1
806     endif
807 endfunction
808
809 " Tlist_Init_Window
810 " Set the default options for the taglist window
811 function! s:Tlist_Init_Window(bufnum)
812     " Set report option to a huge value to prevent informations messages
813     " while deleting the lines
814     let old_report = &report
815     set report=99999
816
817     " Mark the buffer as modifiable
818     setlocal modifiable
819
820     " Delete the contents of the buffer to the black-hole register
821     silent! %delete _
822
823     " Mark the buffer as not modifiable
824     setlocal nomodifiable
825
826     " Restore the report option
827     let &report = old_report
828
829     " Clean up all the old variables used for the last filetype
830     call <SID>Tlist_Cleanup()
831
832     let filename = fnamemodify(bufname(a:bufnum), ':p')
833
834     " Set the sort type. First time, use the global setting. After that use
835     " the previous setting
836     let b:tlist_sort_type = getbufvar(a:bufnum, 'tlist_sort_type')
837     if b:tlist_sort_type == ''
838         let b:tlist_sort_type = g:Tlist_Sort_Type
839     endif
840
841     let b:tlist_tag_count = 0
842     let b:tlist_bufnum = a:bufnum
843     let b:tlist_bufname = fnamemodify(bufname(a:bufnum), ':p')
844     let b:tlist_ftype = getbufvar(a:bufnum, '&filetype')
845
846     " Mark the buffer as modifiable
847     setlocal modifiable
848
849     if s:tlist_part_of_winmanager
850         " To handle a bug in the winmanager plugin, add a space at the
851         " last line
852         call setline('$', ' ')
853     endif
854
855     if g:Tlist_Compact_Format == 0
856         if exists("s:tlist_show_help") && s:tlist_show_help == 1
857             call append(0, '" <enter> : Jump to tag definition')
858             call append(1, '" o : Jump to tag definition in new window')
859             call append(2, '" <space> : Display tag prototype')
860             call append(3, '" u : Update tag list')
861             call append(4, '" s : Select sort field')
862             call append(5, '" x : Zoom-out/Zoom-in taglist window')
863             call append(6, '" + : Open a fold')
864             call append(7, '" - : Close a fold')
865             call append(8, '" * : Open all folds')
866             call append(9, '" q : Close the taglist window')
867             call append(10, '" ? : Remove help text')
868             call append(11, '" Sorted by ' . b:tlist_sort_type)
869             call append(12, '"= ' . fnamemodify(filename, ':t') . ' (' . 
870                                    \ fnamemodify(filename, ':p:h') . ')')
871         else
872             call append(0, '" Press ? to display help text')
873             call append(1, '" Sorted by ' . b:tlist_sort_type)
874             call append(2, '"= ' . fnamemodify(filename, ':t') . ' (' . 
875                                    \ fnamemodify(filename, ':p:h') . ')')
876         endif
877     endif
878
879     " Mark the buffer as not modifiable
880     setlocal nomodifiable
881
882     " Highlight the comments
883     if has('syntax')
884         syntax match TagListComment '^" .*'
885         syntax match TagListSortBy  '^" Sorted by .*'
886         syntax match TagListCurDir  '^"= .*'
887
888         " Colors used to highlight the selected tag name
889         highlight clear TagName
890         if has('gui_running') || &t_Co > 2
891             highlight link TagName Search
892         else
893             highlight TagName term=reverse cterm=reverse
894         endif
895
896         " Colors to highlight comments and titles
897         highlight clear TagListComment
898         highlight link TagListComment Comment
899         highlight clear TagListTitle
900         highlight link TagListTitle Title
901         highlight clear TagListSortBy
902         highlight link TagListSortBy String
903         highlight clear TagListCurDir
904         highlight link TagListCurDir Statement
905     endif
906
907     " Folding related settings
908     if has('folding')
909         setlocal foldenable
910         setlocal foldmethod=manual
911         setlocal foldcolumn=2
912         setlocal foldtext=v:folddashes.getline(v:foldstart)
913     endif
914
915     if !s:tlist_part_of_winmanager
916     " Mark buffer as scratch
917     silent! setlocal buftype=nofile
918     silent! setlocal bufhidden=delete
919     silent! setlocal noswapfile
920     " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted
921     " buffers. So if the taglist buffer is unlisted, multiple taglist
922     " windows will be opened. This bug is fixed in Vim 6.1 and above
923     if v:version >= 601
924         silent! setlocal nobuflisted
925     endif
926     endif
927
928     silent! setlocal nowrap
929
930     " If the 'number' option is set in the source window, it will affect the
931     " taglist window. So forcefully disable 'number' option for the taglist
932     " window
933     silent! setlocal nonumber
934
935     " Create buffer local mappings for jumping to the tags and sorting the list
936     nnoremap <buffer> <silent> <CR> :call <SID>Tlist_Jump_To_Tag(0)<CR>
937     nnoremap <buffer> <silent> o :call <SID>Tlist_Jump_To_Tag(1)<CR>
938     nnoremap <buffer> <silent> <2-LeftMouse> :call <SID>Tlist_Jump_To_Tag(0)<CR>
939     nnoremap <buffer> <silent> s :call <SID>Tlist_Change_Sort()<CR>
940     nnoremap <buffer> <silent> + :silent! foldopen<CR>
941     nnoremap <buffer> <silent> - :silent! foldclose<CR>
942     nnoremap <buffer> <silent> * :silent! %foldopen!<CR>
943     nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR>
944     nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR>
945     nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR>
946     nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Show_Tag_Prototype()<CR>
947     nnoremap <buffer> <silent> u :call <SID>Tlist_Update_Window()<CR>
948     nnoremap <buffer> <silent> x :call <SID>Tlist_Zoom_Window()<CR>
949     nnoremap <buffer> <silent> ? :call <SID>Tlist_Show_Help()<CR>
950     nnoremap <buffer> <silent> q :close<CR>
951
952     " Map single left mouse click if the user wants this functionality
953     if g:Tlist_Use_SingleClick == 1
954     nnoremap <silent> <LeftMouse> <LeftMouse>:if bufname("%") =~ "__Tag_List__"
955                         \ <bar> call <SID>Tlist_Jump_To_Tag(0) <bar> endif <CR>
956     endif
957
958     " Define the autocommand to highlight the current tag
959     augroup TagListAutoCmds
960         autocmd!
961         " Display the tag prototype for the tag under the cursor.
962         autocmd CursorHold __Tag_List__ call s:Tlist_Show_Tag_Prototype()
963         " Highlight the current tag 
964         autocmd CursorHold * silent call <SID>Tlist_Highlight_Tag(bufnr('%'), 
965                                         \ line('.'))
966         autocmd BufUnload __Tag_List__ call <SID>Tlist_Close_Window()
967         if !s:tlist_part_of_winmanager
968         " Adjust the Vim window width when taglist window is closed
969         " Auto refresh the taglisting window
970         autocmd BufEnter * call <SID>Tlist_Refresh_Window()
971         endif
972     augroup end
973 endfunction
974
975 " Tlist_Close_Window()
976 " Close the taglist window and adjust the Vim window width
977 function! s:Tlist_Close_Window()
978     " Remove the autocommands for the taglist window
979     silent! autocmd! TagListAutoCmds
980
981     " Clear all the highlights
982     match none
983
984     if has('syntax')
985         silent! syntax clear TagListTitle
986     endif
987
988     " Remove the left mouse click mapping if it was setup initially
989     if g:Tlist_Use_SingleClick == 1
990         if hasmapto('<LeftMouse>')
991             nunmap <LeftMouse>
992         endif
993     endif
994
995     if !s:tlist_part_of_winmanager
996     if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 ||
997                 \ s:tlist_winsize_chgd == 0 ||
998                 \ &columns < (80 + g:Tlist_WinWidth)
999         " No need to adjust window width if horizontally split tag listing
1000         " window or if columns is less than 101 or if the user chose not to
1001         " adjust the window width
1002     else
1003         " Adjust the Vim window width
1004         let &columns= &columns - (g:Tlist_WinWidth + 1)
1005     endif
1006     endif
1007 endfunction
1008
1009 " Tlist_Explore_File()
1010 " List the tags defined in the specified file in a Vim window
1011 function! s:Tlist_Explore_File(bufnum)
1012     " Get the filename and file type
1013     let filename = fnamemodify(bufname(a:bufnum), ':p')
1014     let ftype = getbufvar(a:bufnum, '&filetype')
1015
1016     " Check for valid filename and valid filetype
1017     if filename == '' || !filereadable(filename) || ftype == ''
1018         return
1019     endif
1020
1021     " If the tag types for this filetype are not yet created, then create
1022     " them now
1023     let var = 's:tlist_' . ftype . '_count'
1024     if !exists(var)
1025         if s:Tlist_FileType_Init(ftype) == 0
1026             return
1027         endif
1028     endif
1029
1030     " If the cached ctags output exists for the specified buffer, then use it.
1031     " Otherwise run ctags to get the output
1032     let valid_cache = getbufvar(a:bufnum, 'tlist_valid_cache')
1033     if valid_cache != ''
1034         " Load the cached processed tags output from the buffer local
1035         " variables
1036         let b:tlist_tag_count = getbufvar(a:bufnum, 'tlist_tag_count') + 0
1037         let i = 1
1038         while i <= b:tlist_tag_count
1039             let var_name = 'tlist_tag_' . i
1040             let b:tlist_tag_{i} =  getbufvar(a:bufnum, var_name)
1041             let i = i + 1
1042         endwhile
1043
1044         let i = 1
1045         while i <= s:tlist_{ftype}_count
1046             let ttype = s:tlist_{ftype}_{i}_name
1047             let var_name = 'tlist_' . ttype . '_start'
1048             let b:tlist_{ftype}_{ttype}_start = 
1049                         \ getbufvar(a:bufnum, var_name) + 0
1050             let var_name = 'tlist_' . ttype . '_count'
1051             let cnt = getbufvar(a:bufnum, var_name) + 0
1052             let b:tlist_{ftype}_{ttype}_count = cnt
1053             let var_name = 'tlist_' . ttype
1054             let l:tlist_{ftype}_{ttype} = getbufvar(a:bufnum, var_name)
1055             let j = 1
1056             while j <= cnt
1057                 let var_name = 'tlist_' . ttype . '_' . j
1058                 let b:tlist_{ftype}_{ttype}_{j} = getbufvar(a:bufnum, var_name)
1059                 let j = j + 1
1060             endwhile
1061             let i = i + 1
1062         endwhile
1063     else
1064         " Exuberant ctags arguments to generate a tag list
1065         let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks '
1066
1067         " Form the ctags argument depending on the sort type 
1068         if b:tlist_sort_type == 'name'
1069             let ctags_args = ctags_args . ' --sort=yes '
1070         else
1071             let ctags_args = ctags_args . ' --sort=no '
1072         endif
1073
1074         " Add the filetype specific arguments
1075         let ctags_args = ctags_args . ' ' . s:tlist_{ftype}_ctags_args
1076
1077         " Ctags command to produce output with regexp for locating the tags
1078         let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args
1079         let ctags_cmd = ctags_cmd . ' "' . filename . '"'
1080
1081         " Run ctags and get the tag list
1082         let cmd_output = system(ctags_cmd)
1083
1084         " Cache the ctags output with a buffer local variable
1085         call setbufvar(a:bufnum, 'tlist_valid_cache', 'Yes')
1086         call setbufvar(a:bufnum, 'tlist_sort_type', b:tlist_sort_type)
1087
1088         " Handle errors
1089         if v:shell_error && cmd_output != ''
1090             call s:Tlist_Warning_Msg(cmd_output)
1091             return
1092         endif
1093
1094         " No tags for current file
1095         if cmd_output == ''
1096             call s:Tlist_Warning_Msg('No tags found for ' . filename)
1097             return
1098         endif
1099
1100         " Initialize variables for the new filetype
1101         let i = 1
1102         while i <= s:tlist_{ftype}_count
1103             let ttype = s:tlist_{ftype}_{i}_name
1104             let b:tlist_{ftype}_{ttype}_start = 0
1105             let b:tlist_{ftype}_{ttype}_count = 0
1106             let l:tlist_{ftype}_{ttype} = ''
1107             let i = i + 1
1108         endwhile
1109
1110         " Process the ctags output one line at a time. Separate the tag output
1111         " based on the tag type and store it in the tag type variable
1112         while cmd_output != ''
1113             " Extract one line at a time
1114             let one_line = strpart(cmd_output, 0, stridx(cmd_output, "\n"))
1115             " Remove the line from the tags output
1116             let cmd_output = strpart(cmd_output, stridx(cmd_output, "\n") + 1)
1117
1118             if one_line == ''
1119                 " Line is not in proper tags format
1120                 continue
1121             endif
1122
1123             " Extract the tag type
1124             let ttype = s:Tlist_Extract_Tagtype(one_line)
1125
1126             if ttype == ''
1127                 " Line is not in proper tags format
1128                 continue
1129             endif
1130
1131             " make sure the tag type is supported
1132             if s:tlist_{ftype}_ctags_flags !~# ttype
1133                 continue
1134             endif
1135
1136             " Extract the tag name
1137             if g:Tlist_Display_Prototype == 0
1138                 let ttxt = '  ' . strpart(one_line, 0, stridx(one_line, "\t"))
1139
1140                 " Add the tag scope, if it is available. Tag scope is the last
1141                 " field after the 'line:<num>\t' field
1142                 let start = strridx(one_line, 'line:')
1143                 let end = strridx(one_line, "\t")
1144                 if end > start
1145                     let tscope = strpart(one_line, end + 1)
1146                     let tscope = strpart(tscope, stridx(tscope, ':') + 1)
1147                     if tscope != ''
1148                         let ttxt = ttxt . ' [' . tscope . ']'
1149                     endif
1150                 endif
1151             else
1152                 let start = stridx(one_line, '/^') + 2
1153                 let end = strridx(one_line, '/;"' . "\t")
1154                 if one_line[end - 1] == '$'
1155                     let end = end -1
1156                 endif
1157                 let ttxt = strpart(one_line, start, end - start)
1158             endif
1159
1160             " Update the count of this tag type
1161             let cnt = b:tlist_{ftype}_{ttype}_count + 1
1162             let b:tlist_{ftype}_{ttype}_count = cnt
1163
1164             " Add this tag to the tag type variable
1165             let l:tlist_{ftype}_{ttype} = l:tlist_{ftype}_{ttype} . ttxt . "\n"
1166
1167             " Update the total tag count
1168             let b:tlist_tag_count = b:tlist_tag_count + 1
1169             let b:tlist_tag_{b:tlist_tag_count} = cnt . ':' . one_line
1170
1171             let b:tlist_{ftype}_{ttype}_{cnt} = b:tlist_tag_count
1172         endwhile
1173
1174         " Cache the processed tags output using buffer local variables
1175         call setbufvar(a:bufnum, 'tlist_tag_count', b:tlist_tag_count)
1176         let i = 1
1177         while i <= b:tlist_tag_count
1178             let var_name = 'tlist_tag_' . i
1179             call setbufvar(a:bufnum, var_name, b:tlist_tag_{i})
1180             let i = i + 1
1181         endwhile
1182
1183         let i = 1
1184         while i <= s:tlist_{ftype}_count
1185             let ttype = s:tlist_{ftype}_{i}_name
1186             let var_name = 'tlist_' . ttype . '_start'
1187             call setbufvar(a:bufnum, var_name, b:tlist_{ftype}_{ttype}_start)
1188             let cnt = b:tlist_{ftype}_{ttype}_count
1189             let var_name = 'tlist_' . ttype . '_count'
1190             call setbufvar(a:bufnum, var_name, cnt)
1191             let var_name = 'tlist_' . ttype
1192             call setbufvar(a:bufnum, var_name, l:tlist_{ftype}_{ttype})
1193             let j = 1
1194             while j <= cnt
1195                 let var_name = 'tlist_' . ttype . '_' . j
1196                 call setbufvar(a:bufnum, var_name, b:tlist_{ftype}_{ttype}_{j})
1197                 let j = j + 1
1198             endwhile
1199             let i = i + 1
1200         endwhile
1201     endif
1202
1203     " Set report option to a huge value to prevent informational messages
1204     " while adding lines to the taglist window
1205     let old_report = &report
1206     set report=99999
1207
1208     " Mark the buffer as modifiable
1209     setlocal modifiable
1210
1211     " Add the tag names grouped by tag type to the buffer with a title
1212     let i = 1
1213     while i <= s:tlist_{ftype}_count
1214         let ttype = s:tlist_{ftype}_{i}_name
1215         " Add the tag type only if there are tags for that type
1216         if l:tlist_{ftype}_{ttype} != ''
1217             if g:Tlist_Compact_Format == 0
1218                 let b:tlist_{ftype}_{ttype}_start = line('.') + 1
1219                 silent! put =s:tlist_{ftype}_{i}_fullname
1220             else
1221                 let b:tlist_{ftype}_{ttype}_start = line('.')
1222                 silent! put! =s:tlist_{ftype}_{i}_fullname
1223             endif
1224             silent! put =l:tlist_{ftype}_{ttype}
1225
1226             " create a fold for this tag type
1227             if has('folding')
1228                 let fold_start = b:tlist_{ftype}_{ttype}_start
1229                 let fold_end = fold_start + b:tlist_{ftype}_{ttype}_count
1230                 exe fold_start . ',' . fold_end  . 'fold'
1231             endif
1232
1233             " Syntax highlight the tag type names
1234             if has('syntax')
1235                 exe 'syntax match TagListTitle /\%' . 
1236                             \ b:tlist_{ftype}_{ttype}_start . 'l.*/'
1237             endif
1238             " Separate the tag types with a empty line
1239             normal! G
1240             if g:Tlist_Compact_Format == 0
1241                 silent! put =''
1242             endif
1243         endif
1244         let i = i + 1
1245     endwhile
1246
1247     if s:tlist_part_of_winmanager
1248         " To handle a bug in the winmanager plugin, add a space at the
1249         " last line
1250         call setline('$', ' ')
1251     endif
1252
1253     " Mark the buffer as not modifiable
1254     setlocal nomodifiable
1255
1256     " Restore the report option
1257     let &report = old_report
1258
1259     " Initially open all the folds
1260     if has('folding')
1261         silent! %foldopen!
1262     endif
1263
1264     " Goto the first line in the buffer
1265     go
1266
1267     return
1268 endfunction
1269
1270 " Tlist_Toggle_Window()
1271 " Open or close a taglist window
1272 function! s:Tlist_Toggle_Window(bufnum)
1273     let curline = line('.')
1274
1275     " If taglist window is open then close it.
1276     let winnum = bufwinnr(g:TagList_title)
1277     if winnum != -1
1278         if winnr() == winnum
1279             " Already in the taglist window. Close it and return
1280             close
1281         else
1282             " Goto the taglist window, close it and then come back to the
1283             " original window
1284             let curbufnr = bufnr('%')
1285             exe winnum . 'wincmd w'
1286             close
1287             " Need to jump back to the original window only if we are not
1288             " already in that window
1289             let winnum = bufwinnr(curbufnr)
1290             if winnr() != winnum
1291                 exe winnum . 'wincmd w'
1292             endif
1293         endif
1294         return
1295     endif
1296
1297     let s:tlist_part_of_winmanager = 0
1298
1299     " Open the taglist window
1300     call s:Tlist_Open_Window()
1301
1302     " Initialize the taglist window
1303     call s:Tlist_Init_Window(a:bufnum)
1304
1305     " List the tags defined in a file
1306     call s:Tlist_Explore_File(a:bufnum)
1307
1308     " Highlight the current tag
1309     call s:Tlist_Highlight_Tag(a:bufnum, curline)
1310
1311     " Go back to the original window
1312     let s:Tlist_Skip_Refresh = 1
1313     wincmd p
1314     let s:Tlist_Skip_Refresh = 0
1315 endfunction
1316
1317 " Tlist_Extract_Tagtype
1318 " Extract the tag type from the tag text
1319 function! s:Tlist_Extract_Tagtype(tag_txt)
1320     " The tag type is after the tag prototype field. The prototype field
1321     " ends with the /;"\t string. We add 4 at the end to skip the characters
1322     " in this special string..
1323     let start = strridx(a:tag_txt, '/;"' . "\t") + 4
1324     let end = strridx(a:tag_txt, 'line:') - 1
1325     let ttype = strpart(a:tag_txt, start, end - start)
1326
1327     return ttype
1328 endfunction
1329
1330 " Tlist_Extract_Tag_Prototype
1331 " Extract the tag protoype from the tag text
1332 function! s:Tlist_Extract_Tag_Prototype(tag_txt)
1333     let start = stridx(a:tag_txt, '/^') + 2
1334     let end = strridx(a:tag_txt, '/;"' . "\t")
1335     if a:tag_txt[end - 1] == '$'
1336         let end = end -1
1337     endif
1338     let tag_pat = strpart(a:tag_txt, start, end - start)
1339
1340     " Remove all the leading space characters
1341     let tag_pat = matchstr(tag_pat, '^\s*\zs.*')
1342
1343     return tag_pat
1344 endfunction
1345
1346 " Tlist_Refresh_Window()
1347 " Refresh the taglist window
1348 function! s:Tlist_Refresh_Window()
1349     " We are entering the buffer from one of the taglist functions. So no need
1350     " to refresh the taglist window again
1351     if s:Tlist_Skip_Refresh == 1
1352         return
1353     endif
1354
1355     " If the buffer doesn't support tag listing, skip it
1356     if s:Tlist_Skip_Buffer(bufnr('%'))
1357         return
1358     endif
1359
1360     let filename = expand('%:p')
1361
1362     let curline = line('.')
1363
1364     " Make sure the taglist window is open. Otherwise, no need to refresh
1365     let winnum = bufwinnr(g:TagList_title)
1366     if winnum == -1
1367         return
1368     endif
1369
1370     let bno = bufnr(g:TagList_title)
1371
1372     let cur_bufnr = bufnr('%')
1373
1374     " If the tag listing for the current window is already present, no need to
1375     " refresh it
1376     if getbufvar(bno, 'tlist_bufnum') == cur_bufnr && 
1377                 \ getbufvar(bno, 'tlist_bufname') == filename
1378         return
1379     endif
1380
1381     " Save the current window number
1382     let cur_winnr = winnr()
1383
1384     call s:Tlist_Open_Window()
1385
1386     call s:Tlist_Init_Window(cur_bufnr)
1387
1388     " Update the taglist window
1389     call s:Tlist_Explore_File(cur_bufnr)
1390
1391     " Highlight the current tag
1392     call s:Tlist_Highlight_Tag(cur_bufnr, curline)
1393
1394     " Refresh the taglist window
1395     redraw
1396
1397     if !s:tlist_part_of_winmanager
1398     " Jump back to the original window
1399     exe cur_winnr . 'wincmd w'
1400     endif
1401 endfunction
1402
1403 " Tlist_Change_Sort()
1404 " Change the sort order of the tag listing
1405 function! s:Tlist_Change_Sort()
1406     if !exists('b:tlist_bufnum') || !exists('b:tlist_ftype')
1407         return
1408     endif
1409
1410     let sort_type = getbufvar(b:tlist_bufnum, 'tlist_sort_type')
1411
1412     " Toggle the sort order from 'name' to 'order' and vice versa
1413     if sort_type == 'name'
1414         call setbufvar(b:tlist_bufnum, 'tlist_sort_type', 'order')
1415     else
1416         call setbufvar(b:tlist_bufnum, 'tlist_sort_type', 'name')
1417     endif
1418
1419     " Save the current line for later restoration
1420     let curline = '\V\^' . getline('.') . '\$'
1421
1422     " Clear out the cached taglist information
1423     call setbufvar(b:tlist_bufnum, 'tlist_valid_cache', '')
1424
1425     call s:Tlist_Open_Window()
1426
1427     call s:Tlist_Init_Window(b:tlist_bufnum)
1428
1429     call s:Tlist_Explore_File(b:tlist_bufnum)
1430
1431     " Go back to the tag line before the list is sorted
1432     call search(curline, 'w')
1433 endfunction
1434
1435 " Tlist_Update_Window()
1436 " Update the window by regenerating the tag list
1437 function! s:Tlist_Update_Window()
1438     if !exists('b:tlist_bufnum') || !exists('b:tlist_ftype')
1439         return
1440     endif
1441
1442     " Save the current line for later restoration
1443     let curline = '\V\^' . getline('.') . '\$'
1444
1445     " Clear out the cached taglist information
1446     call setbufvar(b:tlist_bufnum, 'tlist_valid_cache', '')
1447
1448     call s:Tlist_Open_Window()
1449
1450     call s:Tlist_Init_Window(b:tlist_bufnum)
1451
1452     " Update the taglist window
1453     call s:Tlist_Explore_File(b:tlist_bufnum)
1454
1455     " Go back to the tag line before the list is sorted
1456     call search(curline, 'w')
1457 endfunction
1458
1459 " Tlist_Get_Tag_Linenr()
1460 " Return the tag line for the current line
1461 function! s:Tlist_Get_Tag_Linenr()
1462     if !exists('b:tlist_ftype')
1463         return 0
1464     endif
1465
1466     let lnum = line('.')
1467     let ftype = b:tlist_ftype
1468
1469     " Determine to which tag type the current line number belongs to using the
1470     " tag type start line number and the number of tags in a tag type
1471     let i = 1
1472     while i <= s:tlist_{ftype}_count
1473         let ttype = s:tlist_{ftype}_{i}_name
1474         let end = b:tlist_{ftype}_{ttype}_start + b:tlist_{ftype}_{ttype}_count
1475         if lnum >= b:tlist_{ftype}_{ttype}_start && lnum <= end
1476             break
1477         endif
1478         let i = i + 1
1479     endwhile
1480
1481     " Current line doesn't belong to any of the displayed tag types
1482     if i > s:tlist_{ftype}_count
1483         return 0
1484     endif
1485
1486     " Compute the offset into the displayed tags for the tag type
1487     let offset = lnum - b:tlist_{ftype}_{ttype}_start
1488     if offset == 0
1489         return 0
1490     endif
1491
1492     " Get the corresponding tag line and return it
1493     return b:tlist_{ftype}_{ttype}_{offset}
1494 endfunction
1495
1496 function! s:Tlist_Highlight_Tagline()
1497     " Clear previously selected name
1498     match none
1499
1500     " Highlight the current selected name
1501     if g:Tlist_Display_Prototype == 0
1502         exe 'match TagName /\%' . line('.') . 'l\s\+\zs.*/'
1503     else
1504         exe 'match TagName /\%' . line('.') . 'l.*/'
1505     endif
1506 endfunction
1507
1508 " Tlist_Jump_To_Tag()
1509 " Jump to the location of the current tag
1510 function! s:Tlist_Jump_To_Tag(new_window)
1511     " Do not process comment lines and empty lines
1512     let curline = getline('.')
1513     if curline == '' || curline[0] == '"'
1514         return
1515     endif
1516
1517     " If inside a fold, then don't try to jump to the tag
1518     if foldclosed('.') != -1
1519         return
1520     endif
1521
1522     " Get the tag output for the current tag
1523     let lnum = s:Tlist_Get_Tag_Linenr()
1524     if lnum == 0
1525         return
1526     endif
1527
1528     let mtxt = b:tlist_tag_{lnum}
1529     let start = stridx(mtxt, '/^') + 2
1530     let end = strridx(mtxt, '/;"' . "\t")
1531     if mtxt[end - 1] == '$'
1532         let end = end - 1
1533     endif
1534     let tagpat = '\V\^' . strpart(mtxt, start, end - start) .
1535                                         \ (mtxt[end] == '$' ? '\$' : '')
1536
1537     " Highlight the tagline
1538     call s:Tlist_Highlight_Tagline()
1539
1540     let s:Tlist_Skip_Refresh = 1
1541
1542     if s:tlist_part_of_winmanager
1543         call WinManagerFileEdit(bufname(b:tlist_bufnum), a:new_window)
1544     else
1545     " Goto the window containing the file.  If the window is not there, open a
1546     " new window
1547     let winnum = bufwinnr(b:tlist_bufnum)
1548     if winnum == -1
1549         if g:Tlist_Use_Horiz_Window == 1
1550             exe 'leftabove split #' . b:tlist_bufnum
1551             " Go to the taglist window to change the window size to the user
1552             " configured value
1553             wincmd p
1554             exe 'resize ' . g:Tlist_WinHeight
1555             " Go back to the file window
1556             wincmd p
1557         else
1558             " Open the file in a window and skip refreshing the taglist window
1559             exe 'rightbelow vertical split #' . b:tlist_bufnum
1560             " Go to the taglist window to change the window size to the user
1561             " configured value
1562             wincmd p
1563             exe 'vertical resize ' . g:Tlist_WinWidth
1564             " Go back to the file window
1565             wincmd p
1566         endif
1567     else
1568         exe winnum . 'wincmd w'
1569
1570         " If the user asked to jump to the tag in a new window, then split the
1571         " existing window into two.
1572         if a:new_window
1573             split
1574         endif
1575     endif
1576     endif
1577
1578     " Jump to the tag
1579     silent call search(tagpat, 'w')
1580
1581     " Bring the line to the middle of the window
1582     normal! z.
1583
1584     " If the line is inside a fold, open the fold
1585     if has('folding')
1586         if foldlevel('.') != 0
1587             normal zo
1588         endif
1589     endif
1590
1591     let s:Tlist_Skip_Refresh = 0
1592 endfunction
1593
1594 " Tlist_Show_Tag_Prototype()
1595 " Display the prototype of the tag under the cursor
1596 function! s:Tlist_Show_Tag_Prototype()
1597     " If we have already display prototype in the tag window, no need to
1598     " display it in the status line
1599     if g:Tlist_Display_Prototype == 1
1600         return
1601     endif
1602
1603     " Clear the previously displayed line
1604     echo
1605
1606     " Do not process comment lines and empty lines
1607     let curline = getline('.')
1608     if curline == '' || curline[0] == '"'
1609         return
1610     endif
1611
1612     " If inside a fold, then don't display the prototype
1613     if foldclosed('.') != -1
1614         return
1615     endif
1616
1617     " Get the tag output line for the current tag
1618     let lnum = s:Tlist_Get_Tag_Linenr()
1619     if lnum == 0
1620         return
1621     endif
1622
1623     let mtxt = b:tlist_tag_{lnum}
1624
1625     " Get the tag search pattern and display it
1626     echo s:Tlist_Extract_Tag_Prototype(mtxt)
1627 endfunction
1628
1629 " Tlist_Locate_Tag_Text
1630 " Locate the tag text given the line number in the source window
1631 function! s:Tlist_Locate_Tag_Text(sort_type, linenum)
1632     let left = 1
1633     let right = b:tlist_tag_count
1634
1635     if a:sort_type == 'order'
1636         " Tag list sorted by order, do a binary search comparing the line
1637         " numbers
1638
1639         " If the current line is the less than the first tag, then no need to
1640         " search
1641         let txt = b:tlist_tag_1
1642         let start = strridx(txt, 'line:') + strlen('line:')
1643         let end = strridx(txt, "\t")
1644         if end < start
1645             let first_lnum = strpart(txt, start) + 0
1646         else
1647             let first_lnum = strpart(txt, start, end - start) + 0
1648         endif
1649
1650         if a:linenum < first_lnum
1651             return ""
1652         endif
1653
1654         while left < right
1655             let middle = (right + left + 1) / 2
1656             let txt = b:tlist_tag_{middle}
1657
1658             let start = strridx(txt, 'line:') + strlen('line:')
1659             let end = strridx(txt, "\t")
1660             if end < start
1661                 let middle_lnum = strpart(txt, start) + 0
1662             else
1663                 let middle_lnum = strpart(txt, start, end - start) + 0
1664             endif
1665
1666             if middle_lnum == a:linenum
1667                 let left = middle
1668                 break
1669             endif
1670
1671             if middle_lnum > a:linenum
1672                 let right = middle - 1
1673             else
1674                 let left = middle
1675             endif
1676         endwhile
1677     else
1678         " sorted by name, brute force method (Dave Eggum)
1679         let closest_lnum = 0
1680         let final_left = 0
1681         while left < right
1682             let txt = b:tlist_tag_{left}
1683
1684             let start = strridx(txt, 'line:') + strlen('line:')
1685             let end = strridx(txt, "\t")
1686             if end < start
1687                 let lnum = strpart(txt, start) + 0
1688             else
1689                 let lnum = strpart(txt, start, end - start) + 0
1690             endif
1691
1692             if lnum < a:linenum && lnum > closest_lnum
1693                 let closest_lnum = lnum
1694                 let final_left = left
1695             elseif lnum == a:linenum
1696                 let closest_lnum = lnum
1697                 break
1698             else
1699                 let left = left + 1
1700             endif
1701         endwhile
1702         if closest_lnum == 0
1703             return ""
1704         endif
1705         if left == right
1706             let left = final_left
1707         endif
1708     endif
1709
1710     return b:tlist_tag_{left}
1711 endfunction
1712
1713 " Tlist_Highlight_Tag()
1714 " Do a binary search in the array of tag names and pick a tag entry that
1715 " contains the current line and highlight it.  The idea behind this function
1716 " is taken from the ctags.vim script available at the Vim online website.
1717 function! s:Tlist_Highlight_Tag(bufnum, curline)
1718     let filename = fnamemodify(bufname(a:bufnum), ':p')
1719     if filename == ''
1720         return
1721     endif
1722
1723     " Make sure the taglist window is present
1724     let winnum = bufwinnr(g:TagList_title)
1725     if winnum == -1
1726         return
1727     endif
1728
1729     let bno = bufnr(g:TagList_title)
1730
1731     " Make sure we have the tag listing for the current file
1732     if getbufvar(bno, 'tlist_bufnum') != a:bufnum
1733         return
1734     endif
1735
1736     " If there are no tags for this file, then no need to proceed further
1737     if getbufvar(bno, 'tlist_tag_count') == 0
1738         return
1739     endif
1740
1741     " If part of winmanager then disable winmanager autocommands
1742     if s:tlist_part_of_winmanager
1743         call WinManagerSuspendAUs()
1744     endif
1745
1746     " Save the original window number
1747     let org_winnr = winnr()
1748
1749     if org_winnr == winnum
1750         let in_taglist_window = 1
1751     else
1752         let in_taglist_window = 0
1753     endif
1754
1755     " Go to the taglist window
1756     if !in_taglist_window
1757         exe winnum . 'wincmd w'
1758     endif
1759
1760     " Clear previously selected name
1761     match none
1762
1763     let tag_txt = s:Tlist_Locate_Tag_Text(getbufvar(bno, 'tlist_sort_type'),
1764                                           \ a:curline)
1765     if tag_txt == ""
1766         if !in_taglist_window
1767             let s:Tlist_Skip_Refresh = 1
1768             exe org_winnr . 'wincmd w'
1769             let s:Tlist_Skip_Refresh = 0
1770         endif
1771         if s:tlist_part_of_winmanager
1772             call WinManagerResumeAUs()
1773         endif
1774         return
1775     endif
1776
1777     " Extract the tag type
1778     let ttype = s:Tlist_Extract_Tagtype(tag_txt)
1779
1780     " Extract the tag offset
1781     let offset = strpart(tag_txt, 0, stridx(tag_txt, ':')) + 0
1782
1783     " Compute the line number
1784     let lnum = b:tlist_{b:tlist_ftype}_{ttype}_start + offset
1785
1786     " Goto the line containing the tag
1787     exe lnum
1788
1789     " Open the fold
1790     if has('folding')
1791         silent! .foldopen
1792     endif
1793
1794     " Call winline() to make sure the target line is visible in the taglist
1795     " window. This is a side effect of calling winline(). Don't know of a
1796     " better way to achieve this.
1797     call winline()
1798
1799     " Highlight the tag name
1800     call s:Tlist_Highlight_Tagline()
1801
1802     " Go back to the original window
1803     if !in_taglist_window
1804         let s:Tlist_Skip_Refresh = 1
1805         exe org_winnr . 'wincmd w'
1806         let s:Tlist_Skip_Refresh = 0
1807     endif
1808
1809     if s:tlist_part_of_winmanager
1810         call WinManagerResumeAUs()
1811     endif
1812
1813     return
1814 endfunction
1815
1816 " Tlist_Get_Tag_Prototype_By_Line
1817 function! s:Tlist_Get_Tag_Prototype_By_Line(linenum)
1818     " Make sure the current file has a name
1819     let filename = fnamemodify(bufname("%"), ':p')
1820     if filename == ''
1821         return ""
1822     endif
1823
1824     let linenr = a:linenum
1825     if linenr == ""
1826         " Default is the current line
1827         let linenr = line('.')
1828     endif
1829
1830     " If there are no tags for this file, then no need to proceed further
1831     if !exists("b:tlist_tag_count") || b:tlist_tag_count == 0
1832         return ""
1833     endif
1834
1835     " Get the tag text using the line number
1836     let tag_txt = s:Tlist_Locate_Tag_Text(b:tlist_sort_type, linenr)
1837     if tag_txt == ""
1838         return ""
1839     endif
1840
1841     " Extract the tag search pattern and return it
1842     return s:Tlist_Extract_Tag_Prototype(tag_txt)
1843 endfunction
1844
1845 " Define tag listing autocommand to automatically open the taglist window on
1846 " Vim startup
1847 if g:Tlist_Auto_Open
1848     autocmd VimEnter * nested Tlist
1849 endif
1850
1851 " Define the 'Tlist' and 'TlistSync' user commands to open/close taglist
1852 " window
1853 command! -nargs=0 Tlist call s:Tlist_Toggle_Window(bufnr('%'))
1854 command! -nargs=0 TlistSync call s:Tlist_Highlight_Tag(bufnr('%'), line('.'))
1855 command! -nargs=? TlistShowPrototype echo s:Tlist_Get_Tag_Prototype_By_Line(<q-args>)
1856
1857 " Winmanager integration
1858
1859 " Initialization required for integration with winmanager
1860 function! TagList_Start()
1861     let s:tlist_part_of_winmanager = 1
1862
1863     if bufname('%') != '__Tag_List__'
1864         return
1865     endif
1866
1867     let bufnum = WinManagerGetLastEditedFile()
1868
1869     " If the tags for the buffer is already listed, then no need to do
1870     " anything
1871     if exists('b:tlist_bufnum') && bufnum == b:tlist_bufnum
1872         return
1873     endif
1874
1875     call s:Tlist_Init_Window(bufnum)
1876
1877     " Open the taglist window
1878     call s:Tlist_Explore_File(bufnum)
1879 endfunction
1880
1881 function! TagList_IsValid()
1882     return 0
1883 endfunction
1884
1885 function! TagList_WrapUp()
1886     return 0
1887 endfunction