1 2"********************************************************************* 3" Note: Cream adds one adjustment (marked with "+++ CREAM" below). 4"********************************************************************* 5 6" File: taglist.vim 7" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) 8" Version: 3.3 9" Last Modified: May 26, 2004 10" 11" The "Tag List" plugin is a source code browser plugin for Vim and 12" provides an overview of the structure of source code files and allows 13" you to efficiently browse through source code files for different 14" programming languages. You can visit the taglist plugin home page for 15" more information: 16" 17" http://www.geocities.com/yegappan/taglist 18" 19" You can subscribe to the taglist mailing list to post your questions 20" or suggestions for improvement or to report bugs. Visit the following 21" page for subscribing to the mailing list: 22" 23" http://groups.yahoo.com/group/taglist/ 24" 25" For more information about using this plugin, after installing the 26" taglist plugin, use the ":help taglist" command. 27" 28" Installation 29" ------------ 30" 1. Download the taglist.zip file and unzip the files to the $HOME/.vim 31" or the $HOME/vimfiles or the $VIM/vimfiles directory. This should 32" unzip the following two files (the directory structure should be 33" preserved): 34" 35" plugin/taglist.vim - main taglist plugin file 36" doc/taglist.txt - documentation (help) file 37" 38" Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath' 39" Vim help pages for more details about installing Vim plugins. 40" 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or 41" $VIM/doc/vimfiles directory, start Vim and run the ":helptags ." 42" command to process the taglist help file. 43" 3. Set the Tlist_Ctags_Cmd variable to point to the location of the 44" exuberant ctags utility (not to the directory) in the .vimrc file. 45" 4. If you are running a terminal/console version of Vim and the 46" terminal doesn't support changing the window width then set the 47" 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file. 48" 5. Restart Vim. 49" 6. You can now use the ":Tlist" command to open/close the taglist 50" window. You can use the ":help taglist" command to get more 51" information about using the taglist plugin. 52" 53" ****************** Do not modify after this line ************************ 54if exists('loaded_taglist') || &cp 55 finish 56endif 57let loaded_taglist=1 58 59" Location of the exuberant ctags tool 60if !exists('Tlist_Ctags_Cmd') 61 if executable('exuberant-ctags') 62 let Tlist_Ctags_Cmd = 'exuberant-ctags' 63 elseif executable('ctags') 64 let Tlist_Ctags_Cmd = 'ctags' 65 elseif executable('tags') 66 let Tlist_Ctags_Cmd = 'tags' 67 else 68 "+++ CREAM: 69 "echomsg 'Taglist: Exuberant ctags not found in PATH. ' . 70 " \ 'Plugin is not loaded.' 71 "+++ 72 finish 73 endif 74endif 75 76" Tag listing sort type - 'name' or 'order' 77if !exists('Tlist_Sort_Type') 78 let Tlist_Sort_Type = 'order' 79endif 80 81" Tag listing window split (horizontal/vertical) control 82if !exists('Tlist_Use_Horiz_Window') 83 let Tlist_Use_Horiz_Window = 0 84endif 85 86" Open the vertically split taglist window on the left or on the right side. 87" This setting is relevant only if Tlist_Use_Horiz_Window is set to zero (i.e. 88" only for vertically split windows) 89if !exists('Tlist_Use_Right_Window') 90 let Tlist_Use_Right_Window = 0 91endif 92 93" Increase Vim window width to display vertically split taglist window. For 94" MS-Windows version of Vim running in a MS-DOS window, this must be set to 0 95" otherwise the system may hang due to a Vim limitation. 96if !exists('Tlist_Inc_Winwidth') 97 if (has('win16') || has('win95')) && !has('gui_running') 98 let Tlist_Inc_Winwidth = 0 99 else 100 let Tlist_Inc_Winwidth = 1 101 endif 102endif 103 104" Vertically split taglist window width setting 105if !exists('Tlist_WinWidth') 106 let Tlist_WinWidth = 30 107endif 108 109" Horizontally split taglist window height setting 110if !exists('Tlist_WinHeight') 111 let Tlist_WinHeight = 10 112endif 113 114" Automatically open the taglist window on Vim startup 115if !exists('Tlist_Auto_Open') 116 let Tlist_Auto_Open = 0 117endif 118 119" Display tag prototypes or tag names in the taglist window 120if !exists('Tlist_Display_Prototype') 121 let Tlist_Display_Prototype = 0 122endif 123 124" Display tag scopes in the taglist window 125if !exists('Tlist_Display_Tag_Scope') 126 let Tlist_Display_Tag_Scope = 1 127endif 128 129" Use single left mouse click to jump to a tag. By default this is disabled. 130" Only double click using the mouse will be processed. 131if !exists('Tlist_Use_SingleClick') 132 let Tlist_Use_SingleClick = 0 133endif 134 135" Control whether additional help is displayed as part of the taglist or not. 136" Also, controls whether empty lines are used to separate the tag tree. 137if !exists('Tlist_Compact_Format') 138 let Tlist_Compact_Format = 0 139endif 140 141" Exit Vim if only the taglist window is currently open. By default, this is 142" set to zero. 143if !exists('Tlist_Exit_OnlyWindow') 144 let Tlist_Exit_OnlyWindow = 0 145endif 146 147" Automatically close the folds for the non-active files in the taglist window 148if !exists('Tlist_File_Fold_Auto_Close') 149 let Tlist_File_Fold_Auto_Close = 0 150endif 151 152" Automatically highlight the current tag 153if !exists('Tlist_Auto_Highlight_Tag') 154 let Tlist_Auto_Highlight_Tag = 1 155endif 156 157" Process files even when the taglist window is not open 158if !exists('Tlist_Process_File_Always') 159 let Tlist_Process_File_Always = 0 160endif 161 162" Enable fold column to display the folding for the tag tree 163if !exists('Tlist_Enable_Fold_Column') 164 let Tlist_Enable_Fold_Column = 1 165endif 166 167"------------------- end of user configurable options -------------------- 168 169" Initialize the taglist plugin local variables for the supported file types 170" and tag types 171 172" assembly language 173let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type' 174 175" aspperl language 176let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable' 177 178" aspvbs language 179let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable' 180 181" awk language 182let s:tlist_def_awk_settings = 'awk;f:function' 183 184" beta language 185let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern' 186 187" c language 188let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' . 189 \ 'v:variable;f:function' 190 191" c++ language 192let s:tlist_def_cpp_settings = 'c++;v:variable;d:macro;t:typedef;c:class;' . 193 \ 'n:namespace;g:enum;s:struct;u:union;f:function' 194 195" c# language 196let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' . 197 \ 'E:event;g:enum;s:struct;i:interface;' . 198 \ 'p:properties;m:method' 199 200" cobol language 201let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' . 202 \ 'P:program;s:section' 203 204" eiffel language 205let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature' 206 207" erlang language 208let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function' 209 210" expect (same as tcl) language 211let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure' 212 213" fortran language 214let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' . 215 \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' . 216 \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine' 217 218" HTML language 219let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function' 220 221" java language 222let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' . 223 \ 'f:field;m:method' 224 225" javascript language 226let s:tlist_def_javascript_settings = 'javascript;f:function' 227 228" lisp language 229let s:tlist_def_lisp_settings = 'lisp;f:function' 230 231" lua language 232let s:tlist_def_lua_settings = 'lua;f:function' 233 234" makefiles 235let s:tlist_def_make_settings = 'make;m:macro' 236 237" pascal language 238let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure' 239 240" perl language 241let s:tlist_def_perl_settings = 'perl;p:package;s:subroutine' 242 243" php language 244let s:tlist_def_php_settings = 'php;c:class;f:function' 245 246" python language 247let s:tlist_def_python_settings = 'python;c:class;m:member;f:function' 248 249" rexx language 250let s:tlist_def_rexx_settings = 'rexx;s:subroutine' 251 252" ruby language 253let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' . 254 \ 'm:singleton method' 255 256" scheme language 257let s:tlist_def_scheme_settings = 'scheme;s:set;f:function' 258 259" shell language 260let s:tlist_def_sh_settings = 'sh;f:function' 261 262" C shell language 263let s:tlist_def_csh_settings = 'sh;f:function' 264 265" Z shell language 266let s:tlist_def_zsh_settings = 'sh;f:function' 267 268" slang language 269let s:tlist_def_slang_settings = 'slang;n:namespace;f:function' 270 271" sml language 272let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' . 273 \ 'r:structure;t:type;v:value;f:function' 274 275" sql language 276let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' . 277 \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure' 278 279" tcl language 280let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;p:procedure' 281 282" vera language 283let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' . 284 \ 'f:function;g:enum;m:member;p:program;' . 285 \ 'P:prototype;t:task;T:typedef;v:variable;' . 286 \ 'x:externvar' 287 288"verilog language 289let s:tlist_def_verilog_settings = 'verilog;m:module;P:parameter;r:register;' . 290 \ 't:task;w:write;p:port;v:variable;f:function' 291 292" vim language 293let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function' 294 295" yacc language 296let s:tlist_def_yacc_settings = 'yacc;l:label' 297 298"------------------- end of language specific options -------------------- 299 300" Vim window size is changed or not 301let s:tlist_winsize_chgd = 0 302" Taglist window is maximized or not 303let s:tlist_win_maximized = 0 304" Number of files displayed in the taglist window 305let s:tlist_file_count = 0 306" Number of filetypes supported by taglist 307let s:tlist_ftype_count = 0 308" Is taglist part of other plugins like winmanager or cream? 309let s:tlist_app_name = "none" 310" Are we displaying brief help text 311let s:tlist_brief_help = 1 312" Do not change the name of the taglist title variable. The winmanager plugin 313" relies on this name to determine the title for the taglist plugin. 314let TagList_title = "__Tag_List__" 315 316" An autocommand is used to refresh the taglist window when entering any 317" buffer. We don't want to refresh the taglist window if we are entering the 318" file window from one of the taglist functions. The 'Tlist_Skip_Refresh' 319" variable is used to skip the refresh of the taglist window and is set 320" and cleared appropriately. 321let s:Tlist_Skip_Refresh = 0 322 323" Tlist_Display_Help() 324function! s:Tlist_Display_Help() 325 if s:tlist_app_name == "winmanager" 326 " To handle a bug in the winmanager plugin, add a space at the 327 " last line 328 call setline('$', ' ') 329 endif 330 331 if s:tlist_brief_help 332 " Add the brief help 333 call append(0, '" Press ? to display help text') 334 else 335 " Add the extensive help 336 call append(0, '" <enter> : Jump to tag definition') 337 call append(1, '" o : Jump to tag definition in new window') 338 call append(2, '" p : Preview the tag definition') 339 call append(3, '" <space> : Display tag prototype') 340 call append(4, '" u : Update tag list') 341 call append(5, '" s : Select sort field') 342 call append(6, '" d : Remove file from taglist') 343 call append(7, '" x : Zoom-out/Zoom-in taglist window') 344 call append(8, '" + : Open a fold') 345 call append(9, '" - : Close a fold') 346 call append(10, '" * : Open all folds') 347 call append(11, '" = : Close all folds') 348 call append(12, '" [[ : Move to the start of previous file') 349 call append(13, '" ]] : Move to the start of next file') 350 call append(14, '" q : Close the taglist window') 351 call append(15, '" ? : Remove help text') 352 endif 353endfunction 354 355" Tlist_Toggle_Help_Text() 356" Toggle taglist plugin help text between the full version and the brief 357" version 358function! s:Tlist_Toggle_Help_Text() 359 if g:Tlist_Compact_Format 360 " In compact display mode, do not display help 361 return 362 endif 363 364 " Include the empty line displayed after the help text 365 let brief_help_size = 1 366 let full_help_size = 16 367 368 setlocal modifiable 369 370 " Set report option to a huge value to prevent informational messages 371 " while deleting the lines 372 let old_report = &report 373 set report=99999 374 375 " Remove the currently highlighted tag. Otherwise, the help text 376 " might be highlighted by mistake 377 match none 378 379 " Toggle between brief and full help text 380 if s:tlist_brief_help 381 let s:tlist_brief_help = 0 382 383 " Remove the previous help 384 exe '1,' . brief_help_size . ' delete _' 385 386 " Adjust the start/end line numbers for the files 387 call s:Tlist_Update_Line_Offsets(0, 1, full_help_size - brief_help_size) 388 else 389 let s:tlist_brief_help = 1 390 391 " Remove the previous help 392 exe '1,' . full_help_size . ' delete _' 393 394 " Adjust the start/end line numbers for the files 395 call s:Tlist_Update_Line_Offsets(0, 0, full_help_size - brief_help_size) 396 endif 397 398 call s:Tlist_Display_Help() 399 400 " Restore the report option 401 let &report = old_report 402 403 setlocal nomodifiable 404endfunction 405 406" Tlist_Warning_Msg() 407" Display a message using WarningMsg highlight group 408function! s:Tlist_Warning_Msg(msg) 409 echohl WarningMsg 410 echomsg a:msg 411 echohl None 412endfunction 413 414" Tlist_Get_File_Index() 415" Return the index of the specified filename 416function! s:Tlist_Get_File_Index(fname) 417 let i = 0 418 419 " Do a linear search 420 while i < s:tlist_file_count 421 if s:tlist_{i}_filename == a:fname 422 return i 423 endif 424 let i = i + 1 425 endwhile 426 427 return -1 428endfunction 429 430" Tlist_Get_File_Index_By_Linenum() 431" Return the index of the filename present in the specified line number 432" Line number refers to the line number in the taglist window 433function! s:Tlist_Get_File_Index_By_Linenum(lnum) 434 let i = 0 435 436 " TODO: Convert this to a binary search 437 while i < s:tlist_file_count 438 if a:lnum >= s:tlist_{i}_start && a:lnum <= s:tlist_{i}_end 439 return i 440 endif 441 let i = i + 1 442 endwhile 443 444 return -1 445endfunction 446 447" Tlist_Skip_File() 448" Check whether tag listing is supported for the specified file 449function! s:Tlist_Skip_File(filename, ftype) 450 " Skip buffers with filetype not set 451 if a:ftype == '' 452 return 1 453 endif 454 455 " Skip files which are not supported by exuberant ctags 456 " First check whether default settings for this filetype are available. 457 " If it is not available, then check whether user specified settings are 458 " available. If both are not available, then don't list the tags for this 459 " filetype 460 let var = 's:tlist_def_' . a:ftype . '_settings' 461 if !exists(var) 462 let var = 'g:tlist_' . a:ftype . '_settings' 463 if !exists(var) 464 return 1 465 endif 466 endif 467 468 " Skip buffers with no names 469 if a:filename == '' 470 return 1 471 endif 472 473 " Skip files which are not readable or files which are not yet stored 474 " to the disk 475 if !filereadable(a:filename) 476 return 1 477 endif 478 479 return 0 480endfunction 481 482" Tlist_FileType_Init 483" Initialize the ctags arguments and tag variable for the specified 484" file type 485function! s:Tlist_FileType_Init(ftype) 486 " If the user didn't specify any settings, then use the default 487 " ctags args. Otherwise, use the settings specified by the user 488 let var = 'g:tlist_' . a:ftype . '_settings' 489 if exists(var) 490 " User specified ctags arguments 491 let settings = {var} . ';' 492 else 493 " Default ctags arguments 494 let var = 's:tlist_def_' . a:ftype . '_settings' 495 if !exists(var) 496 " No default settings for this file type. This filetype is 497 " not supported 498 return 0 499 endif 500 let settings = s:tlist_def_{a:ftype}_settings . ';' 501 endif 502 503 let msg = 'Taglist: Invalid ctags option setting - ' . settings 504 505 " Format of the option that specifies the filetype and ctags arugments: 506 " 507 " <language_name>;flag1:name1;flag2:name2;flag3:name3 508 " 509 510 " Extract the file type to pass to ctags. This may be different from the 511 " file type detected by Vim 512 let pos = stridx(settings, ';') 513 if pos == -1 514 call s:Tlist_Warning_Msg(msg) 515 return 0 516 endif 517 let ctags_ftype = strpart(settings, 0, pos) 518 if ctags_ftype == '' 519 call s:Tlist_Warning_Msg(msg) 520 return 0 521 endif 522 " Make sure a valid filetype is supplied. If the user didn't specify a 523 " valid filetype, then the ctags option settings may be treated as the 524 " filetype 525 if ctags_ftype =~ ':' 526 call s:Tlist_Warning_Msg(msg) 527 return 0 528 endif 529 530 " Remove the file type from settings 531 let settings = strpart(settings, pos + 1) 532 if settings == '' 533 call s:Tlist_Warning_Msg(msg) 534 return 0 535 endif 536 537 " Process all the specified ctags flags. The format is 538 " flag1:name1;flag2:name2;flag3:name3 539 let ctags_flags = '' 540 let cnt = 0 541 while settings != '' 542 " Extract the flag 543 let pos = stridx(settings, ':') 544 if pos == -1 545 call s:Tlist_Warning_Msg(msg) 546 return 0 547 endif 548 let flag = strpart(settings, 0, pos) 549 if flag == '' 550 call s:Tlist_Warning_Msg(msg) 551 return 0 552 endif 553 " Remove the flag from settings 554 let settings = strpart(settings, pos + 1) 555 556 " Extract the tag type name 557 let pos = stridx(settings, ';') 558 if pos == -1 559 call s:Tlist_Warning_Msg(msg) 560 return 0 561 endif 562 let name = strpart(settings, 0, pos) 563 if name == '' 564 call s:Tlist_Warning_Msg(msg) 565 return 0 566 endif 567 let settings = strpart(settings, pos + 1) 568 569 let cnt = cnt + 1 570 571 let s:tlist_{a:ftype}_{cnt}_name = flag 572 let s:tlist_{a:ftype}_{cnt}_fullname = name 573 let ctags_flags = ctags_flags . flag 574 endwhile 575 576 let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype . 577 \ ' --' . ctags_ftype . '-types=' . ctags_flags 578 let s:tlist_{a:ftype}_count = cnt 579 let s:tlist_{a:ftype}_ctags_flags = ctags_flags 580 581 " Save the filetype name 582 let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype 583 let s:tlist_ftype_count = s:tlist_ftype_count + 1 584 585 return 1 586endfunction 587 588" Tlist_Discard_TagInfo 589" Discard the stored tag information for a file 590function! s:Tlist_Discard_TagInfo(fidx) 591 let ftype = s:tlist_{a:fidx}_filetype 592 593 " Discard information about the tags defined in the file 594 let i = 1 595 while i <= s:tlist_{a:fidx}_tag_count 596 unlet! s:tlist_{a:fidx}_tag_{i} 597 let i = i + 1 598 endwhile 599 600 let s:tlist_{a:fidx}_tag_count = 0 601 602 " Discard information about tags groups by their type 603 let i = 1 604 while i <= s:tlist_{ftype}_count 605 let ttype = s:tlist_{ftype}_{i}_name 606 if s:tlist_{a:fidx}_{ttype} != '' 607 let s:tlist_{a:fidx}_{ttype} = '' 608 let s:tlist_{a:fidx}_{ttype}_start = 0 609 let cnt = s:tlist_{a:fidx}_{ttype}_count 610 let s:tlist_{a:fidx}_{ttype}_count = 0 611 let j = 1 612 while j <= cnt 613 unlet! s:tlist_{a:fidx}_{ttype}_{j} 614 let j = j + 1 615 endwhile 616 endif 617 let i = i + 1 618 endwhile 619endfunction 620 621" Tlist_Update_Line_Offsets 622" Update the line offsets for tags for files starting from start_idx 623" and displayed in the taglist window by the specified offset 624function! s:Tlist_Update_Line_Offsets(start_idx, increment, offset) 625 let i = a:start_idx 626 627 while i < s:tlist_file_count 628 if s:tlist_{i}_visible 629 " Update the start/end line number only if the file is visible 630 if a:increment 631 let s:tlist_{i}_start = s:tlist_{i}_start + a:offset 632 let s:tlist_{i}_end = s:tlist_{i}_end + a:offset 633 else 634 let s:tlist_{i}_start = s:tlist_{i}_start - a:offset 635 let s:tlist_{i}_end = s:tlist_{i}_end - a:offset 636 endif 637 endif 638 let i = i + 1 639 endwhile 640endfunction 641 642" Tlist_Discard_FileInfo 643" Discard the stored information for a file 644function! s:Tlist_Discard_FileInfo(fidx) 645 call s:Tlist_Discard_TagInfo(a:fidx) 646 647 let ftype = s:tlist_{a:fidx}_filetype 648 649 let i = 1 650 while i <= s:tlist_{ftype}_count 651 let ttype = s:tlist_{ftype}_{i}_name 652 unlet! s:tlist_{a:fidx}_{ttype} 653 unlet! s:tlist_{a:fidx}_{ttype}_start 654 unlet! s:tlist_{a:fidx}_{ttype}_count 655 let i = i + 1 656 endwhile 657 658 unlet! s:tlist_{a:fidx}_filename 659 unlet! s:tlist_{a:fidx}_sort_type 660 unlet! s:tlist_{a:fidx}_filetype 661 unlet! s:tlist_{a:fidx}_mtime 662 unlet! s:tlist_{a:fidx}_start 663 unlet! s:tlist_{a:fidx}_end 664 unlet! s:tlist_{a:fidx}_valid 665 unlet! s:tlist_{a:fidx}_visible 666 unlet! s:tlist_{a:fidx}_tag_count 667endfunction 668 669" Tlist_Remove_File_From_Display 670" Remove the specified file from display 671function! s:Tlist_Remove_File_From_Display(fidx) 672 " Remove the tags displayed for the specified file from the window 673 let start = s:tlist_{a:fidx}_start 674 " Include the empty line after the last line also 675 if g:Tlist_Compact_Format 676 let end = s:tlist_{a:fidx}_end 677 else 678 let end = s:tlist_{a:fidx}_end + 1 679 endif 680 681 setlocal modifiable 682 683 exe 'silent! ' . start . ',' . end . 'delete _' 684 685 setlocal nomodifiable 686 687 " Correct the start and end line offsets for all the files following 688 " this file, as the tags for this file are removed 689 call s:Tlist_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1) 690endfunction 691 692" Tlist_Remove_File 693" Remove the file under the cursor or the specified file index 694function! s:Tlist_Remove_File(file_idx) 695 let fidx = a:file_idx 696 697 if fidx == -1 698 let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) 699 if fidx == -1 700 return 701 endif 702 endif 703 704 call s:Tlist_Remove_File_From_Display(fidx) 705 706 call s:Tlist_Discard_FileInfo(fidx) 707 708 " Shift all the file variables by one index 709 let i = fidx + 1 710 711 while i < s:tlist_file_count 712 let j = i - 1 713 714 let s:tlist_{j}_filename = s:tlist_{i}_filename 715 let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type 716 let s:tlist_{j}_filetype = s:tlist_{i}_filetype 717 let s:tlist_{j}_mtime = s:tlist_{i}_mtime 718 let s:tlist_{j}_start = s:tlist_{i}_start 719 let s:tlist_{j}_end = s:tlist_{i}_end 720 let s:tlist_{j}_valid = s:tlist_{i}_valid 721 let s:tlist_{j}_visible = s:tlist_{i}_visible 722 let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count 723 724 let k = 1 725 while k <= s:tlist_{j}_tag_count 726 let s:tlist_{j}_tag_{k} = s:tlist_{i}_tag_{k} 727 let k = k + 1 728 endwhile 729 730 let ftype = s:tlist_{i}_filetype 731 732 let k = 1 733 while k <= s:tlist_{ftype}_count 734 let ttype = s:tlist_{ftype}_{k}_name 735 let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype} 736 let s:tlist_{j}_{ttype}_start = s:tlist_{i}_{ttype}_start 737 let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count 738 if s:tlist_{j}_{ttype} != '' 739 let l = 1 740 while l <= s:tlist_{j}_{ttype}_count 741 let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l} 742 let l = l + 1 743 endwhile 744 endif 745 let k = k + 1 746 endwhile 747 748 " As the file and tag information is copied to the new index, 749 " discard the previous information 750 call s:Tlist_Discard_FileInfo(i) 751 752 let i = i + 1 753 endwhile 754 755 " Reduce the number of files displayed 756 let s:tlist_file_count = s:tlist_file_count - 1 757endfunction 758 759 760" Tlist_Open_Window 761" Create a new taglist window. If it is already open, jump to it 762function! s:Tlist_Open_Window() 763 " If used with winmanager don't open windows. Winmanager will handle 764 " the window/buffer management 765 if s:tlist_app_name == "winmanager" 766 return 767 endif 768 769 " If the window is open, jump to it 770 let winnum = bufwinnr(g:TagList_title) 771 if winnum != -1 772 " Jump to the existing window 773 if winnr() != winnum 774 exe winnum . 'wincmd w' 775 endif 776 return 777 endif 778 779 " Create a new window. If user prefers a horizontal window, then open 780 " a horizontally split window. Otherwise open a vertically split 781 " window 782 if g:Tlist_Use_Horiz_Window 783 " Open a horizontally split window 784 let win_dir = 'botright' 785 " Horizontal window height 786 let win_size = g:Tlist_WinHeight 787 else 788 " Open a horizontally split window. Increase the window size, if 789 " needed, to accomodate the new window 790 if g:Tlist_Inc_Winwidth && 791 \ &columns < (80 + g:Tlist_WinWidth) 792 " one extra column is needed to include the vertical split 793 let &columns= &columns + (g:Tlist_WinWidth + 1) 794 let s:tlist_winsize_chgd = 1 795 else 796 let s:tlist_winsize_chgd = 0 797 endif 798 799 if g:Tlist_Use_Right_Window 800 " Open the window at the rightmost place 801 let win_dir = 'botright vertical' 802 else 803 " Open the window at the leftmost place 804 let win_dir = 'topleft vertical' 805 endif 806 let win_size = g:Tlist_WinWidth 807 endif 808 809 " If the tag listing temporary buffer already exists, then reuse it. 810 " Otherwise create a new buffer 811 let bufnum = bufnr(g:TagList_title) 812 if bufnum == -1 813 " Create a new buffer 814 let wcmd = g:TagList_title 815 else 816 " Edit the existing buffer 817 let wcmd = '+buffer' . bufnum 818 endif 819 820 " Create the taglist window 821 exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd 822endfunction 823 824" Tlist_Zoom_Window 825" Zoom (maximize/minimize) the taglist window 826function! s:Tlist_Zoom_Window() 827 if s:tlist_win_maximized 828 " Restore the window back to the previous size 829 if g:Tlist_Use_Horiz_Window 830 exe 'resize ' . g:Tlist_WinHeight 831 else 832 exe 'vert resize ' . g:Tlist_WinWidth 833 endif 834 let s:tlist_win_maximized = 0 835 else 836 " Set the window size to the maximum possible without closing other 837 " windows 838 if g:Tlist_Use_Horiz_Window 839 resize 840 else 841 vert resize 842 endif 843 let s:tlist_win_maximized = 1 844 endif 845endfunction 846 847" Tlist_Init_Window 848" Set the default options for the taglist window 849function! s:Tlist_Init_Window() 850 " Define taglist window element highlighting 851 if has('syntax') 852 syntax match TagListComment '^" .*' 853 syntax match TagListFileName '^[^" ].*$' 854 syntax match TagListTitle '^ \S.*$' 855 syntax match TagListTagScope '\s\[.\{-\}\]$' 856 857 " Define the highlighting only if colors are supported 858 if has('gui_running') || &t_Co > 2 859 " Colors to highlight various taglist window elements 860 " If user defined highlighting group exists, then use them. 861 " Otherwise, use default highlight groups. 862 if hlexists('MyTagListTagName') 863 highlight link TagListTagName MyTagListTagName 864 else 865 highlight link TagListTagName Search 866 endif 867 " Colors to highlight comments and titles 868 if hlexists('MyTagListComment') 869 highlight link TagListComment MyTagListComment 870 else 871 highlight clear TagListComment 872 highlight link TagListComment Comment 873 endif 874 if hlexists('MyTagListTitle') 875 highlight link TagListTitle MyTagListTitle 876 else 877 highlight clear TagListTitle 878 highlight link TagListTitle Title 879 endif 880 if hlexists('MyTagListFileName') 881 highlight link TagListFileName MyTagListFileName 882 else 883 highlight clear TagListFileName 884 highlight link TagListFileName LineNr 885 endif 886 if hlexists('MyTagListTagScope') 887 highlight link TagListTagScope MyTagListTagScope 888 else 889 highlight clear TagListTagScope 890 highlight link TagListTagScope Identifier 891 endif 892 else 893 highlight TagListTagName term=reverse cterm=reverse 894 endif 895 endif 896 897 " Folding related settings 898 if has('folding') 899 setlocal foldenable 900 setlocal foldminlines=0 901 setlocal foldmethod=manual 902 if g:Tlist_Enable_Fold_Column 903 setlocal foldcolumn=3 904 else 905 setlocal foldcolumn=0 906 endif 907 setlocal foldtext=v:folddashes.getline(v:foldstart) 908 endif 909 910 if s:tlist_app_name != "winmanager" 911 " Mark buffer as scratch 912 silent! setlocal buftype=nofile 913 914 if s:tlist_app_name == "none" 915 916 silent! setlocal bufhidden=delete 917 918 endif 919 920 silent! setlocal noswapfile 921 " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted 922 " buffers. So if the taglist buffer is unlisted, multiple taglist 923 " windows will be opened. This bug is fixed in Vim 6.1 and above 924 if v:version >= 601 925 silent! setlocal nobuflisted 926 endif 927 endif 928 929 silent! setlocal nowrap 930 931 " If the 'number' option is set in the source window, it will affect the 932 " taglist window. So forcefully disable 'number' option for the taglist 933 " window 934 silent! setlocal nonumber 935 936 " Create buffer local mappings for jumping to the tags and sorting the list 937 nnoremap <buffer> <silent> <CR> :call <SID>Tlist_Jump_To_Tag(0)<CR> 938 nnoremap <buffer> <silent> o :call <SID>Tlist_Jump_To_Tag(1)<CR> 939 nnoremap <buffer> <silent> p :call <SID>Tlist_Jump_To_Tag(2)<CR> 940 nnoremap <buffer> <silent> <2-LeftMouse> :call <SID>Tlist_Jump_To_Tag(0)<CR> 941 nnoremap <buffer> <silent> s :call <SID>Tlist_Change_Sort()<CR> 942 nnoremap <buffer> <silent> + :silent! foldopen<CR> 943 nnoremap <buffer> <silent> - :silent! foldclose<CR> 944 nnoremap <buffer> <silent> * :silent! %foldopen!<CR> 945 nnoremap <buffer> <silent> = :silent! %foldclose<CR> 946 nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR> 947 nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR> 948 nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR> 949 nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Show_Tag_Prototype()<CR> 950 nnoremap <buffer> <silent> u :call <SID>Tlist_Update_Window()<CR> 951 nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1)<CR> 952 nnoremap <buffer> <silent> x :call <SID>Tlist_Zoom_Window()<CR> 953 nnoremap <buffer> <silent> [[ :call <SID>Tlist_Move_To_File(-1)<CR> 954 nnoremap <buffer> <silent> ]] :call <SID>Tlist_Move_To_File(1)<CR> 955 nnoremap <buffer> <silent> ? :call <SID>Tlist_Toggle_Help_Text()<CR> 956 nnoremap <buffer> <silent> q :close<CR> 957 958 " Insert mode mappings 959 imap <buffer> <silent> <CR> <C-b>:call <SID>Tlist_Jump_To_Tag(0)<CR> 960 " Windows needs return 961 imap <buffer> <silent> <Return> <C-b>:call <SID>Tlist_Jump_To_Tag(0)<CR> 962 inoremap <buffer> <silent> o <C-b>:call <SID>Tlist_Jump_To_Tag(1)<CR> 963 inoremap <buffer> <silent> p <C-b>:call <SID>Tlist_Jump_To_Tag(2)<CR> 964 imap <buffer> <silent> <2-LeftMouse> <C-b>:call 965 \ <SID>Tlist_Jump_To_Tag(0)<CR> 966 inoremap <buffer> <silent> s <C-b>:call <SID>Tlist_Change_Sort()<CR> 967 inoremap <buffer> <silent> + <C-b>:silent! foldopen<CR> 968 inoremap <buffer> <silent> - <C-b>:silent! foldclose<CR> 969 inoremap <buffer> <silent> * <C-b>:silent! %foldopen!<CR> 970 inoremap <buffer> <silent> = <C-b>:silent! %foldclose<CR> 971 inoremap <buffer> <silent> <kPlus> <C-b>:silent! foldopen<CR> 972 inoremap <buffer> <silent> <kMinus> <C-b>:silent! foldclose<CR> 973 inoremap <buffer> <silent> <kMultiply> <C-b>:silent! %foldopen!<CR> 974 inoremap <buffer> <silent> <Space> <C-b>:call 975 \ <SID>Tlist_Show_Tag_Prototype()<CR> 976 inoremap <buffer> <silent> u <C-b>:call <SID>Tlist_Update_Window()<CR> 977 inoremap <buffer> <silent> d <C-b>:call <SID>Tlist_Remove_File(-1)<CR> 978 inoremap <buffer> <silent> x <C-b>:call <SID>Tlist_Zoom_Window()<CR> 979 inoremap <buffer> <silent> [[ <C-b>:call <SID>Tlist_Move_To_File(-1)<CR> 980 inoremap <buffer> <silent> ]] <C-b>:call <SID>Tlist_Move_To_File(1)<CR> 981 inoremap <buffer> <silent> ? <C-b>:call <SID>Tlist_Toggle_Help_Text()<CR> 982 inoremap <buffer> <silent> q <C-b>:close<CR> 983 984 " Map single left mouse click if the user wants this functionality 985 if g:Tlist_Use_SingleClick 986 nnoremap <silent> <LeftMouse> <LeftMouse>:if bufname("%") =~ "__Tag_List__" 987 \ <bar> call <SID>Tlist_Jump_To_Tag(0) <bar> endif <CR> 988 endif 989 990 " Define the taglist autocommands 991 augroup TagListAutoCmds 992 autocmd! 993 " Display the tag prototype for the tag under the cursor. 994 autocmd CursorHold __Tag_List__ call s:Tlist_Show_Tag_Prototype() 995 " Highlight the current tag 996 autocmd CursorHold * silent call <SID>Tlist_Highlight_Tag( 997 \ fnamemodify(bufname('%'), ':p'), line('.'), 1) 998 " Adjust the Vim window width when taglist window is closed 999 autocmd BufUnload __Tag_List__ call <SID>Tlist_Post_Close_Cleanup() 1000 " Close the fold for this buffer when it's not visible in any window 1001 autocmd BufWinLeave * silent call <SID>Tlist_Update_File_Display( 1002 \ fnamemodify(expand('<afile>'), ':p'), 1) 1003 " Remove the file from the list when it's buffer is deleted 1004 autocmd BufDelete * silent call <SID>Tlist_Update_File_Display( 1005 \ fnamemodify(expand('<afile>'), ':p'), 2) 1006 " Exit Vim itself if only the taglist window is present (optional) 1007 autocmd BufEnter __Tag_List__ call <SID>Tlist_Check_Only_Window() 1008 if s:tlist_app_name != "winmanager" && !g:Tlist_Process_File_Always 1009 " Auto refresh the taglist window 1010 autocmd BufEnter * call <SID>Tlist_Refresh() 1011 endif 1012 augroup end 1013endfunction 1014 1015" Tlist_Refresh_Window 1016" Display the tags for all the files in the taglist window 1017function! s:Tlist_Refresh_Window() 1018 " Set report option to a huge value to prevent informational messages 1019 " while deleting the lines 1020 let old_report = &report 1021 set report=99999 1022 1023 " Mark the buffer as modifiable 1024 setlocal modifiable 1025 1026 " Delete the contents of the buffer to the black-hole register 1027 silent! %delete _ 1028 1029 if g:Tlist_Compact_Format == 0 1030 " Display help in non-compact mode 1031 call s:Tlist_Display_Help() 1032 endif 1033 1034 " Mark the buffer as not modifiable 1035 setlocal nomodifiable 1036 1037 " Restore the report option 1038 let &report = old_report 1039 1040 " List all the tags for the previously processed files 1041 let i = 0 1042 while i < s:tlist_file_count 1043 " Mark the file as not visible, so that Tlist_Explore_File() will 1044 " display the tags for this file and mark the file as visible 1045 let s:tlist_{i}_visible = 0 1046 call s:Tlist_Explore_File(s:tlist_{i}_filename, s:tlist_{i}_filetype) 1047 let i = i + 1 1048 endwhile 1049 1050 " If Tlist_File_Fold_Auto_Close option is set, then close all the 1051 " folds 1052 if g:Tlist_File_Fold_Auto_Close 1053 if has('folding') 1054 " Close all the folds 1055 silent! %foldclose 1056 endif 1057 endif 1058endfunction 1059 1060" Tlist_Post_Close_Cleanup() 1061" Close the taglist window and adjust the Vim window width 1062function! s:Tlist_Post_Close_Cleanup() 1063 " Mark all the files as not visible 1064 let i = 0 1065 while i < s:tlist_file_count 1066 let s:tlist_{i}_visible = 0 1067 let i = i + 1 1068 endwhile 1069 1070 " Remove the taglist autocommands 1071 silent! autocmd! TagListAutoCmds 1072 1073 " Clear all the highlights 1074 match none 1075 1076 if has('syntax') 1077 silent! syntax clear TagListTitle 1078 silent! syntax clear TagListComment 1079 silent! syntax clear TagListTagScope 1080 endif 1081 1082 " Remove the left mouse click mapping if it was setup initially 1083 if g:Tlist_Use_SingleClick 1084 if hasmapto('<LeftMouse>') 1085 nunmap <LeftMouse> 1086 endif 1087 endif 1088 1089 if s:tlist_app_name != "winmanager" 1090 if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 || 1091 \ s:tlist_winsize_chgd == 0 || 1092 \ &columns < (80 + g:Tlist_WinWidth) 1093 " No need to adjust window width if using horizontally split taglist 1094 " window or if columns is less than 101 or if the user chose not to 1095 " adjust the window width 1096 else 1097 " Adjust the Vim window width 1098 let &columns= &columns - (g:Tlist_WinWidth + 1) 1099 endif 1100 endif 1101 1102 " Reset taglist state variables 1103 if s:tlist_app_name == "winmanager" 1104 let s:tlist_app_name = "none" 1105 let s:tlist_window_initialized = 0 1106 endif 1107endfunction 1108 1109" Tlist_Check_Only_Window 1110" Check if only the taglist window is opened currently. If the 1111" Tlist_Exit_OnlyWindow variable is set, then close the taglist window 1112function! s:Tlist_Check_Only_Window() 1113 if g:Tlist_Exit_OnlyWindow 1114 if winbufnr(2) == -1 && bufname(winbufnr(1)) == g:TagList_title 1115 " If only the taglist window is currently open, then the buffer 1116 " number associated with window 2 will be -1. 1117 quit 1118 endif 1119 endif 1120endfunction 1121 1122" Tlist_Explore_File() 1123" List the tags defined in the specified file in a Vim window 1124function! s:Tlist_Explore_File(filename, ftype) 1125 " First check whether the file already exists 1126 let fidx = s:Tlist_Get_File_Index(a:filename) 1127 if fidx != -1 1128 let file_exists = 1 1129 else 1130 let file_exists = 0 1131 endif 1132 1133 if file_exists && s:tlist_{fidx}_visible 1134 " Check whether the file tags are currently valid 1135 if s:tlist_{fidx}_valid 1136 " Goto the first line in the file 1137 exe s:tlist_{fidx}_start 1138 1139 " If the line is inside a fold, open the fold 1140 if has('folding') 1141 exe "silent! " . s:tlist_{fidx}_start . "," . 1142 \ s:tlist_{fidx}_end . "foldopen!" 1143 endif 1144 return 1145 endif 1146 1147 " Discard and remove the tags for this file from display 1148 call s:Tlist_Discard_TagInfo(fidx) 1149 call s:Tlist_Remove_File_From_Display(fidx) 1150 endif 1151 1152 " Process and generate a list of tags defined in the file 1153 if !file_exists || !s:tlist_{fidx}_valid 1154 let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype) 1155 if ret_fidx == -1 1156 return 1157 endif 1158 let fidx = ret_fidx 1159 endif 1160 1161 " Set report option to a huge value to prevent informational messages 1162 " while adding lines to the taglist window 1163 let old_report = &report 1164 set report=99999 1165 1166 " Mark the buffer as modifiable 1167 setlocal modifiable 1168 1169 " Add new files to the end of the window. For existing files, add them at 1170 " the same line where they were previously present. If the file is not 1171 " visible, then add it at the end 1172 if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible 1173 if g:Tlist_Compact_Format 1174 let s:tlist_{fidx}_start = line('$') 1175 else 1176 let s:tlist_{fidx}_start = line('$') + 1 1177 endif 1178 endif 1179 1180 let s:tlist_{fidx}_visible = 1 1181 1182 " Goto the line where this file should be placed 1183 if g:Tlist_Compact_Format 1184 exe s:tlist_{fidx}_start 1185 else 1186 exe (s:tlist_{fidx}_start - 1) 1187 endif 1188 1189 let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' . 1190 \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')' 1191 if g:Tlist_Compact_Format == 0 1192 silent! put =txt 1193 else 1194 silent! put! =txt 1195 " Move to the next line 1196 exe line('.') + 1 1197 endif 1198 let file_start = s:tlist_{fidx}_start 1199 1200 " Add the tag names grouped by tag type to the buffer with a title 1201 let i = 1 1202 while i <= s:tlist_{a:ftype}_count 1203 let ttype = s:tlist_{a:ftype}_{i}_name 1204 " Add the tag type only if there are tags for that type 1205 if s:tlist_{fidx}_{ttype} != '' 1206 let txt = ' ' . s:tlist_{a:ftype}_{i}_fullname 1207 if g:Tlist_Compact_Format == 0 1208 let ttype_start_lnum = line('.') + 1 1209 silent! put =txt 1210 else 1211 let ttype_start_lnum = line('.') 1212 silent! put! =txt 1213 endif 1214 silent! put =s:tlist_{fidx}_{ttype} 1215 1216 if g:Tlist_Compact_Format 1217 exe (line('.') + s:tlist_{fidx}_{ttype}_count) 1218 endif 1219 1220 let s:tlist_{fidx}_{ttype}_start = ttype_start_lnum - file_start 1221 1222 " create a fold for this tag type 1223 if has('folding') 1224 let fold_start = ttype_start_lnum 1225 let fold_end = fold_start + s:tlist_{fidx}_{ttype}_count 1226 exe fold_start . ',' . fold_end . 'fold' 1227 endif 1228 1229 if g:Tlist_Compact_Format == 0 1230 silent! put ='' 1231 endif 1232 endif 1233 let i = i + 1 1234 endwhile 1235 1236 if s:tlist_{fidx}_tag_count == 0 1237 put ='' 1238 endif 1239 1240 let s:tlist_{fidx}_end = line('.') - 1 1241 1242 " Create a fold for the entire file 1243 if has('folding') 1244 exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold' 1245 exe 'silent! ' . s:tlist_{fidx}_start . ',' . 1246 \ s:tlist_{fidx}_end . 'foldopen!' 1247 endif 1248 1249 " Goto the starting line for this file, 1250 exe s:tlist_{fidx}_start 1251 1252 if s:tlist_app_name == "winmanager" 1253 " To handle a bug in the winmanager plugin, add a space at the 1254 " last line 1255 call setline('$', ' ') 1256 endif 1257 1258 " Mark the buffer as not modifiable 1259 setlocal nomodifiable 1260 1261 " Restore the report option 1262 let &report = old_report 1263 1264 " Update the start and end line numbers for all the files following this 1265 " file 1266 let start = s:tlist_{fidx}_start 1267 " include the empty line after the last line 1268 if g:Tlist_Compact_Format 1269 let end = s:tlist_{fidx}_end 1270 else 1271 let end = s:tlist_{fidx}_end + 1 1272 endif 1273 call s:Tlist_Update_Line_Offsets(fidx + 1, 1, end - start + 1) 1274 1275 return 1276endfunction 1277 1278" Tlist_Init_File 1279" Initialize the variables for a new file 1280function! s:Tlist_Init_File(filename, ftype) 1281 " Add new files at the end of the list 1282 let fidx = s:tlist_file_count 1283 let s:tlist_file_count = s:tlist_file_count + 1 1284 1285 " Initialize the file variables 1286 let s:tlist_{fidx}_filename = a:filename 1287 let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type 1288 let s:tlist_{fidx}_filetype = a:ftype 1289 let s:tlist_{fidx}_mtime = -1 1290 let s:tlist_{fidx}_start = 0 1291 let s:tlist_{fidx}_end = 0 1292 let s:tlist_{fidx}_valid = 0 1293 let s:tlist_{fidx}_visible = 0 1294 let s:tlist_{fidx}_tag_count = 0 1295 1296 " Initialize the tag type variables 1297 let i = 1 1298 while i <= s:tlist_{a:ftype}_count 1299 let ttype = s:tlist_{a:ftype}_{i}_name 1300 let s:tlist_{fidx}_{ttype} = '' 1301 let s:tlist_{fidx}_{ttype}_start = 0 1302 let s:tlist_{fidx}_{ttype}_count = 0 1303 let i = i + 1 1304 endwhile 1305 1306 return fidx 1307endfunction 1308 1309" Tlist_Process_File 1310" Get the list of tags defined in the specified file and store them 1311" in Vim variables. Returns the file index where the tags are stored. 1312function! s:Tlist_Process_File(filename, ftype) 1313 " Check for valid filename and valid filetype 1314 if a:filename == '' || !filereadable(a:filename) || a:ftype == '' 1315 return -1 1316 endif 1317 1318 " If the tag types for this filetype are not yet created, then create 1319 " them now 1320 let var = 's:tlist_' . a:ftype . '_count' 1321 if !exists(var) 1322 if s:Tlist_FileType_Init(a:ftype) == 0 1323 return -1 1324 endif 1325 endif 1326 1327 " If this file is already processed, then use the cached values 1328 let fidx = s:Tlist_Get_File_Index(a:filename) 1329 if fidx == -1 1330 " First time, this file is loaded 1331 let fidx = s:Tlist_Init_File(a:filename, a:ftype) 1332 else 1333 " File was previously processed. Discard the tag information 1334 call s:Tlist_Discard_TagInfo(fidx) 1335 endif 1336 1337 let s:tlist_{fidx}_valid = 1 1338 1339 " Exuberant ctags arguments to generate a tag list 1340 let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks ' 1341 1342 " Form the ctags argument depending on the sort type 1343 if s:tlist_{fidx}_sort_type == 'name' 1344 let ctags_args = ctags_args . ' --sort=yes ' 1345 else 1346 let ctags_args = ctags_args . ' --sort=no ' 1347 endif 1348 1349 " Add the filetype specific arguments 1350 let ctags_args = ctags_args . ' ' . s:tlist_{a:ftype}_ctags_args 1351 1352 " Ctags command to produce output with regexp for locating the tags 1353 let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args 1354 let ctags_cmd = ctags_cmd . ' "' . a:filename . '"' 1355 1356 " In Windows 95, if not using cygwin, disable the 'shellslash' 1357 " option. Otherwise, this will cause problems when running the 1358 " ctags command. 1359 if has("win95") && !has("win32unix") 1360 let myshellslash = &shellslash 1361 set noshellslash 1362 endif 1363 1364 " Run ctags and get the tag list 1365 let cmd_output = system(ctags_cmd) 1366 1367 " Restore the value of the 'shellslash' option. 1368 if has("win95") && !has("win32unix") 1369 let &shellslash = myshellslash 1370 endif 1371 1372 " Handle errors 1373 if v:shell_error && cmd_output != '' 1374 let msg = "Taglist: Failed to generate tags for " . a:filename 1375 call s:Tlist_Warning_Msg(msg) 1376 call s:Tlist_Warning_Msg(cmd_output) 1377 return fidx 1378 endif 1379 1380 " No tags for current file 1381 if cmd_output == '' 1382 call s:Tlist_Warning_Msg('Taglist: No tags found for ' . a:filename) 1383 return fidx 1384 endif 1385 1386 " Store the modification time for the file 1387 let s:tlist_{fidx}_mtime = getftime(a:filename) 1388 1389 " Process the ctags output one line at a time. Separate the tag output 1390 " based on the tag type and store it in the tag type variable 1391 " The format of each line in the ctags output is: 1392 " 1393 " tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields 1394 " 1395 while cmd_output != '' 1396 " Extract one line at a time 1397 let idx = stridx(cmd_output, "\n") 1398 let one_line = strpart(cmd_output, 0, idx) 1399 " Remove the line from the tags output 1400 let cmd_output = strpart(cmd_output, idx + 1) 1401 1402 if one_line == '' 1403 " Line is not in proper tags format 1404 continue 1405 endif 1406 1407 " Extract the tag type 1408 let ttype = s:Tlist_Extract_Tagtype(one_line) 1409 1410 if ttype == '' 1411 " Line is not in proper tags format 1412 continue 1413 endif 1414 1415 " make sure the tag type is supported 1416 if s:tlist_{a:ftype}_ctags_flags !~# ttype 1417 " Tag type is not supported 1418 continue 1419 endif 1420 1421 " Extract the tag name 1422 if g:Tlist_Display_Prototype == 0 1423 let ttxt = ' ' . strpart(one_line, 0, stridx(one_line, "\t")) 1424 1425 " Add the tag scope, if it is available. Tag scope is the last 1426 " field after the 'line:<num>\t' field 1427 if g:Tlist_Display_Tag_Scope " only if it is selected 1428 let tag_scope = s:Tlist_Extract_Tag_Scope(one_line) 1429 if tag_scope != '' 1430 let ttxt = ttxt . ' [' . tag_scope . ']' 1431 endif 1432 endif 1433 else 1434 let ttxt = s:Tlist_Extract_Tag_Prototype(one_line) 1435 endif 1436 1437 " Update the count of this tag type 1438 let cnt = s:tlist_{fidx}_{ttype}_count + 1 1439 let s:tlist_{fidx}_{ttype}_count = cnt 1440 1441 " Add this tag to the tag type variable 1442 let s:tlist_{fidx}_{ttype} = s:tlist_{fidx}_{ttype} . ttxt . "\n" 1443 1444 " Update the total tag count 1445 let s:tlist_{fidx}_tag_count = s:tlist_{fidx}_tag_count + 1 1446 " Store the ctags output line and the tagtype count 1447 let s:tlist_{fidx}_tag_{s:tlist_{fidx}_tag_count} = 1448 \ cnt . ':' . one_line 1449 " Store the tag output index 1450 let s:tlist_{fidx}_{ttype}_{cnt} = s:tlist_{fidx}_tag_count 1451 endwhile 1452 1453 return fidx 1454endfunction 1455 1456" Tlist_Update_File_Tags 1457" Update the tags for a file (if needed) 1458function! Tlist_Update_File_Tags(filename, ftype) 1459 " If the file doesn't support tag listing, skip it 1460 if s:Tlist_Skip_File(a:filename, a:ftype) 1461 return 1462 endif 1463 1464 " First check whether the file already exists 1465 let fidx = s:Tlist_Get_File_Index(a:filename) 1466 1467 if fidx != -1 && s:tlist_{fidx}_valid 1468 " File exists and the tags are valid 1469 return 1470 endif 1471 1472 " If the taglist window is opened, update it 1473 let winnum = bufwinnr(g:TagList_title) 1474 if winnum == -1 1475 " Taglist window is not present. Just update the taglist 1476 " and return 1477 call s:Tlist_Process_File(a:filename, a:ftype) 1478 else 1479 " Save the current window number 1480 let save_winnr = winnr() 1481 1482 " Goto the taglist window 1483 call s:Tlist_Open_Window() 1484 1485 " Update the taglist window 1486 call s:Tlist_Explore_File(a:filename, a:ftype) 1487 1488 if winnr() != save_winnr 1489 " Go back to the original window 1490 exe save_winnr . 'wincmd w' 1491 endif 1492 endif 1493endfunction 1494 1495" Tlist_Close_Window 1496" Close the taglist window 1497function! s:Tlist_Close_Window() 1498 " Make sure the taglist window exists 1499 let winnum = bufwinnr(g:TagList_title) 1500 if winnum == -1 1501 call s:Tlist_Warning_Msg('Error: Taglist window is not open') 1502 return 1503 endif 1504 1505 if winnr() == winnum 1506 " Already in the taglist window. Close it and return 1507 if winbufnr(2) != -1 1508 " If a window other than the taglist window is open, 1509 " then only close the taglist window. 1510 close 1511 endif 1512 else 1513 " Goto the taglist window, close it and then come back to the 1514 " original window 1515 let curbufnr = bufnr('%') 1516 exe winnum . 'wincmd w' 1517 close 1518 " Need to jump back to the original window only if we are not 1519 " already in that window 1520 let winnum = bufwinnr(curbufnr) 1521 if winnr() != winnum 1522 exe winnum . 'wincmd w' 1523 endif 1524 endif 1525endfunction 1526 1527" Tlist_Toggle_Window() 1528" Open or close a taglist window 1529function! s:Tlist_Toggle_Window() 1530 let curline = line('.') 1531 1532 " If taglist window is open then close it. 1533 let winnum = bufwinnr(g:TagList_title) 1534 if winnum != -1 1535 call s:Tlist_Close_Window() 1536 return 1537 endif 1538 1539 if s:tlist_app_name == "winmanager" 1540 " Taglist plugin is no longer part of the winmanager app 1541 let s:tlist_app_name = "none" 1542 endif 1543 1544 " Get the filename and filetype for the specified buffer 1545 let curbuf_name = fnamemodify(bufname('%'), ':p') 1546 let curbuf_ftype = getbufvar('%', '&filetype') 1547 1548 " Mark the current window as the desired window to open a file 1549 " when a tag is selcted 1550 let w:tlist_file_window = "yes" 1551 1552 " Open the taglist window 1553 call s:Tlist_Open_Window() 1554 1555 " Initialize the taglist window 1556 call s:Tlist_Init_Window() 1557 call s:Tlist_Refresh_Window() 1558 1559 " Add and list the tags for all the buffers in the bufferlist 1560 let i = 1 1561 while i < bufnr('$') 1562 let fname = fnamemodify(bufname(i), ':p') 1563 let ftype = getbufvar(i, '&filetype') 1564 call s:Tlist_Explore_File(fname, ftype) 1565 let i = i + 1 1566 endwhile 1567 1568 " Highlight the current tag 1569 call s:Tlist_Highlight_Tag(curbuf_name, curline, 1) 1570 1571 " Go back to the original window 1572 let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh 1573 let s:Tlist_Skip_Refresh = 1 1574 wincmd p 1575 let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh 1576endfunction 1577 1578" Tlist_Extract_Tagtype 1579" Extract the tag type from the tag text 1580function! s:Tlist_Extract_Tagtype(tag_txt) 1581 " The tag type is after the tag prototype field. The prototype field 1582 " ends with the /;"\t string. We add 4 at the end to skip the characters 1583 " in this special string.. 1584 let start = strridx(a:tag_txt, '/;"' . "\t") + 4 1585 let end = strridx(a:tag_txt, 'line:') - 1 1586 let ttype = strpart(a:tag_txt, start, end - start) 1587 1588 return ttype 1589endfunction 1590 1591" Tlist_Extract_Tag_Prototype 1592" Extract the tag protoype from the tag text 1593function! s:Tlist_Extract_Tag_Prototype(tag_txt) 1594 let start = stridx(a:tag_txt, '/^') + 2 1595 let end = strridx(a:tag_txt, '/;"' . "\t") 1596 " The search patterns for some tag types doesn't end with 1597 " the ;" character 1598 if a:tag_txt[end - 1] == '$' 1599 let end = end -1 1600 endif 1601 let tag_pat = strpart(a:tag_txt, start, end - start) 1602 1603 " Remove all the leading space characters 1604 let tag_pat = substitute(tag_pat, '\s*', '', '') 1605 1606 return tag_pat 1607endfunction 1608 1609" Tlist_Extract_Tag_Scope 1610" Extract the tag scope from the tag text 1611function! s:Tlist_Extract_Tag_Scope(tag_txt) 1612 let start = strridx(a:tag_txt, 'line:') 1613 let end = strridx(a:tag_txt, "\t") 1614 if end <= start 1615 return '' 1616 endif 1617 1618 let tag_scope = strpart(a:tag_txt, end + 1) 1619 let tag_scope = strpart(tag_scope, stridx(tag_scope, ':') + 1) 1620 1621 return tag_scope 1622endfunction 1623 1624" Tlist_Refresh() 1625" Refresh the taglist 1626function! s:Tlist_Refresh() 1627 " If we are entering the buffer from one of the taglist functions, then 1628 " no need to refresh the taglist window again. 1629 if s:Tlist_Skip_Refresh || (s:tlist_app_name == "winmanager") 1630 return 1631 endif 1632 1633 " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help 1634 if &buftype != '' 1635 return 1636 endif 1637 1638 let filename = fnamemodify(bufname('%'), ':p') 1639 let ftype = &filetype 1640 1641 " If the file doesn't support tag listing, skip it 1642 if s:Tlist_Skip_File(filename, ftype) 1643 return 1644 endif 1645 1646 let curline = line('.') 1647 1648 " Make sure the taglist window is open. Otherwise, no need to refresh 1649 let winnum = bufwinnr(g:TagList_title) 1650 if winnum == -1 1651 if g:Tlist_Process_File_Always 1652 call Tlist_Update_File_Tags(filename, ftype) 1653 endif 1654 return 1655 endif 1656 1657 let fidx = s:Tlist_Get_File_Index(filename) 1658 if fidx != -1 1659 let mtime = getftime(filename) 1660 if s:tlist_{fidx}_mtime != mtime 1661 " Invalidate the tags listed for this file 1662 let s:tlist_{fidx}_valid = 0 1663 1664 " Update the taglist window 1665 call Tlist_Update_File_Tags(s:tlist_{fidx}_filename, 1666 \ s:tlist_{fidx}_filetype) 1667 1668 " Store the new file modification time 1669 let s:tlist_{fidx}_mtime = mtime 1670 endif 1671 1672 " If the tag listing for the current window is already present, no 1673 " need to refresh it 1674 if !g:Tlist_Auto_Highlight_Tag 1675 return 1676 endif 1677 1678 " Highlight the current tag 1679 call s:Tlist_Highlight_Tag(filename, curline, 1) 1680 1681 return 1682 endif 1683 1684 " Save the current window number 1685 let cur_winnr = winnr() 1686 1687 " Goto the taglist window 1688 call s:Tlist_Open_Window() 1689 1690 if !g:Tlist_Auto_Highlight_Tag 1691 " Save the cursor position 1692 let save_line = line('.') 1693 let save_col = col('.') 1694 endif 1695 1696 " Update the taglist window 1697 call s:Tlist_Explore_File(filename, ftype) 1698 1699 " Highlight the current tag 1700 call s:Tlist_Highlight_Tag(filename, curline, 1) 1701 1702 if !g:Tlist_Auto_Highlight_Tag 1703 " Restore the cursor position 1704 call cursor(save_line, save_col) 1705 endif 1706 1707 " Refresh the taglist window 1708 redraw 1709 1710 if s:tlist_app_name != "winmanager" 1711 " Jump back to the original window 1712 exe cur_winnr . 'wincmd w' 1713 endif 1714endfunction 1715 1716" Tlist_Change_Sort() 1717" Change the sort order of the tag listing 1718function! s:Tlist_Change_Sort() 1719 let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) 1720 if fidx == -1 1721 return 1722 endif 1723 1724 " Remove the previous highlighting 1725 match none 1726 1727 let sort_type = s:tlist_{fidx}_sort_type 1728 1729 " Toggle the sort order from 'name' to 'order' and vice versa 1730 if sort_type == 'name' 1731 let s:tlist_{fidx}_sort_type = 'order' 1732 else 1733 let s:tlist_{fidx}_sort_type = 'name' 1734 endif 1735 1736 " Save the current line for later restoration 1737 let curline = '\V\^' . getline('.') . '\$' 1738 1739 " Invalidate the tags listed for this file 1740 let s:tlist_{fidx}_valid = 0 1741 1742 call s:Tlist_Explore_File(s:tlist_{fidx}_filename, s:tlist_{fidx}_filetype) 1743 1744 " Go back to the cursor line before the tag list is sorted 1745 call search(curline, 'w') 1746endfunction 1747 1748" Tlist_Update_Tags() 1749" Update taglist for the current buffer by regenerating the tag list 1750" Contributed by WEN Guopeng. 1751function! s:Tlist_Update_Tags() 1752 if winnr() == bufwinnr(g:TagList_title) 1753 " In the taglist window. Update the current file 1754 call s:Tlist_Update_Window() 1755 return 1756 else 1757 " Not in the taglist window. Update the current buffer 1758 let filename = fnamemodify(bufname('%'), ':p') 1759 let fidx = s:Tlist_Get_File_Index(filename) 1760 if fidx != -1 1761 let s:tlist_{fidx}_valid = 0 1762 endif 1763 call Tlist_Update_File_Tags(filename, &filetype) 1764 endif 1765endfunction 1766 1767" Tlist_Update_Window() 1768" Update the window by regenerating the tag list 1769function! s:Tlist_Update_Window() 1770 let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) 1771 if fidx == -1 1772 return 1773 endif 1774 1775 " Remove the previous highlighting 1776 match none 1777 1778 " Save the current line for later restoration 1779 let curline = '\V\^' . getline('.') . '\$' 1780 1781 let s:tlist_{fidx}_valid = 0 1782 1783 " Update the taglist window 1784 call s:Tlist_Explore_File(s:tlist_{fidx}_filename, s:tlist_{fidx}_filetype) 1785 1786 " Go back to the tag line before the list is updated 1787 call search(curline, 'w') 1788endfunction 1789 1790" Tlist_Get_Tag_Index() 1791" Return the tag index for the current line 1792function! s:Tlist_Get_Tag_Index(fidx) 1793 let lnum = line('.') 1794 let ftype = s:tlist_{a:fidx}_filetype 1795 1796 " Determine to which tag type the current line number belongs to using the 1797 " tag type start line number and the number of tags in a tag type 1798 let i = 1 1799 while i <= s:tlist_{ftype}_count 1800 let ttype = s:tlist_{ftype}_{i}_name 1801 let start_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_start 1802 let end = start_lnum + s:tlist_{a:fidx}_{ttype}_count 1803 if lnum >= start_lnum && lnum <= end 1804 break 1805 endif 1806 let i = i + 1 1807 endwhile 1808 1809 " Current line doesn't belong to any of the displayed tag types 1810 if i > s:tlist_{ftype}_count 1811 return 0 1812 endif 1813 1814 " Compute the index into the displayed tags for the tag type 1815 let tidx = lnum - start_lnum 1816 if tidx == 0 1817 return 0 1818 endif 1819 1820 " Get the corresponding tag line and return it 1821 return s:tlist_{a:fidx}_{ttype}_{tidx} 1822endfunction 1823 1824" Tlist_Highlight_Tagline 1825" Higlight the current tagline 1826function! s:Tlist_Highlight_Tagline() 1827 " Clear previously selected name 1828 match none 1829 1830 " Highlight the current selected name 1831 if g:Tlist_Display_Prototype == 0 1832 exe 'match TagListTagName /\%' . line('.') . 'l\s\+\zs.*/' 1833 else 1834 exe 'match TagListTagName /\%' . line('.') . 'l.*/' 1835 endif 1836endfunction 1837 1838" Tlist_Jump_To_Tag() 1839" Jump to the location of the current tag 1840" win_ctrl == 0 - Reuse the existing file window 1841" win_ctrl == 1 - Open a new window 1842" win_ctrl == 2 - Preview the tag 1843function! s:Tlist_Jump_To_Tag(win_ctrl) 1844 " Do not process comment lines and empty lines 1845 let curline = getline('.') 1846 if curline =~ '^\s*$' || curline[0] == '"' 1847 return 1848 endif 1849 1850 " If inside a fold, then don't try to jump to the tag 1851 if foldclosed('.') != -1 1852 return 1853 endif 1854 1855 let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) 1856 if fidx == -1 1857 return 1858 endif 1859 1860 " Get the tag output for the current tag 1861 let tidx = s:Tlist_Get_Tag_Index(fidx) 1862 if tidx != 0 1863 let mtxt = s:tlist_{fidx}_tag_{tidx} 1864 let start = stridx(mtxt, '/^') + 2 1865 let end = strridx(mtxt, '/;"' . "\t") 1866 if mtxt[end - 1] == '$' 1867 let end = end - 1 1868 endif 1869 let tagpat = '\V\^' . strpart(mtxt, start, end - start) . 1870 \ (mtxt[end] == '$' ? '\$' : '') 1871 1872 " Highlight the tagline 1873 call s:Tlist_Highlight_Tagline() 1874 else 1875 " Selected a line which is not a tag name. Just edit the file 1876 let tagpat = '' 1877 endif 1878 1879 call s:Tlist_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat) 1880endfunction 1881 1882" Tlist_Open_File 1883" Open the specified file in either a new window or an existing window 1884" and place the cursor at the specified tag pattern 1885function! s:Tlist_Open_File(win_ctrl, filename, tagpat) 1886 let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh 1887 let s:Tlist_Skip_Refresh = 1 1888 1889 if s:tlist_app_name == "winmanager" 1890 " Let the winmanager edit the file 1891 call WinManagerFileEdit(a:filename, a:win_ctrl) 1892 else 1893 " Goto the window containing the file. If the window is not there, open a 1894 " new window 1895 let winnum = bufwinnr(a:filename) 1896 if winnum == -1 1897 " Locate the previously used window for opening a file 1898 let fwin_num = 0 1899 1900 let i = 1 1901 while winbufnr(i) != -1 1902 if getwinvar(i, 'tlist_file_window') == "yes" 1903 let fwin_num = i 1904 break 1905 endif 1906 let i = i + 1 1907 endwhile 1908 1909 if fwin_num != 0 1910 " Jump to the file window 1911 exe fwin_num . "wincmd w" 1912 1913 " If the user asked to jump to the tag in a new window, then split 1914 " the existing window into two. 1915 if a:win_ctrl == 1 1916 split 1917 endif 1918 exe "edit " . a:filename 1919 else 1920 " Open a new window 1921 if g:Tlist_Use_Horiz_Window 1922 exe 'leftabove split #' . bufnr(a:filename) 1923 " Go to the taglist window to change the window size to the user 1924 " configured value 1925 wincmd p 1926 exe 'resize ' . g:Tlist_WinHeight 1927 " Go back to the file window 1928 wincmd p 1929 else 1930 " Open the file in a window and skip refreshing the taglist 1931 " window 1932 exe 'rightbelow vertical split #' . bufnr(a:filename) 1933 " Go to the taglist window to change the window size to the user 1934 " configured value 1935 wincmd p 1936 exe 'vertical resize ' . g:Tlist_WinWidth 1937 " Go back to the file window 1938 wincmd p 1939 endif 1940 let w:tlist_file_window = "yes" 1941 endif 1942 else 1943 exe winnum . 'wincmd w' 1944 1945 " If the user asked to jump to the tag in a new window, then split the 1946 " existing window into two. 1947 if a:win_ctrl == 1 1948 split 1949 endif 1950 endif 1951 endif 1952 1953 " Jump to the tag 1954 if a:tagpat != '' 1955 silent call search(a:tagpat, 'w') 1956 endif 1957 1958 " Bring the line to the middle of the window 1959 normal! z. 1960 1961 " If the line is inside a fold, open the fold 1962 if has('folding') 1963 if foldlevel('.') != 0 1964 normal! zv 1965 endif 1966 endif 1967 1968 " If the user selects to preview the tag then jump back to the 1969 " taglist window 1970 if a:win_ctrl == 2 1971 " Go back to the taglist window 1972 let winnum = bufwinnr(g:TagList_title) 1973 exe winnum . 'wincmd w' 1974 endif 1975 1976 let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh 1977endfunction 1978 1979" Tlist_Show_Tag_Prototype() 1980" Display the prototype of the tag under the cursor 1981function! s:Tlist_Show_Tag_Prototype() 1982 " If we have already display prototype in the tag window, no need to 1983 " display it in the status line 1984 if g:Tlist_Display_Prototype 1985 return 1986 endif 1987 1988 " Clear the previously displayed line 1989 echo 1990 1991 " Do not process comment lines and empty lines 1992 let curline = getline('.') 1993 if curline =~ '^\s*$' || curline[0] == '"' 1994 return 1995 endif 1996 1997 " If inside a fold, then don't display the prototype 1998 if foldclosed('.') != -1 1999 return 2000 endif 2001 2002 " Get the file index 2003 let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) 2004 if fidx == -1 2005 return 2006 endif 2007 2008 " Get the tag output line for the current tag 2009 let tidx = s:Tlist_Get_Tag_Index(fidx) 2010 if tidx == 0 2011 return 2012 endif 2013 2014 let mtxt = s:tlist_{fidx}_tag_{tidx} 2015 2016 " Get the tag search pattern and display it 2017 echo s:Tlist_Extract_Tag_Prototype(mtxt) 2018endfunction 2019 2020" Tlist_Find_Tag_text 2021" Find the tag text given the line number in the source window 2022function! s:Tlist_Find_Tag_text(fidx, linenum) 2023 let sort_type = s:tlist_{a:fidx}_sort_type 2024 2025 let left = 1 2026 let right = s:tlist_{a:fidx}_tag_count 2027 2028 if sort_type == 'order' 2029 " Tag list sorted by order, do a binary search comparing the line 2030 " numbers and pick a tag entry that contains the current line and 2031 " highlight it. The idea behind this function is taken from the 2032 " ctags.vim script (by Alexey Marinichev) available at the Vim online 2033 " website. 2034 2035 " If the current line is the less than the first tag, then no need to 2036 " search 2037 let txt = s:tlist_{a:fidx}_tag_1 2038 let start = strridx(txt, 'line:') + strlen('line:') 2039 let end = strridx(txt, "\t") 2040 if end < start 2041 let first_lnum = strpart(txt, start) + 0 2042 else 2043 let first_lnum = strpart(txt, start, end - start) + 0 2044 endif 2045 2046 if a:linenum < first_lnum 2047 return "" 2048 endif 2049 2050 while left < right 2051 let middle = (right + left + 1) / 2 2052 let txt = s:tlist_{a:fidx}_tag_{middle} 2053 2054 let start = strridx(txt, 'line:') + strlen('line:') 2055 let end = strridx(txt, "\t") 2056 if end < start 2057 let middle_lnum = strpart(txt, start) + 0 2058 else 2059 let middle_lnum = strpart(txt, start, end - start) + 0 2060 endif 2061 2062 if middle_lnum == a:linenum 2063 let left = middle 2064 break 2065 endif 2066 2067 if middle_lnum > a:linenum 2068 let right = middle - 1 2069 else 2070 let left = middle 2071 endif 2072 endwhile 2073 else 2074 " sorted by name, brute force method (Dave Eggum) 2075 let closest_lnum = 0 2076 let final_left = 0 2077 while left < right 2078 let txt = s:tlist_{a:fidx}_tag_{left} 2079 2080 let start = strridx(txt, 'line:') + strlen('line:') 2081 let end = strridx(txt, "\t") 2082 if end < start 2083 let lnum = strpart(txt, start) + 0 2084 else 2085 let lnum = strpart(txt, start, end - start) + 0 2086 endif 2087 2088 if lnum < a:linenum && lnum > closest_lnum 2089 let closest_lnum = lnum 2090 let final_left = left 2091 elseif lnum == a:linenum 2092 let closest_lnum = lnum 2093 break 2094 else 2095 let left = left + 1 2096 endif 2097 endwhile 2098 if closest_lnum == 0 2099 return "" 2100 endif 2101 if left == right 2102 let left = final_left 2103 endif 2104 endif 2105 2106 return s:tlist_{a:fidx}_tag_{left} 2107endfunction 2108 2109" Tlist_Highlight_Tag() 2110" Highlight the current tag 2111" cntx == 1, Called by the taglist plugin itself 2112" cntx == 2, Forced by the user through the TlistSync command 2113function! s:Tlist_Highlight_Tag(filename, curline, cntx) 2114 " Highlight the current tag only if the user configured the 2115 " taglist plugin to do so or if the user explictly invoked the 2116 " command to highlight the current tag. 2117 if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1 2118 return 2119 endif 2120 2121 if a:filename == '' 2122 return 2123 endif 2124 2125 " Make sure the taglist window is present 2126 let winnum = bufwinnr(g:TagList_title) 2127 if winnum == -1 2128 call s:Tlist_Warning_Msg('Error: Taglist window is not open') 2129 return 2130 endif 2131 2132 let fidx = s:Tlist_Get_File_Index(a:filename) 2133 if fidx == -1 2134 return 2135 endif 2136 2137 " If there are no tags for this file, then no need to proceed further 2138 if s:tlist_{fidx}_tag_count == 0 2139 return 2140 endif 2141 2142 " If part of winmanager then disable winmanager autocommands 2143 if s:tlist_app_name == "winmanager" 2144 call WinManagerSuspendAUs() 2145 endif 2146 2147 " Save the original window number 2148 let org_winnr = winnr() 2149 2150 if org_winnr == winnum 2151 let in_taglist_window = 1 2152 else 2153 let in_taglist_window = 0 2154 endif 2155 2156 " Go to the taglist window 2157 if !in_taglist_window 2158 exe winnum . 'wincmd w' 2159 endif 2160 2161 " Clear previously selected name 2162 match none 2163 2164 let tag_txt = s:Tlist_Find_Tag_text(fidx, a:curline) 2165 if tag_txt == "" 2166 " Make sure the current tag line is visible in the taglist window. 2167 " Calling the winline() function makes the line visible. Don't know 2168 " of a better way to achieve this. 2169 let cur_lnum = line('.') 2170 2171 if cur_lnum < s:tlist_{fidx}_start || cur_lnum > s:tlist_{fidx}_end 2172 " Move the cursor to the beginning of the file 2173 exe s:tlist_{fidx}_start 2174 endif 2175 2176 if has('folding') 2177 normal! zv 2178 endif 2179 2180 call winline() 2181 2182 if !in_taglist_window 2183 let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh 2184 let s:Tlist_Skip_Refresh = 1 2185 exe org_winnr . 'wincmd w' 2186 let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh 2187 endif 2188 if s:tlist_app_name == "winmanager" 2189 call WinManagerResumeAUs() 2190 endif 2191 return 2192 endif 2193 2194 " Extract the tag type 2195 let ttype = s:Tlist_Extract_Tagtype(tag_txt) 2196 2197 " Extract the tag offset 2198 let offset = strpart(tag_txt, 0, stridx(tag_txt, ':')) + 0 2199 2200 " Compute the line number 2201 let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_start + offset 2202 2203 " Goto the line containing the tag 2204 exe lnum 2205 2206 " Open the fold 2207 if has('folding') 2208 normal! zv 2209 endif 2210 2211 " Make sure the current tag line is visible in the taglist window. 2212 " Calling the winline() function makes the line visible. Don't know 2213 " of a better way to achieve this. 2214 call winline() 2215 2216 " Highlight the tag name 2217 call s:Tlist_Highlight_Tagline() 2218 2219 " Go back to the original window 2220 if !in_taglist_window 2221 let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh 2222 let s:Tlist_Skip_Refresh = 1 2223 exe org_winnr . 'wincmd w' 2224 let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh 2225 endif 2226 2227 if s:tlist_app_name == "winmanager" 2228 call WinManagerResumeAUs() 2229 endif 2230 2231 return 2232endfunction 2233 2234" Tlist_Get_Tag_Prototype_By_Line 2235" Get the prototype for the tag on or before the specified line number in the 2236" current buffer 2237function! Tlist_Get_Tag_Prototype_By_Line(...) 2238 if a:0 == 0 2239 " Arguments are not supplied. Use the current buffer name 2240 " and line number 2241 let filename = bufname('%') 2242 let linenr = line('.') 2243 elseif a:0 == 2 2244 " Filename and line number are specified 2245 let filename = a:1 2246 let linenr = a:2 2247 if linenr !~ '\d\+' 2248 " Invalid line number 2249 return "" 2250 endif 2251 else 2252 " Sufficient arguments are not supplied 2253 let msg = 'Usage: Tlist_Get_Tag_Prototype_By_Line <filename> ' . 2254 \ '<line_number>' 2255 call s:Tlist_Warning_Msg(msg) 2256 return "" 2257 endif 2258 2259 " Expand the file to a fully qualified name 2260 let filename = fnamemodify(filename, ':p') 2261 if filename == '' 2262 return "" 2263 endif 2264 2265 let fidx = s:Tlist_Get_File_Index(filename) 2266 if fidx == -1 2267 return "" 2268 endif 2269 2270 " If there are no tags for this file, then no need to proceed further 2271 if s:tlist_{fidx}_tag_count == 0 2272 return "" 2273 endif 2274 2275 " Get the tag text using the line number 2276 let tag_txt = s:Tlist_Find_Tag_text(fidx, linenr) 2277 if tag_txt == "" 2278 return "" 2279 endif 2280 2281 " Extract the tag search pattern and return it 2282 return s:Tlist_Extract_Tag_Prototype(tag_txt) 2283endfunction 2284 2285" Tlist_Get_Tagname_By_Line 2286" Get the tag name on or before the specified line number in the 2287" current buffer 2288function! Tlist_Get_Tagname_By_Line(...) 2289 if a:0 == 0 2290 " Arguments are not supplied. Use the current buffer name 2291 " and line number 2292 let filename = bufname('%') 2293 let linenr = line('.') 2294 elseif a:0 == 2 2295 " Filename and line number are specified 2296 let filename = a:1 2297 let linenr = a:2 2298 if linenr !~ '\d\+' 2299 " Invalid line number 2300 return "" 2301 endif 2302 else 2303 " Sufficient arguments are not supplied 2304 let msg = 'Usage: Tlist_Get_Tagname_By_Line <filename> <line_number>' 2305 call s:Tlist_Warning_Msg(msg) 2306 return "" 2307 endif 2308 2309 " Make sure the current file has a name 2310 let filename = fnamemodify(filename, ':p') 2311 if filename == '' 2312 return "" 2313 endif 2314 2315 let fidx = s:Tlist_Get_File_Index(filename) 2316 if fidx == -1 2317 return "" 2318 endif 2319 2320 " If there are no tags for this file, then no need to proceed further 2321 if s:tlist_{fidx}_tag_count == 0 2322 return "" 2323 endif 2324 2325 " Get the tag name using the line number 2326 let tag_txt = s:Tlist_Find_Tag_text(fidx, linenr) 2327 if tag_txt == "" 2328 return "" 2329 endif 2330 2331 " Remove the line number at the beginning 2332 let start = stridx(tag_txt, ':') + 1 2333 2334 " Extract the tag name and return it 2335 return strpart(tag_txt, start, stridx(tag_txt, "\t") - start) 2336endfunction 2337 2338" Tlist_Move_To_File 2339" Move the cursor to the beginning of the current file or the next file 2340" or the previous file in the taglist window 2341" dir == -1, move to start of current or previous function 2342" dir == 1, move to start of next function 2343function! s:Tlist_Move_To_File(dir) 2344 if foldlevel('.') == 0 2345 " Cursor is on a non-folded line (it is not in any of the files) 2346 " Move it to a folded line 2347 if a:dir == -1 2348 normal! zk 2349 else 2350 " While moving down to the start of the next fold, 2351 " no need to do go to the start of the next file. 2352 normal! zj 2353 return 2354 endif 2355 endif 2356 2357 let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) 2358 if fidx == -1 2359 return 2360 endif 2361 2362 let cur_lnum = line('.') 2363 2364 if a:dir == -1 2365 if cur_lnum > s:tlist_{fidx}_start 2366 " Move to the beginning of the current file 2367 exe s:tlist_{fidx}_start 2368 return 2369 endif 2370 2371 if fidx == 0 2372 " At the first file, can't move to previous file 2373 return 2374 endif 2375 2376 " Otherwise, move to the beginning of the previous file 2377 let fidx = fidx - 1 2378 exe s:tlist_{fidx}_start 2379 return 2380 else 2381 let fidx = fidx + 1 2382 2383 if fidx == s:tlist_file_count 2384 " At the last file, can't move to the next file 2385 return 2386 endif 2387 2388 " Otherwise, move to the beginning of the next file 2389 exe s:tlist_{fidx}_start 2390 return 2391 endif 2392endfunction 2393 2394" Tlist_Session_Load 2395" Load a taglist session (information about all the displayed files 2396" and the tags) from the specified file 2397function! s:Tlist_Session_Load(...) 2398 if a:0 == 0 || a:1 == '' 2399 call s:Tlist_Warning_Msg('Usage: TlistSessionLoad <filename>') 2400 return 2401 endif 2402 2403 let sessionfile = a:1 2404 2405 if !filereadable(sessionfile) 2406 let msg = 'Taglist: Error - Unable to open file ' . sessionfile 2407 call s:Tlist_Warning_Msg(msg) 2408 return 2409 endif 2410 2411 " Mark the current window as the file window 2412 if bufname('%') !~ g:TagList_title 2413 let w:tlist_file_window = "yes" 2414 endif 2415 2416 " Open to the taglist window 2417 call s:Tlist_Open_Window() 2418 2419 " Source the session file 2420 exe 'source ' . sessionfile 2421 2422 let new_file_count = g:tlist_file_count 2423 unlet! g:tlist_file_count 2424 2425 let i = 0 2426 while i < new_file_count 2427 let ftype = g:tlist_{i}_filetype 2428 unlet! g:tlist_{i}_filetype 2429 2430 if !exists("s:tlist_" . ftype . "_count") 2431 if s:Tlist_FileType_Init(ftype) == 0 2432 let i = i + 1 2433 continue 2434 endif 2435 endif 2436 2437 let fname = g:tlist_{i}_filename 2438 unlet! g:tlist_{i}_filename 2439 2440 let fidx = s:Tlist_Get_File_Index(fname) 2441 if fidx != -1 2442 let s:tlist_{fidx}_visible = 0 2443 let i = i + 1 2444 continue 2445 endif 2446 2447 let fidx = s:Tlist_Init_File(fname, ftype) 2448 2449 let s:tlist_{fidx}_filename = fname 2450 2451 let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type 2452 unlet! g:tlist_{i}_sort_type 2453 2454 let s:tlist_{fidx}_filetype = ftype 2455 let s:tlist_{fidx}_mtime = getftime(fname) 2456 2457 let s:tlist_{fidx}_start = 0 2458 let s:tlist_{fidx}_end = 0 2459 2460 let s:tlist_{fidx}_valid = 1 2461 " Mark the file as not visible, so that Tlist_Init_Window() function 2462 " will display the tags for this file 2463 let s:tlist_{fidx}_visible = 0 2464 2465 let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count 2466 unlet! g:tlist_{i}_tag_count 2467 2468 let j = 1 2469 while j <= s:tlist_{fidx}_tag_count 2470 let s:tlist_{fidx}_tag_{j} = g:tlist_{i}_tag_{j} 2471 unlet! g:tlist_{i}_tag_{j} 2472 let j = j + 1 2473 endwhile 2474 2475 let j = 1 2476 while j <= s:tlist_{ftype}_count 2477 let ttype = s:tlist_{ftype}_{j}_name 2478 2479 if exists('g:tlist_' . i . '_' . ttype) 2480 let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype} 2481 unlet! g:tlist_{i}_{ttype} 2482 let s:tlist_{fidx}_{ttype}_start = 0 2483 let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count 2484 unlet! g:tlist_{i}_{ttype}_count 2485 2486 let k = 1 2487 while k <= s:tlist_{fidx}_{ttype}_count 2488 let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k} 2489 unlet! g:tlist_{i}_{ttype}_{k} 2490 let k = k + 1 2491 endwhile 2492 else 2493 let s:tlist_{fidx}_{ttype} = '' 2494 let s:tlist_{fidx}_{ttype}_start = 0 2495 let s:tlist_{fidx}_{ttype}_count = 0 2496 endif 2497 2498 let j = j + 1 2499 endwhile 2500 2501 let i = i + 1 2502 endwhile 2503 2504 " Initialize the taglist window 2505 call s:Tlist_Init_Window() 2506 call s:Tlist_Refresh_Window() 2507 2508 if s:tlist_file_count > 0 2509 " Jump to the beginning of the first file 2510 call cursor(s:tlist_0_start, 1) 2511 endif 2512endfunction 2513 2514" Tlist_Session_Save 2515" Save a taglist session (information about all the displayed files 2516" and the tags) into the specified file 2517function! s:Tlist_Session_Save(...) 2518 if a:0 == 0 || a:1 == '' 2519 call s:Tlist_Warning_Msg('Usage: TlistSessionSave <filename>') 2520 return 2521 endif 2522 2523 let sessionfile = a:1 2524 2525 if s:tlist_file_count == 0 2526 " There is nothing to save 2527 call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.') 2528 return 2529 endif 2530 2531 if filereadable(sessionfile) 2532 let ans = input("Do you want to overwrite " . sessionfile . " (Y/N)?") 2533 if ans !=? 'y' 2534 return 2535 endif 2536 2537 echo "\n" 2538 endif 2539 2540 exe 'redir! > ' . sessionfile 2541 2542 silent! echo '" Taglist session file. This file is auto-generated.' 2543 silent! echo '" File information' 2544 silent! echo 'let tlist_file_count = ' . s:tlist_file_count 2545 2546 let i = 0 2547 2548 while i < s:tlist_file_count 2549 " Store information about the file 2550 silent! echo 'let tlist_' . i . "_filename = '" . 2551 \ s:tlist_{i}_filename . "'" 2552 silent! echo 'let tlist_' . i . '_sort_type = "' . 2553 \ s:tlist_{i}_sort_type . '"' 2554 silent! echo 'let tlist_' . i . '_filetype = "' . 2555 \ s:tlist_{i}_filetype . '"' 2556 silent! echo 'let tlist_' . i . '_tag_count = ' . 2557 \ s:tlist_{i}_tag_count 2558 " Store information about all the tags 2559 let j = 1 2560 while j <= s:tlist_{i}_tag_count 2561 let txt = escape(s:tlist_{i}_tag_{j}, '"\\') 2562 silent! echo 'let tlist_' . i . '_tag_' . j . ' = "' . txt . '"' 2563 let j = j + 1 2564 endwhile 2565 2566 " Store information about all the tags grouped by their type 2567 let ftype = s:tlist_{i}_filetype 2568 let j = 1 2569 while j <= s:tlist_{ftype}_count 2570 let ttype = s:tlist_{ftype}_{j}_name 2571 if s:tlist_{i}_{ttype}_count != 0 2572 let txt = substitute(s:tlist_{i}_{ttype}, "\n", "\\\\n", "g") 2573 silent! echo 'let tlist_' . i . '_' . ttype . ' = "' . 2574 \ txt . '"' 2575 silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' . 2576 \ s:tlist_{i}_{ttype}_count 2577 let k = 1 2578 while k <= s:tlist_{i}_{ttype}_count 2579 silent! echo 'let tlist_' . i . '_' . ttype . '_' . k . 2580 \ ' = ' . s:tlist_{i}_{ttype}_{k} 2581 let k = k + 1 2582 endwhile 2583 endif 2584 let j = j + 1 2585 endwhile 2586 2587 silent! echo 2588 2589 let i = i + 1 2590 endwhile 2591 2592 redir END 2593endfunction 2594 2595" Tlist_Update_File_Display 2596" Update a file displayed in the taglist window. 2597" action == 1, Close the fold for the file 2598" action == 2, Remove the file from the taglist window 2599function! s:Tlist_Update_File_Display(filename, action) 2600 " Make sure a valid filename is supplied 2601 if a:filename == '' 2602 return 2603 endif 2604 2605 " Make sure the taglist window is present 2606 let winnum = bufwinnr(g:TagList_title) 2607 if winnum == -1 2608 call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open') 2609 return 2610 endif 2611 2612 " Save the original window number 2613 let org_winnr = winnr() 2614 if org_winnr == winnum 2615 let in_taglist_window = 1 2616 else 2617 let in_taglist_window = 0 2618 endif 2619 2620 " Go to the taglist window 2621 if !in_taglist_window 2622 exe winnum . 'wincmd w' 2623 endif 2624 2625 " Get tag list index of the specified file 2626 let idx = s:Tlist_Get_File_Index(a:filename) 2627 if idx != -1 2628 " Save the cursor position 2629 let save_lnum = line('.') 2630 2631 " Perform the requested action on the file 2632 if a:action == 1 2633 " Close the fold for the file 2634 2635 if g:Tlist_File_Fold_Auto_Close 2636 " Close the fold for the file 2637 if has('folding') 2638 exe "silent! " . s:tlist_{idx}_start . "," . 2639 \ s:tlist_{idx}_end . "foldclose" 2640 endif 2641 endif 2642 elseif a:action == 2 2643 " Remove the file from the list 2644 call s:Tlist_Remove_File(idx) 2645 endif 2646 2647 " Move the cursor to the original location 2648 exe save_lnum 2649 endif 2650 2651 " Go back to the original window 2652 if !in_taglist_window 2653 let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh 2654 let s:Tlist_Skip_Refresh = 1 2655 exe org_winnr . 'wincmd w' 2656 let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh 2657 endif 2658endfunction 2659 2660" Define the taglist autocommand to automatically open the taglist window on 2661" Vim startup 2662if g:Tlist_Auto_Open 2663 autocmd VimEnter * nested Tlist 2664endif 2665 2666" Refresh the taglist 2667if g:Tlist_Process_File_Always 2668 autocmd BufEnter * call <SID>Tlist_Refresh() 2669endif 2670 2671" Define the user commands to manage the taglist window 2672command! -nargs=0 Tlist call s:Tlist_Toggle_Window() 2673command! -nargs=0 TlistClose call s:Tlist_Close_Window() 2674command! -nargs=0 TlistUpdate call s:Tlist_Update_Tags() 2675command! -nargs=0 TlistSync call s:Tlist_Highlight_Tag( 2676 \ fnamemodify(bufname('%'), ':p'), line('.'), 2) 2677command! -nargs=* -complete=buffer TlistShowPrototype 2678 \ echo Tlist_Get_Tag_Prototype_By_Line(<f-args>) 2679command! -nargs=* -complete=buffer TlistShowTag 2680 \ echo Tlist_Get_Tagname_By_Line(<f-args>) 2681command! -nargs=* -complete=file TlistSessionLoad 2682 \ call s:Tlist_Session_Load(<q-args>) 2683command! -nargs=* -complete=file TlistSessionSave 2684 \ call s:Tlist_Session_Save(<q-args>) 2685 2686" Tlist_Set_App 2687" Set the name of the external plugin/application to which taglist 2688" belongs. 2689" Taglist plugin is part of another plugin like cream or winmanager. 2690function! Tlist_Set_App(name) 2691 if a:name == "" 2692 return 2693 endif 2694 2695 let s:tlist_app_name = a:name 2696endfunction 2697 2698" Winmanager integration 2699 2700" Initialization required for integration with winmanager 2701function! TagList_Start() 2702 " If current buffer is not taglist buffer, then don't proceed 2703 if bufname('%') != '__Tag_List__' 2704 return 2705 endif 2706 2707 call Tlist_Set_App("winmanager") 2708 2709 " Get the current filename from the winmanager plugin 2710 let bufnum = WinManagerGetLastEditedFile() 2711 if bufnum != -1 2712 let filename = fnamemodify(bufname(bufnum), ':p') 2713 let ftype = getbufvar(bufnum, '&filetype') 2714 endif 2715 2716 " Initialize the taglist window, if it is not already initialized 2717 if !exists("s:tlist_window_initialized") || !s:tlist_window_initialized 2718 call s:Tlist_Init_Window() 2719 call s:Tlist_Refresh_Window() 2720 let s:tlist_window_initialized = 1 2721 endif 2722 2723 " Open the taglist window 2724 if bufnum != -1 2725 call s:Tlist_Explore_File(filename, ftype) 2726 endif 2727endfunction 2728 2729function! TagList_IsValid() 2730 return 0 2731endfunction 2732 2733function! TagList_WrapUp() 2734 return 0 2735endfunction 2736