[cscope] Adding cctree.vim vi plugin

Neil Horman nhorman at fedoraproject.org
Thu May 26 20:01:45 UTC 2011


commit 07eae65deefd0e839c735274b7e7c318f205ea79
Author: Neil Horman <nhorman at tuxdriver.com>
Date:   Thu May 26 16:01:23 2011 -0400

    Adding cctree.vim vi plugin

 cscope-15.7a-add-cctree.patch | 3943 +++++++++++++++++++++++++++++++++++++++++
 cscope.spec                   |   20 +-
 2 files changed, 3960 insertions(+), 3 deletions(-)
---
diff --git a/cscope-15.7a-add-cctree.patch b/cscope-15.7a-add-cctree.patch
new file mode 100644
index 0000000..2ca6542
--- /dev/null
+++ b/cscope-15.7a-add-cctree.patch
@@ -0,0 +1,3943 @@
+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 at 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
++" }}}
diff --git a/cscope.spec b/cscope.spec
index 17569a1..e7653b5 100644
--- a/cscope.spec
+++ b/cscope.spec
@@ -1,7 +1,7 @@
 Summary: C source code tree search and browse tool 
 Name: cscope
 Version: 15.7a
-Release: 3%{?dist}
+Release: 4%{?dist}
 Source0: http://unc.dl.sourceforge.net/sourceforge/cscope/cscope-15.7a.tar.bz2
 URL: http://cscope.sourceforge.net
 License: BSD 
@@ -12,11 +12,13 @@ BuildRequires: pkgconfig ncurses-devel flex bison m4
 %define cscope_share_path %{_datadir}/cscope
 %define xemacs_lisp_path %{_datadir}/xemacs/site-packages/lisp
 %define emacs_lisp_path %{_datadir}/emacs/site-lisp
+%define vim_plugin_path %{datadir}/vim/vimfiles/plugin
 
 Patch0:cscope-15.6-findassign.patch
 Patch1:cscope-15.6-ocs.patch
 Patch2:cscope-15.6-xcscope-man.patch
 Patch3:cscope-15.7-sig_pipe.patch
+Patch4:cscope-15.7a-add-cctree.patch
 
 %description
 cscope is a mature, ncurses based, C source code tree browsing tool.  It 
@@ -31,6 +33,7 @@ matches for use in file editing.
 %patch1 -p1
 %patch2 -p1
 %patch3 -p1
+%patch4 -p1
 
 %build
 %configure
@@ -43,6 +46,7 @@ mkdir -p $RPM_BUILD_ROOT/var/lib/cs
 mkdir -p $RPM_BUILD_ROOT%{cscope_share_path}
 cp -a contrib/xcscope/xcscope.el $RPM_BUILD_ROOT%{cscope_share_path}
 cp -a contrib/xcscope/cscope-indexer $RPM_BUILD_ROOT%{_bindir}
+cp -a contrib/cctree.vim $RPM_BUILD_ROOT%{cscope_share_path}
 for dir in %{xemacs_lisp_path} %{emacs_lisp_path} ; do
   mkdir -p $RPM_BUILD_ROOT$dir
   ln -s %{cscope_share_path}/xcscope.el $RPM_BUILD_ROOT$dir
@@ -59,10 +63,10 @@ rm -rf $RPM_BUILD_ROOT
 %defattr(-,root,root,-)
 %{_bindir}/*
 %dir %{cscope_share_path}
-%{cscope_share_path}/xcscope.el
+%{cscope_share_path}/
 %{_mandir}/man1/*
 %dir /var/lib/cs
-%doc AUTHORS COPYING ChangeLog README TODO
+%doc AUTHORS COPYING ChangeLog README TODO contrib/cctree.txt
 
 %triggerin -- xemacs
 ln -sf %{cscope_share_path}/xcscope.el %{xemacs_lisp_path}/xcscope.el
@@ -70,6 +74,9 @@ ln -sf %{cscope_share_path}/xcscope.el %{xemacs_lisp_path}/xcscope.el
 %triggerin -- emacs
 ln -sf %{cscope_share_path}/xcscope.el %{emacs_lisp_path}/xcscope.el
 
+%triggerin -- vim-filesystem
+ln -sf %{cscope_share_path}/cctree.vim %{vim_plugin_path}/cctree.vim
+
 %triggerun -- xemacs
 [ $2 -gt 0 ] && exit 0
 rm -f %{xemacs_lisp_path}/xcscope.el
@@ -78,7 +85,14 @@ rm -f %{xemacs_lisp_path}/xcscope.el
 [ $2 -gt 0 ] && exit 0
 rm -f %{emacs_lisp_path}/xcscope.el
 
+%triggerun -- vim-filesystem
+[ $2 -gt 0 ] && exit 0
+rm -f %{vim_plugin_path}/cctree.vim
+
 %changelog
+* Thu May 26 2011 Neil Horman <nhorman at redhat.com> - 15.7a-4
+- Added cctree.vim vi plugin
+
 * Tue Feb 08 2011 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 15.7a-3
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
 


More information about the scm-commits mailing list