]> git.r.bdr.sh - rbdr/dotfiles/blob - vim/plugin/taglist.vim
59901f64fa0999e7884e7b71ed751debbe68fd07
[rbdr/dotfiles] / vim / plugin / taglist.vim
1 " File: taglist.vim
2 " Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com)
3 " Version: 4.5
4 " Last Modified: September 21, 2007
5 " Copyright: Copyright (C) 2002-2007 Yegappan Lakshmanan
6 " Permission is hereby granted to use and distribute this code,
7 " with or without modifications, provided that this copyright
8 " notice is copied with it. Like anything else that's free,
9 " taglist.vim is provided *as is* and comes with no warranty of any
10 " kind, either expressed or implied. In no event will the copyright
11 " holder be liable for any damamges resulting from the use of this
12 " software.
13 "
14 " The "Tag List" plugin is a source code browser plugin for Vim and provides
15 " an overview of the structure of the programming language files and allows
16 " you to efficiently browse through source code files for different
17 " programming languages. You can visit the taglist plugin home page for more
18 " information:
19 "
20 " http://vim-taglist.sourceforge.net
21 "
22 " You can subscribe to the taglist mailing list to post your questions
23 " or suggestions for improvement or to report bugs. Visit the following
24 " page for subscribing to the mailing list:
25 "
26 " http://groups.yahoo.com/group/taglist/
27 "
28 " For more information about using this plugin, after installing the
29 " taglist plugin, use the ":help taglist" command.
30 "
31 " Installation
32 " ------------
33 " 1. Download the taglist.zip file and unzip the files to the $HOME/.vim
34 " or the $HOME/vimfiles or the $VIM/vimfiles directory. This should
35 " unzip the following two files (the directory structure should be
36 " preserved):
37 "
38 " plugin/taglist.vim - main taglist plugin file
39 " doc/taglist.txt - documentation (help) file
40 "
41 " Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath'
42 " Vim help pages for more details about installing Vim plugins.
43 " 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or
44 " $VIM/vimfiles/doc directory, start Vim and run the ":helptags ."
45 " command to process the taglist help file.
46 " 3. If the exuberant ctags utility is not present in your PATH, then set the
47 " Tlist_Ctags_Cmd variable to point to the location of the exuberant ctags
48 " utility (not to the directory) in the .vimrc file.
49 " 4. If you are running a terminal/console version of Vim and the
50 " terminal doesn't support changing the window width then set the
51 " 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file.
52 " 5. Restart Vim.
53 " 6. You can now use the ":TlistToggle" command to open/close the taglist
54 " window. You can use the ":help taglist" command to get more
55 " information about using the taglist plugin.
56 "
57 " ****************** Do not modify after this line ************************
58
59 " Line continuation used here
60 let s:cpo_save = &cpo
61 set cpo&vim
62
63 if !exists('loaded_taglist')
64 " First time loading the taglist plugin
65 "
66 " To speed up the loading of Vim, the taglist plugin uses autoload
67 " mechanism to load the taglist functions.
68 " Only define the configuration variables, user commands and some
69 " auto-commands and finish sourcing the file
70
71 " The taglist plugin requires the built-in Vim system() function. If this
72 " function is not available, then don't load the plugin.
73 if !exists('*system')
74 echomsg 'Taglist: Vim system() built-in function is not available. ' .
75 \ 'Plugin is not loaded.'
76 let loaded_taglist = 'no'
77 let &cpo = s:cpo_save
78 finish
79 endif
80
81 " Location of the exuberant ctags tool
82 if !exists('Tlist_Ctags_Cmd')
83 if executable('exuberant-ctags')
84 " On Debian Linux, exuberant ctags is installed
85 " as exuberant-ctags
86 let Tlist_Ctags_Cmd = 'exuberant-ctags'
87 elseif executable('exctags')
88 " On Free-BSD, exuberant ctags is installed as exctags
89 let Tlist_Ctags_Cmd = 'exctags'
90 elseif executable('ctags')
91 let Tlist_Ctags_Cmd = 'ctags'
92 elseif executable('ctags.exe')
93 let Tlist_Ctags_Cmd = 'ctags.exe'
94 elseif executable('tags')
95 let Tlist_Ctags_Cmd = 'tags'
96 else
97 echomsg 'Taglist: Exuberant ctags (http://ctags.sf.net) ' .
98 \ 'not found in PATH. Plugin is not loaded.'
99 " Skip loading the plugin
100 let loaded_taglist = 'no'
101 let &cpo = s:cpo_save
102 finish
103 endif
104 endif
105
106
107 " Automatically open the taglist window on Vim startup
108 if !exists('Tlist_Auto_Open')
109 let Tlist_Auto_Open = 0
110 endif
111
112 " When the taglist window is toggle opened, move the cursor to the
113 " taglist window
114 if !exists('Tlist_GainFocus_On_ToggleOpen')
115 let Tlist_GainFocus_On_ToggleOpen = 0
116 endif
117
118 " Process files even when the taglist window is not open
119 if !exists('Tlist_Process_File_Always')
120 let Tlist_Process_File_Always = 0
121 endif
122
123 if !exists('Tlist_Show_Menu')
124 let Tlist_Show_Menu = 0
125 endif
126
127 " Tag listing sort type - 'name' or 'order'
128 if !exists('Tlist_Sort_Type')
129 let Tlist_Sort_Type = 'order'
130 endif
131
132 " Tag listing window split (horizontal/vertical) control
133 if !exists('Tlist_Use_Horiz_Window')
134 let Tlist_Use_Horiz_Window = 0
135 endif
136
137 " Open the vertically split taglist window on the left or on the right
138 " side. This setting is relevant only if Tlist_Use_Horiz_Window is set to
139 " zero (i.e. only for vertically split windows)
140 if !exists('Tlist_Use_Right_Window')
141 let Tlist_Use_Right_Window = 0
142 endif
143
144 " Increase Vim window width to display vertically split taglist window.
145 " For MS-Windows version of Vim running in a MS-DOS window, this must be
146 " set to 0 otherwise the system may hang due to a Vim limitation.
147 if !exists('Tlist_Inc_Winwidth')
148 if (has('win16') || has('win95')) && !has('gui_running')
149 let Tlist_Inc_Winwidth = 0
150 else
151 let Tlist_Inc_Winwidth = 1
152 endif
153 endif
154
155 " Vertically split taglist window width setting
156 if !exists('Tlist_WinWidth')
157 let Tlist_WinWidth = 30
158 endif
159
160 " Horizontally split taglist window height setting
161 if !exists('Tlist_WinHeight')
162 let Tlist_WinHeight = 10
163 endif
164
165 " Display tag prototypes or tag names in the taglist window
166 if !exists('Tlist_Display_Prototype')
167 let Tlist_Display_Prototype = 0
168 endif
169
170 " Display tag scopes in the taglist window
171 if !exists('Tlist_Display_Tag_Scope')
172 let Tlist_Display_Tag_Scope = 1
173 endif
174
175 " Use single left mouse click to jump to a tag. By default this is disabled.
176 " Only double click using the mouse will be processed.
177 if !exists('Tlist_Use_SingleClick')
178 let Tlist_Use_SingleClick = 0
179 endif
180
181 " Control whether additional help is displayed as part of the taglist or
182 " not. Also, controls whether empty lines are used to separate the tag
183 " tree.
184 if !exists('Tlist_Compact_Format')
185 let Tlist_Compact_Format = 0
186 endif
187
188 " Exit Vim if only the taglist window is currently open. By default, this is
189 " set to zero.
190 if !exists('Tlist_Exit_OnlyWindow')
191 let Tlist_Exit_OnlyWindow = 0
192 endif
193
194 " Automatically close the folds for the non-active files in the taglist
195 " window
196 if !exists('Tlist_File_Fold_Auto_Close')
197 let Tlist_File_Fold_Auto_Close = 0
198 endif
199
200 " Close the taglist window when a tag is selected
201 if !exists('Tlist_Close_On_Select')
202 let Tlist_Close_On_Select = 0
203 endif
204
205 " Automatically update the taglist window to display tags for newly
206 " edited files
207 if !exists('Tlist_Auto_Update')
208 let Tlist_Auto_Update = 1
209 endif
210
211 " Automatically highlight the current tag
212 if !exists('Tlist_Auto_Highlight_Tag')
213 let Tlist_Auto_Highlight_Tag = 1
214 endif
215
216 " Automatically highlight the current tag on entering a buffer
217 if !exists('Tlist_Highlight_Tag_On_BufEnter')
218 let Tlist_Highlight_Tag_On_BufEnter = 1
219 endif
220
221 " Enable fold column to display the folding for the tag tree
222 if !exists('Tlist_Enable_Fold_Column')
223 let Tlist_Enable_Fold_Column = 1
224 endif
225
226 " Display the tags for only one file in the taglist window
227 if !exists('Tlist_Show_One_File')
228 let Tlist_Show_One_File = 0
229 endif
230
231 if !exists('Tlist_Max_Submenu_Items')
232 let Tlist_Max_Submenu_Items = 20
233 endif
234
235 if !exists('Tlist_Max_Tag_Length')
236 let Tlist_Max_Tag_Length = 10
237 endif
238
239 " Do not change the name of the taglist title variable. The winmanager
240 " plugin relies on this name to determine the title for the taglist
241 " plugin.
242 let TagList_title = "__Tag_List__"
243
244 " Taglist debug messages
245 let s:tlist_msg = ''
246
247 " Define the taglist autocommand to automatically open the taglist window
248 " on Vim startup
249 if g:Tlist_Auto_Open
250 autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open()
251 endif
252
253 " Refresh the taglist
254 if g:Tlist_Process_File_Always
255 autocmd BufEnter * call s:Tlist_Refresh()
256 endif
257
258 if g:Tlist_Show_Menu
259 autocmd GUIEnter * call s:Tlist_Menu_Init()
260 endif
261
262 " When the taglist buffer is created when loading a Vim session file,
263 " the taglist buffer needs to be initialized. The BufFilePost event
264 " is used to handle this case.
265 autocmd BufFilePost __Tag_List__ call s:Tlist_Vim_Session_Load()
266
267 " Define the user commands to manage the taglist window
268 command! -nargs=0 -bar TlistToggle call s:Tlist_Window_Toggle()
269 command! -nargs=0 -bar TlistOpen call s:Tlist_Window_Open()
270 " For backwards compatiblity define the Tlist command
271 command! -nargs=0 -bar Tlist TlistToggle
272 command! -nargs=+ -complete=file TlistAddFiles
273 \ call s:Tlist_Add_Files(<f-args>)
274 command! -nargs=+ -complete=dir TlistAddFilesRecursive
275 \ call s:Tlist_Add_Files_Recursive(<f-args>)
276 command! -nargs=0 -bar TlistClose call s:Tlist_Window_Close()
277 command! -nargs=0 -bar TlistUpdate call s:Tlist_Update_Current_File()
278 command! -nargs=0 -bar TlistHighlightTag call s:Tlist_Window_Highlight_Tag(
279 \ fnamemodify(bufname('%'), ':p'), line('.'), 2, 1)
280 " For backwards compatiblity define the TlistSync command
281 command! -nargs=0 -bar TlistSync TlistHighlightTag
282 command! -nargs=* -complete=buffer TlistShowPrototype
283 \ echo Tlist_Get_Tag_Prototype_By_Line(<f-args>)
284 command! -nargs=* -complete=buffer TlistShowTag
285 \ echo Tlist_Get_Tagname_By_Line(<f-args>)
286 command! -nargs=* -complete=file TlistSessionLoad
287 \ call s:Tlist_Session_Load(<q-args>)
288 command! -nargs=* -complete=file TlistSessionSave
289 \ call s:Tlist_Session_Save(<q-args>)
290 command! -bar TlistLock let Tlist_Auto_Update=0
291 command! -bar TlistUnlock let Tlist_Auto_Update=1
292
293 " Commands for enabling/disabling debug and to display debug messages
294 command! -nargs=? -complete=file -bar TlistDebug
295 \ call s:Tlist_Debug_Enable(<q-args>)
296 command! -nargs=0 -bar TlistUndebug call s:Tlist_Debug_Disable()
297 command! -nargs=0 -bar TlistMessages call s:Tlist_Debug_Show()
298
299 " Define autocommands to autoload the taglist plugin when needed.
300
301 " Trick to get the current script ID
302 map <SID>xx <SID>xx
303 let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$',
304 \ '\1', '')
305 unmap <SID>xx
306
307 exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' .
308 \ escape(expand('<sfile>'), ' ')
309 exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' .
310 \ escape(expand('<sfile>'), ' ')
311 exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' .
312 \ escape(expand('<sfile>'), ' ')
313 exe 'autocmd FuncUndefined Tlist_* source ' .
314 \ escape(expand('<sfile>'), ' ')
315 exe 'autocmd FuncUndefined TagList_* source ' .
316 \ escape(expand('<sfile>'), ' ')
317
318 let loaded_taglist = 'fast_load_done'
319
320 if g:Tlist_Show_Menu && has('gui_running')
321 call s:Tlist_Menu_Init()
322 endif
323
324 " restore 'cpo'
325 let &cpo = s:cpo_save
326 finish
327 endif
328
329 if !exists('s:tlist_sid')
330 " Two or more versions of taglist plugin are installed. Don't
331 " load this version of the plugin.
332 finish
333 endif
334
335 unlet! s:tlist_sid
336
337 if loaded_taglist != 'fast_load_done'
338 " restore 'cpo'
339 let &cpo = s:cpo_save
340 finish
341 endif
342
343 " Taglist plugin functionality is available
344 let loaded_taglist = 'available'
345
346 "------------------- end of user configurable options --------------------
347
348 " Default language specific settings for supported file types and tag types
349 "
350 " Variable name format:
351 "
352 " s:tlist_def_{vim_ftype}_settings
353 "
354 " vim_ftype - Filetype detected by Vim
355 "
356 " Value format:
357 "
358 " <ctags_ftype>;<flag>:<name>;<flag>:<name>;...
359 "
360 " ctags_ftype - File type supported by exuberant ctags
361 " flag - Flag supported by exuberant ctags to generate a tag type
362 " name - Name of the tag type used in the taglist window to display the
363 " tags of this type
364 "
365
366 " assembly language
367 let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type'
368
369 " aspperl language
370 let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable'
371
372 " aspvbs language
373 let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable'
374
375 " awk language
376 let s:tlist_def_awk_settings = 'awk;f:function'
377
378 " beta language
379 let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern'
380
381 " c language
382 let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' .
383 \ 'v:variable;f:function'
384
385 " c++ language
386 let s:tlist_def_cpp_settings = 'c++;n:namespace;v:variable;d:macro;t:typedef;' .
387 \ 'c:class;g:enum;s:struct;u:union;f:function'
388
389 " c# language
390 let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' .
391 \ 'E:event;g:enum;s:struct;i:interface;' .
392 \ 'p:properties;m:method'
393
394 " cobol language
395 let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' .
396 \ 'P:program;s:section'
397
398 " eiffel language
399 let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature'
400
401 " erlang language
402 let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function'
403
404 " expect (same as tcl) language
405 let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure'
406
407 " fortran language
408 let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' .
409 \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' .
410 \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine'
411
412 " HTML language
413 let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function'
414
415 " java language
416 let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
417 \ 'f:field;m:method'
418
419 " javascript language
420 let s:tlist_def_javascript_settings = 'javascript;f:function'
421
422 " lisp language
423 let s:tlist_def_lisp_settings = 'lisp;f:function'
424
425 " lua language
426 let s:tlist_def_lua_settings = 'lua;f:function'
427
428 " makefiles
429 let s:tlist_def_make_settings = 'make;m:macro'
430
431 " pascal language
432 let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure'
433
434 " perl language
435 let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine'
436
437 " php language
438 let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function'
439
440 " python language
441 let s:tlist_def_python_settings = 'python;c:class;m:member;f:function'
442
443 " rexx language
444 let s:tlist_def_rexx_settings = 'rexx;s:subroutine'
445
446 " ruby language
447 let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' .
448 \ 'm:singleton method'
449
450 " scheme language
451 let s:tlist_def_scheme_settings = 'scheme;s:set;f:function'
452
453 " shell language
454 let s:tlist_def_sh_settings = 'sh;f:function'
455
456 " C shell language
457 let s:tlist_def_csh_settings = 'sh;f:function'
458
459 " Z shell language
460 let s:tlist_def_zsh_settings = 'sh;f:function'
461
462 " slang language
463 let s:tlist_def_slang_settings = 'slang;n:namespace;f:function'
464
465 " sml language
466 let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' .
467 \ 'r:structure;t:type;v:value;f:function'
468
469 " sql language
470 let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' .
471 \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure'
472
473 " tcl language
474 let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure'
475
476 " vera language
477 let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' .
478 \ 'f:function;g:enum;m:member;p:program;' .
479 \ 'P:prototype;t:task;T:typedef;v:variable;' .
480 \ 'x:externvar'
481
482 "verilog language
483 let s:tlist_def_verilog_settings = 'verilog;m:module;c:constant;P:parameter;' .
484 \ 'e:event;r:register;t:task;w:write;p:port;v:variable;f:function'
485
486 " vim language
487 let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function'
488
489 " yacc language
490 let s:tlist_def_yacc_settings = 'yacc;l:label'
491
492 "------------------- end of language specific options --------------------
493
494 " Vim window size is changed by the taglist plugin or not
495 let s:tlist_winsize_chgd = -1
496 " Taglist window is maximized or not
497 let s:tlist_win_maximized = 0
498 " Name of files in the taglist
499 let s:tlist_file_names=''
500 " Number of files in the taglist
501 let s:tlist_file_count = 0
502 " Number of filetypes supported by taglist
503 let s:tlist_ftype_count = 0
504 " Is taglist part of other plugins like winmanager or cream?
505 let s:tlist_app_name = "none"
506 " Are we displaying brief help text
507 let s:tlist_brief_help = 1
508 " List of files removed on user request
509 let s:tlist_removed_flist = ""
510 " Index of current file displayed in the taglist window
511 let s:tlist_cur_file_idx = -1
512 " Taglist menu is empty or not
513 let s:tlist_menu_empty = 1
514
515 " An autocommand is used to refresh the taglist window when entering any
516 " buffer. We don't want to refresh the taglist window if we are entering the
517 " file window from one of the taglist functions. The 'Tlist_Skip_Refresh'
518 " variable is used to skip the refresh of the taglist window and is set
519 " and cleared appropriately.
520 let s:Tlist_Skip_Refresh = 0
521
522 " Tlist_Window_Display_Help()
523 function! s:Tlist_Window_Display_Help()
524 if s:tlist_app_name == "winmanager"
525 " To handle a bug in the winmanager plugin, add a space at the
526 " last line
527 call setline('$', ' ')
528 endif
529
530 if s:tlist_brief_help
531 " Add the brief help
532 call append(0, '" Press <F1> to display help text')
533 else
534 " Add the extensive help
535 call append(0, '" <enter> : Jump to tag definition')
536 call append(1, '" o : Jump to tag definition in new window')
537 call append(2, '" p : Preview the tag definition')
538 call append(3, '" <space> : Display tag prototype')
539 call append(4, '" u : Update tag list')
540 call append(5, '" s : Select sort field')
541 call append(6, '" d : Remove file from taglist')
542 call append(7, '" x : Zoom-out/Zoom-in taglist window')
543 call append(8, '" + : Open a fold')
544 call append(9, '" - : Close a fold')
545 call append(10, '" * : Open all folds')
546 call append(11, '" = : Close all folds')
547 call append(12, '" [[ : Move to the start of previous file')
548 call append(13, '" ]] : Move to the start of next file')
549 call append(14, '" q : Close the taglist window')
550 call append(15, '" <F1> : Remove help text')
551 endif
552 endfunction
553
554 " Tlist_Window_Toggle_Help_Text()
555 " Toggle taglist plugin help text between the full version and the brief
556 " version
557 function! s:Tlist_Window_Toggle_Help_Text()
558 if g:Tlist_Compact_Format
559 " In compact display mode, do not display help
560 return
561 endif
562
563 " Include the empty line displayed after the help text
564 let brief_help_size = 1
565 let full_help_size = 16
566
567 setlocal modifiable
568
569 " Set report option to a huge value to prevent informational messages
570 " while deleting the lines
571 let old_report = &report
572 set report=99999
573
574 " Remove the currently highlighted tag. Otherwise, the help text
575 " might be highlighted by mistake
576 match none
577
578 " Toggle between brief and full help text
579 if s:tlist_brief_help
580 let s:tlist_brief_help = 0
581
582 " Remove the previous help
583 exe '1,' . brief_help_size . ' delete _'
584
585 " Adjust the start/end line numbers for the files
586 call s:Tlist_Window_Update_Line_Offsets(0, 1, full_help_size - brief_help_size)
587 else
588 let s:tlist_brief_help = 1
589
590 " Remove the previous help
591 exe '1,' . full_help_size . ' delete _'
592
593 " Adjust the start/end line numbers for the files
594 call s:Tlist_Window_Update_Line_Offsets(0, 0, full_help_size - brief_help_size)
595 endif
596
597 call s:Tlist_Window_Display_Help()
598
599 " Restore the report option
600 let &report = old_report
601
602 setlocal nomodifiable
603 endfunction
604
605 " Taglist debug support
606 let s:tlist_debug = 0
607
608 " File for storing the debug messages
609 let s:tlist_debug_file = ''
610
611 " Tlist_Debug_Enable
612 " Enable logging of taglist debug messages.
613 function! s:Tlist_Debug_Enable(...)
614 let s:tlist_debug = 1
615
616 " Check whether a valid file name is supplied.
617 if a:1 != ''
618 let s:tlist_debug_file = fnamemodify(a:1, ':p')
619
620 " Empty the log file
621 exe 'redir! > ' . s:tlist_debug_file
622 redir END
623
624 " Check whether the log file is present/created
625 if !filewritable(s:tlist_debug_file)
626 call s:Tlist_Warning_Msg('Taglist: Unable to create log file '
627 \ . s:tlist_debug_file)
628 let s:tlist_debug_file = ''
629 endif
630 endif
631 endfunction
632
633 " Tlist_Debug_Disable
634 " Disable logging of taglist debug messages.
635 function! s:Tlist_Debug_Disable(...)
636 let s:tlist_debug = 0
637 let s:tlist_debug_file = ''
638 endfunction
639
640 " Tlist_Debug_Show
641 " Display the taglist debug messages in a new window
642 function! s:Tlist_Debug_Show()
643 if s:tlist_msg == ''
644 call s:Tlist_Warning_Msg('Taglist: No debug messages')
645 return
646 endif
647
648 " Open a new window to display the taglist debug messages
649 new taglist_debug.txt
650 " Delete all the lines (if the buffer already exists)
651 silent! %delete _
652 " Add the messages
653 silent! put =s:tlist_msg
654 " Move the cursor to the first line
655 normal! gg
656 endfunction
657
658 " Tlist_Log_Msg
659 " Log the supplied debug message along with the time
660 function! s:Tlist_Log_Msg(msg)
661 if s:tlist_debug
662 if s:tlist_debug_file != ''
663 exe 'redir >> ' . s:tlist_debug_file
664 silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n"
665 redir END
666 else
667 " Log the message into a variable
668 " Retain only the last 3000 characters
669 let len = strlen(s:tlist_msg)
670 if len > 3000
671 let s:tlist_msg = strpart(s:tlist_msg, len - 3000)
672 endif
673 let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' .
674 \ a:msg . "\n"
675 endif
676 endif
677 endfunction
678
679 " Tlist_Warning_Msg()
680 " Display a message using WarningMsg highlight group
681 function! s:Tlist_Warning_Msg(msg)
682 echohl WarningMsg
683 echomsg a:msg
684 echohl None
685 endfunction
686
687 " Last returned file index for file name lookup.
688 " Used to speed up file lookup
689 let s:tlist_file_name_idx_cache = -1
690
691 " Tlist_Get_File_Index()
692 " Return the index of the specified filename
693 function! s:Tlist_Get_File_Index(fname)
694 if s:tlist_file_count == 0 || a:fname == ''
695 return -1
696 endif
697
698 " If the new filename is same as the last accessed filename, then
699 " return that index
700 if s:tlist_file_name_idx_cache != -1 &&
701 \ s:tlist_file_name_idx_cache < s:tlist_file_count
702 if s:tlist_{s:tlist_file_name_idx_cache}_filename == a:fname
703 " Same as the last accessed file
704 return s:tlist_file_name_idx_cache
705 endif
706 endif
707
708 " First, check whether the filename is present
709 let s_fname = a:fname . "\n"
710 let i = stridx(s:tlist_file_names, s_fname)
711 if i == -1
712 let s:tlist_file_name_idx_cache = -1
713 return -1
714 endif
715
716 " Second, compute the file name index
717 let nl_txt = substitute(strpart(s:tlist_file_names, 0, i), "[^\n]", '', 'g')
718 let s:tlist_file_name_idx_cache = strlen(nl_txt)
719 return s:tlist_file_name_idx_cache
720 endfunction
721
722 " Last returned file index for line number lookup.
723 " Used to speed up file lookup
724 let s:tlist_file_lnum_idx_cache = -1
725
726 " Tlist_Window_Get_File_Index_By_Linenum()
727 " Return the index of the filename present in the specified line number
728 " Line number refers to the line number in the taglist window
729 function! s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
730 call s:Tlist_Log_Msg('Tlist_Window_Get_File_Index_By_Linenum (' . a:lnum . ')')
731
732 " First try to see whether the new line number is within the range
733 " of the last returned file
734 if s:tlist_file_lnum_idx_cache != -1 &&
735 \ s:tlist_file_lnum_idx_cache < s:tlist_file_count
736 if a:lnum >= s:tlist_{s:tlist_file_lnum_idx_cache}_start &&
737 \ a:lnum <= s:tlist_{s:tlist_file_lnum_idx_cache}_end
738 return s:tlist_file_lnum_idx_cache
739 endif
740 endif
741
742 let fidx = -1
743
744 if g:Tlist_Show_One_File
745 " Displaying only one file in the taglist window. Check whether
746 " the line is within the tags displayed for that file
747 if s:tlist_cur_file_idx != -1
748 if a:lnum >= s:tlist_{s:tlist_cur_file_idx}_start
749 \ && a:lnum <= s:tlist_{s:tlist_cur_file_idx}_end
750 let fidx = s:tlist_cur_file_idx
751 endif
752
753 endif
754 else
755 " Do a binary search in the taglist
756 let left = 0
757 let right = s:tlist_file_count - 1
758
759 while left < right
760 let mid = (left + right) / 2
761
762 if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end
763 let s:tlist_file_lnum_idx_cache = mid
764 return mid
765 endif
766
767 if a:lnum < s:tlist_{mid}_start
768 let right = mid - 1
769 else
770 let left = mid + 1
771 endif
772 endwhile
773
774 if left >= 0 && left < s:tlist_file_count
775 \ && a:lnum >= s:tlist_{left}_start
776 \ && a:lnum <= s:tlist_{left}_end
777 let fidx = left
778 endif
779 endif
780
781 let s:tlist_file_lnum_idx_cache = fidx
782
783 return fidx
784 endfunction
785
786 " Tlist_Exe_Cmd_No_Acmds
787 " Execute the specified Ex command after disabling autocommands
788 function! s:Tlist_Exe_Cmd_No_Acmds(cmd)
789 let old_eventignore = &eventignore
790 set eventignore=all
791 exe a:cmd
792 let &eventignore = old_eventignore
793 endfunction
794
795 " Tlist_Skip_File()
796 " Check whether tag listing is supported for the specified file
797 function! s:Tlist_Skip_File(filename, ftype)
798 " Skip buffers with no names and buffers with filetype not set
799 if a:filename == '' || a:ftype == ''
800 return 1
801 endif
802
803 " Skip files which are not supported by exuberant ctags
804 " First check whether default settings for this filetype are available.
805 " If it is not available, then check whether user specified settings are
806 " available. If both are not available, then don't list the tags for this
807 " filetype
808 let var = 's:tlist_def_' . a:ftype . '_settings'
809 if !exists(var)
810 let var = 'g:tlist_' . a:ftype . '_settings'
811 if !exists(var)
812 return 1
813 endif
814 endif
815
816 " Skip files which are not readable or files which are not yet stored
817 " to the disk
818 if !filereadable(a:filename)
819 return 1
820 endif
821
822 return 0
823 endfunction
824
825 " Tlist_User_Removed_File
826 " Returns 1 if a file is removed by a user from the taglist
827 function! s:Tlist_User_Removed_File(filename)
828 return stridx(s:tlist_removed_flist, a:filename . "\n") != -1
829 endfunction
830
831 " Tlist_Update_Remove_List
832 " Update the list of user removed files from the taglist
833 " add == 1, add the file to the removed list
834 " add == 0, delete the file from the removed list
835 function! s:Tlist_Update_Remove_List(filename, add)
836 if a:add
837 let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n"
838 else
839 let idx = stridx(s:tlist_removed_flist, a:filename . "\n")
840 let text_before = strpart(s:tlist_removed_flist, 0, idx)
841 let rem_text = strpart(s:tlist_removed_flist, idx)
842 let next_idx = stridx(rem_text, "\n")
843 let text_after = strpart(rem_text, next_idx + 1)
844
845 let s:tlist_removed_flist = text_before . text_after
846 endif
847 endfunction
848
849 " Tlist_FileType_Init
850 " Initialize the ctags arguments and tag variable for the specified
851 " file type
852 function! s:Tlist_FileType_Init(ftype)
853 call s:Tlist_Log_Msg('Tlist_FileType_Init (' . a:ftype . ')')
854 " If the user didn't specify any settings, then use the default
855 " ctags args. Otherwise, use the settings specified by the user
856 let var = 'g:tlist_' . a:ftype . '_settings'
857 if exists(var)
858 " User specified ctags arguments
859 let settings = {var} . ';'
860 else
861 " Default ctags arguments
862 let var = 's:tlist_def_' . a:ftype . '_settings'
863 if !exists(var)
864 " No default settings for this file type. This filetype is
865 " not supported
866 return 0
867 endif
868 let settings = s:tlist_def_{a:ftype}_settings . ';'
869 endif
870
871 let msg = 'Taglist: Invalid ctags option setting - ' . settings
872
873 " Format of the option that specifies the filetype and ctags arugments:
874 "
875 " <language_name>;flag1:name1;flag2:name2;flag3:name3
876 "
877
878 " Extract the file type to pass to ctags. This may be different from the
879 " file type detected by Vim
880 let pos = stridx(settings, ';')
881 if pos == -1
882 call s:Tlist_Warning_Msg(msg)
883 return 0
884 endif
885 let ctags_ftype = strpart(settings, 0, pos)
886 if ctags_ftype == ''
887 call s:Tlist_Warning_Msg(msg)
888 return 0
889 endif
890 " Make sure a valid filetype is supplied. If the user didn't specify a
891 " valid filetype, then the ctags option settings may be treated as the
892 " filetype
893 if ctags_ftype =~ ':'
894 call s:Tlist_Warning_Msg(msg)
895 return 0
896 endif
897
898 " Remove the file type from settings
899 let settings = strpart(settings, pos + 1)
900 if settings == ''
901 call s:Tlist_Warning_Msg(msg)
902 return 0
903 endif
904
905 " Process all the specified ctags flags. The format is
906 " flag1:name1;flag2:name2;flag3:name3
907 let ctags_flags = ''
908 let cnt = 0
909 while settings != ''
910 " Extract the flag
911 let pos = stridx(settings, ':')
912 if pos == -1
913 call s:Tlist_Warning_Msg(msg)
914 return 0
915 endif
916 let flag = strpart(settings, 0, pos)
917 if flag == ''
918 call s:Tlist_Warning_Msg(msg)
919 return 0
920 endif
921 " Remove the flag from settings
922 let settings = strpart(settings, pos + 1)
923
924 " Extract the tag type name
925 let pos = stridx(settings, ';')
926 if pos == -1
927 call s:Tlist_Warning_Msg(msg)
928 return 0
929 endif
930 let name = strpart(settings, 0, pos)
931 if name == ''
932 call s:Tlist_Warning_Msg(msg)
933 return 0
934 endif
935 let settings = strpart(settings, pos + 1)
936
937 let cnt = cnt + 1
938
939 let s:tlist_{a:ftype}_{cnt}_name = flag
940 let s:tlist_{a:ftype}_{cnt}_fullname = name
941 let ctags_flags = ctags_flags . flag
942 endwhile
943
944 let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype .
945 \ ' --' . ctags_ftype . '-types=' . ctags_flags
946 let s:tlist_{a:ftype}_count = cnt
947 let s:tlist_{a:ftype}_ctags_flags = ctags_flags
948
949 " Save the filetype name
950 let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype
951 let s:tlist_ftype_count = s:tlist_ftype_count + 1
952
953 return 1
954 endfunction
955
956 " Tlist_Detect_Filetype
957 " Determine the filetype for the specified file using the filetypedetect
958 " autocmd.
959 function! s:Tlist_Detect_Filetype(fname)
960 " Ignore the filetype autocommands
961 let old_eventignore = &eventignore
962 set eventignore=FileType
963
964 " Save the 'filetype', as this will be changed temporarily
965 let old_filetype = &filetype
966
967 " Run the filetypedetect group of autocommands to determine
968 " the filetype
969 exe 'doautocmd filetypedetect BufRead ' . a:fname
970
971 " Save the detected filetype
972 let ftype = &filetype
973
974 " Restore the previous state
975 let &filetype = old_filetype
976 let &eventignore = old_eventignore
977
978 return ftype
979 endfunction
980
981 " Tlist_Get_Buffer_Filetype
982 " Get the filetype for the specified buffer
983 function! s:Tlist_Get_Buffer_Filetype(bnum)
984 let buf_ft = getbufvar(a:bnum, '&filetype')
985
986 if bufloaded(a:bnum)
987 " For loaded buffers, the 'filetype' is already determined
988 return buf_ft
989 endif
990
991 " For unloaded buffers, if the 'filetype' option is set, return it
992 if buf_ft != ''
993 return buf_ft
994 endif
995
996 " Skip non-existent buffers
997 if !bufexists(a:bnum)
998 return ''
999 endif
1000
1001 " For buffers whose filetype is not yet determined, try to determine
1002 " the filetype
1003 let bname = bufname(a:bnum)
1004
1005 return s:Tlist_Detect_Filetype(bname)
1006 endfunction
1007
1008 " Tlist_Discard_TagInfo
1009 " Discard the stored tag information for a file
1010 function! s:Tlist_Discard_TagInfo(fidx)
1011 call s:Tlist_Log_Msg('Tlist_Discard_TagInfo (' .
1012 \ s:tlist_{a:fidx}_filename . ')')
1013 let ftype = s:tlist_{a:fidx}_filetype
1014
1015 " Discard information about the tags defined in the file
1016 let i = 1
1017 while i <= s:tlist_{a:fidx}_tag_count
1018 let fidx_i = 's:tlist_' . a:fidx . '_' . i
1019 unlet! {fidx_i}_tag
1020 unlet! {fidx_i}_tag_name
1021 unlet! {fidx_i}_tag_type
1022 unlet! {fidx_i}_ttype_idx
1023 unlet! {fidx_i}_tag_proto
1024 unlet! {fidx_i}_tag_searchpat
1025 unlet! {fidx_i}_tag_linenum
1026 let i = i + 1
1027 endwhile
1028
1029 let s:tlist_{a:fidx}_tag_count = 0
1030
1031 " Discard information about tag type groups
1032 let i = 1
1033 while i <= s:tlist_{ftype}_count
1034 let ttype = s:tlist_{ftype}_{i}_name
1035 if s:tlist_{a:fidx}_{ttype} != ''
1036 let fidx_ttype = 's:tlist_' . a:fidx . '_' . ttype
1037 let {fidx_ttype} = ''
1038 let {fidx_ttype}_offset = 0
1039 let cnt = {fidx_ttype}_count
1040 let {fidx_ttype}_count = 0
1041 let j = 1
1042 while j <= cnt
1043 unlet! {fidx_ttype}_{j}
1044 let j = j + 1
1045 endwhile
1046 endif
1047 let i = i + 1
1048 endwhile
1049
1050 " Discard the stored menu command also
1051 let s:tlist_{a:fidx}_menu_cmd = ''
1052 endfunction
1053
1054 " Tlist_Window_Update_Line_Offsets
1055 " Update the line offsets for tags for files starting from start_idx
1056 " and displayed in the taglist window by the specified offset
1057 function! s:Tlist_Window_Update_Line_Offsets(start_idx, increment, offset)
1058 let i = a:start_idx
1059
1060 while i < s:tlist_file_count
1061 if s:tlist_{i}_visible
1062 " Update the start/end line number only if the file is visible
1063 if a:increment
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 else
1067 let s:tlist_{i}_start = s:tlist_{i}_start - a:offset
1068 let s:tlist_{i}_end = s:tlist_{i}_end - a:offset
1069 endif
1070 endif
1071 let i = i + 1
1072 endwhile
1073 endfunction
1074
1075 " Tlist_Discard_FileInfo
1076 " Discard the stored information for a file
1077 function! s:Tlist_Discard_FileInfo(fidx)
1078 call s:Tlist_Log_Msg('Tlist_Discard_FileInfo (' .
1079 \ s:tlist_{a:fidx}_filename . ')')
1080 call s:Tlist_Discard_TagInfo(a:fidx)
1081
1082 let ftype = s:tlist_{a:fidx}_filetype
1083
1084 let i = 1
1085 while i <= s:tlist_{ftype}_count
1086 let ttype = s:tlist_{ftype}_{i}_name
1087 unlet! s:tlist_{a:fidx}_{ttype}
1088 unlet! s:tlist_{a:fidx}_{ttype}_offset
1089 unlet! s:tlist_{a:fidx}_{ttype}_count
1090 let i = i + 1
1091 endwhile
1092
1093 unlet! s:tlist_{a:fidx}_filename
1094 unlet! s:tlist_{a:fidx}_sort_type
1095 unlet! s:tlist_{a:fidx}_filetype
1096 unlet! s:tlist_{a:fidx}_mtime
1097 unlet! s:tlist_{a:fidx}_start
1098 unlet! s:tlist_{a:fidx}_end
1099 unlet! s:tlist_{a:fidx}_valid
1100 unlet! s:tlist_{a:fidx}_visible
1101 unlet! s:tlist_{a:fidx}_tag_count
1102 unlet! s:tlist_{a:fidx}_menu_cmd
1103 endfunction
1104
1105 " Tlist_Window_Remove_File_From_Display
1106 " Remove the specified file from display
1107 function! s:Tlist_Window_Remove_File_From_Display(fidx)
1108 call s:Tlist_Log_Msg('Tlist_Window_Remove_File_From_Display (' .
1109 \ s:tlist_{a:fidx}_filename . ')')
1110 " If the file is not visible then no need to remove it
1111 if !s:tlist_{a:fidx}_visible
1112 return
1113 endif
1114
1115 " Remove the tags displayed for the specified file from the window
1116 let start = s:tlist_{a:fidx}_start
1117 " Include the empty line after the last line also
1118 if g:Tlist_Compact_Format
1119 let end = s:tlist_{a:fidx}_end
1120 else
1121 let end = s:tlist_{a:fidx}_end + 1
1122 endif
1123
1124 setlocal modifiable
1125 exe 'silent! ' . start . ',' . end . 'delete _'
1126 setlocal nomodifiable
1127
1128 " Correct the start and end line offsets for all the files following
1129 " this file, as the tags for this file are removed
1130 call s:Tlist_Window_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1)
1131 endfunction
1132
1133 " Tlist_Remove_File
1134 " Remove the file under the cursor or the specified file index
1135 " user_request - User requested to remove the file from taglist
1136 function! s:Tlist_Remove_File(file_idx, user_request)
1137 let fidx = a:file_idx
1138
1139 if fidx == -1
1140 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
1141 if fidx == -1
1142 return
1143 endif
1144 endif
1145 call s:Tlist_Log_Msg('Tlist_Remove_File (' .
1146 \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')')
1147
1148 let save_winnr = winnr()
1149 let winnum = bufwinnr(g:TagList_title)
1150 if winnum != -1
1151 " Taglist window is open, remove the file from display
1152
1153 if save_winnr != winnum
1154 let old_eventignore = &eventignore
1155 set eventignore=all
1156 exe winnum . 'wincmd w'
1157 endif
1158
1159 call s:Tlist_Window_Remove_File_From_Display(fidx)
1160
1161 if save_winnr != winnum
1162 exe save_winnr . 'wincmd w'
1163 let &eventignore = old_eventignore
1164 endif
1165 endif
1166
1167 let fname = s:tlist_{fidx}_filename
1168
1169 if a:user_request
1170 " As the user requested to remove the file from taglist,
1171 " add it to the removed list
1172 call s:Tlist_Update_Remove_List(fname, 1)
1173 endif
1174
1175 " Remove the file name from the taglist list of filenames
1176 let idx = stridx(s:tlist_file_names, fname . "\n")
1177 let text_before = strpart(s:tlist_file_names, 0, idx)
1178 let rem_text = strpart(s:tlist_file_names, idx)
1179 let next_idx = stridx(rem_text, "\n")
1180 let text_after = strpart(rem_text, next_idx + 1)
1181 let s:tlist_file_names = text_before . text_after
1182
1183 call s:Tlist_Discard_FileInfo(fidx)
1184
1185 " Shift all the file variables by one index
1186 let i = fidx + 1
1187
1188 while i < s:tlist_file_count
1189 let j = i - 1
1190
1191 let s:tlist_{j}_filename = s:tlist_{i}_filename
1192 let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type
1193 let s:tlist_{j}_filetype = s:tlist_{i}_filetype
1194 let s:tlist_{j}_mtime = s:tlist_{i}_mtime
1195 let s:tlist_{j}_start = s:tlist_{i}_start
1196 let s:tlist_{j}_end = s:tlist_{i}_end
1197 let s:tlist_{j}_valid = s:tlist_{i}_valid
1198 let s:tlist_{j}_visible = s:tlist_{i}_visible
1199 let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count
1200 let s:tlist_{j}_menu_cmd = s:tlist_{i}_menu_cmd
1201
1202 let k = 1
1203 while k <= s:tlist_{j}_tag_count
1204 let s:tlist_{j}_{k}_tag = s:tlist_{i}_{k}_tag
1205 let s:tlist_{j}_{k}_tag_name = s:tlist_{i}_{k}_tag_name
1206 let s:tlist_{j}_{k}_tag_type = s:Tlist_Get_Tag_Type_By_Tag(i, k)
1207 let s:tlist_{j}_{k}_ttype_idx = s:tlist_{i}_{k}_ttype_idx
1208 let s:tlist_{j}_{k}_tag_proto = s:Tlist_Get_Tag_Prototype(i, k)
1209 let s:tlist_{j}_{k}_tag_searchpat = s:Tlist_Get_Tag_SearchPat(i, k)
1210 let s:tlist_{j}_{k}_tag_linenum = s:Tlist_Get_Tag_Linenum(i, k)
1211 let k = k + 1
1212 endwhile
1213
1214 let ftype = s:tlist_{i}_filetype
1215
1216 let k = 1
1217 while k <= s:tlist_{ftype}_count
1218 let ttype = s:tlist_{ftype}_{k}_name
1219 let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype}
1220 let s:tlist_{j}_{ttype}_offset = s:tlist_{i}_{ttype}_offset
1221 let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count
1222 if s:tlist_{j}_{ttype} != ''
1223 let l = 1
1224 while l <= s:tlist_{j}_{ttype}_count
1225 let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l}
1226 let l = l + 1
1227 endwhile
1228 endif
1229 let k = k + 1
1230 endwhile
1231
1232 " As the file and tag information is copied to the new index,
1233 " discard the previous information
1234 call s:Tlist_Discard_FileInfo(i)
1235
1236 let i = i + 1
1237 endwhile
1238
1239 " Reduce the number of files displayed
1240 let s:tlist_file_count = s:tlist_file_count - 1
1241
1242 if g:Tlist_Show_One_File
1243 " If the tags for only one file is displayed and if we just
1244 " now removed that file, then invalidate the current file idx
1245 if s:tlist_cur_file_idx == fidx
1246 let s:tlist_cur_file_idx = -1
1247 endif
1248 endif
1249 endfunction
1250
1251 " Tlist_Window_Goto_Window
1252 " Goto the taglist window
1253 function! s:Tlist_Window_Goto_Window()
1254 let winnum = bufwinnr(g:TagList_title)
1255 if winnum != -1
1256 if winnr() != winnum
1257 call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
1258 endif
1259 endif
1260 endfunction
1261
1262 " Tlist_Window_Create
1263 " Create a new taglist window. If it is already open, jump to it
1264 function! s:Tlist_Window_Create()
1265 call s:Tlist_Log_Msg('Tlist_Window_Create()')
1266 " If the window is open, jump to it
1267 let winnum = bufwinnr(g:TagList_title)
1268 if winnum != -1
1269 " Jump to the existing window
1270 if winnr() != winnum
1271 exe winnum . 'wincmd w'
1272 endif
1273 return
1274 endif
1275
1276 " If used with winmanager don't open windows. Winmanager will handle
1277 " the window/buffer management
1278 if s:tlist_app_name == "winmanager"
1279 return
1280 endif
1281
1282 " Create a new window. If user prefers a horizontal window, then open
1283 " a horizontally split window. Otherwise open a vertically split
1284 " window
1285 if g:Tlist_Use_Horiz_Window
1286 " Open a horizontally split window
1287 let win_dir = 'botright'
1288 " Horizontal window height
1289 let win_size = g:Tlist_WinHeight
1290 else
1291 if s:tlist_winsize_chgd == -1
1292 " Open a vertically split window. Increase the window size, if
1293 " needed, to accomodate the new window
1294 if g:Tlist_Inc_Winwidth &&
1295 \ &columns < (80 + g:Tlist_WinWidth)
1296 " Save the original window position
1297 let s:tlist_pre_winx = getwinposx()
1298 let s:tlist_pre_winy = getwinposy()
1299
1300 " one extra column is needed to include the vertical split
1301 let &columns= &columns + g:Tlist_WinWidth + 1
1302
1303 let s:tlist_winsize_chgd = 1
1304 else
1305 let s:tlist_winsize_chgd = 0
1306 endif
1307 endif
1308
1309 if g:Tlist_Use_Right_Window
1310 " Open the window at the rightmost place
1311 let win_dir = 'botright vertical'
1312 else
1313 " Open the window at the leftmost place
1314 let win_dir = 'topleft vertical'
1315 endif
1316 let win_size = g:Tlist_WinWidth
1317 endif
1318
1319 " If the tag listing temporary buffer already exists, then reuse it.
1320 " Otherwise create a new buffer
1321 let bufnum = bufnr(g:TagList_title)
1322 if bufnum == -1
1323 " Create a new buffer
1324 let wcmd = g:TagList_title
1325 else
1326 " Edit the existing buffer
1327 let wcmd = '+buffer' . bufnum
1328 endif
1329
1330 " Create the taglist window
1331 exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd
1332
1333 " Save the new window position
1334 let s:tlist_winx = getwinposx()
1335 let s:tlist_winy = getwinposy()
1336
1337 " Initialize the taglist window
1338 call s:Tlist_Window_Init()
1339 endfunction
1340
1341 " Tlist_Window_Zoom
1342 " Zoom (maximize/minimize) the taglist window
1343 function! s:Tlist_Window_Zoom()
1344 if s:tlist_win_maximized
1345 " Restore the window back to the previous size
1346 if g:Tlist_Use_Horiz_Window
1347 exe 'resize ' . g:Tlist_WinHeight
1348 else
1349 exe 'vert resize ' . g:Tlist_WinWidth
1350 endif
1351 let s:tlist_win_maximized = 0
1352 else
1353 " Set the window size to the maximum possible without closing other
1354 " windows
1355 if g:Tlist_Use_Horiz_Window
1356 resize
1357 else
1358 vert resize
1359 endif
1360 let s:tlist_win_maximized = 1
1361 endif
1362 endfunction
1363
1364 " Tlist_Ballon_Expr
1365 " When the mouse cursor is over a tag in the taglist window, display the
1366 " tag prototype (balloon)
1367 function! Tlist_Ballon_Expr()
1368 " Get the file index
1369 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(v:beval_lnum)
1370 if fidx == -1
1371 return ''
1372 endif
1373
1374 " Get the tag output line for the current tag
1375 let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum)
1376 if tidx == 0
1377 return ''
1378 endif
1379
1380 " Get the tag search pattern and display it
1381 return s:Tlist_Get_Tag_Prototype(fidx, tidx)
1382 endfunction
1383
1384 " Tlist_Window_Check_Width
1385 " Check the width of the taglist window. For horizontally split windows, the
1386 " 'winfixheight' option is used to fix the height of the window. For
1387 " vertically split windows, Vim doesn't support the 'winfixwidth' option. So
1388 " need to handle window width changes from this function.
1389 function! s:Tlist_Window_Check_Width()
1390 let tlist_winnr = bufwinnr(g:TagList_title)
1391 if tlist_winnr == -1
1392 return
1393 endif
1394
1395 let width = winwidth(tlist_winnr)
1396 if width != g:Tlist_WinWidth
1397 call s:Tlist_Log_Msg("Tlist_Window_Check_Width: Changing window " .
1398 \ "width from " . width . " to " . g:Tlist_WinWidth)
1399 let save_winnr = winnr()
1400 if save_winnr != tlist_winnr
1401 call s:Tlist_Exe_Cmd_No_Acmds(tlist_winnr . 'wincmd w')
1402 endif
1403 exe 'vert resize ' . g:Tlist_WinWidth
1404 if save_winnr != tlist_winnr
1405 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
1406 endif
1407 endif
1408 endfunction
1409
1410 " Tlist_Window_Exit_Only_Window
1411 " If the 'Tlist_Exit_OnlyWindow' option is set, then exit Vim if only the
1412 " taglist window is present.
1413 function! s:Tlist_Window_Exit_Only_Window()
1414 " Before quitting Vim, delete the taglist buffer so that
1415 " the '0 mark is correctly set to the previous buffer.
1416 if v:version < 700
1417 if winbufnr(2) == -1
1418 bdelete
1419 quit
1420 endif
1421 else
1422 if winbufnr(2) == -1
1423 if tabpagenr('$') == 1
1424 " Only one tag page is present
1425 bdelete
1426 quit
1427 else
1428 " More than one tab page is present. Close only the current
1429 " tab page
1430 close
1431 endif
1432 endif
1433 endif
1434 endfunction
1435
1436 " Tlist_Window_Init
1437 " Set the default options for the taglist window
1438 function! s:Tlist_Window_Init()
1439 call s:Tlist_Log_Msg('Tlist_Window_Init()')
1440
1441 " The 'readonly' option should not be set for the taglist buffer.
1442 " If Vim is started as "view/gview" or if the ":view" command is
1443 " used, then the 'readonly' option is set for all the buffers.
1444 " Unset it for the taglist buffer
1445 setlocal noreadonly
1446
1447 " Set the taglist buffer filetype to taglist
1448 setlocal filetype=taglist
1449
1450 " Define taglist window element highlighting
1451 syntax match TagListComment '^" .*'
1452 syntax match TagListFileName '^[^" ].*$'
1453 syntax match TagListTitle '^ \S.*$'
1454 syntax match TagListTagScope '\s\[.\{-\}\]$'
1455
1456 " Define the highlighting only if colors are supported
1457 if has('gui_running') || &t_Co > 2
1458 " Colors to highlight various taglist window elements
1459 " If user defined highlighting group exists, then use them.
1460 " Otherwise, use default highlight groups.
1461 if hlexists('MyTagListTagName')
1462 highlight link TagListTagName MyTagListTagName
1463 else
1464 highlight default link TagListTagName Search
1465 endif
1466 " Colors to highlight comments and titles
1467 if hlexists('MyTagListComment')
1468 highlight link TagListComment MyTagListComment
1469 else
1470 highlight clear TagListComment
1471 highlight default link TagListComment Comment
1472 endif
1473 if hlexists('MyTagListTitle')
1474 highlight link TagListTitle MyTagListTitle
1475 else
1476 highlight clear TagListTitle
1477 highlight default link TagListTitle Title
1478 endif
1479 if hlexists('MyTagListFileName')
1480 highlight link TagListFileName MyTagListFileName
1481 else
1482 highlight clear TagListFileName
1483 highlight default TagListFileName guibg=Grey ctermbg=darkgray
1484 \ guifg=white ctermfg=white
1485 endif
1486 if hlexists('MyTagListTagScope')
1487 highlight link TagListTagScope MyTagListTagScope
1488 else
1489 highlight clear TagListTagScope
1490 highlight default link TagListTagScope Identifier
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 nnoremap <buffer> <silent> o
1554 \ :call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
1555 nnoremap <buffer> <silent> p
1556 \ :call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
1557 nnoremap <buffer> <silent> P
1558 \ :call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
1559 if v:version >= 700
1560 nnoremap <buffer> <silent> t
1561 \ :call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
1562 nnoremap <buffer> <silent> <C-t>
1563 \ :call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
1564 endif
1565 nnoremap <buffer> <silent> <2-LeftMouse>
1566 \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1567 nnoremap <buffer> <silent> s
1568 \ :call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
1569 nnoremap <buffer> <silent> + :silent! foldopen<CR>
1570 nnoremap <buffer> <silent> - :silent! foldclose<CR>
1571 nnoremap <buffer> <silent> * :silent! %foldopen!<CR>
1572 nnoremap <buffer> <silent> = :silent! %foldclose<CR>
1573 nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR>
1574 nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR>
1575 nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR>
1576 nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Window_Show_Info()<CR>
1577 nnoremap <buffer> <silent> u :call <SID>Tlist_Window_Update_File()<CR>
1578 nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1, 1)<CR>
1579 nnoremap <buffer> <silent> x :call <SID>Tlist_Window_Zoom()<CR>
1580 nnoremap <buffer> <silent> [[ :call <SID>Tlist_Window_Move_To_File(-1)<CR>
1581 nnoremap <buffer> <silent> <BS> :call <SID>Tlist_Window_Move_To_File(-1)<CR>
1582 nnoremap <buffer> <silent> ]] :call <SID>Tlist_Window_Move_To_File(1)<CR>
1583 nnoremap <buffer> <silent> <Tab> :call <SID>Tlist_Window_Move_To_File(1)<CR>
1584 nnoremap <buffer> <silent> <F1> :call <SID>Tlist_Window_Toggle_Help_Text()<CR>
1585 nnoremap <buffer> <silent> q :close<CR>
1586
1587 " Insert mode mappings
1588 inoremap <buffer> <silent> <CR>
1589 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1590 " Windows needs return
1591 inoremap <buffer> <silent> <Return>
1592 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1593 inoremap <buffer> <silent> o
1594 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
1595 inoremap <buffer> <silent> p
1596 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
1597 inoremap <buffer> <silent> P
1598 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
1599 if v:version >= 700
1600 inoremap <buffer> <silent> t
1601 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
1602 inoremap <buffer> <silent> <C-t>
1603 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
1604 endif
1605 inoremap <buffer> <silent> <2-LeftMouse>
1606 \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
1607 inoremap <buffer> <silent> s
1608 \ <C-o>:call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
1609 inoremap <buffer> <silent> + <C-o>:silent! foldopen<CR>
1610 inoremap <buffer> <silent> - <C-o>:silent! foldclose<CR>
1611 inoremap <buffer> <silent> * <C-o>:silent! %foldopen!<CR>
1612 inoremap <buffer> <silent> = <C-o>:silent! %foldclose<CR>
1613 inoremap <buffer> <silent> <kPlus> <C-o>:silent! foldopen<CR>
1614 inoremap <buffer> <silent> <kMinus> <C-o>:silent! foldclose<CR>
1615 inoremap <buffer> <silent> <kMultiply> <C-o>:silent! %foldopen!<CR>
1616 inoremap <buffer> <silent> <Space> <C-o>:call
1617 \ <SID>Tlist_Window_Show_Info()<CR>
1618 inoremap <buffer> <silent> u
1619 \ <C-o>:call <SID>Tlist_Window_Update_File()<CR>
1620 inoremap <buffer> <silent> d <C-o>:call <SID>Tlist_Remove_File(-1, 1)<CR>
1621 inoremap <buffer> <silent> x <C-o>:call <SID>Tlist_Window_Zoom()<CR>
1622 inoremap <buffer> <silent> [[ <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
1623 inoremap <buffer> <silent> <BS> <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
1624 inoremap <buffer> <silent> ]] <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
1625 inoremap <buffer> <silent> <Tab> <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
1626 inoremap <buffer> <silent> <F1> <C-o>:call <SID>Tlist_Window_Toggle_Help_Text()<CR>
1627 inoremap <buffer> <silent> q <C-o>:close<CR>
1628
1629 " Map single left mouse click if the user wants this functionality
1630 if g:Tlist_Use_SingleClick == 1
1631 " Contributed by Bindu Wavell
1632 " attempt to perform single click mapping, it would be much
1633 " nicer if we could nnoremap <buffer> ... however vim does
1634 " not fire the <buffer> <leftmouse> when you use the mouse
1635 " to enter a buffer.
1636 let clickmap = ':if bufname("%") =~ "__Tag_List__" <bar> ' .
1637 \ 'call <SID>Tlist_Window_Jump_To_Tag("useopen") ' .
1638 \ '<bar> endif <CR>'
1639 if maparg('<leftmouse>', 'n') == ''
1640 " no mapping for leftmouse
1641 exe ':nnoremap <silent> <leftmouse> <leftmouse>' . clickmap
1642 else
1643 " we have a mapping
1644 let mapcmd = ':nnoremap <silent> <leftmouse> <leftmouse>'
1645 let mapcmd = mapcmd . substitute(substitute(
1646 \ maparg('<leftmouse>', 'n'), '|', '<bar>', 'g'),
1647 \ '\c^<leftmouse>', '', '')
1648 let mapcmd = mapcmd . clickmap
1649 exe mapcmd
1650 endif
1651 endif
1652
1653 " Define the taglist autocommands
1654 augroup TagListAutoCmds
1655 autocmd!
1656 " Display the tag prototype for the tag under the cursor.
1657 autocmd CursorHold __Tag_List__ call s:Tlist_Window_Show_Info()
1658 " Highlight the current tag periodically
1659 autocmd CursorHold * silent call s:Tlist_Window_Highlight_Tag(
1660 \ fnamemodify(bufname('%'), ':p'), line('.'), 1, 0)
1661
1662 " Adjust the Vim window width when taglist window is closed
1663 autocmd BufUnload __Tag_List__ call s:Tlist_Post_Close_Cleanup()
1664 " Close the fold for this buffer when leaving the buffer
1665 if g:Tlist_File_Fold_Auto_Close
1666 autocmd BufEnter * silent
1667 \ call s:Tlist_Window_Open_File_Fold(expand('<abuf>'))
1668 endif
1669 " Exit Vim itself if only the taglist window is present (optional)
1670 if g:Tlist_Exit_OnlyWindow
1671 autocmd BufEnter __Tag_List__ nested
1672 \ call s:Tlist_Window_Exit_Only_Window()
1673 endif
1674 if s:tlist_app_name != "winmanager" &&
1675 \ !g:Tlist_Process_File_Always &&
1676 \ (!has('gui_running') || !g:Tlist_Show_Menu)
1677 " Auto refresh the taglist window
1678 autocmd BufEnter * call s:Tlist_Refresh()
1679 endif
1680
1681 if !g:Tlist_Use_Horiz_Window
1682 if v:version < 700
1683 autocmd WinEnter * call s:Tlist_Window_Check_Width()
1684 endif
1685 endif
1686 if v:version >= 700
1687 autocmd TabEnter * silent call s:Tlist_Refresh_Folds()
1688 endif
1689 augroup end
1690
1691 " Restore the previous cpoptions settings
1692 let &cpoptions = old_cpoptions
1693 endfunction
1694
1695 " Tlist_Window_Refresh
1696 " Display the tags for all the files in the taglist window
1697 function! s:Tlist_Window_Refresh()
1698 call s:Tlist_Log_Msg('Tlist_Window_Refresh()')
1699 " Set report option to a huge value to prevent informational messages
1700 " while deleting the lines
1701 let old_report = &report
1702 set report=99999
1703
1704 " Mark the buffer as modifiable
1705 setlocal modifiable
1706
1707 " Delete the contents of the buffer to the black-hole register
1708 silent! %delete _
1709
1710 " As we have cleared the taglist window, mark all the files
1711 " as not visible
1712 let i = 0
1713 while i < s:tlist_file_count
1714 let s:tlist_{i}_visible = 0
1715 let i = i + 1
1716 endwhile
1717
1718 if g:Tlist_Compact_Format == 0
1719 " Display help in non-compact mode
1720 call s:Tlist_Window_Display_Help()
1721 endif
1722
1723 " Mark the buffer as not modifiable
1724 setlocal nomodifiable
1725
1726 " Restore the report option
1727 let &report = old_report
1728
1729 " If the tags for only one file should be displayed in the taglist
1730 " window, then no need to add the tags here. The bufenter autocommand
1731 " will add the tags for that file.
1732 if g:Tlist_Show_One_File
1733 return
1734 endif
1735
1736 " List all the tags for the previously processed files
1737 " Do this only if taglist is configured to display tags for more than
1738 " one file. Otherwise, when Tlist_Show_One_File is configured,
1739 " tags for the wrong file will be displayed.
1740 let i = 0
1741 while i < s:tlist_file_count
1742 call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename,
1743 \ s:tlist_{i}_filetype)
1744 let i = i + 1
1745 endwhile
1746
1747 if g:Tlist_Auto_Update
1748 " Add and list the tags for all buffers in the Vim buffer list
1749 let i = 1
1750 let last_bufnum = bufnr('$')
1751 while i <= last_bufnum
1752 if buflisted(i)
1753 let fname = fnamemodify(bufname(i), ':p')
1754 let ftype = s:Tlist_Get_Buffer_Filetype(i)
1755 " If the file doesn't support tag listing, skip it
1756 if !s:Tlist_Skip_File(fname, ftype)
1757 call s:Tlist_Window_Refresh_File(fname, ftype)
1758 endif
1759 endif
1760 let i = i + 1
1761 endwhile
1762 endif
1763
1764 " If Tlist_File_Fold_Auto_Close option is set, then close all the folds
1765 if g:Tlist_File_Fold_Auto_Close
1766 " Close all the folds
1767 silent! %foldclose
1768 endif
1769
1770 " Move the cursor to the top of the taglist window
1771 normal! gg
1772 endfunction
1773
1774 " Tlist_Post_Close_Cleanup()
1775 " Close the taglist window and adjust the Vim window width
1776 function! s:Tlist_Post_Close_Cleanup()
1777 call s:Tlist_Log_Msg('Tlist_Post_Close_Cleanup()')
1778 " Mark all the files as not visible
1779 let i = 0
1780 while i < s:tlist_file_count
1781 let s:tlist_{i}_visible = 0
1782 let i = i + 1
1783 endwhile
1784
1785 " Remove the taglist autocommands
1786 silent! autocmd! TagListAutoCmds
1787
1788 " Clear all the highlights
1789 match none
1790
1791 silent! syntax clear TagListTitle
1792 silent! syntax clear TagListComment
1793 silent! syntax clear TagListTagScope
1794
1795 " Remove the left mouse click mapping if it was setup initially
1796 if g:Tlist_Use_SingleClick
1797 if hasmapto('<LeftMouse>')
1798 nunmap <LeftMouse>
1799 endif
1800 endif
1801
1802 if s:tlist_app_name != "winmanager"
1803 if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 ||
1804 \ s:tlist_winsize_chgd != 1 ||
1805 \ &columns < (80 + g:Tlist_WinWidth)
1806 " No need to adjust window width if using horizontally split taglist
1807 " window or if columns is less than 101 or if the user chose not to
1808 " adjust the window width
1809 else
1810 " If the user didn't manually move the window, then restore the window
1811 " position to the pre-taglist position
1812 if s:tlist_pre_winx != -1 && s:tlist_pre_winy != -1 &&
1813 \ getwinposx() == s:tlist_winx &&
1814 \ getwinposy() == s:tlist_winy
1815 exe 'winpos ' . s:tlist_pre_winx . ' ' . s:tlist_pre_winy
1816 endif
1817
1818 " Adjust the Vim window width
1819 let &columns= &columns - (g:Tlist_WinWidth + 1)
1820 endif
1821 endif
1822
1823 let s:tlist_winsize_chgd = -1
1824
1825 " Reset taglist state variables
1826 if s:tlist_app_name == "winmanager"
1827 let s:tlist_app_name = "none"
1828 endif
1829 let s:tlist_window_initialized = 0
1830 endfunction
1831
1832 " Tlist_Window_Refresh_File()
1833 " List the tags defined in the specified file in a Vim window
1834 function! s:Tlist_Window_Refresh_File(filename, ftype)
1835 call s:Tlist_Log_Msg('Tlist_Window_Refresh_File (' . a:filename . ')')
1836 " First check whether the file already exists
1837 let fidx = s:Tlist_Get_File_Index(a:filename)
1838 if fidx != -1
1839 let file_listed = 1
1840 else
1841 let file_listed = 0
1842 endif
1843
1844 if !file_listed
1845 " Check whether this file is removed based on user request
1846 " If it is, then don't display the tags for this file
1847 if s:Tlist_User_Removed_File(a:filename)
1848 return
1849 endif
1850 endif
1851
1852 if file_listed && s:tlist_{fidx}_visible
1853 " Check whether the file tags are currently valid
1854 if s:tlist_{fidx}_valid
1855 " Goto the first line in the file
1856 exe s:tlist_{fidx}_start
1857
1858 " If the line is inside a fold, open the fold
1859 if foldclosed('.') != -1
1860 exe "silent! " . s:tlist_{fidx}_start . "," .
1861 \ s:tlist_{fidx}_end . "foldopen!"
1862 endif
1863 return
1864 endif
1865
1866 " Discard and remove the tags for this file from display
1867 call s:Tlist_Discard_TagInfo(fidx)
1868 call s:Tlist_Window_Remove_File_From_Display(fidx)
1869 endif
1870
1871 " Process and generate a list of tags defined in the file
1872 if !file_listed || !s:tlist_{fidx}_valid
1873 let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype)
1874 if ret_fidx == -1
1875 return
1876 endif
1877 let fidx = ret_fidx
1878 endif
1879
1880 " Set report option to a huge value to prevent informational messages
1881 " while adding lines to the taglist window
1882 let old_report = &report
1883 set report=99999
1884
1885 if g:Tlist_Show_One_File
1886 " Remove the previous file
1887 if s:tlist_cur_file_idx != -1
1888 call s:Tlist_Window_Remove_File_From_Display(s:tlist_cur_file_idx)
1889 let s:tlist_{s:tlist_cur_file_idx}_visible = 0
1890 let s:tlist_{s:tlist_cur_file_idx}_start = 0
1891 let s:tlist_{s:tlist_cur_file_idx}_end = 0
1892 endif
1893 let s:tlist_cur_file_idx = fidx
1894 endif
1895
1896 " Mark the buffer as modifiable
1897 setlocal modifiable
1898
1899 " Add new files to the end of the window. For existing files, add them at
1900 " the same line where they were previously present. If the file is not
1901 " visible, then add it at the end
1902 if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible
1903 if g:Tlist_Compact_Format
1904 let s:tlist_{fidx}_start = line('$')
1905 else
1906 let s:tlist_{fidx}_start = line('$') + 1
1907 endif
1908 endif
1909
1910 let s:tlist_{fidx}_visible = 1
1911
1912 " Goto the line where this file should be placed
1913 if g:Tlist_Compact_Format
1914 exe s:tlist_{fidx}_start
1915 else
1916 exe s:tlist_{fidx}_start - 1
1917 endif
1918
1919 let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' .
1920 \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')'
1921 if g:Tlist_Compact_Format == 0
1922 silent! put =txt
1923 else
1924 silent! put! =txt
1925 " Move to the next line
1926 exe line('.') + 1
1927 endif
1928 let file_start = s:tlist_{fidx}_start
1929
1930 " Add the tag names grouped by tag type to the buffer with a title
1931 let i = 1
1932 let ttype_cnt = s:tlist_{a:ftype}_count
1933 while i <= ttype_cnt
1934 let ttype = s:tlist_{a:ftype}_{i}_name
1935 " Add the tag type only if there are tags for that type
1936 let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
1937 let ttype_txt = {fidx_ttype}
1938 if ttype_txt != ''
1939 let txt = ' ' . s:tlist_{a:ftype}_{i}_fullname
1940 if g:Tlist_Compact_Format == 0
1941 let ttype_start_lnum = line('.') + 1
1942 silent! put =txt
1943 else
1944 let ttype_start_lnum = line('.')
1945 silent! put! =txt
1946 endif
1947 silent! put =ttype_txt
1948
1949 let {fidx_ttype}_offset = ttype_start_lnum - file_start
1950
1951 " create a fold for this tag type
1952 let fold_start = ttype_start_lnum
1953 let fold_end = fold_start + {fidx_ttype}_count
1954 exe fold_start . ',' . fold_end . 'fold'
1955
1956 " Adjust the cursor position
1957 if g:Tlist_Compact_Format == 0
1958 exe ttype_start_lnum + {fidx_ttype}_count
1959 else
1960 exe ttype_start_lnum + {fidx_ttype}_count + 1
1961 endif
1962
1963 if g:Tlist_Compact_Format == 0
1964 " Separate the tag types by a empty line
1965 silent! put =''
1966 endif
1967 endif
1968 let i = i + 1
1969 endwhile
1970
1971 if s:tlist_{fidx}_tag_count == 0
1972 if g:Tlist_Compact_Format == 0
1973 silent! put =''
1974 endif
1975 endif
1976
1977 let s:tlist_{fidx}_end = line('.') - 1
1978
1979 " Create a fold for the entire file
1980 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
1981 exe 'silent! ' . s:tlist_{fidx}_start . ',' .
1982 \ s:tlist_{fidx}_end . 'foldopen!'
1983
1984 " Goto the starting line for this file,
1985 exe s:tlist_{fidx}_start
1986
1987 if s:tlist_app_name == "winmanager"
1988 " To handle a bug in the winmanager plugin, add a space at the
1989 " last line
1990 call setline('$', ' ')
1991 endif
1992
1993 " Mark the buffer as not modifiable
1994 setlocal nomodifiable
1995
1996 " Restore the report option
1997 let &report = old_report
1998
1999 " Update the start and end line numbers for all the files following this
2000 " file
2001 let start = s:tlist_{fidx}_start
2002 " include the empty line after the last line
2003 if g:Tlist_Compact_Format
2004 let end = s:tlist_{fidx}_end
2005 else
2006 let end = s:tlist_{fidx}_end + 1
2007 endif
2008 call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1)
2009
2010 " Now that we have updated the taglist window, update the tags
2011 " menu (if present)
2012 if g:Tlist_Show_Menu
2013 call s:Tlist_Menu_Update_File(1)
2014 endif
2015 endfunction
2016
2017 " Tlist_Init_File
2018 " Initialize the variables for a new file
2019 function! s:Tlist_Init_File(filename, ftype)
2020 call s:Tlist_Log_Msg('Tlist_Init_File (' . a:filename . ')')
2021 " Add new files at the end of the list
2022 let fidx = s:tlist_file_count
2023 let s:tlist_file_count = s:tlist_file_count + 1
2024 " Add the new file name to the taglist list of file names
2025 let s:tlist_file_names = s:tlist_file_names . a:filename . "\n"
2026
2027 " Initialize the file variables
2028 let s:tlist_{fidx}_filename = a:filename
2029 let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type
2030 let s:tlist_{fidx}_filetype = a:ftype
2031 let s:tlist_{fidx}_mtime = -1
2032 let s:tlist_{fidx}_start = 0
2033 let s:tlist_{fidx}_end = 0
2034 let s:tlist_{fidx}_valid = 0
2035 let s:tlist_{fidx}_visible = 0
2036 let s:tlist_{fidx}_tag_count = 0
2037 let s:tlist_{fidx}_menu_cmd = ''
2038
2039 " Initialize the tag type variables
2040 let i = 1
2041 while i <= s:tlist_{a:ftype}_count
2042 let ttype = s:tlist_{a:ftype}_{i}_name
2043 let s:tlist_{fidx}_{ttype} = ''
2044 let s:tlist_{fidx}_{ttype}_offset = 0
2045 let s:tlist_{fidx}_{ttype}_count = 0
2046 let i = i + 1
2047 endwhile
2048
2049 return fidx
2050 endfunction
2051
2052 " Tlist_Get_Tag_Type_By_Tag
2053 " Return the tag type for the specified tag index
2054 function! s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
2055 let ttype_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_type'
2056
2057 " Already parsed and have the tag name
2058 if exists(ttype_var)
2059 return {ttype_var}
2060 endif
2061
2062 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2063 let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line)
2064
2065 return {ttype_var}
2066 endfunction
2067
2068 " Tlist_Get_Tag_Prototype
2069 function! s:Tlist_Get_Tag_Prototype(fidx, tidx)
2070 let tproto_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_proto'
2071
2072 " Already parsed and have the tag prototype
2073 if exists(tproto_var)
2074 return {tproto_var}
2075 endif
2076
2077 " Parse and extract the tag prototype
2078 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2079 let start = stridx(tag_line, '/^') + 2
2080 let end = stridx(tag_line, '/;"' . "\t")
2081 if tag_line[end - 1] == '$'
2082 let end = end -1
2083 endif
2084 let tag_proto = strpart(tag_line, start, end - start)
2085 let {tproto_var} = substitute(tag_proto, '\s*', '', '')
2086
2087 return {tproto_var}
2088 endfunction
2089
2090 " Tlist_Get_Tag_SearchPat
2091 function! s:Tlist_Get_Tag_SearchPat(fidx, tidx)
2092 let tpat_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_searchpat'
2093
2094 " Already parsed and have the tag search pattern
2095 if exists(tpat_var)
2096 return {tpat_var}
2097 endif
2098
2099 " Parse and extract the tag search pattern
2100 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2101 let start = stridx(tag_line, '/^') + 2
2102 let end = stridx(tag_line, '/;"' . "\t")
2103 if tag_line[end - 1] == '$'
2104 let end = end -1
2105 endif
2106 let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) .
2107 \ (tag_line[end] == '$' ? '\$' : '')
2108
2109 return {tpat_var}
2110 endfunction
2111
2112 " Tlist_Get_Tag_Linenum
2113 " Return the tag line number, given the tag index
2114 function! s:Tlist_Get_Tag_Linenum(fidx, tidx)
2115 let tline_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_linenum'
2116
2117 " Already parsed and have the tag line number
2118 if exists(tline_var)
2119 return {tline_var}
2120 endif
2121
2122 " Parse and extract the tag line number
2123 let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag
2124 let start = strridx(tag_line, 'line:') + 5
2125 let end = strridx(tag_line, "\t")
2126 if end < start
2127 let {tline_var} = strpart(tag_line, start) + 0
2128 else
2129 let {tline_var} = strpart(tag_line, start, end - start) + 0
2130 endif
2131
2132 return {tline_var}
2133 endfunction
2134
2135 " Tlist_Parse_Tagline
2136 " Parse a tag line from the ctags output. Separate the tag output based on the
2137 " tag type and store it in the tag type variable.
2138 " The format of each line in the ctags output is:
2139 "
2140 " tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields
2141 "
2142 function! s:Tlist_Parse_Tagline(tag_line)
2143 if a:tag_line == ''
2144 " Skip empty lines
2145 return
2146 endif
2147
2148 " Extract the tag type
2149 let ttype = s:Tlist_Extract_Tagtype(a:tag_line)
2150
2151 " Make sure the tag type is a valid and supported one
2152 if ttype == '' || stridx(s:ctags_flags, ttype) == -1
2153 " Line is not in proper tags format or Tag type is not supported
2154 return
2155 endif
2156
2157 " Update the total tag count
2158 let s:tidx = s:tidx + 1
2159
2160 " The following variables are used to optimize this code. Vim is slow in
2161 " using curly brace names. To reduce the amount of processing needed, the
2162 " curly brace variables are pre-processed here
2163 let fidx_tidx = 's:tlist_' . s:fidx . '_' . s:tidx
2164 let fidx_ttype = 's:tlist_' . s:fidx . '_' . ttype
2165
2166 " Update the count of this tag type
2167 let ttype_idx = {fidx_ttype}_count + 1
2168 let {fidx_ttype}_count = ttype_idx
2169
2170 " Store the ctags output for this tag
2171 let {fidx_tidx}_tag = a:tag_line
2172
2173 " Store the tag index and the tag type index (back pointers)
2174 let {fidx_ttype}_{ttype_idx} = s:tidx
2175 let {fidx_tidx}_ttype_idx = ttype_idx
2176
2177 " Extract the tag name
2178 let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t"))
2179
2180 " Extract the tag scope/prototype
2181 if g:Tlist_Display_Prototype
2182 let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx)
2183 else
2184 let ttxt = ' ' . tag_name
2185
2186 " Add the tag scope, if it is available and is configured. Tag
2187 " scope is the last field after the 'line:<num>\t' field
2188 if g:Tlist_Display_Tag_Scope
2189 let tag_scope = s:Tlist_Extract_Tag_Scope(a:tag_line)
2190 if tag_scope != ''
2191 let ttxt = ttxt . ' [' . tag_scope . ']'
2192 endif
2193 endif
2194 endif
2195
2196 " Add this tag to the tag type variable
2197 let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
2198
2199 " Save the tag name
2200 let {fidx_tidx}_tag_name = tag_name
2201 endfunction
2202
2203 " Tlist_Process_File
2204 " Get the list of tags defined in the specified file and store them
2205 " in Vim variables. Returns the file index where the tags are stored.
2206 function! s:Tlist_Process_File(filename, ftype)
2207 call s:Tlist_Log_Msg('Tlist_Process_File (' . a:filename . ', ' .
2208 \ a:ftype . ')')
2209 " Check whether this file is supported
2210 if s:Tlist_Skip_File(a:filename, a:ftype)
2211 return -1
2212 endif
2213
2214 " If the tag types for this filetype are not yet created, then create
2215 " them now
2216 let var = 's:tlist_' . a:ftype . '_count'
2217 if !exists(var)
2218 if s:Tlist_FileType_Init(a:ftype) == 0
2219 return -1
2220 endif
2221 endif
2222
2223 " If this file is already processed, then use the cached values
2224 let fidx = s:Tlist_Get_File_Index(a:filename)
2225 if fidx == -1
2226 " First time, this file is loaded
2227 let fidx = s:Tlist_Init_File(a:filename, a:ftype)
2228 else
2229 " File was previously processed. Discard the tag information
2230 call s:Tlist_Discard_TagInfo(fidx)
2231 endif
2232
2233 let s:tlist_{fidx}_valid = 1
2234
2235 " Exuberant ctags arguments to generate a tag list
2236 let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks '
2237
2238 " Form the ctags argument depending on the sort type
2239 if s:tlist_{fidx}_sort_type == 'name'
2240 let ctags_args = ctags_args . '--sort=yes'
2241 else
2242 let ctags_args = ctags_args . '--sort=no'
2243 endif
2244
2245 " Add the filetype specific arguments
2246 let ctags_args = ctags_args . ' ' . s:tlist_{a:ftype}_ctags_args
2247
2248 " Ctags command to produce output with regexp for locating the tags
2249 let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args
2250 let ctags_cmd = ctags_cmd . ' "' . a:filename . '"'
2251
2252 if &shellxquote == '"'
2253 " Double-quotes within double-quotes will not work in the
2254 " command-line.If the 'shellxquote' option is set to double-quotes,
2255 " then escape the double-quotes in the ctags command-line.
2256 let ctags_cmd = escape(ctags_cmd, '"')
2257 endif
2258
2259 " In Windows 95, if not using cygwin, disable the 'shellslash'
2260 " option. Otherwise, this will cause problems when running the
2261 " ctags command.
2262 if has('win95') && !has('win32unix')
2263 let old_shellslash = &shellslash
2264 set noshellslash
2265 endif
2266
2267 if has('win32') && !has('win32unix') && !has('win95')
2268 \ && (&shell =~ 'cmd.exe')
2269 " Windows does not correctly deal with commands that have more than 1
2270 " set of double quotes. It will strip them all resulting in:
2271 " 'C:\Program' is not recognized as an internal or external command
2272 " operable program or batch file. To work around this, place the
2273 " command inside a batch file and call the batch file.
2274 " Do this only on Win2K, WinXP and above.
2275 " Contributed by: David Fishburn.
2276 let s:taglist_tempfile = fnamemodify(tempname(), ':h') .
2277 \ '\taglist.cmd'
2278 exe 'redir! > ' . s:taglist_tempfile
2279 silent echo ctags_cmd
2280 redir END
2281
2282 call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd)
2283 let ctags_cmd = '"' . s:taglist_tempfile . '"'
2284 endif
2285
2286 call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd)
2287
2288 " Run ctags and get the tag list
2289 let cmd_output = system(ctags_cmd)
2290
2291 " Restore the value of the 'shellslash' option.
2292 if has('win95') && !has('win32unix')
2293 let &shellslash = old_shellslash
2294 endif
2295
2296 if exists('s:taglist_tempfile')
2297 " Delete the temporary cmd file created on MS-Windows
2298 call delete(s:taglist_tempfile)
2299 endif
2300
2301 " Handle errors
2302 if v:shell_error
2303 let msg = "Taglist: Failed to generate tags for " . a:filename
2304 call s:Tlist_Warning_Msg(msg)
2305 if cmd_output != ''
2306 call s:Tlist_Warning_Msg(cmd_output)
2307 endif
2308 return fidx
2309 endif
2310
2311 " Store the modification time for the file
2312 let s:tlist_{fidx}_mtime = getftime(a:filename)
2313
2314 " No tags for current file
2315 if cmd_output == ''
2316 call s:Tlist_Log_Msg('No tags defined in ' . a:filename)
2317 return fidx
2318 endif
2319
2320 call s:Tlist_Log_Msg('Generated tags information for ' . a:filename)
2321
2322 if v:version > 601
2323 " The following script local variables are used by the
2324 " Tlist_Parse_Tagline() function.
2325 let s:ctags_flags = s:tlist_{a:ftype}_ctags_flags
2326 let s:fidx = fidx
2327 let s:tidx = 0
2328
2329 " Process the ctags output one line at a time. The substitute()
2330 " command is used to parse the tag lines instead of using the
2331 " matchstr()/stridx()/strpart() functions for performance reason
2332 call substitute(cmd_output, "\\([^\n]\\+\\)\n",
2333 \ '\=s:Tlist_Parse_Tagline(submatch(1))', 'g')
2334
2335 " Save the number of tags for this file
2336 let s:tlist_{fidx}_tag_count = s:tidx
2337
2338 " The following script local variables are no longer needed
2339 unlet! s:ctags_flags
2340 unlet! s:tidx
2341 unlet! s:fidx
2342 else
2343 " Due to a bug in Vim earlier than version 6.1,
2344 " we cannot use substitute() to parse the ctags output.
2345 " Instead the slow str*() functions are used
2346 let ctags_flags = s:tlist_{a:ftype}_ctags_flags
2347 let tidx = 0
2348
2349 while cmd_output != ''
2350 " Extract one line at a time
2351 let idx = stridx(cmd_output, "\n")
2352 let one_line = strpart(cmd_output, 0, idx)
2353 " Remove the line from the tags output
2354 let cmd_output = strpart(cmd_output, idx + 1)
2355
2356 if one_line == ''
2357 " Line is not in proper tags format
2358 continue
2359 endif
2360
2361 " Extract the tag type
2362 let ttype = s:Tlist_Extract_Tagtype(one_line)
2363
2364 " Make sure the tag type is a valid and supported one
2365 if ttype == '' || stridx(ctags_flags, ttype) == -1
2366 " Line is not in proper tags format or Tag type is not
2367 " supported
2368 continue
2369 endif
2370
2371 " Update the total tag count
2372 let tidx = tidx + 1
2373
2374 " The following variables are used to optimize this code. Vim is
2375 " slow in using curly brace names. To reduce the amount of
2376 " processing needed, the curly brace variables are pre-processed
2377 " here
2378 let fidx_tidx = 's:tlist_' . fidx . '_' . tidx
2379 let fidx_ttype = 's:tlist_' . fidx . '_' . ttype
2380
2381 " Update the count of this tag type
2382 let ttype_idx = {fidx_ttype}_count + 1
2383 let {fidx_ttype}_count = ttype_idx
2384
2385 " Store the ctags output for this tag
2386 let {fidx_tidx}_tag = one_line
2387
2388 " Store the tag index and the tag type index (back pointers)
2389 let {fidx_ttype}_{ttype_idx} = tidx
2390 let {fidx_tidx}_ttype_idx = ttype_idx
2391
2392 " Extract the tag name
2393 let tag_name = strpart(one_line, 0, stridx(one_line, "\t"))
2394
2395 " Extract the tag scope/prototype
2396 if g:Tlist_Display_Prototype
2397 let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(fidx, tidx)
2398 else
2399 let ttxt = ' ' . tag_name
2400
2401 " Add the tag scope, if it is available and is configured. Tag
2402 " scope is the last field after the 'line:<num>\t' field
2403 if g:Tlist_Display_Tag_Scope
2404 let tag_scope = s:Tlist_Extract_Tag_Scope(one_line)
2405 if tag_scope != ''
2406 let ttxt = ttxt . ' [' . tag_scope . ']'
2407 endif
2408 endif
2409 endif
2410
2411 " Add this tag to the tag type variable
2412 let {fidx_ttype} = {fidx_ttype} . ttxt . "\n"
2413
2414 " Save the tag name
2415 let {fidx_tidx}_tag_name = tag_name
2416 endwhile
2417
2418 " Save the number of tags for this file
2419 let s:tlist_{fidx}_tag_count = tidx
2420 endif
2421
2422 call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count .
2423 \ ' tags in ' . a:filename)
2424
2425 return fidx
2426 endfunction
2427
2428 " Tlist_Update_File
2429 " Update the tags for a file (if needed)
2430 function! Tlist_Update_File(filename, ftype)
2431 call s:Tlist_Log_Msg('Tlist_Update_File (' . a:filename . ')')
2432 " If the file doesn't support tag listing, skip it
2433 if s:Tlist_Skip_File(a:filename, a:ftype)
2434 return
2435 endif
2436
2437 " Convert the file name to a full path
2438 let fname = fnamemodify(a:filename, ':p')
2439
2440 " First check whether the file already exists
2441 let fidx = s:Tlist_Get_File_Index(fname)
2442
2443 if fidx != -1 && s:tlist_{fidx}_valid
2444 " File exists and the tags are valid
2445 " Check whether the file was modified after the last tags update
2446 " If it is modified, then update the tags
2447 if s:tlist_{fidx}_mtime == getftime(fname)
2448 return
2449 endif
2450 else
2451 " If the tags were removed previously based on a user request,
2452 " as we are going to update the tags (based on the user request),
2453 " remove the filename from the deleted list
2454 call s:Tlist_Update_Remove_List(fname, 0)
2455 endif
2456
2457 " If the taglist window is opened, update it
2458 let winnum = bufwinnr(g:TagList_title)
2459 if winnum == -1
2460 " Taglist window is not present. Just update the taglist
2461 " and return
2462 call s:Tlist_Process_File(fname, a:ftype)
2463 else
2464 if g:Tlist_Show_One_File && s:tlist_cur_file_idx != -1
2465 " If tags for only one file are displayed and we are not
2466 " updating the tags for that file, then no need to
2467 " refresh the taglist window. Otherwise, the taglist
2468 " window should be updated.
2469 if s:tlist_{s:tlist_cur_file_idx}_filename != fname
2470 call s:Tlist_Process_File(fname, a:ftype)
2471 return
2472 endif
2473 endif
2474
2475 " Save the current window number
2476 let save_winnr = winnr()
2477
2478 " Goto the taglist window
2479 call s:Tlist_Window_Goto_Window()
2480
2481 " Save the cursor position
2482 let save_line = line('.')
2483 let save_col = col('.')
2484
2485 " Update the taglist window
2486 call s:Tlist_Window_Refresh_File(fname, a:ftype)
2487
2488 " Restore the cursor position
2489 if v:version >= 601
2490 call cursor(save_line, save_col)
2491 else
2492 exe save_line
2493 exe 'normal! ' . save_col . '|'
2494 endif
2495
2496 if winnr() != save_winnr
2497 " Go back to the original window
2498 call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
2499 endif
2500 endif
2501
2502 " Update the taglist menu
2503 if g:Tlist_Show_Menu
2504 call s:Tlist_Menu_Update_File(1)
2505 endif
2506 endfunction
2507
2508 " Tlist_Window_Close
2509 " Close the taglist window
2510 function! s:Tlist_Window_Close()
2511 call s:Tlist_Log_Msg('Tlist_Window_Close()')
2512 " Make sure the taglist window exists
2513 let winnum = bufwinnr(g:TagList_title)
2514 if winnum == -1
2515 call s:Tlist_Warning_Msg('Error: Taglist window is not open')
2516 return
2517 endif
2518
2519 if winnr() == winnum
2520 " Already in the taglist window. Close it and return
2521 if winbufnr(2) != -1
2522 " If a window other than the taglist window is open,
2523 " then only close the taglist window.
2524 close
2525 endif
2526 else
2527 " Goto the taglist window, close it and then come back to the
2528 " original window
2529 let curbufnr = bufnr('%')
2530 exe winnum . 'wincmd w'
2531 close
2532 " Need to jump back to the original window only if we are not
2533 " already in that window
2534 let winnum = bufwinnr(curbufnr)
2535 if winnr() != winnum
2536 exe winnum . 'wincmd w'
2537 endif
2538 endif
2539 endfunction
2540
2541 " Tlist_Window_Mark_File_Window
2542 " Mark the current window as the file window to use when jumping to a tag.
2543 " Only if the current window is a non-plugin, non-preview and non-taglist
2544 " window
2545 function! s:Tlist_Window_Mark_File_Window()
2546 if getbufvar('%', '&buftype') == '' && !&previewwindow
2547 let w:tlist_file_window = "yes"
2548 endif
2549 endfunction
2550
2551 " Tlist_Window_Open
2552 " Open and refresh the taglist window
2553 function! s:Tlist_Window_Open()
2554 call s:Tlist_Log_Msg('Tlist_Window_Open()')
2555 " If the window is open, jump to it
2556 let winnum = bufwinnr(g:TagList_title)
2557 if winnum != -1
2558 " Jump to the existing window
2559 if winnr() != winnum
2560 exe winnum . 'wincmd w'
2561 endif
2562 return
2563 endif
2564
2565 if s:tlist_app_name == "winmanager"
2566 " Taglist plugin is no longer part of the winmanager app
2567 let s:tlist_app_name = "none"
2568 endif
2569
2570 " Get the filename and filetype for the specified buffer
2571 let curbuf_name = fnamemodify(bufname('%'), ':p')
2572 let curbuf_ftype = s:Tlist_Get_Buffer_Filetype('%')
2573 let cur_lnum = line('.')
2574
2575 " Mark the current window as the desired window to open a file when a tag
2576 " is selected.
2577 call s:Tlist_Window_Mark_File_Window()
2578
2579 " Open the taglist window
2580 call s:Tlist_Window_Create()
2581
2582 call s:Tlist_Window_Refresh()
2583
2584 if g:Tlist_Show_One_File
2585 " Add only the current buffer and file
2586 "
2587 " If the file doesn't support tag listing, skip it
2588 if !s:Tlist_Skip_File(curbuf_name, curbuf_ftype)
2589 call s:Tlist_Window_Refresh_File(curbuf_name, curbuf_ftype)
2590 endif
2591 endif
2592
2593 if g:Tlist_File_Fold_Auto_Close
2594 " Open the fold for the current file, as all the folds in
2595 " the taglist window are closed
2596 let fidx = s:Tlist_Get_File_Index(curbuf_name)
2597 if fidx != -1
2598 exe "silent! " . s:tlist_{fidx}_start . "," .
2599 \ s:tlist_{fidx}_end . "foldopen!"
2600 endif
2601 endif
2602
2603 " Highlight the current tag
2604 call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1)
2605 endfunction
2606
2607 " Tlist_Window_Toggle()
2608 " Open or close a taglist window
2609 function! s:Tlist_Window_Toggle()
2610 call s:Tlist_Log_Msg('Tlist_Window_Toggle()')
2611 " If taglist window is open then close it.
2612 let winnum = bufwinnr(g:TagList_title)
2613 if winnum != -1
2614 call s:Tlist_Window_Close()
2615 return
2616 endif
2617
2618 call s:Tlist_Window_Open()
2619
2620 " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not
2621 " set
2622 if !g:Tlist_GainFocus_On_ToggleOpen
2623 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
2624 endif
2625
2626 " Update the taglist menu
2627 if g:Tlist_Show_Menu
2628 call s:Tlist_Menu_Update_File(0)
2629 endif
2630 endfunction
2631
2632 " Tlist_Process_Filelist
2633 " Process multiple files. Each filename is separated by "\n"
2634 " Returns the number of processed files
2635 function! s:Tlist_Process_Filelist(file_names)
2636 let flist = a:file_names
2637
2638 " Enable lazy screen updates
2639 let old_lazyredraw = &lazyredraw
2640 set lazyredraw
2641
2642 " Keep track of the number of processed files
2643 let fcnt = 0
2644
2645 " Process one file at a time
2646 while flist != ''
2647 let nl_idx = stridx(flist, "\n")
2648 let one_file = strpart(flist, 0, nl_idx)
2649
2650 " Remove the filename from the list
2651 let flist = strpart(flist, nl_idx + 1)
2652
2653 if one_file == ''
2654 continue
2655 endif
2656
2657 " Skip directories
2658 if isdirectory(one_file)
2659 continue
2660 endif
2661
2662 let ftype = s:Tlist_Detect_Filetype(one_file)
2663
2664 echon "\r "
2665 echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t')
2666
2667 let fcnt = fcnt + 1
2668
2669 call Tlist_Update_File(one_file, ftype)
2670 endwhile
2671
2672 " Clear the displayed informational messages
2673 echon "\r "
2674
2675 " Restore the previous state
2676 let &lazyredraw = old_lazyredraw
2677
2678 return fcnt
2679 endfunction
2680
2681 " Tlist_Process_Dir
2682 " Process the files in a directory matching the specified pattern
2683 function! s:Tlist_Process_Dir(dir_name, pat)
2684 let flist = glob(a:dir_name . '/' . a:pat) . "\n"
2685
2686 let fcnt = s:Tlist_Process_Filelist(flist)
2687
2688 let len = strlen(a:dir_name)
2689 if a:dir_name[len - 1] == '\' || a:dir_name[len - 1] == '/'
2690 let glob_expr = a:dir_name . '*'
2691 else
2692 let glob_expr = a:dir_name . '/*'
2693 endif
2694 let all_files = glob(glob_expr) . "\n"
2695
2696 while all_files != ''
2697 let nl_idx = stridx(all_files, "\n")
2698 let one_file = strpart(all_files, 0, nl_idx)
2699
2700 let all_files = strpart(all_files, nl_idx + 1)
2701 if one_file == ''
2702 continue
2703 endif
2704
2705 " Skip non-directory names
2706 if !isdirectory(one_file)
2707 continue
2708 endif
2709
2710 echon "\r "
2711 echon "\rProcessing files in directory " . fnamemodify(one_file, ':t')
2712 let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat)
2713 endwhile
2714
2715 return fcnt
2716 endfunction
2717
2718 " Tlist_Add_Files_Recursive
2719 " Add files recursively from a directory
2720 function! s:Tlist_Add_Files_Recursive(dir, ...)
2721 let dir_name = fnamemodify(a:dir, ':p')
2722 if !isdirectory(dir_name)
2723 call s:Tlist_Warning_Msg('Error: ' . dir_name . ' is not a directory')
2724 return
2725 endif
2726
2727 if a:0 == 1
2728 " User specified file pattern
2729 let pat = a:1
2730 else
2731 " Default file pattern
2732 let pat = '*'
2733 endif
2734
2735 echon "\r "
2736 echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t')
2737 let fcnt = s:Tlist_Process_Dir(dir_name, pat)
2738
2739 echon "\rAdded " . fcnt . " files to the taglist"
2740 endfunction
2741
2742 " Tlist_Add_Files
2743 " Add the specified list of files to the taglist
2744 function! s:Tlist_Add_Files(...)
2745 let flist = ''
2746 let i = 1
2747
2748 " Get all the files matching the file patterns supplied as argument
2749 while i <= a:0
2750 let flist = flist . glob(a:{i}) . "\n"
2751 let i = i + 1
2752 endwhile
2753
2754 if flist == ''
2755 call s:Tlist_Warning_Msg('Error: No matching files are found')
2756 return
2757 endif
2758
2759 let fcnt = s:Tlist_Process_Filelist(flist)
2760 echon "\rAdded " . fcnt . " files to the taglist"
2761 endfunction
2762
2763 " Tlist_Extract_Tagtype
2764 " Extract the tag type from the tag text
2765 function! s:Tlist_Extract_Tagtype(tag_line)
2766 " The tag type is after the tag prototype field. The prototype field
2767 " ends with the /;"\t string. We add 4 at the end to skip the characters
2768 " in this special string..
2769 let start = strridx(a:tag_line, '/;"' . "\t") + 4
2770 let end = strridx(a:tag_line, 'line:') - 1
2771 let ttype = strpart(a:tag_line, start, end - start)
2772
2773 return ttype
2774 endfunction
2775
2776 " Tlist_Extract_Tag_Scope
2777 " Extract the tag scope from the tag text
2778 function! s:Tlist_Extract_Tag_Scope(tag_line)
2779 let start = strridx(a:tag_line, 'line:')
2780 let end = strridx(a:tag_line, "\t")
2781 if end <= start
2782 return ''
2783 endif
2784
2785 let tag_scope = strpart(a:tag_line, end + 1)
2786 let tag_scope = strpart(tag_scope, stridx(tag_scope, ':') + 1)
2787
2788 return tag_scope
2789 endfunction
2790
2791 " Tlist_Refresh()
2792 " Refresh the taglist
2793 function! s:Tlist_Refresh()
2794 call s:Tlist_Log_Msg('Tlist_Refresh (Skip_Refresh = ' .
2795 \ s:Tlist_Skip_Refresh . ', ' . bufname('%') . ')')
2796 " If we are entering the buffer from one of the taglist functions, then
2797 " no need to refresh the taglist window again.
2798 if s:Tlist_Skip_Refresh
2799 " We still need to update the taglist menu
2800 if g:Tlist_Show_Menu
2801 call s:Tlist_Menu_Update_File(0)
2802 endif
2803 return
2804 endif
2805
2806 " If part of the winmanager plugin and not configured to process
2807 " tags always and not configured to display the tags menu, then return
2808 if (s:tlist_app_name == 'winmanager') && !g:Tlist_Process_File_Always
2809 \ && !g:Tlist_Show_Menu
2810 return
2811 endif
2812
2813 " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
2814 if &buftype != ''
2815 return
2816 endif
2817
2818 let filename = fnamemodify(bufname('%'), ':p')
2819 let ftype = s:Tlist_Get_Buffer_Filetype('%')
2820
2821 " If the file doesn't support tag listing, skip it
2822 if s:Tlist_Skip_File(filename, ftype)
2823 return
2824 endif
2825
2826 let tlist_win = bufwinnr(g:TagList_title)
2827
2828 " If the taglist window is not opened and not configured to process
2829 " tags always and not displaying the tags menu, then return
2830 if tlist_win == -1 && !g:Tlist_Process_File_Always && !g:Tlist_Show_Menu
2831 return
2832 endif
2833
2834 let fidx = s:Tlist_Get_File_Index(filename)
2835 if fidx == -1
2836 " Check whether this file is removed based on user request
2837 " If it is, then don't display the tags for this file
2838 if s:Tlist_User_Removed_File(filename)
2839 return
2840 endif
2841
2842 " If the taglist should not be auto updated, then return
2843 if !g:Tlist_Auto_Update
2844 return
2845 endif
2846 endif
2847
2848 let cur_lnum = line('.')
2849
2850 if fidx == -1
2851 " Update the tags for the file
2852 let fidx = s:Tlist_Process_File(filename, ftype)
2853 else
2854 let mtime = getftime(filename)
2855 if s:tlist_{fidx}_mtime != mtime
2856 " Invalidate the tags listed for this file
2857 let s:tlist_{fidx}_valid = 0
2858
2859 " Update the taglist and the window
2860 call Tlist_Update_File(filename, ftype)
2861
2862 " Store the new file modification time
2863 let s:tlist_{fidx}_mtime = mtime
2864 endif
2865 endif
2866
2867 " Update the taglist window
2868 if tlist_win != -1
2869 " Disable screen updates
2870 let old_lazyredraw = &lazyredraw
2871 set nolazyredraw
2872
2873 " Save the current window number
2874 let save_winnr = winnr()
2875
2876 " Goto the taglist window
2877 call s:Tlist_Window_Goto_Window()
2878
2879 if !g:Tlist_Auto_Highlight_Tag || !g:Tlist_Highlight_Tag_On_BufEnter
2880 " Save the cursor position
2881 let save_line = line('.')
2882 let save_col = col('.')
2883 endif
2884
2885 " Update the taglist window
2886 call s:Tlist_Window_Refresh_File(filename, ftype)
2887
2888 " Open the fold for the file
2889 exe "silent! " . s:tlist_{fidx}_start . "," .
2890 \ s:tlist_{fidx}_end . "foldopen!"
2891
2892 if g:Tlist_Highlight_Tag_On_BufEnter && g:Tlist_Auto_Highlight_Tag
2893 if g:Tlist_Show_One_File && s:tlist_cur_file_idx != fidx
2894 " If displaying tags for only one file in the taglist
2895 " window and about to display the tags for a new file,
2896 " then center the current tag line for the new file
2897 let center_tag_line = 1
2898 else
2899 let center_tag_line = 0
2900 endif
2901
2902 " Highlight the current tag
2903 call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line)
2904 else
2905 " Restore the cursor position
2906 if v:version >= 601
2907 call cursor(save_line, save_col)
2908 else
2909 exe save_line
2910 exe 'normal! ' . save_col . '|'
2911 endif
2912 endif
2913
2914 " Jump back to the original window
2915 if save_winnr != winnr()
2916 call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w')
2917 endif
2918
2919 " Restore screen updates
2920 let &lazyredraw = old_lazyredraw
2921 endif
2922
2923 " Update the taglist menu
2924 if g:Tlist_Show_Menu
2925 call s:Tlist_Menu_Update_File(0)
2926 endif
2927 endfunction
2928
2929 " Tlist_Change_Sort()
2930 " Change the sort order of the tag listing
2931 " caller == 'cmd', command used in the taglist window
2932 " caller == 'menu', taglist menu
2933 " action == 'toggle', toggle sort from name to order and vice versa
2934 " action == 'set', set the sort order to sort_type
2935 function! s:Tlist_Change_Sort(caller, action, sort_type)
2936 call s:Tlist_Log_Msg('Tlist_Change_Sort (caller = ' . a:caller .
2937 \ ', action = ' . a:action . ', sort_type = ' . a:sort_type . ')')
2938 if a:caller == 'cmd'
2939 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
2940 if fidx == -1
2941 return
2942 endif
2943
2944 " Remove the previous highlighting
2945 match none
2946 elseif a:caller == 'menu'
2947 let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
2948 if fidx == -1
2949 return
2950 endif
2951 endif
2952
2953 if a:action == 'toggle'
2954 let sort_type = s:tlist_{fidx}_sort_type
2955
2956 " Toggle the sort order from 'name' to 'order' and vice versa
2957 if sort_type == 'name'
2958 let s:tlist_{fidx}_sort_type = 'order'
2959 else
2960 let s:tlist_{fidx}_sort_type = 'name'
2961 endif
2962 else
2963 let s:tlist_{fidx}_sort_type = a:sort_type
2964 endif
2965
2966 " Invalidate the tags listed for this file
2967 let s:tlist_{fidx}_valid = 0
2968
2969 if a:caller == 'cmd'
2970 " Save the current line for later restoration
2971 let curline = '\V\^' . getline('.') . '\$'
2972
2973 call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
2974 \ s:tlist_{fidx}_filetype)
2975
2976 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
2977
2978 " Go back to the cursor line before the tag list is sorted
2979 call search(curline, 'w')
2980
2981 call s:Tlist_Menu_Update_File(1)
2982 else
2983 call s:Tlist_Menu_Remove_File()
2984
2985 call s:Tlist_Refresh()
2986 endif
2987 endfunction
2988
2989 " Tlist_Update_Current_File()
2990 " Update taglist for the current buffer by regenerating the tag list
2991 " Contributed by WEN Guopeng.
2992 function! s:Tlist_Update_Current_File()
2993 call s:Tlist_Log_Msg('Tlist_Update_Current_File()')
2994 if winnr() == bufwinnr(g:TagList_title)
2995 " In the taglist window. Update the current file
2996 call s:Tlist_Window_Update_File()
2997 else
2998 " Not in the taglist window. Update the current buffer
2999 let filename = fnamemodify(bufname('%'), ':p')
3000 let fidx = s:Tlist_Get_File_Index(filename)
3001 if fidx != -1
3002 let s:tlist_{fidx}_valid = 0
3003 endif
3004 let ft = s:Tlist_Get_Buffer_Filetype('%')
3005 call Tlist_Update_File(filename, ft)
3006 endif
3007 endfunction
3008
3009 " Tlist_Window_Update_File()
3010 " Update the tags displayed in the taglist window
3011 function! s:Tlist_Window_Update_File()
3012 call s:Tlist_Log_Msg('Tlist_Window_Update_File()')
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
3021 " Save the current line for later restoration
3022 let curline = '\V\^' . getline('.') . '\$'
3023
3024 let s:tlist_{fidx}_valid = 0
3025
3026 " Update the taglist window
3027 call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename,
3028 \ s:tlist_{fidx}_filetype)
3029
3030 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!'
3031
3032 " Go back to the tag line before the list is updated
3033 call search(curline, 'w')
3034 endfunction
3035
3036 " Tlist_Window_Get_Tag_Type_By_Linenum()
3037 " Return the tag type index for the specified line in the taglist window
3038 function! s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
3039 let ftype = s:tlist_{a:fidx}_filetype
3040
3041 " Determine to which tag type the current line number belongs to using the
3042 " tag type start line number and the number of tags in a tag type
3043 let i = 1
3044 while i <= s:tlist_{ftype}_count
3045 let ttype = s:tlist_{ftype}_{i}_name
3046 let start_lnum =
3047 \ s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
3048 let end = start_lnum + s:tlist_{a:fidx}_{ttype}_count
3049 if a:lnum >= start_lnum && a:lnum <= end
3050 break
3051 endif
3052 let i = i + 1
3053 endwhile
3054
3055 " Current line doesn't belong to any of the displayed tag types
3056 if i > s:tlist_{ftype}_count
3057 return ''
3058 endif
3059
3060 return ttype
3061 endfunction
3062
3063 " Tlist_Window_Get_Tag_Index()
3064 " Return the tag index for the specified line in the taglist window
3065 function! s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3066 let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(a:fidx, a:lnum)
3067
3068 " Current line doesn't belong to any of the displayed tag types
3069 if ttype == ''
3070 return 0
3071 endif
3072
3073 " Compute the index into the displayed tags for the tag type
3074 let ttype_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset
3075 let tidx = a:lnum - ttype_lnum
3076 if tidx == 0
3077 return 0
3078 endif
3079
3080 " Get the corresponding tag line and return it
3081 return s:tlist_{a:fidx}_{ttype}_{tidx}
3082 endfunction
3083
3084 " Tlist_Window_Highlight_Line
3085 " Highlight the current line
3086 function! s:Tlist_Window_Highlight_Line()
3087 " Clear previously selected name
3088 match none
3089
3090 " Highlight the current line
3091 if g:Tlist_Display_Prototype == 0
3092 let pat = '/\%' . line('.') . 'l\s\+\zs.*/'
3093 else
3094 let pat = '/\%' . line('.') . 'l.*/'
3095 endif
3096
3097 exe 'match TagListTagName ' . pat
3098 endfunction
3099
3100 " Tlist_Window_Open_File
3101 " Open the specified file in either a new window or an existing window
3102 " and place the cursor at the specified tag pattern
3103 function! s:Tlist_Window_Open_File(win_ctrl, filename, tagpat)
3104 call s:Tlist_Log_Msg('Tlist_Window_Open_File (' . a:filename . ',' .
3105 \ a:win_ctrl . ')')
3106 let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh
3107 let s:Tlist_Skip_Refresh = 1
3108
3109 if s:tlist_app_name == "winmanager"
3110 " Let the winmanager edit the file
3111 call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin')
3112 else
3113
3114 if a:win_ctrl == 'newtab'
3115 " Create a new tab
3116 exe 'tabnew ' . escape(a:filename, ' ')
3117 " Open the taglist window in the new tab
3118 call s:Tlist_Window_Open()
3119 endif
3120
3121 if a:win_ctrl == 'checktab'
3122 " Check whether the file is present in any of the tabs.
3123 " If the file is present in the current tab, then use the
3124 " current tab.
3125 if bufwinnr(a:filename) != -1
3126 let file_present_in_tab = 1
3127 let i = tabpagenr()
3128 else
3129 let i = 1
3130 let bnum = bufnr(a:filename)
3131 let file_present_in_tab = 0
3132 while i <= tabpagenr('$')
3133 if index(tabpagebuflist(i), bnum) != -1
3134 let file_present_in_tab = 1
3135 break
3136 endif
3137 let i += 1
3138 endwhile
3139 endif
3140
3141 if file_present_in_tab
3142 " Goto the tab containing the file
3143 exe 'tabnext ' . i
3144 else
3145 " Open a new tab
3146 exe 'tabnew ' . escape(a:filename, ' ')
3147
3148 " Open the taglist window
3149 call s:Tlist_Window_Open()
3150 endif
3151 endif
3152
3153 let winnum = -1
3154 if a:win_ctrl == 'prevwin'
3155 " Open the file in the previous window, if it is usable
3156 let cur_win = winnr()
3157 wincmd p
3158 if &buftype == '' && !&previewwindow
3159 exe "edit " . escape(a:filename, ' ')
3160 let winnum = winnr()
3161 else
3162 " Previous window is not usable
3163 exe cur_win . 'wincmd w'
3164 endif
3165 endif
3166
3167 " Goto the window containing the file. If the window is not there, open a
3168 " new window
3169 if winnum == -1
3170 let winnum = bufwinnr(a:filename)
3171 endif
3172
3173 if winnum == -1
3174 " Locate the previously used window for opening a file
3175 let fwin_num = 0
3176 let first_usable_win = 0
3177
3178 let i = 1
3179 let bnum = winbufnr(i)
3180 while bnum != -1
3181 if getwinvar(i, 'tlist_file_window') == 'yes'
3182 let fwin_num = i
3183 break
3184 endif
3185 if first_usable_win == 0 &&
3186 \ getbufvar(bnum, '&buftype') == '' &&
3187 \ !getwinvar(i, '&previewwindow')
3188 " First non-taglist, non-plugin and non-preview window
3189 let first_usable_win = i
3190 endif
3191 let i = i + 1
3192 let bnum = winbufnr(i)
3193 endwhile
3194
3195 " If a previously used window is not found, then use the first
3196 " non-taglist window
3197 if fwin_num == 0
3198 let fwin_num = first_usable_win
3199 endif
3200
3201 if fwin_num != 0
3202 " Jump to the file window
3203 exe fwin_num . "wincmd w"
3204
3205 " If the user asked to jump to the tag in a new window, then split
3206 " the existing window into two.
3207 if a:win_ctrl == 'newwin'
3208 split
3209 endif
3210 exe "edit " . escape(a:filename, ' ')
3211 else
3212 " Open a new window
3213 if g:Tlist_Use_Horiz_Window
3214 exe 'leftabove split ' . escape(a:filename, ' ')
3215 else
3216 if winbufnr(2) == -1
3217 " Only the taglist window is present
3218 if g:Tlist_Use_Right_Window
3219 exe 'leftabove vertical split ' .
3220 \ escape(a:filename, ' ')
3221 else
3222 exe 'rightbelow vertical split ' .
3223 \ escape(a:filename, ' ')
3224 endif
3225
3226 " Go to the taglist window to change the window size to
3227 " the user configured value
3228 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3229 if g:Tlist_Use_Horiz_Window
3230 exe 'resize ' . g:Tlist_WinHeight
3231 else
3232 exe 'vertical resize ' . g:Tlist_WinWidth
3233 endif
3234 " Go back to the file window
3235 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3236 else
3237 " A plugin or help window is also present
3238 wincmd w
3239 exe 'leftabove split ' . escape(a:filename, ' ')
3240 endif
3241 endif
3242 endif
3243 " Mark the window, so that it can be reused.
3244 call s:Tlist_Window_Mark_File_Window()
3245 else
3246 if v:version >= 700
3247 " If the file is opened in more than one window, then check
3248 " whether the last accessed window has the selected file.
3249 " If it does, then use that window.
3250 let lastwin_bufnum = winbufnr(winnr('#'))
3251 if bufnr(a:filename) == lastwin_bufnum
3252 let winnum = winnr('#')
3253 endif
3254 endif
3255 exe winnum . 'wincmd w'
3256
3257 " If the user asked to jump to the tag in a new window, then split the
3258 " existing window into two.
3259 if a:win_ctrl == 'newwin'
3260 split
3261 endif
3262 endif
3263 endif
3264
3265 " Jump to the tag
3266 if a:tagpat != ''
3267 " Add the current cursor position to the jump list, so that user can
3268 " jump back using the ' and ` marks.
3269 mark '
3270 silent call search(a:tagpat, 'w')
3271
3272 " Bring the line to the middle of the window
3273 normal! z.
3274
3275 " If the line is inside a fold, open the fold
3276 if foldclosed('.') != -1
3277 .foldopen
3278 endif
3279 endif
3280
3281 " If the user selects to preview the tag then jump back to the
3282 " taglist window
3283 if a:win_ctrl == 'preview'
3284 " Go back to the taglist window
3285 let winnum = bufwinnr(g:TagList_title)
3286 exe winnum . 'wincmd w'
3287 else
3288 " If the user has selected to close the taglist window, when a
3289 " tag is selected, close the taglist window
3290 if g:Tlist_Close_On_Select
3291 call s:Tlist_Window_Goto_Window()
3292 close
3293
3294 " Go back to the window displaying the selected file
3295 let wnum = bufwinnr(a:filename)
3296 if wnum != -1 && wnum != winnr()
3297 call s:Tlist_Exe_Cmd_No_Acmds(wnum . 'wincmd w')
3298 endif
3299 endif
3300 endif
3301
3302 let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh
3303 endfunction
3304
3305 " Tlist_Window_Jump_To_Tag()
3306 " Jump to the location of the current tag
3307 " win_ctrl == useopen - Reuse the existing file window
3308 " win_ctrl == newwin - Open a new window
3309 " win_ctrl == preview - Preview the tag
3310 " win_ctrl == prevwin - Open in previous window
3311 " win_ctrl == newtab - Open in new tab
3312 function! s:Tlist_Window_Jump_To_Tag(win_ctrl)
3313 call s:Tlist_Log_Msg('Tlist_Window_Jump_To_Tag(' . a:win_ctrl . ')')
3314 " Do not process comment lines and empty lines
3315 let curline = getline('.')
3316 if curline =~ '^\s*$' || curline[0] == '"'
3317 return
3318 endif
3319
3320 " If inside a closed fold, then use the first line of the fold
3321 " and jump to the file.
3322 let lnum = foldclosed('.')
3323 if lnum == -1
3324 " Jump to the selected tag or file
3325 let lnum = line('.')
3326 else
3327 " Open the closed fold
3328 .foldopen!
3329 endif
3330
3331 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
3332 if fidx == -1
3333 return
3334 endif
3335
3336 " Get the tag output for the current tag
3337 let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3338 if tidx != 0
3339 let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx)
3340
3341 " Highlight the tagline
3342 call s:Tlist_Window_Highlight_Line()
3343 else
3344 " Selected a line which is not a tag name. Just edit the file
3345 let tagpat = ''
3346 endif
3347
3348 call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat)
3349 endfunction
3350
3351 " Tlist_Window_Show_Info()
3352 " Display information about the entry under the cursor
3353 function! s:Tlist_Window_Show_Info()
3354 call s:Tlist_Log_Msg('Tlist_Window_Show_Info()')
3355
3356 " Clear the previously displayed line
3357 echo
3358
3359 " Do not process comment lines and empty lines
3360 let curline = getline('.')
3361 if curline =~ '^\s*$' || curline[0] == '"'
3362 return
3363 endif
3364
3365 " If inside a fold, then don't display the prototype
3366 if foldclosed('.') != -1
3367 return
3368 endif
3369
3370 let lnum = line('.')
3371
3372 " Get the file index
3373 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum)
3374 if fidx == -1
3375 return
3376 endif
3377
3378 if lnum == s:tlist_{fidx}_start
3379 " Cursor is on a file name
3380 let fname = s:tlist_{fidx}_filename
3381 if strlen(fname) > 50
3382 let fname = fnamemodify(fname, ':t')
3383 endif
3384 echo fname . ', Filetype=' . s:tlist_{fidx}_filetype .
3385 \ ', Tag count=' . s:tlist_{fidx}_tag_count
3386 return
3387 endif
3388
3389 " Get the tag output line for the current tag
3390 let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum)
3391 if tidx == 0
3392 " Cursor is on a tag type
3393 let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum)
3394 if ttype == ''
3395 return
3396 endif
3397
3398 let ttype_name = ''
3399
3400 let ftype = s:tlist_{fidx}_filetype
3401 let i = 1
3402 while i <= s:tlist_{ftype}_count
3403 if ttype == s:tlist_{ftype}_{i}_name
3404 let ttype_name = s:tlist_{ftype}_{i}_fullname
3405 break
3406 endif
3407 let i = i + 1
3408 endwhile
3409
3410 echo 'Tag type=' . ttype_name .
3411 \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count
3412 return
3413 endif
3414
3415 " Get the tag search pattern and display it
3416 echo s:Tlist_Get_Tag_Prototype(fidx, tidx)
3417 endfunction
3418
3419 " Tlist_Find_Nearest_Tag_Idx
3420 " Find the tag idx nearest to the supplied line number
3421 " Returns -1, if a tag couldn't be found for the specified line number
3422 function! s:Tlist_Find_Nearest_Tag_Idx(fidx, linenum)
3423 let sort_type = s:tlist_{a:fidx}_sort_type
3424
3425 let left = 1
3426 let right = s:tlist_{a:fidx}_tag_count
3427
3428 if sort_type == 'order'
3429 " Tags sorted by order, use a binary search.
3430 " The idea behind this function is taken from the ctags.vim script (by
3431 " Alexey Marinichev) available at the Vim online website.
3432
3433 " If the current line is the less than the first tag, then no need to
3434 " search
3435 let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1)
3436
3437 if a:linenum < first_lnum
3438 return -1
3439 endif
3440
3441 while left < right
3442 let middle = (right + left + 1) / 2
3443 let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle)
3444
3445 if middle_lnum == a:linenum
3446 let left = middle
3447 break
3448 endif
3449
3450 if middle_lnum > a:linenum
3451 let right = middle - 1
3452 else
3453 let left = middle
3454 endif
3455 endwhile
3456 else
3457 " Tags sorted by name, use a linear search. (contributed by Dave
3458 " Eggum).
3459 " Look for a tag with a line number less than or equal to the supplied
3460 " line number. If multiple tags are found, then use the tag with the
3461 " line number closest to the supplied line number. IOW, use the tag
3462 " with the highest line number.
3463 let closest_lnum = 0
3464 let final_left = 0
3465 while left <= right
3466 let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left)
3467
3468 if lnum < a:linenum && lnum > closest_lnum
3469 let closest_lnum = lnum
3470 let final_left = left
3471 elseif lnum == a:linenum
3472 let closest_lnum = lnum
3473 let final_left = left
3474 break
3475 else
3476 let left = left + 1
3477 endif
3478 endwhile
3479 if closest_lnum == 0
3480 return -1
3481 endif
3482 if left >= right
3483 let left = final_left
3484 endif
3485 endif
3486
3487 return left
3488 endfunction
3489
3490 " Tlist_Window_Highlight_Tag()
3491 " Highlight the current tag
3492 " cntx == 1, Called by the taglist plugin itself
3493 " cntx == 2, Forced by the user through the TlistHighlightTag command
3494 " center = 1, move the tag line to the center of the taglist window
3495 function! s:Tlist_Window_Highlight_Tag(filename, cur_lnum, cntx, center)
3496 " Highlight the current tag only if the user configured the
3497 " taglist plugin to do so or if the user explictly invoked the
3498 " command to highlight the current tag.
3499 if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1
3500 return
3501 endif
3502
3503 if a:filename == ''
3504 return
3505 endif
3506
3507 " Make sure the taglist window is present
3508 let winnum = bufwinnr(g:TagList_title)
3509 if winnum == -1
3510 call s:Tlist_Warning_Msg('Error: Taglist window is not open')
3511 return
3512 endif
3513
3514 let fidx = s:Tlist_Get_File_Index(a:filename)
3515 if fidx == -1
3516 return
3517 endif
3518
3519 " If the file is currently not displayed in the taglist window, then retrn
3520 if !s:tlist_{fidx}_visible
3521 return
3522 endif
3523
3524 " If there are no tags for this file, then no need to proceed further
3525 if s:tlist_{fidx}_tag_count == 0
3526 return
3527 endif
3528
3529 " Ignore all autocommands
3530 let old_ei = &eventignore
3531 set eventignore=all
3532
3533 " Save the original window number
3534 let org_winnr = winnr()
3535
3536 if org_winnr == winnum
3537 let in_taglist_window = 1
3538 else
3539 let in_taglist_window = 0
3540 endif
3541
3542 " Go to the taglist window
3543 if !in_taglist_window
3544 exe winnum . 'wincmd w'
3545 endif
3546
3547 " Clear previously selected name
3548 match none
3549
3550 let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum)
3551 if tidx == -1
3552 " Make sure the current tag line is visible in the taglist window.
3553 " Calling the winline() function makes the line visible. Don't know
3554 " of a better way to achieve this.
3555 let lnum = line('.')
3556
3557 if lnum < s:tlist_{fidx}_start || lnum > s:tlist_{fidx}_end
3558 " Move the cursor to the beginning of the file
3559 exe s:tlist_{fidx}_start
3560 endif
3561
3562 if foldclosed('.') != -1
3563 .foldopen
3564 endif
3565
3566 call winline()
3567
3568 if !in_taglist_window
3569 exe org_winnr . 'wincmd w'
3570 endif
3571
3572 " Restore the autocommands
3573 let &eventignore = old_ei
3574 return
3575 endif
3576
3577 " Extract the tag type
3578 let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx)
3579
3580 " Compute the line number
3581 " Start of file + Start of tag type + offset
3582 let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset +
3583 \ s:tlist_{fidx}_{tidx}_ttype_idx
3584
3585 " Goto the line containing the tag
3586 exe lnum
3587
3588 " Open the fold
3589 if foldclosed('.') != -1
3590 .foldopen
3591 endif
3592
3593 if a:center
3594 " Move the tag line to the center of the taglist window
3595 normal! z.
3596 else
3597 " Make sure the current tag line is visible in the taglist window.
3598 " Calling the winline() function makes the line visible. Don't know
3599 " of a better way to achieve this.
3600 call winline()
3601 endif
3602
3603 " Highlight the tag name
3604 call s:Tlist_Window_Highlight_Line()
3605
3606 " Go back to the original window
3607 if !in_taglist_window
3608 exe org_winnr . 'wincmd w'
3609 endif
3610
3611 " Restore the autocommands
3612 let &eventignore = old_ei
3613 return
3614 endfunction
3615
3616 " Tlist_Get_Tag_Prototype_By_Line
3617 " Get the prototype for the tag on or before the specified line number in the
3618 " current buffer
3619 function! Tlist_Get_Tag_Prototype_By_Line(...)
3620 if a:0 == 0
3621 " Arguments are not supplied. Use the current buffer name
3622 " and line number
3623 let filename = bufname('%')
3624 let linenr = line('.')
3625 elseif a:0 == 2
3626 " Filename and line number are specified
3627 let filename = a:1
3628 let linenr = a:2
3629 if linenr !~ '\d\+'
3630 " Invalid line number
3631 return ""
3632 endif
3633 else
3634 " Sufficient arguments are not supplied
3635 let msg = 'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' .
3636 \ '<line_number>'
3637 call s:Tlist_Warning_Msg(msg)
3638 return ""
3639 endif
3640
3641 " Expand the file to a fully qualified name
3642 let filename = fnamemodify(filename, ':p')
3643 if filename == ''
3644 return ""
3645 endif
3646
3647 let fidx = s:Tlist_Get_File_Index(filename)
3648 if fidx == -1
3649 return ""
3650 endif
3651
3652 " If there are no tags for this file, then no need to proceed further
3653 if s:tlist_{fidx}_tag_count == 0
3654 return ""
3655 endif
3656
3657 " Get the tag text using the line number
3658 let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
3659 if tidx == -1
3660 return ""
3661 endif
3662
3663 return s:Tlist_Get_Tag_Prototype(fidx, tidx)
3664 endfunction
3665
3666 " Tlist_Get_Tagname_By_Line
3667 " Get the tag name on or before the specified line number in the
3668 " current buffer
3669 function! Tlist_Get_Tagname_By_Line(...)
3670 if a:0 == 0
3671 " Arguments are not supplied. Use the current buffer name
3672 " and line number
3673 let filename = bufname('%')
3674 let linenr = line('.')
3675 elseif a:0 == 2
3676 " Filename and line number are specified
3677 let filename = a:1
3678 let linenr = a:2
3679 if linenr !~ '\d\+'
3680 " Invalid line number
3681 return ""
3682 endif
3683 else
3684 " Sufficient arguments are not supplied
3685 let msg = 'Usage: Tlist_Get_Tagname_By_Line <filename> <line_number>'
3686 call s:Tlist_Warning_Msg(msg)
3687 return ""
3688 endif
3689
3690 " Make sure the current file has a name
3691 let filename = fnamemodify(filename, ':p')
3692 if filename == ''
3693 return ""
3694 endif
3695
3696 let fidx = s:Tlist_Get_File_Index(filename)
3697 if fidx == -1
3698 return ""
3699 endif
3700
3701 " If there are no tags for this file, then no need to proceed further
3702 if s:tlist_{fidx}_tag_count == 0
3703 return ""
3704 endif
3705
3706 " Get the tag name using the line number
3707 let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr)
3708 if tidx == -1
3709 return ""
3710 endif
3711
3712 return s:tlist_{fidx}_{tidx}_tag_name
3713 endfunction
3714
3715 " Tlist_Window_Move_To_File
3716 " Move the cursor to the beginning of the current file or the next file
3717 " or the previous file in the taglist window
3718 " dir == -1, move to start of current or previous function
3719 " dir == 1, move to start of next function
3720 function! s:Tlist_Window_Move_To_File(dir)
3721 if foldlevel('.') == 0
3722 " Cursor is on a non-folded line (it is not in any of the files)
3723 " Move it to a folded line
3724 if a:dir == -1
3725 normal! zk
3726 else
3727 " While moving down to the start of the next fold,
3728 " no need to do go to the start of the next file.
3729 normal! zj
3730 return
3731 endif
3732 endif
3733
3734 let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.'))
3735 if fidx == -1
3736 return
3737 endif
3738
3739 let cur_lnum = line('.')
3740
3741 if a:dir == -1
3742 if cur_lnum > s:tlist_{fidx}_start
3743 " Move to the beginning of the current file
3744 exe s:tlist_{fidx}_start
3745 return
3746 endif
3747
3748 if fidx != 0
3749 " Move to the beginning of the previous file
3750 let fidx = fidx - 1
3751 else
3752 " Cursor is at the first file, wrap around to the last file
3753 let fidx = s:tlist_file_count - 1
3754 endif
3755
3756 exe s:tlist_{fidx}_start
3757 return
3758 else
3759 " Move to the beginning of the next file
3760 let fidx = fidx + 1
3761
3762 if fidx >= s:tlist_file_count
3763 " Cursor is at the last file, wrap around to the first file
3764 let fidx = 0
3765 endif
3766
3767 if s:tlist_{fidx}_start != 0
3768 exe s:tlist_{fidx}_start
3769 endif
3770 return
3771 endif
3772 endfunction
3773
3774 " Tlist_Session_Load
3775 " Load a taglist session (information about all the displayed files
3776 " and the tags) from the specified file
3777 function! s:Tlist_Session_Load(...)
3778 if a:0 == 0 || a:1 == ''
3779 call s:Tlist_Warning_Msg('Usage: TlistSessionLoad <filename>')
3780 return
3781 endif
3782
3783 let sessionfile = a:1
3784
3785 if !filereadable(sessionfile)
3786 let msg = 'Taglist: Error - Unable to open file ' . sessionfile
3787 call s:Tlist_Warning_Msg(msg)
3788 return
3789 endif
3790
3791 " Mark the current window as the file window
3792 call s:Tlist_Window_Mark_File_Window()
3793
3794 " Source the session file
3795 exe 'source ' . sessionfile
3796
3797 let new_file_count = g:tlist_file_count
3798 unlet! g:tlist_file_count
3799
3800 let i = 0
3801 while i < new_file_count
3802 let ftype = g:tlist_{i}_filetype
3803 unlet! g:tlist_{i}_filetype
3804
3805 if !exists('s:tlist_' . ftype . '_count')
3806 if s:Tlist_FileType_Init(ftype) == 0
3807 let i = i + 1
3808 continue
3809 endif
3810 endif
3811
3812 let fname = g:tlist_{i}_filename
3813 unlet! g:tlist_{i}_filename
3814
3815 let fidx = s:Tlist_Get_File_Index(fname)
3816 if fidx != -1
3817 let s:tlist_{fidx}_visible = 0
3818 let i = i + 1
3819 continue
3820 else
3821 " As we are loading the tags from the session file, if this
3822 " file was previously deleted by the user, now we need to
3823 " add it back. So remove the file from the deleted list.
3824 call s:Tlist_Update_Remove_List(fname, 0)
3825 endif
3826
3827 let fidx = s:Tlist_Init_File(fname, ftype)
3828
3829 let s:tlist_{fidx}_filename = fname
3830
3831 let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type
3832 unlet! g:tlist_{i}_sort_type
3833
3834 let s:tlist_{fidx}_filetype = ftype
3835 let s:tlist_{fidx}_mtime = getftime(fname)
3836
3837 let s:tlist_{fidx}_start = 0
3838 let s:tlist_{fidx}_end = 0
3839
3840 let s:tlist_{fidx}_valid = 1
3841
3842 let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count
3843 unlet! g:tlist_{i}_tag_count
3844
3845 let j = 1
3846 while j <= s:tlist_{fidx}_tag_count
3847 let s:tlist_{fidx}_{j}_tag = g:tlist_{i}_{j}_tag
3848 let s:tlist_{fidx}_{j}_tag_name = g:tlist_{i}_{j}_tag_name
3849 let s:tlist_{fidx}_{j}_ttype_idx = g:tlist_{i}_{j}_ttype_idx
3850 unlet! g:tlist_{i}_{j}_tag
3851 unlet! g:tlist_{i}_{j}_tag_name
3852 unlet! g:tlist_{i}_{j}_ttype_idx
3853 let j = j + 1
3854 endwhile
3855
3856 let j = 1
3857 while j <= s:tlist_{ftype}_count
3858 let ttype = s:tlist_{ftype}_{j}_name
3859
3860 if exists('g:tlist_' . i . '_' . ttype)
3861 let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype}
3862 unlet! g:tlist_{i}_{ttype}
3863 let s:tlist_{fidx}_{ttype}_offset = 0
3864 let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count
3865 unlet! g:tlist_{i}_{ttype}_count
3866
3867 let k = 1
3868 while k <= s:tlist_{fidx}_{ttype}_count
3869 let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k}
3870 unlet! g:tlist_{i}_{ttype}_{k}
3871 let k = k + 1
3872 endwhile
3873 else
3874 let s:tlist_{fidx}_{ttype} = ''
3875 let s:tlist_{fidx}_{ttype}_offset = 0
3876 let s:tlist_{fidx}_{ttype}_count = 0
3877 endif
3878
3879 let j = j + 1
3880 endwhile
3881
3882 let i = i + 1
3883 endwhile
3884
3885 " If the taglist window is open, then update it
3886 let winnum = bufwinnr(g:TagList_title)
3887 if winnum != -1
3888 let save_winnr = winnr()
3889
3890 " Goto the taglist window
3891 call s:Tlist_Window_Goto_Window()
3892
3893 " Refresh the taglist window
3894 call s:Tlist_Window_Refresh()
3895
3896 " Go back to the original window
3897 if save_winnr != winnr()
3898 call s:Tlist_Exe_Cmd_No_Acmds('wincmd p')
3899 endif
3900 endif
3901 endfunction
3902
3903 " Tlist_Session_Save
3904 " Save a taglist session (information about all the displayed files
3905 " and the tags) into the specified file
3906 function! s:Tlist_Session_Save(...)
3907 if a:0 == 0 || a:1 == ''
3908 call s:Tlist_Warning_Msg('Usage: TlistSessionSave <filename>')
3909 return
3910 endif
3911
3912 let sessionfile = a:1
3913
3914 if s:tlist_file_count == 0
3915 " There is nothing to save
3916 call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.')
3917 return
3918 endif
3919
3920 if filereadable(sessionfile)
3921 let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?')
3922 if ans !=? 'y'
3923 return
3924 endif
3925
3926 echo "\n"
3927 endif
3928
3929 let old_verbose = &verbose
3930 set verbose&vim
3931
3932 exe 'redir! > ' . sessionfile
3933
3934 silent! echo '" Taglist session file. This file is auto-generated.'
3935 silent! echo '" File information'
3936 silent! echo 'let tlist_file_count = ' . s:tlist_file_count
3937
3938 let i = 0
3939
3940 while i < s:tlist_file_count
3941 " Store information about the file
3942 silent! echo 'let tlist_' . i . "_filename = '" .
3943 \ s:tlist_{i}_filename . "'"
3944 silent! echo 'let tlist_' . i . '_sort_type = "' .
3945 \ s:tlist_{i}_sort_type . '"'
3946 silent! echo 'let tlist_' . i . '_filetype = "' .
3947 \ s:tlist_{i}_filetype . '"'
3948 silent! echo 'let tlist_' . i . '_tag_count = ' .
3949 \ s:tlist_{i}_tag_count
3950 " Store information about all the tags
3951 let j = 1
3952 while j <= s:tlist_{i}_tag_count
3953 let txt = escape(s:tlist_{i}_{j}_tag, '"\\')
3954 silent! echo 'let tlist_' . i . '_' . j . '_tag = "' . txt . '"'
3955 silent! echo 'let tlist_' . i . '_' . j . '_tag_name = "' .
3956 \ s:tlist_{i}_{j}_tag_name . '"'
3957 silent! echo 'let tlist_' . i . '_' . j . '_ttype_idx' . ' = ' .
3958 \ s:tlist_{i}_{j}_ttype_idx
3959 let j = j + 1
3960 endwhile
3961
3962 " Store information about all the tags grouped by their type
3963 let ftype = s:tlist_{i}_filetype
3964 let j = 1
3965 while j <= s:tlist_{ftype}_count
3966 let ttype = s:tlist_{ftype}_{j}_name
3967 if s:tlist_{i}_{ttype}_count != 0
3968 let txt = escape(s:tlist_{i}_{ttype}, '"\')
3969 let txt = substitute(txt, "\n", "\\\\n", 'g')
3970 silent! echo 'let tlist_' . i . '_' . ttype . ' = "' .
3971 \ txt . '"'
3972 silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' .
3973 \ s:tlist_{i}_{ttype}_count
3974 let k = 1
3975 while k <= s:tlist_{i}_{ttype}_count
3976 silent! echo 'let tlist_' . i . '_' . ttype . '_' . k .
3977 \ ' = ' . s:tlist_{i}_{ttype}_{k}
3978 let k = k + 1
3979 endwhile
3980 endif
3981 let j = j + 1
3982 endwhile
3983
3984 silent! echo
3985
3986 let i = i + 1
3987 endwhile
3988
3989 redir END
3990
3991 let &verbose = old_verbose
3992 endfunction
3993
3994 " Tlist_Buffer_Removed
3995 " A buffer is removed from the Vim buffer list. Remove the tags defined
3996 " for that file
3997 function! s:Tlist_Buffer_Removed(filename)
3998 call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename . ')')
3999
4000 " Make sure a valid filename is supplied
4001 if a:filename == ''
4002 return
4003 endif
4004
4005 " Get tag list index of the specified file
4006 let fidx = s:Tlist_Get_File_Index(a:filename)
4007 if fidx == -1
4008 " File not present in the taglist
4009 return
4010 endif
4011
4012 " Remove the file from the list
4013 call s:Tlist_Remove_File(fidx, 0)
4014 endfunction
4015
4016 " When a buffer is deleted, remove the file from the taglist
4017 autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand('<afile>:p'))
4018
4019 " Tlist_Window_Open_File_Fold
4020 " Open the fold for the specified file and close the fold for all the
4021 " other files
4022 function! s:Tlist_Window_Open_File_Fold(acmd_bufnr)
4023 call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')')
4024
4025 " Make sure the taglist window is present
4026 let winnum = bufwinnr(g:TagList_title)
4027 if winnum == -1
4028 call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open')
4029 return
4030 endif
4031
4032 " Save the original window number
4033 let org_winnr = winnr()
4034 if org_winnr == winnum
4035 let in_taglist_window = 1
4036 else
4037 let in_taglist_window = 0
4038 endif
4039
4040 if in_taglist_window
4041 " When entering the taglist window, no need to update the folds
4042 return
4043 endif
4044
4045 " Go to the taglist window
4046 if !in_taglist_window
4047 call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w')
4048 endif
4049
4050 " Close all the folds
4051 silent! %foldclose
4052
4053 " Get tag list index of the specified file
4054 let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p')
4055 if filereadable(fname)
4056 let fidx = s:Tlist_Get_File_Index(fname)
4057 if fidx != -1
4058 " Open the fold for the file
4059 exe "silent! " . s:tlist_{fidx}_start . "," .
4060 \ s:tlist_{fidx}_end . "foldopen"
4061 endif
4062 endif
4063
4064 " Go back to the original window
4065 if !in_taglist_window
4066 call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w')
4067 endif
4068 endfunction
4069
4070 " Tlist_Window_Check_Auto_Open
4071 " Open the taglist window automatically on Vim startup.
4072 " Open the window only when files present in any of the Vim windows support
4073 " tags.
4074 function! s:Tlist_Window_Check_Auto_Open()
4075 let open_window = 0
4076
4077 let i = 1
4078 let buf_num = winbufnr(i)
4079 while buf_num != -1
4080 let filename = fnamemodify(bufname(buf_num), ':p')
4081 let ft = s:Tlist_Get_Buffer_Filetype(buf_num)
4082 if !s:Tlist_Skip_File(filename, ft)
4083 let open_window = 1
4084 break
4085 endif
4086 let i = i + 1
4087 let buf_num = winbufnr(i)
4088 endwhile
4089
4090 if open_window
4091 call s:Tlist_Window_Toggle()
4092 endif
4093 endfunction
4094
4095 " Tlist_Refresh_Folds
4096 " Remove and create the folds for all the files displayed in the taglist
4097 " window. Used after entering a tab. If this is not done, then the folds
4098 " are not properly created for taglist windows displayed in multiple tabs.
4099 function! s:Tlist_Refresh_Folds()
4100 let winnum = bufwinnr(g:TagList_title)
4101 if winnum == -1
4102 return
4103 endif
4104
4105 let save_wnum = winnr()
4106 exe winnum . 'wincmd w'
4107
4108 " First remove all the existing folds
4109 normal! zE
4110
4111 " Create the folds for each in the tag list
4112 let fidx = 0
4113 while fidx < s:tlist_file_count
4114 let ftype = s:tlist_{fidx}_filetype
4115
4116 " Create the folds for each tag type in a file
4117 let j = 1
4118 while j <= s:tlist_{ftype}_count
4119 let ttype = s:tlist_{ftype}_{j}_name
4120 if s:tlist_{fidx}_{ttype}_count
4121 let s = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset
4122 let e = s + s:tlist_{fidx}_{ttype}_count
4123 exe s . ',' . e . 'fold'
4124 endif
4125 let j = j + 1
4126 endwhile
4127
4128 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold'
4129 exe 'silent! ' . s:tlist_{fidx}_start . ',' .
4130 \ s:tlist_{fidx}_end . 'foldopen!'
4131 let fidx = fidx + 1
4132 endwhile
4133
4134 exe save_wnum . 'wincmd w'
4135 endfunction
4136
4137 function! s:Tlist_Menu_Add_Base_Menu()
4138 call s:Tlist_Log_Msg('Adding the base menu')
4139
4140 " Add the menu
4141 anoremenu <silent> T&ags.Refresh\ menu :call <SID>Tlist_Menu_Refresh()<CR>
4142 anoremenu <silent> T&ags.Sort\ menu\ by.Name
4143 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
4144 anoremenu <silent> T&ags.Sort\ menu\ by.Order
4145 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
4146 anoremenu T&ags.-SEP1- :
4147
4148 if &mousemodel =~ 'popup'
4149 anoremenu <silent> PopUp.T&ags.Refresh\ menu
4150 \ :call <SID>Tlist_Menu_Refresh()<CR>
4151 anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Name
4152 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
4153 anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Order
4154 \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
4155 anoremenu PopUp.T&ags.-SEP1- :
4156 endif
4157 endfunction
4158
4159 let s:menu_char_prefix =
4160 \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
4161
4162 " Tlist_Menu_Get_Tag_Type_Cmd
4163 " Get the menu command for the specified tag type
4164 " fidx - File type index
4165 " ftype - File Type
4166 " add_ttype_name - To add or not to add the tag type name to the menu entries
4167 " ttype_idx - Tag type index
4168 function! s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, ttype_idx)
4169 " Curly brace variable name optimization
4170 let ftype_ttype_idx = a:ftype . '_' . a:ttype_idx
4171
4172 let ttype = s:tlist_{ftype_ttype_idx}_name
4173 if a:add_ttype_name
4174 " If the tag type name contains space characters, escape it. This
4175 " will be used to create the menu entries.
4176 let ttype_fullname = escape(s:tlist_{ftype_ttype_idx}_fullname, ' ')
4177 endif
4178
4179 " Curly brace variable name optimization
4180 let fidx_ttype = a:fidx . '_' . ttype
4181
4182 " Number of tag entries for this tag type
4183 let tcnt = s:tlist_{fidx_ttype}_count
4184 if tcnt == 0 " No entries for this tag type
4185 return ''
4186 endif
4187
4188 let mcmd = ''
4189
4190 " Create the menu items for the tags.
4191 " Depending on the number of tags of this type, split the menu into
4192 " multiple sub-menus, if needed.
4193 if tcnt > g:Tlist_Max_Submenu_Items
4194 let j = 1
4195 while j <= tcnt
4196 let final_index = j + g:Tlist_Max_Submenu_Items - 1
4197 if final_index > tcnt
4198 let final_index = tcnt
4199 endif
4200
4201 " Extract the first and last tag name and form the
4202 " sub-menu name
4203 let tidx = s:tlist_{fidx_ttype}_{j}
4204 let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name
4205
4206 let tidx = s:tlist_{fidx_ttype}_{final_index}
4207 let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name
4208
4209 " Truncate the names, if they are greater than the
4210 " max length
4211 let first_tag = strpart(first_tag, 0, g:Tlist_Max_Tag_Length)
4212 let last_tag = strpart(last_tag, 0, g:Tlist_Max_Tag_Length)
4213
4214 " Form the menu command prefix
4215 let m_prefix = 'anoremenu <silent> T\&ags.'
4216 if a:add_ttype_name
4217 let m_prefix = m_prefix . ttype_fullname . '.'
4218 endif
4219 let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.'
4220
4221 " Character prefix used to number the menu items (hotkey)
4222 let m_prefix_idx = 0
4223
4224 while j <= final_index
4225 let tidx = s:tlist_{fidx_ttype}_{j}
4226
4227 let tname = s:tlist_{a:fidx}_{tidx}_tag_name
4228
4229 let mcmd = mcmd . m_prefix . '\&' .
4230 \ s:menu_char_prefix[m_prefix_idx] . '\.' .
4231 \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' .
4232 \ tidx . ')<CR>|'
4233
4234 let m_prefix_idx = m_prefix_idx + 1
4235 let j = j + 1
4236 endwhile
4237 endwhile
4238 else
4239 " Character prefix used to number the menu items (hotkey)
4240 let m_prefix_idx = 0
4241
4242 let m_prefix = 'anoremenu <silent> T\&ags.'
4243 if a:add_ttype_name
4244 let m_prefix = m_prefix . ttype_fullname . '.'
4245 endif
4246 let j = 1
4247 while j <= tcnt
4248 let tidx = s:tlist_{fidx_ttype}_{j}
4249
4250 let tname = s:tlist_{a:fidx}_{tidx}_tag_name
4251
4252 let mcmd = mcmd . m_prefix . '\&' .
4253 \ s:menu_char_prefix[m_prefix_idx] . '\.' .
4254 \ tname . ' :call <SID>Tlist_Menu_Jump_To_Tag(' . tidx
4255 \ . ')<CR>|'
4256
4257 let m_prefix_idx = m_prefix_idx + 1
4258 let j = j + 1
4259 endwhile
4260 endif
4261
4262 return mcmd
4263 endfunction
4264
4265 " Update the taglist menu with the tags for the specified file
4266 function! s:Tlist_Menu_File_Refresh(fidx)
4267 call s:Tlist_Log_Msg('Refreshing the tag menu for ' . s:tlist_{a:fidx}_filename)
4268 " The 'B' flag is needed in the 'cpoptions' option
4269 let old_cpoptions = &cpoptions
4270 set cpoptions&vim
4271
4272 exe s:tlist_{a:fidx}_menu_cmd
4273
4274 " Update the popup menu (if enabled)
4275 if &mousemodel =~ 'popup'
4276 let cmd = substitute(s:tlist_{a:fidx}_menu_cmd, ' T\\&ags\.',
4277 \ ' PopUp.T\\\&ags.', "g")
4278 exe cmd
4279 endif
4280
4281 " The taglist menu is not empty now
4282 let s:tlist_menu_empty = 0
4283
4284 " Restore the 'cpoptions' settings
4285 let &cpoptions = old_cpoptions
4286 endfunction
4287
4288 " Tlist_Menu_Update_File
4289 " Add the taglist menu
4290 function! s:Tlist_Menu_Update_File(clear_menu)
4291 if !has('gui_running')
4292 " Not running in GUI mode
4293 return
4294 endif
4295
4296 call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu)
4297
4298 " Remove the tags menu
4299 if a:clear_menu
4300 call s:Tlist_Menu_Remove_File()
4301
4302 endif
4303
4304 " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help
4305 if &buftype != ''
4306 return
4307 endif
4308
4309 let filename = fnamemodify(bufname('%'), ':p')
4310 let ftype = s:Tlist_Get_Buffer_Filetype('%')
4311
4312 " If the file doesn't support tag listing, skip it
4313 if s:Tlist_Skip_File(filename, ftype)
4314 return
4315 endif
4316
4317 let fidx = s:Tlist_Get_File_Index(filename)
4318 if fidx == -1 || !s:tlist_{fidx}_valid
4319 " Check whether this file is removed based on user request
4320 " If it is, then don't display the tags for this file
4321 if s:Tlist_User_Removed_File(filename)
4322 return
4323 endif
4324
4325 " Process the tags for the file
4326 let fidx = s:Tlist_Process_File(filename, ftype)
4327 if fidx == -1
4328 return
4329 endif
4330 endif
4331
4332 let fname = escape(fnamemodify(bufname('%'), ':t'), '.')
4333 if fname != ''
4334 exe 'anoremenu T&ags.' . fname . ' <Nop>'
4335 anoremenu T&ags.-SEP2- :
4336 endif
4337
4338 if !s:tlist_{fidx}_tag_count
4339 return
4340 endif
4341
4342 if s:tlist_{fidx}_menu_cmd != ''
4343 " Update the menu with the cached command
4344 call s:Tlist_Menu_File_Refresh(fidx)
4345
4346 return
4347 endif
4348
4349 " We are going to add entries to the tags menu, so the menu won't be
4350 " empty
4351 let s:tlist_menu_empty = 0
4352
4353 let cmd = ''
4354
4355 " Determine whether the tag type name needs to be added to the menu
4356 " If more than one tag type is present in the taglisting for a file,
4357 " then the tag type name needs to be present
4358 let add_ttype_name = -1
4359 let i = 1
4360 while i <= s:tlist_{ftype}_count && add_ttype_name < 1
4361 let ttype = s:tlist_{ftype}_{i}_name
4362 if s:tlist_{fidx}_{ttype}_count
4363 let add_ttype_name = add_ttype_name + 1
4364 endif
4365 let i = i + 1
4366 endwhile
4367
4368 " Process the tags by the tag type and get the menu command
4369 let i = 1
4370 while i <= s:tlist_{ftype}_count
4371 let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i)
4372 if mcmd != ''
4373 let cmd = cmd . mcmd
4374 endif
4375
4376 let i = i + 1
4377 endwhile
4378
4379 " Cache the menu command for reuse
4380 let s:tlist_{fidx}_menu_cmd = cmd
4381
4382 " Update the menu
4383 call s:Tlist_Menu_File_Refresh(fidx)
4384 endfunction
4385
4386 " Tlist_Menu_Remove_File
4387 " Remove the tags displayed in the tags menu
4388 function! s:Tlist_Menu_Remove_File()
4389 if !has('gui_running') || s:tlist_menu_empty
4390 return
4391 endif
4392
4393 call s:Tlist_Log_Msg('Removing the tags menu for a file')
4394
4395 " Cleanup the Tags menu
4396 silent! unmenu T&ags
4397 if &mousemodel =~ 'popup'
4398 silent! unmenu PopUp.T&ags
4399 endif
4400
4401 " Add a dummy menu item to retain teared off menu
4402 noremenu T&ags.Dummy l
4403
4404 silent! unmenu! T&ags
4405 if &mousemodel =~ 'popup'
4406 silent! unmenu! PopUp.T&ags
4407 endif
4408
4409 call s:Tlist_Menu_Add_Base_Menu()
4410
4411 " Remove the dummy menu item
4412 unmenu T&ags.Dummy
4413
4414 let s:tlist_menu_empty = 1
4415 endfunction
4416
4417 " Tlist_Menu_Refresh
4418 " Refresh the taglist menu
4419 function! s:Tlist_Menu_Refresh()
4420 call s:Tlist_Log_Msg('Refreshing the tags menu')
4421 let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
4422 if fidx != -1
4423 " Invalidate the cached menu command
4424 let s:tlist_{fidx}_menu_cmd = ''
4425 endif
4426
4427 " Update the taglist, menu and window
4428 call s:Tlist_Update_Current_File()
4429 endfunction
4430
4431 " Tlist_Menu_Jump_To_Tag
4432 " Jump to the selected tag
4433 function! s:Tlist_Menu_Jump_To_Tag(tidx)
4434 let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p'))
4435 if fidx == -1
4436 return
4437 endif
4438
4439 let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx)
4440 if tagpat == ''
4441 return
4442 endif
4443
4444 " Add the current cursor position to the jump list, so that user can
4445 " jump back using the ' and ` marks.
4446 mark '
4447
4448 silent call search(tagpat, 'w')
4449
4450 " Bring the line to the middle of the window
4451 normal! z.
4452
4453 " If the line is inside a fold, open the fold
4454 if foldclosed('.') != -1
4455 .foldopen
4456 endif
4457 endfunction
4458
4459 " Tlist_Menu_Init
4460 " Initialize the taglist menu
4461 function! s:Tlist_Menu_Init()
4462 call s:Tlist_Menu_Add_Base_Menu()
4463
4464 " Automatically add the tags defined in the current file to the menu
4465 augroup TagListMenuCmds
4466 autocmd!
4467
4468 if !g:Tlist_Process_File_Always
4469 autocmd BufEnter * call s:Tlist_Refresh()
4470 endif
4471 autocmd BufLeave * call s:Tlist_Menu_Remove_File()
4472 augroup end
4473
4474 call s:Tlist_Menu_Update_File(0)
4475 endfunction
4476
4477 " Tlist_Vim_Session_Load
4478 " Initialize the taglist window/buffer, which is created when loading
4479 " a Vim session file.
4480 function! s:Tlist_Vim_Session_Load()
4481 call s:Tlist_Log_Msg('Tlist_Vim_Session_Load')
4482
4483 " Initialize the taglist window
4484 call s:Tlist_Window_Init()
4485
4486 " Refresh the taglist window
4487 call s:Tlist_Window_Refresh()
4488 endfunction
4489
4490 " Tlist_Set_App
4491 " Set the name of the external plugin/application to which taglist
4492 " belongs.
4493 " Taglist plugin is part of another plugin like cream or winmanager.
4494 function! Tlist_Set_App(name)
4495 if a:name == ""
4496 return
4497 endif
4498
4499 let s:tlist_app_name = a:name
4500 endfunction
4501
4502 " Winmanager integration
4503
4504 " Initialization required for integration with winmanager
4505 function! TagList_Start()
4506 " If current buffer is not taglist buffer, then don't proceed
4507 if bufname('%') != '__Tag_List__'
4508 return
4509 endif
4510
4511 call Tlist_Set_App('winmanager')
4512
4513 " Get the current filename from the winmanager plugin
4514 let bufnum = WinManagerGetLastEditedFile()
4515 if bufnum != -1
4516 let filename = fnamemodify(bufname(bufnum), ':p')
4517 let ftype = s:Tlist_Get_Buffer_Filetype(bufnum)
4518 endif
4519
4520 " Initialize the taglist window, if it is not already initialized
4521 if !exists('s:tlist_window_initialized') || !s:tlist_window_initialized
4522 call s:Tlist_Window_Init()
4523 call s:Tlist_Window_Refresh()
4524 let s:tlist_window_initialized = 1
4525 endif
4526
4527 " Update the taglist window
4528 if bufnum != -1
4529 if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update
4530 call s:Tlist_Window_Refresh_File(filename, ftype)
4531 endif
4532 endif
4533 endfunction
4534
4535 function! TagList_IsValid()
4536 return 0
4537 endfunction
4538
4539 function! TagList_WrapUp()
4540 return 0
4541 endfunction
4542
4543 " restore 'cpo'
4544 let &cpo = s:cpo_save
4545 unlet s:cpo_save
4546