cscope/cscope-15.7a-add-cctree.patch

3944 lines
129 KiB
Diff
Raw Normal View History

2011-05-26 20:01:23 +00:00
diff -up /dev/null cscope-15.7a/contrib/cctree.txt
--- /dev/null 2011-05-25 12:40:15.391845002 -0400
+++ cscope-15.7a/contrib/cctree.txt 2011-05-26 14:45:02.905838546 -0400
@@ -0,0 +1,537 @@
+*CCTree.txt* Plugin for C Call-Tree Explorer *CCTree*
+
+Author: Hari Rangarajan (First.Last AT gmail DOT com)
+Last Change: 20 May 2011
+
+CCTree version 1.51
+
+For Vim version 7.0 and above
+
+==============================================================================
+
+1. Overview |CCTree-overview|
+2. Downloads |CCTree-download|
+3. Installation |CCTree-installation|
+4. Configuration |CCTree-configuration|
+5. Features |CCTree-features|
+6. Limitations |CCTree-limitations|
+7. FAQ & TIPS |CCTree-faq|
+8. History |CCTree-history|
+9. Thanks |CCTree-thanks|
+
+==============================================================================
+1. Overview~
+ *CCTree-overview*
+
+Plugin generates dependency-trees for symbols using a cscope database in Vim.
+Basic cross-referencing includes functions and macros. Enhanced symbol
+processing covers macros, typedefs, enums, and global variables.
+
+Requires Cscope and works best with C code.
+
+==============================================================================
+2. Downloads~
+ *CCTree-download*
+
+You can download the latest release of the script from this url :
+ http://www.vim.org/scripts/script.php?script_id=2368
+
+
+Cscope packages can be found here:
+ http://cscope.sourceforge.net/
+ http://code.google.com/p/cscope-win32/
+
+
+==============================================================================
+3. Installation~
+ *CCTree-installation*
+
+Copy this file to ~/.vim/plugins/ or to /vimfiles/plugins/ (on Win32
+platforms)
+
+It should also be possible to load it as a filetype plugin ~/.vim/ftplugin/c/
+Need to set :filetype plugin on
+
+
+==============================================================================
+CONFIGURATION *CCTree-configuration*
+4. Options~
+
+You can customize behavior by changing the following variable settings
+
+4.1.1 Cscope Symbol Database~
+ *CCTreeCscopeDb*
+
+Cscope database file, g:CCTreeCscopeDb = "cscope.out"
+
+4.1.2 Call-tree Depth~
+ *CCTreeRecursiveDepth*
+Maximum call levels, g:CCTreeRecursiveDepth = 3
+
+4.1.3 Call-tree Minimum Visible Depth~
+ *CCTreeMinVisibleDepth*
+Maximum visible(unfolded) level, g:CCTreeMinVisibleDepth = 3
+
+4.1.4 Call-tree window display~
+
+4.4.1 Orientation~
+ *CCTreeOrientation*
+Orientation of window, g:CCTreeOrientation = "leftabove"
+ (standard vim options for split: [right|left][above|below])
+
+4.5 Direction~
+ *CCTreeWindowVertical*
+Use Vertical window, g:CCTreeWindowVertical = 1
+
+4.5.1 Dimensions~
+
+These settings determine the layout of the CCTree preview window.
+
+4.5.2 Horizontal Window Settings~
+ *CCTreeWindowHeight*
+ Horizontal window, g:CCTreeWindowHeight, default is -1.
+
+4.5.2 Vertical Window Settings~
+ *CCTreeWindowMinWidth*
+ *CCTreeWindowWidth*
+ Minimum width for window, g:CCTreeWindowMinWidth = 40.
+ g:CCTreeWindowWidth = -1, auto-select best width to fit.
+
+
+4.6 Call-tree display format~
+ *CCTreeDisplayMode*
+Display format, g:CCTreeDisplayMode, default: 1
+
+Values: 1 -- Ultra-compact (takes minimum screen width)
+ 2 -- Compact (Takes little more space)
+ 3 -- Wide (Takes copious amounts of space)
+
+For vertical splits, 1 and 2 are good, while 3 is good for horizontal
+displays.
+
+4.7. Dynamic Call-tree highlighting~
+ *CCTreeHilightCallTree*
+
+Enable/disable dynamic call-tree highlighting, default: 1
+
+
+4.7.1 Syntax items~
+ *CCTreeSymbol* *CCTreeHiSymbol*
+CCTreeSymbol is the symbol name.
+CCTreeHiSymbol is the highlighted call tree functions.
+
+ *CCTreeMarkers* *CCTreeHiMarkers*
+CCTreeMarkers include "|","+--->".
+CCTreeHiMarkers is the same as CCTreeMarkers except these denote the
+highlighted call-tree.
+
+
+
+==============================================================================
+COMMAND LIST *CCTree-commands-list*
+
+Database Management~
+ CCTreeLoadDB <dbname>
+ CCTreeAppendDB <dbname>
+ CCTreeUnLoadDB
+ CCTreeShowLoadedDBs
+ Refer to |CCTree-usage|
+
+Native Xref Database~
+ CCTreeLoadXRefDB <dbname>
+ CCTreeSaveXRefDB <dbname>
+
+ Refer to |CCTree-fast-loading|
+
+Symbol tracing~
+ CCTreeTraceForward <symbolname>
+ CCTreeTraceReverse <symbolname>
+ CCTreeRecurseDepthPlus
+ CCTreeRecurseDepthMinus
+ Refer to |CCTree-explore-source|
+Trace Management~
+ CCTreeWindowSaveCopy
+ CCTreeWindowHiCallTree
+ Refer to |CCTree-preview-window|
+
+Dynamic configuration~
+ CCTreeOptsEnable <option> (<tab> for auto-complete)
+ CCTreeOptsDisable <option> (<tab> for auto-complete)
+ CCTreeOptsToggle <option> (<tab> for auto-complete)
+ Options~
+ DynamicTreeHiLights: Control dynamic tree highlighting
+ UseUnicodeSymbols: Use of UTF-8 special characters for tree
+ UseConceal: Use (+Conceal) feature instead of 'ignore'
+ syntax highlighting. Allows CCTree window
+ to be exported in HTML without syntax markup
+ characters. (Vim 7.3+ only)
+ *CCTree-Enhanced-Symbol-Processing*
+ EnhancedSymbolProcessing: Cross-reference enums, macros,
+ global variables, typedefs (WARNING: Database
+ processing speeds will be slow).
+
+SHORTCUT KEYS *CCTree-Key-Map*
+Default Mappings~
+ *CCTree-Default-Key-Map*
+ Get reverse call tree for symbol <C-\><
+ Get forward call tree for symbol <C-\>>
+ Increase depth of tree and update <C-\>=
+ Decrease depth of tree and update <C-\>-
+
+ Open symbol in other window <CR>
+ Preview symbol in other window <Ctrl-P>
+
+ Save copy of preview window <C-\>y
+ Highlight current call-tree flow <C-l>
+ Compress(Fold) call tree view zs
+ (This is useful for viewing long
+ call trees which span across
+ multiple pages)
+
+Custom user-mappings
+ *CCTree-Custom-Key-Map*
+ Users can custom-map the short-cut keys by
+ overriding the following variables in their
+ Vim start-up configuration
+>
+ let g:CCTreeKeyTraceForwardTree = '<C-\>>'
+ let g:CCTreeKeyTraceReverseTree = '<C-\><'
+ let g:CCTreeKeyHilightTree = '<C-l>' " Static highlighting
+ let g:CCTreeKeySaveWindow = '<C-\>y'
+ let g:CCTreeKeyToggleWindow = '<C-\>w'
+ let g:CCTreeKeyCompressTree = 'zs' " Compress call-tree
+ let g:CCTreeKeyDepthPlus = '<C-\>='
+ let g:CCTreeKeyDepthMinus = '<C-\>-'
+<
+
+==============================================================================
+FEATURES *CCTree-features*
+
+5.1. Symbol database~
+ *CCTree-usage*
+Build cscope database, for example:
+> cscope -b -i cscope.files
+ [Tip: add -c option to build uncompressed databases for faster
+ load speeds]
+
+Load database~
+>
+ :CCTreeLoadDB
+<
+ (Please note that it might take a while depending on the
+ database size)
+
+A database name, i.e., my_cscope.out, can be specified with the command. If
+not provided, a prompt will ask for the filename; default is cscope.out.
+
+Unload database ~
+ >
+ :CCTreeUnLoadDB
+<
+Append database~
+ >
+ :CCTreeAppendDB
+<
+ Allows multiple cscope files to be loaded and cross-referenced
+ Illustration: >
+ :CCTreeAppendDB ./cscope.out
+ :CCTreeAppendDB ./dir1/cscope.out
+ :CCTreeAppendDB ./dir2/cscope.out
+<
+ A database name, i.e., my_cscope.out, can be specified with
+ the command. If not provided, a prompt will ask for the
+ filename; default is cscope.out.
+
+FASTER DATABASE LOADING *CCTree-fast-loading*
+
+Save native Xref Db~
+>
+ :CCTreeSaveXRefDb cctree.out
+<
+This command will save the cross-referenced symbols currently loaded into
+memory into a serialized format for faster loading.
+
+Load native XRef Db~
+>
+ :CCTreeLoadXRefDb cctree.out
+<
+This command will load cross-referenced symbols from the previously saved
+native format database.
+
+ccglue~
+ *CCTree-ccglue*
+
+Check out the ccglue project at http://ccglue.sourceforge.net for an external
+tool that can build cctree-compatible xref databases.
+
+
+5.2. Exploring source-code~
+ *CCTree-explore-source*
+
+Get reverse call tree for symbol <C-\><
+>
+ :CCTreeTraceReverse <symbolname>
+<
+
+Get forward call tree for symbol <C-\>>
+>
+ :CCTreeTraceForward <symbolname>
+<
+Increase depth of tree and update <C-\>=
+>
+ :CCTreeRecurseDepthPlus
+<
+Decrease depth of tree and update <C-\>-
+>
+ :CCTreeRecurseDepthMinus
+<
+5.3. Preview Window~
+ *CCTree-preview-window*
+Open symbol in other window <CR>
+Preview symbol in other window <Ctrl-P>
+
+5.4. Syntax Coloring~
+ *CCTree-Syntax*
+CCTreeHiXXXX allows dynamic highlighting of the call-tree. To observe the
+effect, move the cursor to the function to highlight the current call-tree.
+This option can be turned off using the setting, *CCTreeHilightCallTree* .
+
+For faster highlighting, the value of 'updatetime' can be changed.
+
+5.5 Support for large database files~
+ *CCTree-LargeDatabase* *CCTree-LargeFile*
+Vimscript does not have an API for reading files line-by-line. This
+becomes a problem when parsing large databases. CCTree can overcome
+the limitation using an external utility (i.e., GNU coreutils: split)
+or VimScript's perl interpreter interface (:version must indicate +perl)
+
+5.5.1 Using GNU Coreutils (split/cat)~
+ *CCTree-Tools-split* *CCTree-Tools-cat*
+ The following settings are tailored to suit GNU coreutils split; the
+default settings should work with no changes on typical linux/unix distros.
+Monopoly OSes will require installation of unixutils or equivalent.
+
+External command is setup with the following parameters~
+>
+ let g:CCTreeSplitProgCmd =
+ 'PROG_SPLIT SPLIT_OPT SPLIT_SIZE IN_FILE OUT_FILE_PREFIX'
+<
+
+Break-down of individual parameters~
+The split utility is assumed to be on the path; otherwise, specify full path
+ g:CCTreeSplitProg = 'split'
+
+Option for splitting files (-C or -l)~
+>
+ let g:CCTreeSplitProgOption = '-C'
+<
+If split program does not support -C, then this parameter must be set to
+the number of lines in the split files
+>
+ let g:CCTreeDbFileSplitLines = -1
+<
+Largest filesize Vimscript can handle; file sizes greater than this will
+be temporarily split
+>
+ let g:CCTreeDbFileMaxSize = 40000000 (40 Mbytes)
+<
+Sample system command~
+Typical:
+>
+ split -C 40000000 inputFile outputFilePrefix
+<
+ When g:CCTreeDbFileSplitLines is set to 10000 (-C options will be ignored)
+>
+ split -l 10000 inputFile outputFilePrefix
+<
+ *CCTree-Tools-Perl*
+ *CCTree-Tools-Perl-LargeFile*
+Enabling perl interface~
+
+ By default, perl usage is disabled. Set
+>
+ let g:CCTreeUsePerl = 1
+< to enable the perl interface.
+
+ Perl interface is typically faster than native Vimscript.
+ This option can be used independent of the file size
+
+ For more info on setting up perl interface
+ :help |perl-using| or :help |perl-dynamic|
+
+5.6. Miscellaneous *CCTree-Miscellaneous*
+
+ UTF-8 usage *CCTree-UTF8-Symbols*
+ UTF-8 symbols should work fine on the majority of
+ X11 systems; however, some terminals might cause problems.
+
+ To use symbols for drawing the tree, this option can be enabled.
+>
+ let g:CCTreeUseUTF8Symbols = 1
+<
+ The options interface (CCTreeOptsxxx) can be used to
+ modify options on-the-fly.
+
+==============================================================================
+6. Limitations~
+ *CCTree-limitations*
+
+The following are known limitations:
+
+Basic Symbol Processing:
+ (1) The accuracy of the call-tree will only be as good as the cscope database
+generation. (NOTE: Different flavors of Cscope have some known limitations
+due to the lexical analysis engine. This results in incorrectly identified
+function blocks, etc.)
+
+Enhanced Symbol Processing:
+ (1) Cscope does not mark-up nameless enums correctly; hence,
+CCTree cannot recognize nameless enum symbols.
+
+
+==============================================================================
+7. FAQ~
+ *CCTree-faq*
+
++ I see strange characters "!#@" on my screen when dynamic highlighting is
+enabled. Why do I see them?
+
+Check :hi ignore. You will see something like
+hi ignore ctermfg=white guifg=bg
+
+ For console, white must be your background color; for GUI, guifg must be set
+to bg.
+
+==============================================================================
+8. History~
+ *CCTree-history*
+Version 1.51: May 18, 2011
+ 1. Robust error reporting when external (split/cat) utils fail
+
+Version 1.50: May 6, 2011
+ 1. Support cross-referencing of global variables, macros,
+ enums, and typedefs.
+
+Version 1.40: April 22, 2011
+ 1. Maintain order of functions called during forward tracing
+
+Version 1.39: April 18, 2011
+ 1. Use +Conceal feature for highlighting (only Vim 7.3)
+
+Version 1.33: April 5, 2011
+ 1. Load and trace CCTree native XRefDb directly from disk
+ 2. Fix AppendDB command when 'ignorecase' is set
+
+Version 1.26: March 28, 2011
+ 1. Fix macro cross-referencing limitation
+ 2. Correct native xref file format
+
+Version 1.21: March 21, 2011
+ 1. Support serialization of loaded
+ cscope databases (for faster loading)
+
+Version 1.07: March 09, 2011
+ 1. Fix new keymaps incorrectly applied to buffer
+ 2. CCTreeOptsToggle command for toggling options
+
+Version 1.04: March 06, 2011
+ 1. Customization for key mappings
+ 2. Dynamic configuration of UI variables
+ 3. Folding long call-trees to show current path dynamically
+
+Version 1.01: March 04, 2011
+ 1. Make UTF-8 symbols for tree optional
+
+Version 1.00: March 02, 2011
+ 1. Staging release for upcoming features
+ - Complete refactoring of code to take
+ advantage of VimScript's OO features
+ 2. Faster decompression of symbols
+ 3. Display related changes
+ - Use of unicode symbols for tree
+ 4. Bugfixes related to multi-database loading
+
+Version 0.90: February 18, 2011
+ 1. Support for large databases using external split utility or perl
+ interface
+
+Version 0.85: February 9, 2011
+ 1. Significant increase in database loading and decompression speeds
+
+Version 0.80: February 4, 2011
+ 1. Reduce memory usage by removing unused xref symbols
+
+Version 0.75: June 23, 2010
+ 1. Support for saving CCTree preview window; multiple
+ CCTree windows can now be open
+
+ersion 0.71: May 11, 2010
+ 1. Fix script bug
+
+Version 0.70: May 8, 2010
+ 1. Functionality to load multiple cscope databases
+
+Version 0.65: July 12, 2009
+ 1. Toggle preview window
+
+Version 0.61: December 24, 2008
+ 1. Fixed bug when processing include files
+ 2. Remove 'set ruler' option
+
+Version 0.60: November 26, 2008
+ 1. Added support for source-file dependency tree
+
+Version 0.50: October 17, 2008
+ 1. Optimizations for compact memory foot-print and
+ improved compressed-database load speeds
+
+Version 0.41: October 6, 2008
+ 1. Minor fix: Compressed cscope databases will load
+ incorrectly if encoding is not 8-bit
+
+Version 0.4: September 28, 2008
+ 1. Rewrite of display-related code
+ 2. New syntax hightlighting
+ 3. Dynamic highlighting for call-trees
+ 4. Support for new window modes (vertical, horizontal)
+ 5. New display format option for compact or wide call-trees
+ 6. Preview window fix
+
+Version 0.3: September 21, 2008
+ 1. Support compressed cscope databases
+ 2. Display window related bugs fixed
+ 3. More intuitive display and folding capabilities
+
+Version 0.2: September 12, 2008
+ (Patches from Yegappan Lakshmanan, thanks!)
+ 1. Support for using the plugin in Vi-compatible mode
+ 2. Filtering out unwanted lines before processing the db
+ 3. Command-line completion for the commands
+ 4. Using the cscope db from any directory
+
+Version 0.1: August 31,2008
+ 1. Cross-referencing support for only functions and macros
+ (Note: Functions inside macro definitions will be incorrectly
+ attributed to the top level calling function)
+
+
+==============================================================================
+9. Thanks~
+ *CCTree-thanks*
+
+
+ Qaiser Durrani (ver 1.51 -- Reporting issues with SunOS)
+ Ben Fritz (ver 1.39 -- Suggestion/Testing for
+ conceal feature)
+ Ben Fritz (ver 1.26 -- Bug report)
+ Frank Chang (ver 1.0x -- testing/UI enhancement
+ ideas/bug fixes)
+ Arun Chaganty/Timo Tiefel (Ver 0.60 -- bug report)
+ Michael Wookey (Ver 0.40 -- Testing/bug report/patches)
+ Yegappan Lakshmanan (Ver 0.20 -- Patches)
+
+ The Vim Community, ofcourse :)
+
+
+vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:
+
diff -up /dev/null cscope-15.7a/contrib/cctree.vim
--- /dev/null 2011-05-25 12:40:15.391845002 -0400
+++ cscope-15.7a/contrib/cctree.vim 2011-05-26 14:45:02.906838571 -0400
@@ -0,0 +1,3398 @@
+" C Call-Tree Explorer (CCTree) <CCTree.vim>
+"
+"
+" Script Info and Documentation
+"=============================================================================
+" Copyright: Copyright (C) August 2008 - 2011, Hari Rangarajan
+" Permission is hereby granted to use and distribute this code,
+" with or without modifications, provided that this copyright
+" notice is copied with it. Like anything else that's free,
+" cctree.vim is provided *as is* and comes with no
+" warranty of any kind, either expressed or implied. In no
+" event will the copyright holder be liable for any damamges
+" resulting from the use of this software.
+"
+" Name Of File: CCTree.vim
+" Description: C Call-Tree Explorer Vim Plugin
+" Maintainer: Hari Rangarajan <hari.rangarajan@gmail.com>
+" URL: http://vim.sourceforge.net/scripts/script.php?script_id=2368
+" Last Change: May 18, 2011
+" Version: 1.51
+"
+"=============================================================================
+"
+" {{{ Description:
+" Plugin generates dependency-trees for symbols using a cscope database
+" in Vim.
+" }}}
+" {{{ Requirements: 1) Vim 7.xx , 2) Cscope
+"
+" Tested on Unix and the following Win32 versions:
+" + Cscope, mlcscope (WIN32)
+" http://code.google.com/p/cscope-win32/
+" http://www.bell-labs.com/project/wwexptools/packages.html
+" }}}
+" {{{ Installation:
+" Copy this file to ~/.vim/plugins/
+" or to /vimfiles/plugins/ (on Win32 platforms)
+"
+" It might also be possible to load it as a filetype plugin
+" ~/.vim/ftplugin/c/
+"
+" Need to set :filetype plugin on
+"
+" }}}
+" {{{ Usage:
+" Build cscope database, for example:
+" > cscope -b -i cscope.files
+" [Tip: add -c option to build uncompressed databases for faster
+" load speeds]
+"
+" Load database with command ":CCTreeLoadDB"
+" (Please note that it might take a while depending on the
+" database size)
+"
+" Append database with command ":CCTreeAppendDB"
+" Allows multiple cscope files to be loaded and cross-referenced
+" Illustration:
+" :CCTreeAppendDB ./cscope.out
+" :CCTreeAppendDB ./dir1/cscope.out
+" :CCTreeAppendDB ./dir2/cscope.out
+"
+" A database name, i.e., my_cscope.out, can be specified with
+" the command. If not provided, a prompt will ask for the
+" filename; default is cscope.out.
+"
+" To show loaded databases, use command ":CCTreeShowLoadedDBs"
+"
+" To unload all databases, use command ":CCTreeUnLoadDB"
+" Note: There is no provision to unload databases individually
+"
+" To save the current set of databases loaded in to memory onto disk
+" in native CCTree XRef format, use command ":CCTreeSaveXRefDB"
+"
+" To load a saved native CCTree XRef format file, use
+" command ":CCTreeLoadXRefDB"
+"
+" To load a saved native CCTree XRef format file, use
+" command ":CCTreeLoadXRefDBFromDisk"
+"
+" Notes: No merging database support for CCTree native DB's [at present].
+"
+"
+" To have multiple CCTree preview windows, use ":CCTreeWindowSaveCopy"
+" Note: Once saved, only the depth of the preview window can be changed
+"
+" Default Mappings:
+" Get reverse call tree for symbol <C-\><
+" Get forward call tree for symbol <C-\>>
+" Increase depth of tree and update <C-\>=
+" Decrease depth of tree and update <C-\>-
+"
+" Open symbol in other window <CR>
+" Preview symbol in other window <Ctrl-P>
+"
+" Save copy of preview window <C-\>y
+" Highlight current call-tree flow <C-l>
+" Compress(Fold) call tree view zs
+" (This is useful for viewing long
+" call trees which span across
+" multiple pages)
+"
+" Custom user-mappings:
+" Users can custom-map the short-cut keys by
+" overriding the following variables in their
+" Vim start-up configuration
+"
+" g:CCTreeKeyTraceForwardTree = '<C-\>>'
+" g:CCTreeKeyTraceReverseTree = '<C-\><'
+" g:CCTreeKeyHilightTree = '<C-l>' " Static highlighting
+" g:CCTreeKeySaveWindow = '<C-\>y'
+" g:CCTreeKeyToggleWindow = '<C-\>w'
+" g:CCTreeKeyCompressTree = 'zs' " Compress call-tree
+" g:CCTreeKeyDepthPlus = '<C-\>='
+" g:CCTreeKeyDepthMinus = '<C-\>-'
+"
+" Command List:
+" CCTreeLoadDB <dbname>
+" CCTreeAppendDB <dbname>
+" CCTreeLoadXRefDB <dbname>
+" CCTreeSaveXRefDB <dbname>
+" CCTreeLoadXRefDBFromDisk <dbname>
+"
+" CCTreeUnLoadDB
+" CCTreeShowLoadedDBs
+"
+" CCTreeTraceForward <symbolname>
+" CCTreeTraceReverse <symbolname>
+" CCTreeRecurseDepthPlus
+" CCTreeRecurseDepthMinus
+" CCTreeWindowSaveCopy
+"
+" Only in preview window:
+" CCTreeWindowHiCallTree (same as <C-l> shorcut)
+" Highlight calling tree for keyword at cursor
+"
+" Dynamic configuration:
+" CCTreeOptsEnable <option> (<tab> for auto-complete)
+" CCTreeOptsDisable <option> (<tab> for auto-complete)
+" CCTreeOptsToggle <option> (<tab> for auto-complete)
+" Options:
+" DynamicTreeHiLights: Control dynamic tree highlighting
+" UseUnicodeSymbols: Use of UTF-8 special characters for
+" tree
+" UseConceal: Use (+Conceal) feature instead of 'ignore'
+" syntax highlighting. Allows CCTree window
+" to be exported in HTML without syntax markup
+" characters. (Vim 7.3+ only)
+" EnhancedSymbolProcessing: Cross-reference enums, macros,
+" global variables, typedefs (Warning: Database
+" processing speeds will be slow).
+"
+"
+"
+" Settings:
+" Customize behavior by changing the variable settings
+"
+" UTF-8 usage:
+" UTF-8 symbols should work fine on the majority of
+" X11 systems; however, some terminals might cause problems.
+"
+" To use symbols for drawing the tree, this option can be enabled.
+" g:CCTreeUseUTF8Symbols = 1
+" The options interface (CCTreeOptsxxx) can be used to
+" modify options on-the-fly.
+"
+" Cscope database file, g:CCTreeCscopeDb = "cscope.out"
+" Maximum call levels, g:CCTreeRecursiveDepth = 3
+" Maximum visible(unfolded) level, g:CCTreeMinVisibleDepth = 3
+" Orientation of window, g:CCTreeOrientation = "topleft"
+" (standard vim options for split: [right|left][above|below])
+"
+" Use Vertical window, g:CCTreeWindowVertical = 1
+" Min width for window, g:CCTreeWindowMinWidth = 40
+" g:CCTreeWindowWidth = -1, auto-select best width to fit
+"
+" Horizontal window, g:CCTreeWindowHeight, default is -1
+"
+"
+" Display format, g:CCTreeDisplayMode, default 1
+"
+" Values: 1 -- Ultra-compact (takes minimum screen width)
+" 2 -- Compact (Takes little more space)
+" 3 -- Wide (Takes copious amounts of space)
+"
+" For vertical splits, 1 and 2 are good, while 3 is good for
+" horizontal displays
+"
+" NOTE: To get older behavior, add the following to your vimrc
+" let g:CCTreeDisplayMode = 3
+" let g:CCTreeWindowVertical = 0
+"
+" Syntax Coloring:
+" CCTreeSymbol is the symbol name
+" CCTreeMarkers include "|","+--->"
+"
+" CCTreeHiSymbol is the highlighted call tree functions
+" CCTreeHiMarkers is the same as CCTreeMarkers except
+" these denote the highlighted call-tree
+"
+"
+" CCTreeHiXXXX allows dynamic highlighting of the call-tree.
+" To observe the effect, move the cursor to the function to
+" highlight the current call-tree. This option can be
+" turned off using the setting, g:CCTreeHilightCallTree.
+" For faster highlighting, the value of 'updatetime' can be
+" changed.
+"
+" Support for large database files:
+" Vimscript does not have an API for reading files line-by-line. This
+" becomes a problem when parsing large databases. CCTree can overcome
+" the limitation using an external utility (i.e., GNU coreutils: split)
+" or VimScript's perl interpreter interface (:version must indicate +perl)
+"
+" The following settings are tailored to suit GNU coreutils split; the default
+" settings should work with no changes on typical linux/unix distros
+" (Monopoly OSes will require installation of unixutils or equivalent)
+"
+" External command is setup with the following parameters:
+" g:CCTreeSplitProgCmd = 'PROG_SPLIT SPLIT_OPT SPLIT_SIZE IN_FILE OUT_FILE_PREFIX'
+"
+" Break-down of individual parameters:
+" The split utility is assumed to be on the path; otherwise, specify full path
+" g:CCTreeSplitProg = 'split'
+"
+" Option for splitting files (-C or -l)
+" g:CCTreeSplitProgOption = '-C'
+" If split program does not support -C, then this parameter must be set to
+" the number of lines in the split files
+" g:CCTreeDbFileSplitLines = -1
+" Largest filesize Vimscript can handle; file sizes greater than this will
+" be temporarily split
+" g:CCTreeDbFileMaxSize = 40000000 (40 Mbytes)
+"
+" Sample system command:
+" Typical:
+" split -C 40000000 inputFile outputFilePrefix
+"
+" When g:CCTreeDbFileSplitLines is set to 10000 (-C options will be ignored)
+" split -l 10000 inputFile outputFilePrefix
+"
+"
+" Using perl interface:
+" By default, perl usage is disabled. Set
+" g:CCTreeUsePerl = 1 to enable the perl interface.
+"
+" Perl interface is typically faster than native Vimscript.
+" This option can be used independent of the file size
+"
+" For more info on setting up perl interface
+" :help perl-using or :help perl-dynamic
+"
+" Writing large Xref Databases:
+" CCTree can use external utilities to write extremely large files beyond
+" VimScripts capabilities. It requires the use of an external tool that can
+" join text files (i.e., 'cat' in unix). This utility is triggered if the size
+" of the file being written exceeds g:CCTreeDbFileMaxSize (40 Mb or as configured)
+"
+" The join utility command is configured by default as follows:
+" let CCTreeJoinProgCmd = 'PROG_JOIN JOIN_OPT IN_FILES > OUT_FILE'
+"
+" let g:CCTreeJoinProg = 'cat' " PROG_JOIN
+" let g:CCTreeJoinProgOpts = "" " JOIN_OPT
+"
+"
+" }}}
+" {{{ Limitations:
+" Basic Symbol Processing:
+" The accuracy of the call-tree will only be as good as the cscope
+" database generation.
+" NOTE: Different flavors of Cscope have some known
+" limitations due to the lexical analysis engine. This results
+" in incorrectly identified function blocks, etc.
+" Enhanced Symbol Processing:
+" (1) Cscope does not mark-up nameless enums correctly; hence,
+" CCTree cannot recognize nameless enum symbols.
+" }}}
+" {{{ History:
+" Version 1.51: May 18, 2011
+" 1. Robust error reporting when external (split/cat) utils fail
+" Version 1.50: May 6, 2011
+" 1. Support cross-referencing of global variables, macros,
+" enums, and typedefs.
+" Version 1.40: April 22, 2011
+" 1. Maintain order of functions called during forward tracing
+" Version 1.39: April 18, 2011
+" 1. Use +Conceal feature for highlighting (only Vim 7.3)
+" Version 1.33: April 5, 2011
+" 1. Load and trace CCTree native XRefDb directly from disk
+" 2. Fix AppendDB command when 'ignorecase' is set
+" Version 1.26: March 28, 2011
+" 1. Fix macro cross-referencing limitation
+" 2. Correct native xref file format
+" Version 1.21: March 21, 2011
+" 1. Support serialization of loaded
+" cscope databases (for faster loading)
+" Version 1.07: March 09, 2011
+" 1. Fix new keymaps incorrectly applied to buffer
+" 2. CCTreeOptsToggle command for toggling options
+"
+" Version 1.04: March 06, 2011
+" 1. Customization for key mappings
+" 2. Dynamic configuration of UI variables
+" 3. Folding long call-trees to show current path dynamically
+"
+" Version 1.01: March 04, 2011
+" 1. Make UTF-8 symbols for tree optional
+"
+" Version 1.00: March 02, 2011
+" 1. Staging release for upcoming features
+" - Complete refactoring of code to take
+" advantage of VimScript's OO features
+" 2. Faster decompression of symbols
+" 3. Display related changes
+" - Use of unicode symbols for tree
+" 4. Bugfixes related to multi-database loading
+"
+" Version 0.90: February 18, 2011
+" 1. Support for large databases using external split utility or perl
+" interface
+"
+" Version 0.85: February 9, 2011
+" 1. Significant increase in database loading and decompression speeds
+"
+" Version 0.80: February 4, 2011
+" 1. Reduce memory usage by removing unused xref symbols
+"
+" Version 0.75: June 23, 2010
+" 1. Support for saving CCTree preview window; multiple
+" CCTree windows can now be open
+"
+" Version 0.71: May 11, 2010
+" 1. Fix script bug
+
+" Version 0.70: May 8, 2010
+" 1. Functionality to load multiple cscope databases
+"
+" Version 0.65: July 12, 2009
+" 1. Toggle preview window
+"
+" Version 0.61: December 24, 2008
+" 1. Fixed bug when processing include files
+" 2. Remove 'set ruler' option
+"
+" Version 0.60: November 26, 2008
+" 1. Added support for source-file dependency tree
+"
+" Version 0.50: October 17, 2008
+" 1. Optimizations for compact memory foot-print and
+" improved compressed-database load speeds
+"
+" Version 0.41: October 6, 2008
+" 1. Minor fix: Compressed cscope databases will load
+" incorrectly if encoding is not 8-bit
+"
+" Version 0.4: September 28, 2008
+" 1. Rewrite of "tree-display" code
+" 2. New syntax hightlighting
+" 3. Dynamic highlighting for call-trees
+" 4. Support for new window modes (vertical, horizontal)
+" 5. New display format option for compact or wide call-trees
+" NOTE: defaults for tree-orientation set to vertical
+"
+" Version 0.3:
+" September 21, 2008
+" 1. Support compressed cscope databases
+" 2. Display window related bugs fixed
+" 3. More intuitive display and folding capabilities
+"
+" Version 0.2:
+" September 12, 2008
+" (Patches from Yegappan Lakshmanan, thanks!)
+" 1. Support for using the plugin in Vi-compatible mode.
+" 2. Filtering out unwanted lines before processing the db.
+" 3. Command-line completion for the commands.
+" 4. Using the cscope db from any directory.
+"
+" Version 0.1:
+" August 31,2008
+" 1. Cross-referencing support for only functions and macros
+" Functions inside macro definitions will be incorrectly
+" attributed to the top level calling function
+"
+" }}}
+" {{{ Thanks:
+"
+" Qaiser Durrani (ver 1.51 -- Reporting issues with SunOS)
+" Ben Fritz (ver 1.39 -- Suggestion/Testing for conceal feature)
+" Ben Fritz (ver 1.26 -- Bug report)
+" Frank Chang (ver 1.0x -- testing/UI enhancement ideas/bug fixes)
+" Arun Chaganty/Timo Tiefel (Ver 0.60 -- bug report)
+" Michael Wookey (Ver 0.4 -- Testing/bug report/patches)
+" Yegappan Lakshmanan (Ver 0.2 -- Patches)
+"
+" The Vim Community, ofcourse :)
+"=============================================================================
+" }}}
+
+" {{{ Init
+if !exists('loaded_cctree') && v:version >= 700
+ " First time loading the cctree plugin
+ let loaded_cctree = 1
+else
+ "finish
+endif
+
+" Line continuation used here
+let s:cpo_save = &cpoptions
+set cpoptions&vim
+
+" Trick to get the current script ID
+map <SID>xx <SID>xx
+let s:sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$', '\1', '')
+unmap <SID>xx
+"}}}
+" {{{ Global variables; Modify in .vimrc to modify default behavior
+" {{{General
+if !exists('CCTreeCscopeDb')
+ let CCTreeCscopeDb = "cscope.out"
+endif
+" revisit
+if !exists('CCTreeDb')
+ let CCTreeDb = "cctree.out"
+endif
+if !exists('CCTreeRecursiveDepth')
+ let CCTreeRecursiveDepth = 3
+endif
+if !exists('CCTreeMinVisibleDepth')
+ let CCTreeMinVisibleDepth = 3
+endif
+if !exists('CCTreeEnhancedSymbolProcessing')
+ let CCTreeEnhancedSymbolProcessing = 0
+endif
+" }}}
+" {{{ Custom user-key mappings
+if !exists('CCTreeKeyTraceForwardTree')
+ let g:CCTreeKeyTraceForwardTree = '<C-\>>'
+endif
+if !exists('CCTreeKeyTraceReverseTree')
+ let g:CCTreeKeyTraceReverseTree = '<C-\><'
+endif
+if !exists('CCTreeKeyHilightTree')
+ let g:CCTreeKeyHilightTree = '<C-l>' " Static highlighting
+endif
+if !exists('CCTreeKeySaveWindow ')
+ let g:CCTreeKeySaveWindow = '<C-\>y'
+endif
+if !exists('CCTreeKeyToggleWindow ')
+ let g:CCTreeKeyToggleWindow = '<C-\>w'
+endif
+if !exists('CCTreeKeyCompressTree ')
+ let g:CCTreeKeyCompressTree = 'zs' " Compress call-tree
+endif
+if !exists('CCTreeKeyDepthPlus')
+ let g:CCTreeKeyDepthPlus = '<C-\>='
+endif
+if !exists('CCTreeKeyDepthMinus')
+ let g:CCTreeKeyDepthMinus = '<C-\>-'
+endif
+" }}}
+" {{{ CCTree UI settings
+if !exists('CCTreeOrientation')
+ let CCTreeOrientation = "topleft"
+endif
+if !exists('CCTreeWindowVertical')
+ let CCTreeWindowVertical = 1
+endif
+if !exists('CCTreeWindowWidth')
+ " -1 is auto select best width
+ let CCTreeWindowWidth = -1
+endif
+if !exists('CCTreeWindowMinWidth')
+ let CCTreeWindowMinWidth = 25
+endif
+if !exists('CCTreeWindowHeight')
+ let CCTreeWindowHeight = -1
+endif
+if !exists('CCTreeDisplayMode')
+ let CCTreeDisplayMode = 1
+endif
+if !exists('CCTreeHilightCallTree')
+ let CCTreeHilightCallTree = 1
+endif
+" }}}
+" {{{ Split prog
+if !exists('CCTreeSplitProgCmd')
+ let CCTreeSplitProgCmd = 'PROG_SPLIT SPLIT_OPT SPLIT_SIZE IN_FILE OUT_FILE_PREFIX'
+endif
+
+if !exists('CCTreeSplitProg')
+ "PROG_SPLIT
+ let CCTreeSplitProg = 'split'
+endif
+
+if !exists('CCTreeSplitProgOption')
+ "SPLIT_OPT
+ let CCTreeSplitProgOption = '-C'
+endif
+
+if !exists('CCTreeDbFileSplitLines')
+ " if SPLIT_OPT is -l
+ " If split program does not support -C, then this parameter must be set to
+ " the number of lines in the split files
+ let CCTreeDbFileSplitLines = -1
+endif
+
+if !exists('CCTreeSplitProgCmd')
+ let CCTreeSplitProgCmd = 'PROG_SPLIT SPLIT_OPT SPLIT_SIZE IN_FILE OUT_FILE_PREFIX'
+endif
+
+if !exists('CCTreeDbFileMaxSize')
+ " if SPLIT_OPT is -C
+ let CCTreeDbFileMaxSize = 40000000 "40 Mbytes
+endif
+
+" }}}
+" {{{ Join/Cat prog
+if !exists('CCTreeJoinProgCmd')
+ let CCTreeJoinProgCmd = 'PROG_JOIN JOIN_OPT IN_FILES > OUT_FILE'
+endif
+
+if !exists('CCTreeJoinProg')
+ "PROG_JOIN
+ let CCTreeJoinProg = 'cat'
+endif
+
+if !exists('CCTreeJoinProgOpts')
+ let CCTreeJoinProgOpts = ""
+endif
+" }}}
+" {{{ Misc (perl)
+if !exists('CCTreeUsePerl')
+ " Disabled by default
+ let CCTreeUsePerl = 0
+if 0 " Auto-detect perl interface (Experimental code)
+ if has('perl)
+perl << PERL_EOF
+ VIM::DoCommand("let CCTreeUsePerl = 1");
+PERL_EOF
+ endif
+endif
+endif
+
+if has('conceal')
+ let s:CCTreeUseConceal = 1
+else
+ let s:CCTreeUseConceal = 0
+endif
+
+if !exists('CCTreeUseUTF8Symbols')
+ let CCTreeUseUTF8Symbols = 0
+endif
+" }}}
+" }}}
+" {{{ Plugin related local variables
+let s:pluginname = 'CCTree'
+let s:windowtitle = 'CCTree-View'
+let s:windowsavetitle = 'CCTree-View-Copy'
+
+let s:DBClasses = { 'cscopeid': 'Cscope', 'cctreexref' : 'CCTree XRef'}
+let s:DBStorage = { 'memory': 'Memory', 'disk' : 'Disk'}
+
+" }}}
+" {{{ Turn on/off debugs
+let s:tag_debug=0
+
+" Use the Decho plugin for debugging
+function! DBGecho(...)
+ if s:tag_debug
+ Decho(a:000)
+ endif
+endfunction
+
+function! DBGredir(...)
+ if s:tag_debug
+ Decho(a:000)
+ endif
+endfunction
+
+function! Pause()
+ call input("sasasD", "asdads")
+endfunction
+" }}}
+" {{{ Progress bar (generic, numeric, rolling)
+let s:GenericProgressBar= {
+ \ 'depth': 0,
+ \ 'depthChar': '',
+ \ 'currentChar': 0,
+ \ 'updateTime': 0,
+ \ 'rangeChars': [],
+ \ 'formatStr' : '',
+ \ 'units' : ''
+ \ }
+
+function! s:GenericProgressBar.mCreate(rangechars, depthchar, fmtStr)
+ let pbr = deepcopy(s:GenericProgressBar)
+ unlet pbr.mCreate
+
+ let pbr.rangeChars = a:rangechars
+ let pbr.depthChar = a:depthchar
+ let pbr.formatStr = a:fmtStr
+
+ return pbr
+endfunction
+
+function! s:GenericProgressBar.mSetDepth(val) dict
+ let self.depth = a:val
+endfunction
+
+function! s:GenericProgressBar.mUpdate() dict
+ let staticchars = repeat(self.depthChar, self.depth)
+ let displayStr = substitute(self.formatStr, "\@PROGRESS\@",
+ \ staticchars . self.rangeChars[self.currentChar], "")
+ call s:StatusLine.mSetExtraInfo(displayStr)
+endfunction
+
+function! s:GenericProgressBar.mDone()
+ call s:StatusLine.mSetExtraInfo("")
+endfunction
+
+let s:ProgressBarRoll = {
+ \ 'updateTime' : 0,
+ \ 'curTime' : 0
+ \}
+
+function! s:ProgressBarRoll.mCreate(rollchars, depthChar) dict
+ let gpbr = s:GenericProgressBar.mCreate(a:rollchars, a:depthChar, "\@PROGRESS\@")
+ let pbr = extend(gpbr, deepcopy(s:ProgressBarRoll))
+ unlet pbr.mCreate
+
+ let pbr.curTime = localtime()
+
+ return pbr
+endfunction
+
+function! s:ProgressBarRoll.mTick(count) dict
+ if (localtime() - self.curTime) > self.updateTime
+ let self.currentChar += 1
+ if self.currentChar == len(self.rangeChars)
+ let self.currentChar = 0
+ endif
+ let self.curTime = localtime()
+ call self.mUpdate()
+ endif
+endfunction
+
+let s:ProgressBarNumeric = {
+ \ 'progress1current' : 0,
+ \ 'progressmax' : 0,
+ \ 'progress1percent' : 0,
+ \ 'progresspercent' : 0,
+ \}
+
+function! s:ProgressBarNumeric.mCreate(maxcount, unit) dict
+ let gpbr = s:GenericProgressBar.mCreate(range(0,200), '',
+ \ "Processing \@PROGRESS\@\%, total ". a:maxcount . " " . a:unit)
+ let progressbar = extend(gpbr, deepcopy(s:ProgressBarNumeric))
+ unlet progressbar.mCreate
+
+ let progressbar.progressmax = a:maxcount
+ let progressbar.progress1percent = a:maxcount/100
+
+ let progressbar.units = a:unit
+
+ return progressbar
+endfunction
+
+
+function! s:ProgressBarNumeric.mTick(count) dict
+ let self.progress1current += a:count
+ if self.progress1percent <= self.progress1current
+ let tmp = (self.progress1current/self.progress1percent)
+ let self.progresspercent += tmp
+ let self.progress1current -= tmp * self.progress1percent
+ let self.currentChar += 1
+ call self.mUpdate()
+ endif
+endfunction
+
+" }}}
+" {{{ Status line
+let s:StatusLine = {
+ \ 'symlastprogress' : 0,
+ \ 'symprogress' : 0,
+ \ 'cursym' : 0,
+ \ 'savedStatusLine' : '',
+ \ 'statusextra' : '',
+ \ 'local':0
+ \}
+
+function! s:StatusLine.mInit() dict
+ let self.savedStatusLine = &l:statusline
+ setlocal statusline=%{CCTreeStatusLine()}
+endfunction
+
+function! s:StatusLine.mRestore() dict
+ let self.currentstatus = ''
+ let self.statusextra = ''
+
+ let &l:statusline = s:StatusLine.savedStatusLine
+ redrawstatus
+endfunction
+
+function! s:StatusLine.mSetInfo(msg) dict
+ let s:StatusLine.currentstatus = a:msg
+ redrawstatus
+endfunction
+
+function! s:StatusLine.mSetExtraInfo(msg) dict
+ let s:StatusLine.statusextra = a:msg
+ redrawstatus
+endfunction
+
+function! CCTreeStatusLine()
+ return s:pluginname. " ".
+ \ s:StatusLine.currentstatus . " -- ".
+ \ s:StatusLine.statusextra
+endfunction
+"}}}
+" {{{ Shell command interface
+
+let s:ShellCmds = {'shellOutput': ''}
+
+function! s:ShellCmds.mSplit(inFile, outFile)
+ let cmdEx = substitute(g:CCTreeSplitProgCmd, "PROG_SPLIT", g:CCTreeSplitProg,"")
+ let cmdEx = substitute(cmdEx, "SPLIT_OPT", g:CCTreeSplitProgOption,"")
+ if g:CCTreeDbFileSplitLines != -1
+ let cmdEx = substitute(cmdEx, "SPLIT_SIZE", g:CCTreeDbFileSplitLines,"")
+ else
+ let cmdEx = substitute(cmdEx, "SPLIT_SIZE", g:CCTreeDbFileMaxSize,"")
+ endif
+ let cmdEx = substitute(cmdEx, "IN_FILE", a:inFile,"")
+ let cmdEx = substitute(cmdEx, "OUT_FILE_PREFIX", a:outFile,"")
+
+ return cmdEx
+endfunction
+
+function! s:ShellCmds.mJoin(inFileList, outFile)
+ let cmdEx = substitute(g:CCTreeJoinProgCmd, "PROG_JOIN", g:CCTreeJoinProg,"")
+ let cmdEx = substitute(cmdEx, "JOIN_OPT", g:CCTreeJoinProgOpts,"")
+ let cmdEx = substitute(cmdEx, "IN_FILES", a:inFileList,"")
+ let cmdEx = substitute(cmdEx, "OUT_FILE", a:outFile,"")
+
+ return cmdEx
+endfunction
+
+function! s:ShellCmds.mExec(cmd)
+ let s:shellOutput= system(a:cmd)
+ if s:shellOutput != ''
+ " Failed
+ return s:CCTreeRC.Error
+ endif
+ return s:CCTreeRC.Success
+endfunction
+
+" }}}
+
+" {{{ Virtual file interface
+let s:vFile = {}
+
+function! s:vFile.mCreate(fname, mode)
+ if a:mode == 'r'
+ return s:vFileR.mCreate(a:fname)
+ elseif a:mode == 'w'
+ return s:vFileW.mCreate(a:fname)
+ endif
+ return -1
+endfunction
+
+let s:vFileW = {
+ \ 'splitfiles' : [],
+ \ 'totSplits' : 0,
+ \ 'lines' : [],
+ \ 'fileSize' : 0
+ \}
+
+function! s:vFileW.mCreate(fname) dict
+ let vfile = deepcopy(s:vFileW)
+ unlet vfile.mCreate
+ let vfile.link = a:fname
+
+ return vfile
+endfunction
+
+function! s:vFileW.mCreateSplit() dict
+ " first split, create name
+ if self.totSplits == 0
+ let self.tlink = tempname()
+ endif
+ let fname = self.tlink .'_'. self.totSplits
+ call writefile(self.lines, fname)
+ call add(self.splitfiles, fname)
+ let self.lines = []
+ let self.totSplits += 1
+endfunction
+
+function! s:vFileW.mTestForSplit() dict
+ if self.fileSize > g:CCTreeDbFileMaxSize
+ call self.mCreateSplit()
+ endif
+endfunction
+
+function! s:vFileW.mAddFileSize(size) dict
+ let self.fileSize += a:size
+endfunction
+
+function! s:vFileW.mWriteList(linelist) dict
+ call extend(self.lines, a:linelist)
+ call self.mTestForSplit()
+endfunction
+
+function! s:vFileW.mWriteLine(line) dict
+ call add(self.lines, a:line)
+ call self.mAddFileSize(len(a:line))
+ call self.mTestForSplit()
+endfunction
+
+function! s:vFileW.mClose() dict
+ if self.totSplits == 0
+ call writefile(self.lines, self.link)
+ else
+ " force remaining lines into a new split
+ call self.mCreateSplit()
+ " now join all of them
+ let filelist = join(self.splitfiles, " ")
+ let cmdEx = s:ShellCmds.mJoin(filelist, self.link)
+ if s:ShellCmds.mExec(cmdEx) != s:CCTreeRC.Success
+ let msg = s:shellOutput ."Shell command: ".cmdEx. " failed!".
+ \ " Refer help to setup split/join utils."
+ call s:CCTreeUtils.mWarningPrompt(msg)
+ endif
+ endif
+ for afile in self.splitfiles
+ call delete(afile)
+ endfor
+ return 0
+endfunction
+
+let s:vFileR = {
+ \ 'splitfiles' : [],
+ \ 'currentSplitIdx' : 0,
+ \ 'totSplits' : 0,
+ \ 'lines' : [],
+ \ 'valid' : 0,
+ \ 'mode' : ""
+ \}
+
+
+function! s:vFileR.mIsLargeFile() dict
+ if (getfsize(self.link) > g:CCTreeDbFileMaxSize)
+ return 1
+ endif
+ return 0
+endfunction
+
+function! s:vFileR.mCreate(fname) dict
+ let vfile = deepcopy(s:vFileR)
+ unlet vfile.mCreate
+ let vfile.link = a:fname
+ let vfile.valid = filereadable(a:fname)
+ let vfile.size = getfsize(a:fname)
+
+ return vfile
+endfunction
+
+function! s:vFileR.mOpen() dict
+ if self.mode == 'w'
+ " no need to do anything
+ return 0
+ endif
+
+ if self.mIsLargeFile() == 0
+ "little trick to keep interface uniform when we don't split
+ call add(self.splitfiles, self.link)
+ let self.totSplits = 1
+ else
+ let tmpDb = tempname()
+ let cmdEx = s:ShellCmds.mSplit(self.link, tmpDb)
+
+ if s:ShellCmds.mExec(cmdEx) != s:CCTreeRC.Success
+ let msg = s:shellOutput ."Shell command: ".cmdEx. " failed!".
+ \ " Refer help to setup split/join utils."
+ call s:CCTreeUtils.mWarningPrompt(msg)
+ return -1
+ else
+ let self.splitfiles = split(expand(tmpDb."*"), "\n")
+ endif
+ if empty(self.splitfiles)
+ return -1
+ endif
+ endif
+ let self.totSplits = len(self.splitfiles)
+ return 0
+endfunction
+
+function! s:vFileR.mRead() dict
+ if (self.currentSplitIdx >= len(self.splitfiles))
+ " out of bounds
+ return -1
+ endif
+ let self.lines = readfile(self.splitfiles[self.currentSplitIdx])
+ let self.currentSplitIdx += 1
+ return 0
+endfunction
+
+function! s:vFileR.mRewind() dict
+ let self.currentSplitIdx = 0
+ let self.lines = []
+endfunction
+
+
+function! s:vFileR.mClose() dict
+ if self.totSplits == 1
+ return
+ endif
+ for afile in self.splitfiles
+ call delete(afile)
+ endfor
+endfunction
+"}}}
+" {{{Stop watch
+let s:StopWatch = {
+ \ 'text' : "(no reltime feature)",
+ \}
+
+function! s:StopWatch.mCreate() dict
+ let stopWatch = deepcopy(s:StopWatch)
+ unlet stopWatch.mCreate
+
+ call stopWatch.mReset()
+ return stopWatch
+endfunction
+
+function! s:StopWatch.mReset() dict
+ if has('reltime')
+ let self.startRTime = reltime()
+ else
+ let self.startRTime = localtime()
+ endif
+endfunction
+
+function! s:StopWatch.mSnapElapsed() dict
+ if has('reltime')
+ let self.text = reltimestr(reltime(self.startRTime))
+ else
+ let self.text = localtime() - self.startRTime
+ endif
+endfunction
+
+function! s:StopWatch.mGetText() dict
+ return self.text
+endfunction
+"}}}
+" {{{ Digraph character compression/decompression routines
+
+let s:CharMaps = {
+ \'savedEncoding' : '',
+ \'mapkind' : ''
+ \}
+
+" The encoding needs to be changed to 8-bit, otherwise we can't swap special
+" 8-bit characters; restore after done
+function! s:CharMaps.mInitTranslator() dict
+ if self.mapkind == 'Alpha'
+ let self.savedEncoding = &encoding
+ let &encoding="latin1"
+ endif
+endfunction
+
+function! s:CharMaps.mDoneTranslator() dict
+ if self.mapkind == 'Alpha'
+ let &encoding=self.savedEncoding
+ endif
+endfunction
+
+function! s:CharMaps.CrossProduct(seq1, seq2) dict
+ let cpSeq = []
+ for dc1 in range(strlen(a:seq1))
+ for dc2 in range(strlen(a:seq2))
+ call add(cpSeq, a:seq1[dc1].a:seq2[dc2])
+ endfor
+ endfor
+ return cpSeq
+endfunction
+
+let s:TranslateMap = {}
+
+function! s:TranslateMap.mCreate (srcsym, destsym, mapkind, regex) dict
+ let dicttable = extend(deepcopy(s:CharMaps), deepcopy(s:TranslateMap))
+ unlet dicttable.CrossProduct
+
+ let dicttable.mappings = {}
+
+ " map lower
+ let maxsym = min([len(a:srcsym),len (a:destsym)])
+
+ let index = 0
+ while (index < maxsym)
+ let dicttable.mappings[a:srcsym[index]] = a:destsym[index]
+ let index += 1
+ endwhile
+ " Need mapping lens, we assume it's constant across the board
+ let dicttable.mapsrclen = len(a:srcsym[0])
+ let dicttable.regex = a:regex
+
+
+ if a:mapkind == 'Alpha'
+ let dicttable.mTranslate = dicttable.mTranslateAlpha
+ elseif a:mapkind == 'Numeric'
+ let dicttable.mTranslate = dicttable.mTranslateNumeric
+ endif
+
+ let dicttable.mapkind = a:mapkind
+
+ unlet dicttable.mTranslateNumeric
+ unlet dicttable.mTranslateAlpha
+
+ return dicttable
+endfunction
+
+
+function! s:TranslateMap.mTranslateNumeric(value) dict
+ let index = 0
+ let retval = ""
+
+ " remember to deal with multi-byte characters
+ while index < len(a:value)
+ let char1 = char2nr(a:value[index])
+ if has_key(self.mappings, char1)
+ let newmap = self.mappings[char1]
+ else
+ " take only the first character
+ let newmap = a:value[index]
+ endif
+ let retval .= newmap
+ let index += 1
+ endwhile
+ return retval
+endfunction
+
+function! s:TranslateMap.mTranslateAlpha(value) dict
+ let retval = substitute(a:value, self.regex, '\=self.mappings[submatch(1)]', "g")
+ return retval
+endfunction
+
+function! s:CCTreeGetXRefDbMaps(maptype, mapkind)
+ let dichar1 = ",0123456789"
+ let dichar2 = ",0123456789"
+
+ return s:CCTreeCreateGenericMaps(a:maptype, a:mapkind, dichar1, dichar2)
+endfunction
+
+function! s:CCTreeGetCscopeMaps(maptype, mapkind)
+ let dichar1 = " teisaprnl(of)=c"
+ let dichar2 = " tnerpla"
+
+ return s:CCTreeCreateGenericMaps(a:maptype, a:mapkind, dichar1, dichar2)
+endfunction
+
+
+function! s:CCTreeCreateGenericMaps(maptype, mapkind, dichar1, dichar2)
+ let s:CharMaps.mapkind = a:mapkind
+ call s:CharMaps.mInitTranslator()
+ if a:mapkind == 'Numeric'
+ let ab = map(range(128,255), 'v:val')
+ elseif a:mapkind == 'Alpha'
+ let ab = map(range(128,255), 'nr2char(v:val)')
+ else
+ return {}
+ endif
+ let ac = s:CharMaps.CrossProduct(a:dichar1, a:dichar2)
+ if a:maptype == 'Compress'
+ let maps = s:TranslateMap.mCreate(ac, ab, a:mapkind,
+ \'\(['.a:dichar1.']['.a:dichar2.']\)\C')
+ elseif a:maptype == 'Uncompress'
+ let maps = s:TranslateMap.mCreate(ab, ac, a:mapkind,
+ \'\([\d128-\d255]\)')
+ endif
+ call s:CharMaps.mDoneTranslator()
+ return maps
+endfunction
+" }}}
+" {{{ Unique list filter object
+
+let s:UniqList = {}
+
+function! s:UniqList.mFilterEntries(lstval) dict
+ let valdict = {}
+ let reslist = ''
+ for aval in a:lstval
+ if !has_key(valdict, aval)
+ let valdict[aval] = ''
+ let reslist .= (aval . ",")
+ endif
+ endfor
+ return reslist
+endfunction
+
+let s:CCTreeUniqListFilter = deepcopy(s:UniqList)
+function! s:CCTreeMakeCommaListUnique(clist)
+ let entries = split(a:clist, ",")
+ if len(entries) > 0
+ return s:CCTreeUniqListFilter.mFilterEntries(entries)
+ endif
+ return ""
+endfunction
+" }}}
+" {{{ Buffer/Window
+func! s:FindOpenBuffer(filename)
+ let bnrHigh = bufnr("$")
+ "tabpagebuflist(tabpagenr())
+
+ for bufnrs in range(1, bnrHigh)
+ if (bufexists(bufnrs) == 1 && bufname(bufnrs) == a:filename && bufloaded(bufnrs) != 0 )
+ return bufnrs
+ endif
+ endfor
+ " Could not find the buffer
+ return 0
+endfunction
+
+func! s:FindOpenWindow(filename)
+ let bufnr = s:FindOpenBuffer(a:filename)
+ if (bufnr > 0)
+ let newWinnr = bufwinnr(bufnr)
+ if newWinnr != -1
+ exec newWinnr.'wincmd w'
+ return 1
+ endif
+ endif
+ " Could not find the buffer
+ return 0
+endfunction
+" }}}
+" {{{ Utils library
+
+let s:Utils = {}
+
+" Use this function to determine the correct "g" flag
+" for substitution
+function! s:Utils.mGetSearchFlag(gvalue)
+ let ret = (!a:gvalue)* (&gdefault) + (!&gdefault)*(a:gvalue)
+ if ret == 1
+ return 'g'
+ endif
+ return ''
+endfunc
+
+" Strlen works for multibyte characters
+function! s:Utils.mStrlenEx(val)
+ return strlen(substitute(a:val, ".", "x", "g"))
+endfunc
+" }}}
+" {{{ Generic db loader interface
+let s:GenericDbLdr = {
+ \ 'fDBName' : '',
+ \ 'class' : 'Generic',
+ \ }
+
+function! s:GenericDbLdr.mCreate(fname) dict
+ let gdb = deepcopy(s:GenericDbLdr)
+ unlet gdb.mCreate
+ let gdb.fDBName = a:fname
+
+ if !filereadable(a:fname)
+ return s:CCTreeRC.Error
+ endif
+
+ return gdb
+endfunction
+
+function! s:GenericDbLdr.mParseDbHeader(gRdr)
+ let header = readfile(self.fDBName, "", a:gRdr.headerLines)
+ return a:gRdr.mParseDbHeader(header)
+endfunction
+
+let s:XRefMemDbLdr = {
+ \ 'class' : s:DBStorage.memory
+ \}
+
+function! s:XRefMemDbLdr.mCreate(fname) dict
+ let gdb = s:GenericDbLdr.mCreate(a:fname)
+ if type(gdb) != type({})
+ return gdb
+ endif
+ let mdb = extend(gdb, deepcopy(s:XRefMemDbLdr))
+ unlet mdb.mCreate
+
+ return mdb
+endfunction
+
+if has('perl') && g:CCTreeUsePerl == 1
+" Perl function
+function! s:XRefMemDbLdr.mLoadFileIntoXRefDb(xRefDb, gRdr) dict
+ let stage = 1
+ for afltr in a:gRdr.opts
+ let stageidxstr = 'Stage ('.stage.'/'.len(a:gRdr.opts).') '
+ call s:StatusLine.mSetInfo(stageidxstr. ': (PERL) Loading database ')
+ call a:gRdr.mProcessingStateInit()
+ let pBar = s:ProgressBarNumeric.mCreate(getfsize(self.fDBName), "bytes")
+ echomsg 'filtering '. afltr
+perl << PERL_EOF
+ #use strict;
+ #use warnings FATAL => 'all';
+ #use warnings NONFATAL => 'redefine';
+
+ my $filebytes = 0;
+ my $filterpat = VIM::Eval("afltr");
+
+ open (CSCOPEDB, VIM::Eval("self.fDBName")) or die "File trouble!";
+ #VIM::DoCommand("echomsg '".$filterpat."'");
+
+ while (<CSCOPEDB>) {
+ $filebytes += length($_);
+ chomp($_);
+
+ if ($_ !~ $filterpat) {
+ next;
+ }
+ VIM::DoCommand("call pBar.mTick(".$filebytes.")");
+ $filebytes = 0;
+ VIM::DoCommand("call a:gRdr.mProcessSymbol(a:xRefDb, '".$_."')");
+ }
+ VIM::DoCommand("call pBar.mDone()");
+ close(CSCOPEDB);
+PERL_EOF
+ call a:gRdr.mProcessingStateDone()
+ let stage += 1
+ endfor
+endfunction
+else
+" Native Vim function
+function! s:XRefMemDbLdr.mLoadFileIntoXRefDb(xRefDb, gRdr) dict
+ let vDbFile = s:vFile.mCreate(self.fDBName, "r")
+ if vDbFile.valid == 0
+ return -1
+ endif
+ if vDbFile.mIsLargeFile() == 1
+ call s:StatusLine.mSetExtraInfo('Database '
+ \.' >'.g:CCTreeDbFileMaxSize .' bytes. Splitting '.
+ \'into smaller chunks... (this may take some time)')
+ endif
+ try
+ if vDbFile.mOpen() == 0
+ call self.mReadFileIntoXRefDb(vDbFile,
+ \ a:xRefDb,
+ \ a:gRdr)
+ endif
+ finally
+ call vDbFile.mClose()
+ endtry
+endfunction
+endif
+
+function! s:XRefMemDbLdr.mReadFileIntoXRefDb(vDbFile, xrefdb, gRdr)
+ let stage = 0
+ for afltr in a:gRdr.opts
+ call a:vDbFile.mRewind()
+ let stage += 1
+ call a:gRdr.mProcessingStateInit()
+ while 1 == 1
+ if a:vDbFile.mRead() == -1
+ break
+ endif
+ let stageidxstr = 'Stage ('.stage.'/'.len(a:gRdr.opts).') '
+ let fileidxstr = '('.a:vDbFile.currentSplitIdx.'/'.a:vDbFile.totSplits.') '
+ call s:StatusLine.mSetInfo(stageidxstr. ': Reading database chunk '.fileidxstr)
+ " Filter-out lines that doesn't have relevant information
+ let plist = a:gRdr.mReadLinesFromFile(a:vDbFile, afltr)
+ let pBar = s:ProgressBarNumeric.mCreate(len(plist), "items")
+ call s:StatusLine.mSetInfo(stageidxstr.': Analyzing database chunk '.fileidxstr)
+ call self.mProcessListIntoXrefDb(plist, a:gRdr, a:xrefdb, pBar)
+ call pBar.mDone()
+ " clean-up memory
+ call garbagecollect()
+ endwhile
+ call a:gRdr.mProcessingStateDone()
+ endfor
+endfunction
+
+function! s:XRefMemDbLdr.mProcessListIntoXrefDb(symbols, rdr, xrefdb, pbar)
+ for a in a:symbols
+ call a:pbar.mTick(1)
+ call a:rdr.mProcessSymbol(a:xrefdb, a)
+ endfor
+endfunction
+
+function! s:GenericDbLdr.mParseDbHeader(gRdr)
+ let header = readfile(self.fDBName, "", a:gRdr.headerLines)
+ return a:gRdr.mParseDbHeader(header)
+endfunction
+
+" }}}
+" {{{ Generic Disk DB Ldr
+let s:XRefDiskDbLdr = {
+ \ 'class' : s:DBStorage.disk
+ \ }
+
+function! s:XRefDiskDbLdr.mCreate(fname) dict
+ let gdb = s:GenericDbLdr.mCreate(a:fname)
+ if type(gdb) != type({})
+ return gdb
+ endif
+ let mdb = extend(gdb, deepcopy(s:XRefDiskDbLdr))
+ unlet mdb.mCreate
+
+ return mdb
+endfunction
+
+function! s:XRefDiskDbLdr.mLoadFileIntoXRefDb(xRefDb, gRdr) dict
+ call a:xRefDb.mSetLink(self.fDBName)
+endfunction
+
+"}}}
+" {{{ Xref disk DB
+let s:XRefDiskDb = {
+ \ 'link':'',
+ \ 'savedTags': '',
+ \ 'class' : s:DBStorage.disk
+ \ }
+
+function! s:XRefDiskDb.mCreate() dict
+ let fdb = deepcopy(s:XRefDiskDb)
+ unlet fdb.mCreate
+ let fdb.maps = s:CCTreeGetXRefDbMaps('Uncompress', 'Numeric')
+
+ return fdb
+endfunction
+
+function! s:XRefDiskDb.mSetLink(filedb) dict
+ let self.link = a:filedb
+ " revisit, do parse header here
+endfunction
+
+function! s:XRefDiskDb.mClear() dict
+ " do nothing
+endfunction
+
+function! s:XRefDiskDb.mInitState() dict
+ let self.savedTags = &tags
+ let &tags = self.link
+endfunction
+
+function! s:XRefDiskDb.mRestoreState() dict
+ let &tags = self.savedTags
+endfunction
+
+function! s:XRefDiskDb.mDecodeTagEntry(tagentry) dict
+ let itms = split(a:tagentry.name, "#")
+ let a:tagentry.n = itms[1]
+ let a:tagentry.idx = itms[0]
+
+ " Vim taglist() drops empty fields, so need to protect
+ if has_key(a:tagentry, 'c')
+ let a:tagentry.c = self.maps.mTranslate(a:tagentry.c)
+ else
+ let a:tagentry.c = ''
+ endif
+ if has_key(a:tagentry, 'p')
+ let a:tagentry.p = self.maps.mTranslate(a:tagentry.p)
+ else
+ let a:tagentry.p = ''
+ endif
+
+ return a:tagentry
+endfunction
+
+function! s:XRefDiskDb.mGetSymbolIdFromName(symname) dict
+ let symtagline = taglist('\#'.a:symname.'$')
+ let g:xyz = symtagline
+ let asym = self.mDecodeTagEntry(symtagline[0])
+ return asym.idx
+endfunction
+
+function! s:XRefDiskDb.mGetSymbolFromId(symid) dict
+ let symtagline = taglist('^'.a:symid.'\#')
+ if empty(symtagline)
+ echomsg "Failed to locate ".a:symid
+ else
+ return self.mDecodeTagEntry(symtagline[0])
+ endif
+ return {}
+endfunction
+
+function! s:XRefDiskDb.mGetSymbolIds() dict
+ " illegal
+ let symtaglines = taglist('^.')
+ return keys(self.symidhash)
+endfunction
+
+function! s:XRefDiskDb.mGetSymbolNames(lead) dict
+ if empty(a:lead)
+ let symtaglines = taglist('^.')
+ else
+ let symtaglines = taglist('#'.a:lead)
+ endif
+ let alist = []
+ for atag in symtaglines
+ let acctreesym = self.mDecodeTagEntry(atag)
+ call add(alist, acctreesym.n)
+ endfor
+ return alist
+endfunction
+" }}}
+" {{{ TagFile utils
+let s:CCTreeTagDbRdr = {'class': 'CCTreeXrefDb',
+ \ 'headerLines' : 4,
+ \ 'compressed' : 0,
+ \ 'opts': ['v:val !~ "^[\!]"'],
+ \ 'perl_opts': "^[^\!]",
+ \ 'mapPreKeys': {'c':'','p':''},
+ \ 'mapPostKeys': {'c':'','p':''}
+ \ }
+
+function! s:CCTreeTagDbRdr.mCreate(fname) dict
+ let cctxdbrdr = deepcopy(s:CCTreeTagDbRdr)
+ unlet cctxdbrdr.mCreate
+
+ return cctxdbrdr
+endfunction
+
+function! s:CCTreeTagDbRdr.mRequirePreProcessing() dict
+ return s:CCTreeRC.False
+endfunction
+
+function! s:CCTreeTagDbRdr.mRequirePostProcessing() dict
+ return s:CCTreeRC.True
+endfunction
+
+function! s:CCTreeTagDbRdr.mRequireCleanup() dict
+ " Clean-up all symbols [never]
+ return s:CCTreeRC.False
+endfunction
+
+function! s:CCTreeTagDbRdr.mGetPreProcessingMaps() dict
+ return s:CCTreeGetXRefDbMaps('Compress', 'Alpha')
+endfunction
+
+function! s:CCTreeTagDbRdr.mGetPostProcessingMaps() dict
+ return s:CCTreeGetXRefDbMaps('Uncompress', 'Alpha')
+endfunction
+
+
+function! s:CCTreeTagDbRdr.mParseDbHeader(hdr) dict
+ " just check line 3 for sanity
+ if a:hdr[2] =~ "CCTree"
+ return s:CCTreeRC.Success
+ endif
+ return s:CCTreeRC.Error
+endfunction
+
+function! s:CCTreeTagDbRdr.mProcessingStateInit() dict
+endfunction
+
+function! s:CCTreeTagDbRdr.mProcessingStateDone() dict
+endfunction
+
+function! s:CCTreeTagDbRdr.mReadLinesFromFile(vdbFile, filtercmds) dict
+ " Hard-coded assumptions here about format for performance
+ if empty(get(a:vdbFile.lines, 0)) != 1 && a:vdbFile.lines[0][0] == "!"
+ " filter out the first few lines starting with "!"
+ call remove(a:vdbFile.lines, 0, self.headerLines-1)
+ endif
+ return a:vdbFile.lines
+endfunction
+
+function! s:CCTreeTagDbRdr.mProcessSymbol(xrefdb, aline) dict
+ let cctreesym = self.mDecodeTagLine(a:aline)
+ call a:xrefdb.mInsertSym(cctreesym.idx, cctreesym)
+ " we really don't need idx any longer
+ unlet cctreesym.idx
+endfunction
+
+function! s:CCTreeTagDbRdr.mDecodeTagLine(tagline) dict
+
+ let items = split(a:tagline, "\t")
+ let newsym = s:CCTreeSym.mCreate("")
+ try
+ let [newsym.idx, newsym.n] = split(items[0], '#')
+ catch
+ echomsg "problem decoding ". a:tagline
+ endtry
+
+ "let newsym.idx = strpart(items[0], 0, idxBr)
+ "let newsym.n = items[0][ idxBr+1 : -2] "strpart(items[0], idxBr+1, strlen(items[0])-1)
+ if empty(get(items, 3)) != 1
+ let newsym.c = items[3][2:]
+ endif
+ if empty(get(items, 4)) != 1
+ let newsym.p = items[4][2:]
+ endif
+ return newsym
+endfunction
+
+" }}}
+" {{{ Generic Db Serializer
+let s:GenericDbSerializer = {}
+
+function! s:GenericDbSerializer.mCreate(xrefdb) dict
+ let gDbSerializer = deepcopy(s:GenericDbSerializer)
+ let gDbSerializer.xrefdb = a:xrefdb
+ return gDbSerializer
+endfunction
+
+function! s:GenericDbSerializer.mWriteXRefDbToFile(fname,
+ \ gWriter) dict
+ call s:StatusLine.mInit()
+ try
+ call s:StatusLine.mSetInfo('Writing XRefDb')
+ let vDbFile = s:vFile.mCreate(a:fname, "w")
+ call vDbFile.mWriteList(a:gWriter.mBuildHeader())
+ call self.mWriteSymsToFile(vDbFile, a:gWriter)
+ finally
+ call vDbFile.mClose()
+ call s:StatusLine.mRestore()
+ endtry
+endfunction
+
+function! s:GenericDbSerializer.mWriteSymsToFile(dstVFile,
+ \ gWriter) dict
+ let pBar = s:ProgressBarNumeric.mCreate(self.xrefdb.mGetSymbolCount(),
+ \ "items")
+ call a:gWriter.mInitWriting()
+ " write syms
+ for asymid in sort(self.xrefdb.mGetSymbolIds())
+ let acctreesym = self.xrefdb.mGetSymbolFromId(asymid)
+ call a:dstVFile.mWriteLine(a:gWriter.mBuildTagLine(acctreesym,
+ \ asymid))
+ call pBar.mTick(1)
+ endfor
+ call pBar.mDone()
+ call a:gWriter.mDoneWriting()
+endfunction
+" }}}
+" {{{ CCTreeTagDb Writer
+let s:CCTreeTagDbWriter = {}
+
+function! s:CCTreeTagDbWriter.mCreate(tmaps) dict
+ let dbwriter = deepcopy(s:CCTreeTagDbWriter)
+ unlet dbwriter.mCreate
+
+
+ let dbwriter.tmaps = a:tmaps
+ return dbwriter
+endfunction
+
+function! s:CCTreeTagDbWriter.mInitWriting() dict
+ call self.tmaps.mInitTranslator()
+endfunction
+
+function! s:CCTreeTagDbWriter.mDoneWriting() dict
+ call self.tmaps.mDoneTranslator()
+endfunction
+
+function! s:CCTreeTagDbWriter.mBuildHeader() dict
+ let hdr = []
+ call add(hdr, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/")
+ call add(hdr, "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/")
+ call add(hdr, "!_TAG_PROGRAM_NAME\t\tCCTree (Vim plugin)//")
+ call add(hdr, "!_TAG_PROGRAM_URL\thttp://vim.sourceforge.net/scripts/script.php?script_id=2368\t/site/")
+ return hdr
+endfunction
+
+
+function! s:CCTreeTagDbWriter.mBuildTagLine(sym, symid) dict
+ let basetag = a:symid .'#'. a:sym.n."\t"."\t"."/^\$/".";\""
+ let cm = self.tmaps.mTranslate(a:sym.c)
+ let pm = self.tmaps.mTranslate(a:sym.p)
+
+ let basetag .= "\tc:". self.tmaps.mTranslate(a:sym.c)
+ let basetag .= "\tp:". self.tmaps.mTranslate(a:sym.p)
+
+ return basetag
+endfunction
+" }}}
+" {{{ CCTree constants
+let s:CCTreeRC = {
+ \ 'Error' : -1,
+ \ 'True' : 1,
+ \ 'False' : 0,
+ \ 'Success' : 2
+ \ }
+"}}}
+" {{{ CCTree DB Obj
+" Symbol definition
+
+let s:CCTreeSym = {
+ \'k': "",
+ \'n': "",
+ \'c': "",
+ \'p': ""
+ \}
+
+function! s:CCTreeSym.mCreate(name, kind)
+ let sym = deepcopy(s:CCTreeSym)
+ unlet sym.mCreate
+ let sym.n = a:name
+ let sym.k = a:kind
+ return sym
+endfunction
+
+
+" }}}
+" {{{ GenericXref, XrefDb
+let s:GenericXRef = {}
+
+function! s:GenericXRef.mCreate(filedb) dict
+ let gxref = deepcopy(s:GenericXRef)
+ return gxref
+endfunction
+
+function! s:GenericXRef.mInitState() dict
+endfunction
+
+function! s:GenericXRef.mRestoreState() dict
+endfunction
+" {{{ XRef Database object
+let s:xRefMemDb = {
+ \ 'symuniqid': 0,
+ \ 'symidhash' : {},
+ \ 'symnamehash' : {},
+ \ 'class' : s:DBStorage.memory
+ \}
+
+
+function s:xRefMemDb.mCreate() dict
+ let dbObj = deepcopy(s:xRefMemDb)
+ unlet dbObj.mCreate
+
+ return dbObj
+endfunction
+
+function s:xRefMemDb.mInitState() dict
+endfunction
+
+function s:xRefMemDb.mRestoreState() dict
+endfunction
+
+function s:xRefMemDb.mClear() dict
+ let self.symidhash = {}
+ let self.symnamehash = {}
+ let self.symuniqid = 0
+endfunction
+
+function! s:xRefMemDb.mInsertSym(idx, cctreesym) dict
+ let self.symuniqid = max([self.symuniqid, a:idx])
+ let self.symidhash[a:idx] = a:cctreesym
+ let self.symnamehash[a:cctreesym.n] = a:idx
+endfunction
+
+function! s:xRefMemDb.mRemoveSymById(symidx) dict
+ call self.mRemoveSymByName(acctreesym.n)
+ call remove(self.symidhash, a:symidx)
+endfunction
+
+function! s:xRefMemDb.mRemoveSymByName(symname) dict
+ call remove(self.symnamehash, a:symname)
+endfunction
+
+function! s:xRefMemDb.mAddSym(name, kind) dict
+ if !has_key(self.symnamehash, a:name)
+ let self.symnamehash[a:name] = self.symuniqid
+ let self.symidhash[self.symuniqid] =
+ \s:CCTreeSym.mCreate(a:name, a:kind)
+ let self.symuniqid += 1
+ endif
+ let asymid = self.symnamehash[a:name]
+ if a:kind != ""
+ let asym = self.symidhash[asymid]
+ let asym.k = a:kind
+ endif
+ return asymid
+endfunction
+
+function! s:xRefMemDb.mMarkXRefSyms(funcentryidx, newfuncidx) dict
+ let self.symidhash[a:funcentryidx]['c'] .= (",". a:newfuncidx)
+ let self.symidhash[a:newfuncidx]['p'] .= (",". a:funcentryidx)
+endfunction
+
+function! s:xRefMemDb.mGetSymbolFromName(symname) dict
+ return self.symidhash[self.symnamehash[a:symname]]
+endfunction
+
+function! s:xRefMemDb.mGetSymbolIdFromName(symname) dict
+ if has_key(self.symnamehash, a:symname)
+ return self.symnamehash[a:symname]
+ else
+ return s:CCTreeRC.Error
+ endif
+endfunction
+
+function! s:xRefMemDb.mGetSymbolFromId(symid) dict
+ return self.symidhash[a:symid]
+endfunction
+
+function! s:xRefMemDb.mGetSymbolIds() dict
+ return keys(self.symidhash)
+endfunction
+
+function! s:xRefMemDb.mGetSymbolNames(lead) dict
+ let syms = keys(self.symnamehash)
+ if empty(a:lead) != 1
+ return filter(syms, 'v:val =~? a:lead')
+ endif
+ return syms
+endfunction
+
+function! s:xRefMemDb.mGetSymbolCount() dict
+ return len(self.symnamehash)
+endfunction
+
+function! s:xRefMemDb.mTranslateSymbols(map, tkeys) dict
+ call a:map.mInitTranslator()
+ let pBar = s:ProgressBarNumeric.mCreate(len(self.symnamehash), "items")
+
+ for asym in keys(self.symnamehash)
+ let idx = self.symnamehash[asym]
+ let val = self.symidhash[idx]
+ if has_key(a:tkeys, 'n')
+ let uncmpname = a:map.mTranslate(asym)
+ if (asym != uncmpname)
+ "Set up new entry
+ let self.symnamehash[uncmpname] = idx
+ " free the old entry
+ call remove(self.symnamehash, asym)
+ " Set uncompressed name
+ let val.n = uncmpname
+ endif
+ endif
+ if has_key(a:tkeys, 'p')
+ let val.p = a:map.mTranslate(val.p)
+ endif
+ if has_key(a:tkeys, 'c')
+ let val.c = a:map.mTranslate(val.c)
+ endif
+ call pBar.mTick(1)
+ endfor
+ call pBar.mDone()
+ call a:map.mDoneTranslator()
+endfunction
+
+function! s:xRefMemDb.mCleanSymbols () dict
+ let pBar = s:ProgressBarNumeric.mCreate(len(self.symnamehash), "items")
+ for asym in keys(self.symnamehash)
+ let idx = self.symnamehash[asym]
+ let val = self.symidhash[idx]
+ if empty(val.p) && empty(val.c)
+ call remove(self.symnamehash, asym)
+ call remove(self.symidhash, idx)
+ else
+ let val.p = s:CCTreeMakeCommaListUnique(val.p)
+ let val.c = s:CCTreeMakeCommaListUnique(val.c)
+ endif
+ call pBar.mTick(1)
+ endfor
+ call pBar.mDone()
+endfunction
+"}}}
+"}}} End of Xref
+" {{{ Tracer
+let s:CallTree = {
+ \ 'symbol' : ""
+ \ }
+function! s:CallTree.mCreate(name) dict
+ let ct = deepcopy(s:CallTree)
+ unlet ct.mCreate
+
+ let ct.symbol = a:name
+
+ return ct
+endfunction
+
+function! s:CallTree.mAddChildLink(childTree) dict
+ if !has_key(self, 'childlinks')
+ let self.childlinks = []
+ endif
+ call add(self.childlinks, a:childTree)
+endfunction
+
+let s:XRefTracer = {
+ \}
+
+function! s:XRefTracer.mCreate(xrefdb) dict
+ let xreftracer = deepcopy(s:XRefTracer)
+ let xreftracer.xrefdb = a:xrefdb
+
+ return xreftracer
+endfunction
+
+function! s:XRefTracer.mInitTracing() dict
+ call self.xrefdb.mInitState()
+endfunction
+
+function! s:XRefTracer.mDoneTracing() dict
+ call self.xrefdb.mRestoreState()
+endfunction
+
+function! s:XRefTracer.mGetSymbolIdXRef(symid, direction) dict
+ let acctreesym = self.xrefdb.mGetSymbolFromId(a:symid)
+ let symidslist = split(
+ \s:CCTreeMakeCommaListUnique(acctreesym[a:direction]), ",")
+ return symidslist
+endfunction
+
+function! s:XRefTracer.mBuildForSymbol(symid, curdepth, maxdepth,
+ \ direction, pbar) dict
+ if (a:curdepth > a:maxdepth)
+ return {}
+ endif
+
+ call a:pbar.mSetDepth(a:curdepth)
+ let asym = self.xrefdb.mGetSymbolFromId(a:symid)
+ " revisit
+ if empty(asym)
+ return {}
+ endif
+
+ let rtree = s:CallTree.mCreate(asym['n'])
+
+ for entry in self.mGetSymbolIdXRef(a:symid, a:direction)
+ call a:pbar.mTick(1)
+ let ctree =
+ \self.mBuildForSymbol(entry, a:curdepth+1, a:maxdepth,
+ \a:direction, a:pbar)
+ call rtree.mAddChildLink(ctree)
+ endfor
+ return rtree
+endfunction
+" }}}
+
+" {{{ Cscope Reader
+
+
+let s:CscopeDbRdrState = {
+ \'curfuncidx': -1,
+ \'curfileidx': -1,
+ \'curmacroidx': -1,
+ \'curenumidx': -1,
+ \ }
+
+function! s:CscopeDbRdrState.mCreate() dict
+ return deepcopy(s:CscopeDbRdrState)
+endfunction
+
+let s:CscopeDbRdrSymTags = {
+ \'func' : '$}',
+ \'macro' : '#\)',
+ \'file' : '@\~',
+ \'enum' : 'em',
+ \'global' : 'g',
+ \'typedef' : 't',
+ \}
+
+let s:CscopeDbSymFilter = ['v:val =~ "^\t[#`$}@\~\)]"']
+let s:CscopeDbSymEnhFilter = ['v:val =~ "^\t[emgt#`$}@~)]"',
+ \ 'v:val =~ "^\\a\\|^\t[)$}#]"']
+
+let s:CscopeDbSymFilterPerl = ['^\t[\`\#\$\}\@\~\)]']
+let s:CscopeDbSymEnhFilterPerl = ['^\t[\`\#\$\}\@\~\)emgt]',
+ \ '^[A-Za-z]|^\t[\#\$\}\)]']
+
+let s:CscopeDbRdr = {
+ \ 'class': 'Cscope',
+ \ 'headerLines' : 1,
+ \ 'compressed' : 0,
+ \ 'opts': [],
+ \ 'perl_opts': '',
+ \ 'mapPreKeys': {'n':''},
+ \ 'mapPostKeys': {'n':''}
+ \}
+
+function! s:CscopeDbRdr.mCreate(fname, enhanced) dict
+ let csdbrdr = deepcopy(s:CscopeDbRdr)
+ unlet csdbrdr.mCreate
+
+ if a:enhanced == 1
+ if g:CCTreeUsePerl == 1
+ let csdbrdr.opts = s:CscopeDbSymEnhFilterPerl
+ else
+ let csdbrdr.opts = s:CscopeDbSymEnhFilter
+ endif
+ else
+ if g:CCTreeUsePerl == 1
+ let csdbrdr.opts = s:CscopeDbSymFilterPerl
+ else
+ let csdbrdr.opts = s:CscopeDbSymFilter
+ endif
+ endif
+ return csdbrdr
+endfunction
+
+function! s:CscopeDbRdr.mProcessingStateInit() dict
+ let self.iState = s:CscopeDbRdrState.mCreate()
+endfunction
+
+function! s:CscopeDbRdr.mProcessingStateDone() dict
+ " discard state
+ unlet self.iState
+endfunction
+
+function! s:CscopeDbRdr.mReadLinesFromFile(vDbFile, filtercmds) dict
+ return s:CCTreeUtils.mFilter(a:vDbFile.lines, a:filtercmds)
+endfunction
+
+function! s:CscopeDbRdr.mParseDbHeader(dbHeader) dict
+ if a:dbHeader[0] =~ "cscope"
+ if (a:dbHeader[0] !~ "cscope.*\-c")
+ let self.compressed = s:CCTreeRC.True
+ else
+ let self.compressed = s:CCTreeRC.False
+ endif
+ return s:CCTreeRC.Success
+ endif
+ return s:CCTreeRC.Error
+endfunction
+
+function! s:CscopeDbRdr.mRequirePreProcessing() dict
+ return (self.compressed == 1)? s:CCTreeRC.True : s:CCTreeRC.False
+endfunction
+
+function! s:CscopeDbRdr.mRequirePostProcessing() dict
+ return (self.compressed == 1)? s:CCTreeRC.True : s:CCTreeRC.False
+endfunction
+
+function! s:CscopeDbRdr.mRequireCleanup() dict
+ " Clean-up all symbols [always]
+ return s:CCTreeRC.True
+endfunction
+
+function! s:CscopeDbRdr.mGetPreProcessingMaps() dict
+ return s:CCTreeGetCscopeMaps('Compress', 'Alpha')
+endfunction
+
+function! s:CscopeDbRdr.mGetPostProcessingMaps() dict
+ return s:CCTreeGetCscopeMaps('Uncompress', 'Alpha')
+endfunction
+
+function! s:CscopeDbRdr.mProcessSymbol(xrefdb, symbol) dict
+ try
+ if a:symbol[0] == "\t"
+ return self.mProcessTaggedSymbol(a:xrefdb, a:symbol)
+ else
+ return self.mProcessUnTaggedSymbol(a:xrefdb, a:symbol)
+ endif
+ catch
+ echomsg 'Problem with '. a:symbol
+ endtry
+endfunction
+
+function! s:CscopeDbRdr.mProcessUnTaggedSymbol(xrefdb, symbol) dict
+ let cursymidx = a:xrefdb.mGetSymbolIdFromName(a:symbol)
+ if cursymidx != s:CCTreeRC.Error
+ if self.iState.curfuncidx != -1
+ call a:xrefdb.mMarkXRefSyms(self.iState.curfuncidx, cursymidx)
+ elseif self.iState.curmacroidx != -1
+ call a:xrefdb.mMarkXRefSyms(self.iState.curmacroidx, cursymidx)
+ endif
+ endif
+endfunction
+
+function! s:CscopeDbRdr.mProcessTaggedSymbol(xrefdb, symbol) dict
+ if self.iState.curmacroidx != -1
+ if a:symbol[1] == "`"
+ call a:xrefdb.mMarkXRefSyms(self.iState.curmacroidx,
+ \ a:xrefdb.mAddSym(a:symbol[2:], ""))
+ elseif a:symbol[1] == ')'
+ let self.iState.curmacroidx = -1
+ endif
+ elseif self.iState.curfuncidx != -1
+ " inside function
+ if a:symbol[1] == "`"
+ call a:xrefdb.mMarkXRefSyms(self.iState.curfuncidx,
+ \ a:xrefdb.mAddSym(a:symbol[2:], ""))
+ elseif a:symbol[1] == "}"
+ let self.iState.curfuncidx = -1
+ elseif a:symbol[1] == "#"
+ let self.iState.curmacroidx = a:xrefdb.mAddSym(a:symbol[2:], 'm')
+ endif
+ elseif self.iState.curenumidx != -1
+ if a:symbol[1] == "m"
+ call a:xrefdb.mMarkXRefSyms(self.iState.curenumidx,
+ \ a:xrefdb.mAddSym(a:symbol[2:], "em"))
+ else
+ " just reprocess the symbol after changing state
+ let self.iState.curenumidx = -1
+ call self.mProcessTaggedSymbol(a:xrefdb, a:symbol)
+ endif
+ elseif a:symbol[1] == "$"
+ let self.iState.curfuncidx = a:xrefdb.mAddSym(a:symbol[2:], "f")
+ elseif a:symbol[1] == "#"
+ let self.iState.curmacroidx = a:xrefdb.mAddSym(a:symbol[2:], "d")
+ elseif a:symbol[1] == "~"
+ call a:xrefdb.mMarkXRefSyms(self.iState.curfileidx,
+ \a:xrefdb.mAddSym(a:symbol[3:], "i"))
+ elseif a:symbol[1] == "e"
+ let self.iState.curenumidx = a:xrefdb.mAddSym(a:symbol[2:], "e")
+ elseif a:symbol[1] == "g"
+ call a:xrefdb.mAddSym(a:symbol[2:], "g")
+ elseif a:symbol[1] == "@"
+ if a:symbol[2] != ""
+ let self.iState.curfileidx =
+ \a:xrefdb.mAddSym(a:symbol[2:], "F")
+ endif
+ endif
+endfunction
+
+" }}}
+" {{{ CCTree helper library
+let s:CCTreeUtils = {}
+
+function! s:CCTreeUtils.mDetectDB(class)
+ if a:class == s:DBClasses.cctreexref
+ if filereadable(g:CCTreeDb)
+ return g:CCTreeDb
+ endif
+ elseif a:class == s:DBClasses.cscopeid
+ if filereadable(g:CCTreeCscopeDb)
+ return g:CCTreeCscopeDb
+ endif
+ endif
+ return ''
+endfunction
+
+function! s:CCTreeUtils.mFilter(lines, filtercmd) dict
+ let retlst = []
+ let progr = len(a:lines)/100
+ let pBar = s:ProgressBarNumeric.mCreate(len(a:lines), "items")
+ while len(a:lines) > 0
+ if progr <= len(a:lines)
+ let tmplist = remove(a:lines, 0, progr)
+ else
+ let tmplist = remove(a:lines, 0, len(a:lines)-1)
+ endif
+ call filter(tmplist, a:filtercmd)
+ call pBar.mTick(progr)
+ call extend(retlst, tmplist)
+ endwhile
+ call pBar.mDone()
+ return retlst
+endfunction
+
+function! s:CCTreeUtils.mWarningPrompt(msg) dict
+ echohl WarningMsg
+ let a = input(s:pluginname. ": ". a:msg)
+ echohl None
+endfunction
+
+function! s:CCTreeUtils.mWarningMsg(msg) dict
+ echohl WarningMsg
+ echomsg s:pluginname. ": ". a:msg
+ echohl None
+endfunction
+
+function! s:CCTreeUtils.mInfoMsg(msg) dict
+ echohl Title
+ echomsg s:pluginname. ": ". a:msg
+ echohl None
+endfunction
+
+function! s:CCTreeUtils.mWrite(msg) dict
+ echo s:pluginname. ": ". a:msg
+endfunction
+
+" }}}
+" {{{ CCTree DB management
+let s:CCTreeXrefDbEntry = {
+ \ 'type': '',
+ \ 'fname' : '',
+ \ 'fsize' : 0,
+ \ 'fdate' : 0
+ \}
+
+function! s:CCTreeXrefDbEntry.mCreate(fname, type) dict
+ let xrefdbent = deepcopy(s:CCTreeXrefDbEntry)
+ unlet xrefdbent.mCreate
+
+ let xrefdbent.type = a:type
+ let xrefdbent.fname = simplify(getcwd().'/'.a:fname)
+ let xrefdbent.fsize = getfsize(a:fname)
+ let xrefdbent.fdate = strftime("%c", getftime(a:fname))
+ return xrefdbent
+endfunction
+
+let s:CCTreeDBList = {
+ \'loadedDBs' : []
+ \ }
+
+function! s:CCTreeDBList.mCreate() dict
+ let dbList = deepcopy(s:CCTreeDBList)
+ unlet dbList.mCreate
+
+ return dbList
+endfunction
+
+function! s:CCTreeDBList.mShowLoaded() dict
+ let i = 1
+ call s:CCTreeUtils.mWrite(s:pluginname.": List of loaded cscope databases")
+ call s:CCTreeUtils.mWrite("---------------------------------------")
+ for aDBEnt in self.loadedDBs
+ call s:CCTreeUtils.mWrite(i." ".aDBEnt.fname. " ".
+ \ " (".aDBEnt.type.") ".
+ \ aDBEnt.fsize. " bytes ".
+ \ aDBEnt.fdate)
+ let i = i + 1
+ endfor
+endfunction
+
+function! s:CCTreeDBList.mClearAll() dict
+ let self.loadedDBs = []
+endfunction
+
+function! s:CCTreeDBList.mIsEmpty() dict
+ if empty(self.loadedDBs)
+ return s:CCTreeRC.True
+ endif
+ return s:CCTreeRC.False
+endfunction
+
+" Load the cscope db into the global cctree xref db
+function! s:CCTreeDBList.mCreateDbLoaderAndReader(dbName, dbclass, storageclass) dict
+ let dbUser = s:CCTreeCmdLine.mInputDBName('Load', a:dbName, a:dbclass)
+ if dbUser == ''
+ call s:CCTreeUtils.mWarningMsg('Filename required')
+ "User cancel, do nothing
+ return
+ endif
+
+ " Create generic Db loader object
+ if a:storageclass == s:DBStorage.disk
+ let gDbLdr = s:XRefDiskDbLdr.mCreate(dbUser)
+ elseif a:storageclass == s:DBStorage.memory
+ let gDbLdr = s:XRefMemDbLdr.mCreate(dbUser)
+ endif
+
+ if type(gDbLdr) != type({})
+ call s:CCTreeUtils.mWarningMsg(a:dbclass.' database ' . a:dbName .
+ \ ' not found.')
+ return s:CCTreeRC.Error
+ endif
+
+ " Create new DB reader object
+ if a:storageclass == s:DBStorage.memory
+ if a:dbclass == s:DBClasses.cscopeid
+ let gDbRdr = s:CscopeDbRdr.mCreate(dbUser, g:CCTreeEnhancedSymbolProcessing)
+ elseif a:dbclass == s:DBClasses.cctreexref
+ let gDbRdr = s:CCTreeTagDbRdr.mCreate(dbUser)
+ else
+ return s:CCTreeRC.Error
+ endif
+ if gDbLdr.mParseDbHeader(gDbRdr) == s:CCTreeRC.Error
+ call s:CCTreeUtils.mWarningMsg(gDbRdr.class.' database ' . a:dbName .
+ \ ' format is not parseable.')
+ return s:CCTreeRC.Error
+ endif
+ else
+ let gDbRdr = {}
+ endif
+
+ return {'loader': gDbLdr, 'reader': gDbRdr}
+endfunction
+
+function! s:CCTreeDBList.mAddDbToList(dbName, type)
+ let aDBEnt = s:CCTreeXrefDbEntry.mCreate(a:dbName, a:type)
+ call add(self.loadedDBs, aDBEnt)
+endfunction
+
+" Merge the cscope db into the global cctree xref db
+function! s:CCTreeDBList.mMerge(dbName, xRefDb, class)
+ " Check if merge can be supported
+ if self.loadedDBs[0].type == s:DBStorage.disk
+ call s:CCTreeUtils.mInfoMsg("Cannot merge with DBs traced from disk")
+ return
+ endif
+ " Create db loader, reader
+ let gObjs = self.mCreateDbLoaderAndReader(a:dbName, a:class, s:DBStorage.memory)
+
+ if type(gObjs) == type({})
+ " if Db is compressed, then we need to compress our symbols first
+ let swatch = s:StopWatch.mCreate()
+ if self.mLoadDB(gObjs.loader, a:xRefDb,
+ \ gObjs.reader) != s:CCTreeRC.Error
+ call self.mAddDbToList(gObjs.loader.fDBName, gObjs.loader.class)
+ let msg = "Done merging databases. xRef Symbol Count: "
+ \.a:xRefDb.mGetSymbolCount()
+ \.". Time taken: ".swatch.mGetText()." secs"
+ call s:CCTreeUtils.mInfoMsg(msg)
+ endif
+ " Load will auto decompress the symbols
+ endif
+endfunction
+
+" Load the cscope db into the global cctree xref db
+function! s:CCTreeDBList.mAddNew(dbName, xRefDb, dbclass, storageclass)
+ " Create db loader, reader
+ let gObjs = self.mCreateDbLoaderAndReader(a:dbName, a:dbclass, a:storageclass)
+
+ if type(gObjs) == type({})
+ let swatch = s:StopWatch.mCreate()
+ if self.mLoadDB(gObjs.loader, a:xRefDb,
+ \ gObjs.reader) != s:CCTreeRC.Error
+ call self.mAddDbToList(gObjs.loader.fDBName, gObjs.loader.class)
+ call swatch.mSnapElapsed()
+ if a:storageclass == s:DBStorage.memory
+ let msg = "Done loading database. xRef Symbol Count: "
+ \.a:xRefDb.mGetSymbolCount()
+ \.". Time taken: ".swatch.mGetText()." secs"
+ else
+ let msg = "Disk Xref database loaded for tracing"
+ endif
+ call s:CCTreeUtils.mInfoMsg(msg)
+ endif
+ endif
+endfunction
+
+function! s:CCTreeDBList.mLoadDB(gDbLdr, xRefDb, gRdr)
+ let rc = s:CCTreeRC.Success
+ try
+ let swatch = s:StopWatch.mCreate()
+ call s:StatusLine.mInit()
+ " if compression, then we need to compress our symbols first
+ if !empty(a:gRdr) && a:gRdr.mRequirePreProcessing() == s:CCTreeRC.True
+ call s:StatusLine.mSetInfo('Pre-processing existing symbols')
+ call a:xRefDb.mTranslateSymbols(a:gRdr.mGetPreProcessingMaps(),
+ \ a:gRdr.mapPreKeys)
+ endif
+ call garbagecollect()
+ call s:StatusLine.mSetInfo('Loading database')
+ call a:gDbLdr.mLoadFileIntoXRefDb(a:xRefDb, a:gRdr)
+ if !empty(a:gRdr) && a:gRdr.mRequireCleanup() == s:CCTreeRC.True
+ call s:StatusLine.mSetInfo('Symbol clean-up')
+ call a:xRefDb.mCleanSymbols()
+ endif
+ call garbagecollect()
+ if !empty(a:gRdr) && a:gRdr.mRequirePostProcessing() == s:CCTreeRC.True
+ call s:StatusLine.mSetInfo('Post-processing loaded symbols')
+ call a:xRefDb.mTranslateSymbols(a:gRdr.mGetPostProcessingMaps(),
+ \ a:gRdr.mapPostKeys)
+ endif
+ call swatch.mSnapElapsed()
+ " restore normalcy
+ call garbagecollect()
+ redraw
+
+ catch /^Vim:Interrupt$/ " catch interrupts (CTRL-C)
+ call s:CCTreeUtils.mWarningMsg('Loading aborted.')
+ let rc = s:CCTreeRC.Error
+ finally
+ call s:StatusLine.mRestore()
+ endtry
+ return rc
+endfunction
+"}}}
+" {{{ UI Input related
+let s:CCTreeUI = {}
+
+
+function! s:CCTreeUI.mInputDBName(dbName, class, action)
+ let dbUser = a:dbName
+ let dbUser = input(a:action. ' database ('. a:class. '): ', a:dbName, 'file')
+ return dbUser
+endfunction
+" }}}
+" {{{ CCTree Markers
+let s:TreeMarkers_UTF8 = {
+ \ 'splitT' : nr2char(0x251c),
+ \ 'arrowR' : nr2char(0x25c0),
+ \ 'arrowF' : nr2char(0x25B6),
+ \ 'extV' : nr2char(0x2502),
+ \ 'extH': nr2char(0x2500),
+ \ 'depth': nr2char(0x25BC)
+ \}
+
+let s:TreeMarkers_Text = {
+ \ 'splitT' : '+',
+ \ 'arrowF' : '>',
+ \ 'arrowR' : '<',
+ \ 'extV' : '|',
+ \ 'extH': '-',
+ \ 'depth': 'depth:'
+ \}
+
+let s:CCTreeMarkers = {
+ \ 'icons':{}
+ \ }
+function! s:CCTreeMarkers.mCreate() dict
+ let treeMarkers = deepcopy(s:CCTreeMarkers)
+
+ if &encoding == 'utf-8' && g:CCTreeUseUTF8Symbols == 1
+ let treeMarkers.icons = deepcopy(s:TreeMarkers_UTF8)
+ else
+ " default choice
+ let treeMarkers.icons = deepcopy(s:TreeMarkers_Text)
+ endif
+
+ let treeMarkers.icons.arrowSyms = treeMarkers.icons.arrowF . treeMarkers.icons.arrowR
+ let treeMarkers.icons.vertSyms = treeMarkers.icons.splitT . treeMarkers.icons.extV
+
+ return treeMarkers
+endfunction
+
+function! s:CCTreeMarkers.mGetArrow(direction) dict
+ if a:direction == 'p'
+ return self.icons.arrowR
+ elseif a:direction == 'c'
+ return self.icons.arrowF
+ endif
+ return '?'
+endfunction
+" }}}
+" {{{ User key mappings
+let s:CCTreeKeyMappings = {
+ \ 'CTreeF': g:CCTreeKeyTraceForwardTree,
+ \ 'CTreeR': g:CCTreeKeyTraceReverseTree,
+ \ 'CTreeHilight': g:CCTreeKeyHilightTree,
+ \ 'CTreeWSave': g:CCTreeKeySaveWindow,
+ \ 'CTreeWToggle': g:CCTreeKeyToggleWindow,
+ \ 'CTreeCompress': g:CCTreeKeyCompressTree,
+ \ 'CTreeDepthMinus': g:CCTreeKeyDepthMinus,
+ \ 'CTreeDepthPlus': g:CCTreeKeyDepthPlus
+ \}
+" }}}
+" {{{ CCTreeWindow
+let s:CCTreeWindow = {
+ \ 'hiKeyword': '',
+ \ 'hiKeywordLine':'',
+ \ 'lastbufname':'',
+ \ 'treeMarkers': s:CCTreeMarkers.mCreate()}
+
+function! s:CCTreeWindow.mCreate() dict
+ let win = deepcopy(s:CCTreeWindow)
+ unlet win.mCreate
+
+ return win
+endfunction
+
+function! s:CCTreeWindow.mLeave()
+ call s:FindOpenWindow(self.lastbufname)
+endfunction
+
+
+" Definition of a keyword...
+let s:CCTreeKeywordRegEx = '[A-Za-z0-9_\\\.\/]\+'
+
+function! s:CCTreeWindow.mGetKeywordAtCursor() dict
+ let curline = line(".")
+ let self.hiKeyword = ''
+ if foldclosed(curline) == -1
+ let curkeyword = matchstr(getline("."), s:CCTreeKeywordRegEx)
+ if curkeyword != ''
+ if curkeyword != self.hiKeyword || curline != self.hiKeywordLine
+ let self.hiKeyword = curkeyword
+ let self.hiKeywordLine = line(".")
+ return s:CCTreeRC.Success
+ endif
+ else
+ return s:CCTreeRC.Error
+ endif
+ endif
+ if self.hiKeyword == ''
+ return s:CCTreeRC.Error
+ endif
+ return s:CCTreeRC.Success
+endfunction
+
+function! s:CCTreeWindow.mBuildStatusLine(pState, title, items)
+ let needcomma = 0
+ let rtitle = a:title. ' ('. a:pState.keyword
+ let rtitle .= '['
+ if has_key(a:items, "depth")
+ let rtitle .= self.treeMarkers.icons.depth
+ let rtitle .= a:pState.depth
+ let needcomma = 1
+ endif
+ if has_key(a:items, "direction")
+ if needcomma == 1
+ let rtitle .= ','
+ endif
+
+ let rtitle .= self.treeMarkers.mGetArrow(a:pState.direction)
+ endif
+ let rtitle .= '])'
+
+ return rtitle
+endfunction
+
+function! CCTreeWindowPreviewStatusLine()
+ " get global
+ " this is a hack
+ let pState = s:CCTreeGlobals.PreviewState
+ let tMarkers = s:CCTreeGlobals.Window.treeMarkers
+
+ return s:CCTreeGlobals.Window.mBuildStatusLine(
+ \ s:CCTreeGlobals.PreviewState,
+ \ s:windowtitle,
+ \ {'depth':''}
+ \)
+endfunction
+
+function! s:CCTreeWindow.mPreviewSave(savetitle) dict
+ if s:FindOpenWindow(s:windowtitle) == 1
+ setlocal modifiable
+ call self.mClearMarks(b:displayTree)
+ setlocal nomodifiable
+ setlocal statusline=%-F
+ silent! exec ":f ". a:savetitle
+ return s:CCTreeRC.Success
+ endif
+ return s:CCTreeRC.Error
+endfunction
+
+function! s:CCTreeWindow.mIsOpen() dict
+ if s:FindOpenBuffer(s:windowtitle) > 0
+ return s:CCTreeRC.True
+ endif
+ return s:CCTreeRC.False
+endfunction
+
+function! s:CCTreeWindow.mClose() dict
+ if s:FindOpenWindow(s:windowtitle) == 1
+ silent! q!
+ endif
+endfunction
+
+function! s:CCTreeWindow.mDisplayToggle() dict
+ if s:FindOpenWindow(s:windowtitle) == 1
+ silent! hide
+ else
+ let winbufnr = s:FindOpenBuffer(s:windowtitle)
+ if winbufnr > 0
+ call self.mEnter()
+ silent! exec "buf ".winbufnr
+ call self.mResize()
+ silent! wincmd p
+ else
+ call s:CCTreeUtils.mWarningMsg(" No active window found.")
+ endif
+ endif
+endfunction
+
+function! s:CCTreeWindow.mResize() dict
+ if g:CCTreeWindowVertical == 1
+ if g:CCTreeWindowWidth == -1
+ exec "vertical resize ". b:maxwindowlen
+ else
+ exec "vertical resize ". g:CCTreeWindowWidth
+ endif
+ else
+ if g:CCTreeWindowHeight != -1
+ let &winminheight = g:CCTreeWindowHeight
+ exec "resize".g:CCTreeWindowHeight
+ endif
+ endif
+endfunction
+
+function! s:CCTreeWindow.mDisplayTree(atree, direction) dict
+ let incctreewin = 1
+ if (bufname('%') != s:windowtitle)
+ let incctreewin = self.mEnter()
+ endif
+
+ setlocal modifiable
+ silent 1,$d
+ let b:maxwindowlen = g:CCTreeWindowMinWidth
+ let b:displayTree = s:DisplayTree.mCreate(a:atree,
+ \ a:direction, self.treeMarkers)
+ call s:CCTreeDisplay.mPopulateTreeInCurrentBuffer(b:displayTree)
+ exec "normal gg"
+
+ " Need to force this again
+ let &l:foldlevel=g:CCTreeMinVisibleDepth
+ setlocal nomodifiable
+ call self.mResize()
+ if (incctreewin == 0)
+ call s:CCTreeWindow.mLeave()
+ endif
+endfunction
+
+function! s:CCTreeWindow.mExtractTreeSymbols(dtree)
+ let symlist = {}
+ for aentry in a:dtree.entries
+ let symlist[aentry.symbol] = 0
+ endfor
+ return symlist
+endfunction
+
+function! s:CCTreeWindow.mEnter() dict
+ let self.lastbufname = bufname("%")
+ let foundWindow = s:FindOpenWindow(s:windowtitle)
+ if foundWindow == 0
+ if g:CCTreeWindowVertical == 1
+ exec g:CCTreeOrientation." vsplit ". s:windowtitle
+ set winfixwidth
+ else
+ exec g:CCTreeOrientation." split ". s:windowtitle
+ set winfixheight
+ endif
+
+ setlocal buftype=nofile
+ setlocal bufhidden=hide
+ setlocal noswapfile
+ setlocal nonumber
+ setlocal nowrap
+ setlocal nobuflisted
+
+ if s:CCTreeUseConceal == 1
+ setlocal cole=3
+ setlocal cocu=nv
+ endif
+
+ setlocal statusline=%=%{CCTreeWindowPreviewStatusLine()}
+
+ call self.mInitSyntax(self.treeMarkers.icons)
+ let cpo_save = &cpoptions
+ set cpoptions&vim
+
+ call s:CCTreeBufferKeyMappingsCreate(s:CCTreeKeyMappings)
+
+ command! -buffer -nargs=0 CCTreeWindowHiCallTree
+ \ call s:CCTreeGlobals.mCursorHoldHandleEvent()
+
+ exec 'nnoremap <buffer> <silent> '.s:CCTreeKeyMappings.CTreeHilight.
+ \' :CCTreeWindowHiCallTree<CR>'
+ exec 'nnoremap <buffer> <silent> '.s:CCTreeKeyMappings.CTreeCompress.
+ \ ' :2,.foldclose!<CR>zv'
+
+ nnoremap <buffer> <silent> <C-p> :CCTreePreviewBufferUsingTag<CR>
+ nnoremap <buffer> <silent> <CR> :CCTreeLoadBufferUsingTag<CR>
+ nnoremap <buffer> <silent> <2-LeftMouse> :CCTreeLoadBufferUsingTag<CR>
+
+ let &cpoptions = cpo_save
+ endif
+ setlocal foldmethod=expr
+ setlocal foldexpr=CCTreeFoldExpr(getline(v:lnum))
+ setlocal foldtext=CCTreeFoldText()
+ let &l:foldlevel=g:CCTreeMinVisibleDepth
+
+ return foundWindow
+endfunction
+" }}}
+" {{{ Dynamic call-tree highlighting using
+" syntax highlight tricks
+"
+" There are 3 types of lines, marked with the start character [\s, !, #]
+" Also @ is used to mark the path that is going up
+
+function! s:CCTreeWindow.mMarkCallTree(dtree, keyword) dict
+ let declevel = -1
+ let treelst = a:dtree.entries
+ let curLine = line(".")
+
+ let declevel = treelst[curLine-1].level
+
+ let targetlevel = declevel
+ for idx in range(curLine, 1, -1)
+ let aentry = treelst[idx-1]
+
+
+ " Find our keyword
+ let linemarker = 0
+ " Skip folds
+ if declevel != -1 && foldclosed(idx) == -1
+ if targetlevel == aentry.level
+ let linemarker = 1
+ let targetlevel -= 1
+ endif
+ let aline = a:dtree.mGetNotationalTxt(aentry.level, targetlevel+1, linemarker, 1)
+ \ . aentry.symbol
+ call setline(idx, aline)
+ endif
+ endfor
+endfunction
+
+function! s:CCTreeWindow.mClearMarks(dtree) dict
+ for idx in range(line(".")+1, line("$"))
+ let breakout = (getline(idx)[0] !~ "[!#]")
+ if breakout == 1
+ break
+ endif
+ let aentry = a:dtree.entries[idx-1]
+ let aline = a:dtree.mGetNotationalTxt(aentry.level, -1, 0, 0)
+ \ . aentry.symbol
+ call setline(idx, aline)
+ endfor
+endfunction
+
+function! s:CCTreeWindow.mInitSyntax(markers) dict
+ "syntax match CCTreePathMark /\s[|+]/ contained
+ exec 'syntax match CCTreePathMark /\s['. a:markers.vertSyms . ']/ contained'
+ "syntax match CCTreeArrow /-*[<>]/ contained
+ exec 'syntax match CCTreeArrow /'.a:markers.extH.'*['. a:markers.arrowSyms .']/ contained'
+
+ syntax match CCTreeSymbol / [A-Za-z0-9_\.\\\/]\+/ contained
+ syntax region CCTreeSymbolLine start="^\s" end="$" contains=CCTreeArrow,CCTreePathMark,CCTreeSymbol oneline
+
+ "syntax match CCTreeHiArrow /-*[<>]/ contained
+ exec 'syntax match CCTreeHiArrow /'. a:markers.extH .'*['. a:markers.arrowSyms .']/ contained'
+ syntax match CCTreeHiSymbol / [A-Za-z0-9_\.\\\/]\+/ contained
+
+ "syntax match CCTreeHiPathMark /\s[|+]/ contained
+ exec 'syntax match CCTreeHiPathMark /\s[' . a:markers.vertSyms . ']/ contained'
+
+ if s:CCTreeUseConceal == 1
+ syntax match CCTreeMarkExcl /^[!#]/ contained conceal
+ syntax match CCTreeMarkTilde /@/ contained conceal
+ else
+ syntax match CCTreeMarkExcl /^[!#]/ contained
+ syntax match CCTreeMarkTilde /@/ contained
+ endif
+ "syntax region CCTreeUpArrowBlock start="@" end=/[|+]/ contains=CCTreeMarkTilde contained oneline
+ exec 'syntax region CCTreeUpArrowBlock start="@" end=/['. a:markers.vertSyms .']/ contains=CCTreeMarkTilde contained oneline'
+
+ syntax region CCTreeHiSymbolLine start="!" end="$" contains=CCTreeMarkExcl,
+ \ CCTreeUpArrowBlock,
+ \ CCTreeHiSymbol,CCTreeHiArrow,CCTreeHiPathMark oneline
+
+ syntax region CCTreeMarkedSymbolLine start="#" end="$" contains=CCTreeMarkExcl,
+ \ CCTreeMarkTilde,CCTreePathMark,
+ \ CCTreeArrow,CCTreeSymbol,CCTreeUpArrowBlock oneline
+endfunction
+
+
+" }}}
+" {{{ CCTreeDisplay
+
+let s:CCTreeDisplay = {}
+
+function! s:CCTreeDisplay.mPopulateTreeInCurrentBuffer(dtree)
+ let linelist = []
+ for aentry in a:dtree.entries
+ let aline = a:dtree.mGetNotationalTxt(aentry.level, -1, 0, 0)
+ \ . aentry.symbol
+ let len = s:Utils.mStrlenEx(aline)
+ let b:maxwindowlen = max([len+1, b:maxwindowlen])
+ call add(linelist, aline)
+ endfor
+ call setline(".", linelist)
+endfunction
+
+
+
+" }}}
+" {{{ CCTree command line interface
+let s:CCTreeCmdLine = {}
+
+
+function! s:CCTreeCmdLine.mLoadDBFromDisk(dbName) dict
+ call s:CCTreeGlobals.mUnLoadDBs()
+ let s:CCTreeGlobals.XRefDb = s:XRefDiskDb.mCreate()
+ call s:CCTreeGlobals.DbList.mAddNew(a:dbName,
+ \ s:CCTreeGlobals.XRefDb, s:DBClasses.cctreexref, "Disk")
+endfunction
+
+" Unload current db's and load new one
+" There is no selective unloading
+function! s:CCTreeCmdLine.mLoadDB(db_name, class) dict
+ call s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(0)
+ call s:CCTreeGlobals.mUnLoadDBs()
+ let s:CCTreeGlobals.XRefDb = s:xRefMemDb.mCreate()
+ call s:CCTreeGlobals.DbList.mAddNew(a:db_name,
+ \ s:CCTreeGlobals.XRefDb, a:class, s:DBStorage.memory)
+ call s:CCTreeGlobals.mSetupAutoCmds()
+endfunction
+
+function! s:CCTreeCmdLine.mInputDBName(action, dbName, class) dict
+ if a:dbName == ''
+ let dbUser = s:CCTreeUI.mInputDBName(
+ \ s:CCTreeUtils.mDetectDB(a:class),
+ \ a:class, a:action)
+ else
+ let dbUser = a:dbName
+ endif
+ return dbUser
+endfunction
+
+function! s:CCTreeCmdLine.mSaveDB(dbName, class) dict
+ let dbUser = self.mInputDBName('Save', a:dbName, a:class)
+ if dbUser == ''
+ call s:CCTreeUtils.mWarningMsg('Filename required')
+ return
+ endif
+ call s:CCTreeGlobals.Window.mClose()
+ call s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(0)
+ call s:CCTreeGlobals.mWriteXRefDbToFile(dbUser)
+ call s:CCTreeGlobals.mSetupAutoCmds()
+ call s:CCTreeGlobals.mUpdateForCurrentSymbol()
+endfunction
+
+" Merge current db with new one
+function! s:CCTreeCmdLine.mMergeDB(db_name, class) dict
+ "call s:CCTreeGlobals.Window.mClose()
+ call s:CCTreeGlobals.DbList.mMerge(a:db_name, s:CCTreeGlobals.XRefDb, a:class)
+endfunction
+
+
+" }}}
+" {{{ CCTree Buffer mappings
+function! s:CCTreeWindowGetHiKeyword()
+ let keyw = expand("<cword>")
+ let keyf = expand("<cfile>")
+
+ let syms = s:CCTreeGlobals.mGetPreviewTreeSymbols()
+
+ if keyw != keyf
+ if has_key(syms, keyf)
+ return keyf
+ elseif has_key(syms, keyw)
+ return keyw
+ endif
+ else
+ return keyw
+ endif
+ return ''
+endfunction
+
+
+" Keymappings used common to source files and CCTree window
+function! s:CCTreeBufferKeyMappingsCreate(kmaps)
+ let func_expr = '<SNR>'.s:sid.'CCTreeWindowGetHiKeyword()'
+ exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeR.' :CCTreeTraceReverse <C-R>='.
+ \ func_expr.'<CR><CR>'
+ exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeF.' :CCTreeTraceForward <C-R>='
+ \ .func_expr.'<CR><CR>'
+
+ exec 'nnoremap <silent> '.a:kmaps.CTreeWSave. ' :CCTreeWindowSaveCopy<CR>'
+ exec 'nnoremap <silent> '.a:kmaps.CTreeWToggle. ' :CCTreeWindowToggle<CR>'
+
+ exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeDepthPlus.
+ \ ' :CCTreeRecurseDepthPlus<CR>'
+ exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeDepthMinus.
+ \ ' :CCTreeRecurseDepthMinus<CR>'
+endfunction
+
+augroup CCTreeMaps
+au!
+" Header files get detected as cpp?
+" This is a bug in Vim 7.2, a patch needs to be applied to the runtime c
+" syntax files
+" For now, use this hack to make *.h files work
+autocmd FileType * if &ft == 'c'|| &ft == 'cpp' |
+ \ call s:CCTreeBufferKeyMappingsCreate(s:CCTreeKeyMappings)|
+ \ endif
+augroup END
+
+
+" }}}
+" {{{ Tree building
+
+let s:DisplayTreeEntry = {
+ \ 'symbol': "",
+ \ 'level': -1
+ \ }
+
+function! s:DisplayTreeEntry.mCreate(sym, level) dict
+ let te = deepcopy(s:DisplayTreeEntry)
+ let te.symbol = a:sym
+ let te.level = a:level
+ unlet te.mCreate
+
+ return te
+endfunction
+
+let s:calltreemaxdepth = 10
+let s:DisplayTree = {
+ \ 'entries': [],
+ \ 'levelMaxLen': repeat([255], s:calltreemaxdepth),
+ \ 'notTxt': {}
+ \ }
+
+function! s:DisplayTree.mCreate(calltree, direction, markers) dict
+ let dt = deepcopy(s:DisplayTree)
+ call dt.mBuildTreeForLevel(a:calltree, 0)
+ call dt.mBuildNotationalTxtMarkers(a:direction, a:markers.icons)
+
+ unlet dt.mBuildTreeForLevel
+ unlet dt.mCreate
+
+ return dt
+endfunction
+
+function! s:DisplayTree.mBuildTreeForLevel(ctree, level)
+ if !has_key(a:ctree, 'symbol')
+ return
+ endif
+
+ if g:CCTreeDisplayMode == 3
+ let curlevellen = strlen(a:ctree.symbol) + a:level + 2
+ let self.levelMaxLen[a:level] = min([self.levelMaxLen[a:level],
+ \ curlevellen])
+ endif
+
+
+ let aentry = s:DisplayTreeEntry.mCreate(a:ctree.symbol, a:level)
+ call add(self.entries, aentry)
+
+ if has_key(a:ctree, 'childlinks')
+ for alink in a:ctree['childlinks']
+ call self.mBuildTreeForLevel(alink, a:level+1)
+ endfor
+ endif
+endfunction
+
+
+function! s:DisplayTree.mBuildNotationalTxtMarkers(direction, markerSyms) dict
+ " REVISIT
+ if a:direction == 'p'
+ let directiontxt = a:markerSyms.arrowR . " "
+ elseif a:direction == 'c'
+ let directiontxt = a:markerSyms.arrowF . " "
+ endif
+
+
+ let self.notTxt.arrowHead = a:markerSyms.splitT
+ let self.notTxt.arrow = directiontxt
+ let self.notTxt.arrowLead = a:markerSyms.extH
+ let self.notTxt.sep = a:markerSyms.extV
+ if s:CCTreeUseConceal == 1
+ let concealspace = " "
+ else
+ let concealspace = ""
+ endif
+
+ let self.notTxt.symHighlighter= concealspace . "@"
+
+ let self.notTxt.hiSymbolMarker = "!".concealspace
+ let self.notTxt.hiBranchMarker = "#".concealspace
+
+ let self.notTxt.cache = {}
+
+endfunction
+
+function! s:DisplayTree.mGetNotationalTxt(depth, hiDepth, hiSym, hiPath) dict
+ let notkey = join(a:000, ":")
+ if has_key(self.notTxt.cache,notkey) == 1
+ return self.notTxt.cache[notkey]
+ else
+ return self.mBuildNotationalTxt(a:depth, a:hiDepth, a:hiSym, a:hiPath)
+ endif
+endfunction
+
+function! s:DisplayTree.mBuildNotationalTxt(depth, hiDepth, hiSym, hiPath) dict
+ let hiBranch = 0
+ let curDepth = a:depth
+ if 0
+ let Aspace = "A"
+ let Bspace = "B"
+ let Cspace = "C"
+ let Sspace = "S"
+ let Xspace = "X"
+ let Zspace = "Z"
+ let Fspace = "1"
+ else
+ let Aspace = " "
+ let Bspace = " "
+ let Cspace = " "
+ let Sspace = " "
+ let Xspace = " "
+ let Zspace = " "
+ let Fspace = " "
+ endif
+
+ if g:CCTreeDisplayMode == 1
+ let arrowLeads = self.notTxt.arrowLead
+ elseif g:CCTreeDisplayMode >= 2
+ let arrowLeads = repeat(self.notTxt.arrowLead, a:depth)
+ endif
+
+ let indentSpace = ""
+ if g:CCTreeDisplayMode == 2
+ if curDepth > 0
+ let indentSpace = repeat(Aspace, curDepth)
+ endif
+ elseif g:CCTreeDisplayMode == 3
+ if curDepth > 0
+ let indentSpace = repeat(Aspace, self.levelMaxLen[curDepth-1])
+ endif
+ endif
+ let notTxt = self.notTxt.arrowHead. arrowLeads . self.notTxt.arrow
+ if a:hiDepth == a:depth
+ let notTxt = indentSpace . self.notTxt.symHighlighter . notTxt
+ let hiBranch = 1
+ else
+ let notTxt = indentSpace. Cspace. notTxt
+ endif
+ let curDepth -= 1
+
+ let indentSpace = ""
+ while (curDepth > 0)
+ if g:CCTreeDisplayMode == 2
+ let indentSpace = repeat(Bspace, curDepth)
+ elseif g:CCTreeDisplayMode == 3
+ let indentSpace = repeat(Bspace, self.levelMaxLen[curDepth-1])
+ endif
+ let notTxt = self.notTxt.sep . notTxt
+ if a:hiDepth == curDepth && a:hiPath == 1
+ let notTxt = indentSpace . self.notTxt.symHighlighter . notTxt
+ let hiBranch = 1
+ else
+ let notTxt = indentSpace. Cspace. notTxt
+ endif
+ let curDepth -= 1
+ endwhile
+ if curDepth == 0
+ " curdepth is 0
+ if a:hiDepth == curDepth && a:hiPath == 1
+ let notTxt = self.notTxt.symHighlighter . notTxt
+ let hiBranch = 1
+ else
+ let notTxt = Fspace . notTxt
+ endif
+ let curDepth -= 1
+ endif
+ " adjust space
+ if a:depth > 0
+ let notTxt = Xspace . notTxt
+ endif
+ if hiBranch == 1
+ if a:hiSym == 1
+ let notTxt = self.notTxt.hiSymbolMarker . notTxt
+ else
+ let notTxt = self.notTxt.hiBranchMarker . notTxt
+ endif
+ else
+ let notTxt = Sspace . notTxt
+ endif
+ return notTxt
+endfunction
+
+"}}}
+" {{{ Preview window Folding
+function! CCTreeFoldExpr(line)
+ if !exists('b:displayTree') || v:lnum > len(b:displayTree.entries)
+ return 0
+ endif
+
+ let lvl = b:displayTree.entries[v:lnum-1].level
+ if lvl == 0
+ let lvl = 1
+ endif
+ return '>'.lvl
+endfunction
+
+
+function! CCTreeFoldText()
+ if s:CCTreeUseConceal == 1
+ let line = substitute(getline(v:foldstart), '[!@#]', '' , 'g')
+ else
+ let line = substitute(getline(v:foldstart), '[!@#]', ' ' , 'g')
+ endif
+ return line. " (+". (v:foldend - v:foldstart).
+ \ ')'. repeat(" ", winwidth(0))
+endfunction
+" }}}
+" {{{ Syntax coloring definitions
+"Standard display
+highlight default link CCTreeSymbol Function
+highlight default link CCTreeMarkers LineNr
+highlight default link CCTreeArrow CCTreeMarkers
+highlight default link CCTreePathMark CCTreeArrow
+highlight default link CCTreeHiPathMark CCTreePathMark
+
+" highlighted display
+highlight default link CCTreeHiKeyword Macro
+highlight default link CCTreeHiSymbol TODO
+highlight default link CCTreeHiMarkers NonText
+highlight default link CCTreeHiArrow CCTreeHiMarkers
+highlight default link CCTreeUpArrowBlock CCTreeHiArrow
+
+highlight default link CCTreeMarkExcl Ignore
+highlight default link CCTreeMarkTilde Ignore
+"}}}
+" {{{ CCTree global state
+
+let s:CCTreePreviewState = {
+ \ 'keyword':'',
+ \ 'direction': '',
+ \ 'depth' : ''
+ \}
+
+function! s:CCTreePreviewState.mCreate()
+ let state = deepcopy(s:CCTreePreviewState)
+ unlet state.mCreate
+
+ return state
+endfunction
+
+function! s:CCTreePreviewState.mStore(symbol, direction)
+ let self.keyword = a:symbol
+ let self.direction = a:direction
+endfunction
+" }}}
+" {{{ CCTree global objects
+
+let s:CCTreeGlobals = {
+ \ 'XRefDb': {},
+ \ 'DbList': s:CCTreeDBList.mCreate(),
+ \ 'PreviewState': s:CCTreePreviewState.mCreate(),
+ \ 'Window': s:CCTreeWindow.mCreate()
+ \}
+
+let g:CCTreeGlobals = s:CCTreeGlobals
+
+function! s:CCTreeGlobals.mEnable(opt) dict
+ if (has_key(s:CCTreeOptions, a:opt))
+ call s:CCTreeOptions[a:opt](1)
+ else
+ call s:CCTreeUtils.mWarningMsg('Invalid option')
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mDisable(opt) dict
+ if (has_key(s:CCTreeOptions, a:opt))
+ call s:CCTreeOptions[a:opt](0)
+ else
+ call s:CCTreeUtils.mWarningMsg('Invalid option')
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mToggle(opt) dict
+ if (has_key(s:CCTreeOptions, a:opt))
+ call s:CCTreeOptions[a:opt](-1)
+ else
+ call s:CCTreeUtils.mWarningMsg('Invalid option')
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mGetSymNames(lead) dict
+ call self.XRefDb.mInitState()
+ let syms = self.XRefDb.mGetSymbolNames(a:lead)
+ call self.XRefDb.mRestoreState()
+ return syms
+endfunction
+
+
+function! s:CCTreeGlobals.mGetCallsForSymbol(name, depth, direction) dict
+ let pbar = s:ProgressBarRoll.mCreate(['-','\','|','/'], '*')
+ call s:StatusLine.mSetInfo('Building ')
+ redrawstatus!
+ " Create tracer
+ let xtracer = s:XRefTracer.mCreate(self.XRefDb)
+ call xtracer.mInitTracing()
+ let symid = self.XRefDb.mGetSymbolIdFromName(a:name)
+ let xrefs = xtracer.mBuildForSymbol(symid,
+ \ a:depth, self.PreviewState.depth, a:direction, pbar)
+ call xtracer.mDoneTracing()
+ return xrefs
+endfunction
+
+function! s:CCTreeGlobals.mShowLoadedDBs() dict
+ call self.DbList.mShowLoaded()
+endfunction
+
+function! s:CCTreeGlobals.mUnLoadDBs() dict
+ call s:CCTreeGlobals.Window.mClose()
+ if !empty(s:CCTreeGlobals.XRefDb)
+ call s:CCTreeGlobals.XRefDb.mClear()
+ endif
+ call s:CCTreeGlobals.DbList.mClearAll()
+endfunction
+
+function! s:CCTreeGlobals.mSetPreviewState(name, depth, direction) dict
+ let self.PreviewState.keyword = a:name
+ let self.PreviewState.direction = a:direction
+ let self.PreviewState.depth = a:depth
+endfunction
+
+function! s:CCTreeGlobals.mUpdateForCurrentSymbol() dict
+ if self.DbList.mIsEmpty() == s:CCTreeRC.True
+ return s:CCTreeRC.Error
+ endif
+ if self.PreviewState.keyword != ''
+ let swatch = s:StopWatch.mCreate()
+ " Move this function to globals?
+ call s:StatusLine.mInit()
+ let atree = self.mGetCallsForSymbol(self.PreviewState.keyword,
+ \ 0,
+ \ self.PreviewState.direction)
+ call s:StatusLine.mRestore()
+ call self.Window.mDisplayTree(atree, self.PreviewState.direction)
+
+ call swatch.mSnapElapsed()
+ endif
+endfunction
+
+
+function! s:CCTreeGlobals.mGetPreviewTreeSymbols()
+ " REVIST
+ if exists('b:displayTree')
+ return self.Window.mExtractTreeSymbols(b:displayTree)
+ end
+ return {}
+endfunction
+
+function! s:CCTreeGlobals.mSanitizeCallDepth() dict
+ let error = 0
+ if self.PreviewState.depth >= s:calltreemaxdepth
+ self.PreviewState.depth = s:calltreemaxdepth
+ let error = 1
+ elseif self.PreviewState.depth < 1
+ let self.PreviewState.depth = 1
+ let error = 1
+ endif
+
+ if error == 1
+ call s:CCTreeUtils.mWarningMsg('Depth out of bounds')
+ endif
+ return error
+endfunction
+
+function! s:CCTreeGlobals.mRecursiveDepthIncrease() dict
+ let self.PreviewState.depth += 1
+ if self.mSanitizeCallDepth() == 0
+ call self.mUpdateForCurrentSymbol()
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mRecursiveDepthDecrease() dict
+ let self.PreviewState.depth -= 1
+ if self.mSanitizeCallDepth() == 0
+ call self.mUpdateForCurrentSymbol()
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mDisplayToggle() dict
+ call self.Window.mDisplayToggle()
+endfunction
+
+function! s:CCTreeGlobals.mSetupAutoCmds() dict
+ augroup CCTreeGeneral
+ au!
+ augroup END
+ call s:CCTreeGlobals.mSetupCursorMoveAutoCmd(g:CCTreeHilightCallTree)
+ call s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(g:CCTreeUseUTF8Symbols)
+endfunction
+
+function! s:CCTreeGlobals.mSetupCursorMoveAutoCmd(enable) dict
+ if a:enable == 1
+ exec 'autocmd CCTreeGeneral CursorMoved '.s:windowtitle.' call s:CCTreeGlobals.mCursorHoldHandleEvent()'
+ else
+ exec 'autocmd! CCTreeGeneral CursorMoved '.s:windowtitle
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(enable) dict
+ return
+ if a:enable == 1
+ autocmd CCTreeGeneral EncodingChanged * call s:CCTreeGlobals.mEncodingChangedHandleEvent()
+ else
+ autocmd! CCTreeGeneral EncodingChanged *
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mPreviewSave() dict
+ let rtitle = s:CCTreeGlobals.Window.mBuildStatusLine(
+ \ s:CCTreeGlobals.PreviewState,
+ \ s:windowsavetitle,
+ \ {'depth':'', 'direction':''}
+ \)
+
+ if self.Window.mPreviewSave(rtitle) == s:CCTreeRC.Success
+ call s:CCTreeUtils.mInfoMsg('Window saved as '. rtitle .
+ \ '. New window will be opened on next usage.')
+ else
+ call s:CCTreeUtils.mWarningMsg('No active window found to be saved.')
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mWriteXRefDbToFile(fname) dict
+ " create db serializer and writer
+ let gDbSz = s:GenericDbSerializer.mCreate(self.XRefDb)
+ let gDbWriter = s:CCTreeTagDbWriter.mCreate(
+ \ s:CCTreeGetXRefDbMaps('Compress', 'Alpha'))
+ call gDbSz.mWriteXRefDbToFile(a:fname, gDbWriter)
+endfunction
+
+function! s:CCTreeGlobals.mReadToXRefDb(fname) dict
+ call s:StatusLine.mInit()
+ call s:StatusLine.mSetInfo('Reading XRefDb')
+ let vDbFile = s:vFile.mCreate(a:fname, "r")
+ if vDbFile.mIsLargeFile() == 1
+ call s:StatusLine.mSetExtraInfo('Xref DB '
+ \.' >'.g:CCTreeDbFileMaxSize .' bytes. Splitting '.
+ \'into smaller chunks... (this may take some time)')
+ endif
+ try
+ if vDbFile.mOpen() == 0
+ call s:TagFile.mReadToXRefDb(self.XRefDb, vDbFile)
+ endif
+ finally
+ call vDbFile.mClose()
+ call s:StatusLine.mRestore()
+ call self.DbList.mAddDbToList(a:fname, s:DBStorage.memory)
+ endtry
+endfunction
+
+function! s:CCTreeGlobals.mCursorHoldHandleEvent() dict
+ if self.Window.mGetKeywordAtCursor() != s:CCTreeRC.Error
+ setlocal modifiable
+ call self.Window.mClearMarks(b:displayTree)
+ call self.Window.mMarkCallTree(b:displayTree,
+ \ self.Window.hiKeyword)
+ setlocal nomodifiable
+ endif
+endfunction
+
+function! s:CCTreeGlobals.mEncodingChangedHandleEvent() dict
+ let self.Window.treeMarkers = s:CCTreeMarkers.mCreate()
+ if self.Window.mIsOpen() == s:CCTreeRC.True
+ call self.Window.mClose()
+ call self.mUpdateForCurrentSymbol()
+ endif
+endfunction
+
+
+function! s:CCTreeGlobals.mInit() dict
+ call self.mSetupAutoCmds()
+endfunction
+
+" }}}
+" {{{ CCTree options
+function! s:CCTreeSetUseCallTreeHiLights(val)
+ if a:val == -1
+ let g:CCTreeHilightCallTree = !g:CCTreeHilightCallTree
+ else
+ let g:CCTreeHilightCallTree = a:val
+ endif
+ call s:CCTreeGlobals.mSetupAutoCmds()
+endfunction
+
+function! s:CCTreeSetUseUtf8Symbols(val)
+ if a:val == -1
+ let g:CCTreeUseUTF8Symbols = !g:CCTreeUseUTF8Symbols
+ else
+ let g:CCTreeUseUTF8Symbols = a:val
+ endif
+ call s:CCTreeGlobals.mEncodingChangedHandleEvent()
+endfunction
+
+function! s:CCTreeSetUseConceal(val)
+ if a:val == -1
+ let s:CCTreeUseConceal = !s:CCTreeUseConceal
+ else
+ let s:CCTreeUseConceal = a:val
+ endif
+ if !has('conceal')
+ call s:CCTreeUtils.mWarningMsg('+conceal feature not available')
+ let s:CCTreeUseConceal = 0
+ endif
+endfunction
+
+function! s:CCTreeSetEnhancedSymbolProcessing(val)
+ if a:val == -1
+ let g:CCTreeEnhancedSymbolProcessing = !g:CCTreeEnhancedSymbolProcessing
+ else
+ let g:CCTreeEnhancedSymbolProcessing = a:val
+ endif
+endfunction
+
+function! s:CCTreeOptionsList(arglead, cmdline, cursorpos)
+ let opts = keys(s:CCTreeOptions)
+ if a:arglead == ''
+ return opts
+ else
+ return filter(opts, 'v:val =~? a:arglead')
+ endif
+endfunction
+
+let s:CCTreeOptions = {'UseUnicodeSymbols': function('s:CCTreeSetUseUtf8Symbols'),
+ \ 'DynamicTreeHiLights': function('s:CCTreeSetUseCallTreeHiLights'),
+ \ 'UseConceal': function('s:CCTreeSetUseConceal'),
+ \ 'EnhancedSymbolProcessing': function('s:CCTreeSetEnhancedSymbolProcessing')
+ \}
+
+" }}}
+" {{{ Vim tags interface
+
+" CCTreeCompleteKwd
+" Command line completion function to return names from the db
+function! s:CCTreeCompleteKwd(arglead, cmdline, cursorpos)
+ let syms = s:CCTreeGlobals.mGetSymNames(a:arglead)
+ if a:arglead == ''
+ return syms
+ else
+ return filter(syms, 'v:val =~? a:arglead')
+ endif
+endfunction
+
+function! s:CCTreeTraceTreeForSymbol(sym_arg, direction)
+ if s:CCTreeGlobals.DbList.mIsEmpty() == s:CCTreeRC.True
+ call s:CCTreeUtils.mWarningMsg('No database loaded')
+ return
+ endif
+
+ let symbol = a:sym_arg
+ if symbol == ''
+ let symbol = input('Trace symbol: ', expand('<cword>'),
+ \ 'customlist,<SNR>' . s:sid . 'CCTreeCompleteKwd')
+ if symbol == ''
+ return
+ endif
+ endif
+ let symmatch = s:CCTreeGlobals.mGetSymNames(symbol)
+ if len(symmatch) > 0 && index(symmatch, symbol) >= 0
+ call s:CCTreeGlobals.mSetPreviewState(symbol,
+ \ g:CCTreeRecursiveDepth,
+ \ a:direction)
+ call s:CCTreeGlobals.mUpdateForCurrentSymbol()
+ else
+ call s:CCTreeUtils.mWarningMsg('Symbol not found')
+ endif
+endfunction
+
+
+
+
+function! s:CCTreeGlobals.mLoadBufferFromKeyword()
+ " REVISIT
+ if s:CCTreeGlobals.Window.mGetKeywordAtCursor() == s:CCTreeRC.Error
+ call s:CCTreeUtils.mWarningMsg('No keyword at cursor')
+ return
+ endif
+
+ let hiKeyword = s:CCTreeGlobals.Window.hiKeyword
+ try
+ wincmd p
+ catch
+ call s:CCTreeUtils.mWarningMsg('No buffer to load file')
+ finally
+ if (cscope_connection() > 0)
+ try
+ exec "cs find g ". hiKeyword
+ catch
+ " cheap hack
+ exec "cs find f ". hiKeyword
+ endtry
+ else
+ try
+ " Ctags is smart enough to figure the path
+ exec "tag ".fnamemodify(hiKeyword, ":t")
+ catch /^Vim\%((\a\+)\)\=:E433/
+ call s:CCTreeUtils.mWarningMsg('Tag file not found')
+ catch /^Vim\%((\a\+)\)\=:E426/
+ call s:CCTreeUtils.mWarningMsg('Tag '. hiKeyword .' not found')
+ wincmd p
+ endtry
+ endif
+ endtry
+endfunction
+
+function! s:CCTreeGlobals.mPreviewBufferFromKeyword()
+ if self.Window.mGetKeywordAtCursor() == s:CCTreeRC.Error
+ call s:CCTreeUtils.mWarningMsg('No keyword found')
+ return
+ endif
+
+ let hiKeyword = s:CCTreeGlobals.Window.hiKeyword
+ silent! wincmd P
+ if !&previewwindow
+ wincmd p
+ endif
+ try
+ exec "ptag ". hiKeyword
+ catch
+ call s:CCTreeUtils.mWarningMsg('Tag '.hiKeyword. ' not found')
+ endtry
+endfunction
+
+" }}}
+" {{{ Define commands
+command! -nargs=? -complete=file CCTreeLoadXRefDBFromDisk
+ \ call s:CCTreeCmdLine.mLoadDBFromDisk(<q-args>)
+command! -nargs=? -complete=file CCTreeLoadDB call s:CCTreeCmdLine.mLoadDB(<q-args>, s:DBClasses.cscopeid)
+command! -nargs=? -complete=file CCTreeLoadXRefDB call s:CCTreeCmdLine.mLoadDB(<q-args>, s:DBClasses.cctreexref)
+command! -nargs=? -complete=file CCTreeSaveXRefDB call s:CCTreeCmdLine.mSaveDB(<q-args>, s:DBClasses.cctreexref)
+command! -nargs=? -complete=file CCTreeAppendDB call s:CCTreeCmdLine.mMergeDB(<q-args>, s:DBClasses.cscopeid)
+command! -nargs=0 CCTreeUnLoadDB call s:CCTreeGlobals.mUnLoadDBs()
+command! -nargs=0 CCTreeShowLoadedDBs call s:CCTreeGlobals.mShowLoadedDBs()
+command! -nargs=? -complete=customlist,s:CCTreeCompleteKwd
+ \ CCTreeTraceForward call s:CCTreeTraceTreeForSymbol(<q-args>, 'c')
+command! -nargs=? -complete=customlist,s:CCTreeCompleteKwd CCTreeTraceReverse
+ \ call s:CCTreeTraceTreeForSymbol(<q-args>, 'p')
+command! -nargs=0 CCTreeLoadBufferUsingTag call s:CCTreeGlobals.mLoadBufferFromKeyword()
+command! -nargs=0 CCTreePreviewBufferUsingTag call s:CCTreeGlobals.mPreviewBufferFromKeyword()
+command! -nargs=0 CCTreeRecurseDepthPlus call s:CCTreeGlobals.mRecursiveDepthIncrease()
+command! -nargs=0 CCTreeRecurseDepthMinus call s:CCTreeGlobals.mRecursiveDepthDecrease()
+" Preview Window
+command! -nargs=0 CCTreeWindowToggle call s:CCTreeGlobals.mDisplayToggle()
+command! -nargs=0 CCTreeWindowSaveCopy call s:CCTreeGlobals.mPreviewSave()
+" Run-time dynamic options
+command! -nargs=1 -complete=customlist,s:CCTreeOptionsList CCTreeOptsEnable call s:CCTreeGlobals.mEnable(<q-args>)
+command! -nargs=1 -complete=customlist,s:CCTreeOptionsList CCTreeOptsDisable call s:CCTreeGlobals.mDisable(<q-args>)
+command! -nargs=1 -complete=customlist,s:CCTreeOptionsList CCTreeOptsToggle call s:CCTreeGlobals.mToggle(<q-args>)
+"}}}
+" {{{ finish (and init)
+call s:CCTreeGlobals.mInit()
+" restore 'cpo'
+let &cpoptions = s:cpo_save
+unlet s:cpo_save
+" vim: ts=8 sw=4 sts=4 et foldenable foldmethod=marker foldcolumn=1
+" }}}