1 " C Call-Tree Explorer (CCTree) <CCTree.vim>
4 " Script Info and Documentation
5 "=============================================================================
6 " Copyright: Copyright (C) August 2008 - 2010, Hari Rangarajan
7 " Permission is hereby granted to use and distribute this code,
8 " with or without modifications, provided that this copyright
9 " notice is copied with it. Like anything else that's free,
10 " cctree.vim is provided *as is* and comes with no
11 " warranty of any kind, either expressed or implied. In no
12 " event will the copyright holder be liable for any damamges
13 " resulting from the use of this software.
15 " Name Of File: CCTree.vim
16 " Description: C Call-Tree Explorer Vim Plugin
17 " Maintainer: Hari Rangarajan <hari.rangarajan@gmail.com>
18 " URL: http://vim.sourceforge.net/scripts/script.php?script_id=2368
19 " Last Change: July 12, 2009
22 "=============================================================================
25 " Plugin generates call-trees for any function or macro in real-time inside
28 " Requirements: 1) Cscope
31 " Tested on Unix and the following Win32 versions:
32 " + Cscope, mlcscope (WIN32)
33 " http://www.geocities.com/shankara_c/cscope.html
34 " http://www.bell-labs.com/project/wwexptools/packages.html
39 " Copy this file to ~/.vim/plugins/
40 " or to /vimfiles/plugins/ (on Win32 platforms)
42 " It might also be possible to load it as a filetype plugin
45 " Need to set :filetype plugin on
49 " Build cscope database, for example:
50 " > cscope -b -i cscope.files
51 " [Tip: add -c option to build uncompressed databases for faster
54 " Load database with command ":CCTreeLoadDB"
55 " (Please note that it might take a while depending on the
58 " Append database with command ":CCTreeAppendDB"
59 " Allows multiple cscope files to be loaded and cross-referenced
61 " :CCTreeAppendDB ./cscope.out
62 " :CCTreeAppendDB ./dir1/cscope.out
63 " :CCTreeAppendDB ./dir2/cscope.out
65 " A database name, i.e., my_cscope.out, can be specified with
66 " the command. If not provided, a prompt will ask for the
67 " filename; default is cscope.out.
69 " To show loaded databases, use command ":CCTreeShowLoadedDBs"
71 " To unload all databases, use command ":CCTreeUnLoadDB"
72 " Note: There is no provision to unload databases individually
75 " Get reverse call tree for symbol <C-\><
76 " Get forward call tree for symbol <C-\>>
77 " Increase depth of tree and update <C-\>=
78 " Decrease depth of tree and update <C-\>-
80 " Open symbol in other window <CR>
81 " Preview symbol in other window <Ctrl-P>
84 " CCTreeLoadDB <dbname>
85 " CCTreeAppendDB <dbname>
87 " CCTreeTraceForward <symbolname>
88 " CCTreeTraceReverse <symbolname>
89 " CCTreeRecurseDepthPlus
90 " CCTreeRecurseDepthMinus
95 " Customize behavior by changing the variable settings
97 " Cscope database file, g:CCTreeCscopeDb = "cscope.out"
98 " Maximum call levels, g:CCTreeRecursiveDepth = 3
99 " Maximum visible(unfolded) level, g:CCTreeMinVisibleDepth = 3
100 " Orientation of window, g:CCTreeOrientation = "topleft"
101 " (standard vim options for split: [right|left][above|below])
103 " Use Vertical window, g:CCTreeWindowVertical = 1
104 " Min width for window, g:CCTreeWindowMinWidth = 40
105 " g:CCTreeWindowWidth = -1, auto-select best width to fit
107 " Horizontal window, g:CCTreeWindowHeight, default is -1
110 " Display format, g:CCTreeDisplayMode, default 1
112 " Values: 1 -- Ultra-compact (takes minimum screen width)
113 " 2 -- Compact (Takes little more space)
114 " 3 -- Wide (Takes copious amounts of space)
116 " For vertical splits, 1 and 2 are good, while 3 is good for
117 " horizontal displays
119 " NOTE: To get older behavior, add the following to your vimrc
120 " let g:CCTreeDisplayMode = 3
121 " let g:CCTreeWindowVertical = 0
124 " CCTreeSymbol is the symbol name
125 " CCTreeMarkers include "|","+--->"
127 " CCTreeHiSymbol is the highlighted call tree functions
128 " CCTreeHiMarkers is the same as CCTreeMarkers except
129 " these denote the highlighted call-tree
132 " CCTreeHiXXXX allows dynamic highlighting of the call-tree.
133 " To observe the effect, move the cursor to the function to
134 " highlight the current call-tree. This option can be
135 " turned off using the setting, g:CCTreeHilightCallTree.
136 " For faster highlighting, the value of 'updatetime' can be
140 " The accuracy of the call-tree will only be as good as the cscope
141 " database generation.
142 " NOTE: Different flavors of Cscope have some known
143 " limitations due to the lexical analysis engine. This results
144 " in incorrectly identified function blocks, etc.
147 " Version 0.71: May 11, 2010
150 " Version 0.70: May 8, 2010
151 " 1. Functionality to load multiple cscope databases
153 " Version 0.65: July 12, 2009
154 " 1. Toggle preview window
156 " Version 0.61: December 24, 2008
157 " 1. Fixed bug when processing include files
158 " 2. Remove 'set ruler' option
160 " Version 0.60: November 26, 2008
161 " 1. Added support for source-file dependency tree
163 " Version 0.50: October 17, 2008
164 " 1. Optimizations for compact memory foot-print and
165 " improved compressed-database load speeds
167 " Version 0.41: October 6, 2008
168 " 1. Minor fix: Compressed cscope databases will load
169 " incorrectly if encoding is not 8-bit
171 " Version 0.4: September 28, 2008
172 " 1. Rewrite of "tree-display" code
173 " 2. New syntax hightlighting
174 " 3. Dynamic highlighting for call-trees
175 " 4. Support for new window modes (vertical, horizontal)
176 " 5. New display format option for compact or wide call-trees
177 " NOTE: defaults for tree-orientation set to vertical
181 " 1. Support compressed cscope databases
182 " 2. Display window related bugs fixed
183 " 3. More intuitive display and folding capabilities
187 " (Patches from Yegappan Lakshmanan, thanks!)
188 " 1. Support for using the plugin in Vi-compatible mode.
189 " 2. Filtering out unwanted lines before processing the db.
190 " 3. Command-line completion for the commands.
191 " 4. Using the cscope db from any directory.
195 " 1. Cross-referencing support for only functions and macros
196 " Functions inside macro definitions will be incorrectly
197 " attributed to the top level calling function
202 " Arun Chaganty/Timo Tiefel (Ver 0.60 -- bug report)
203 " Michael Wookey (Ver 0.4 -- Testing/bug report/patches)
204 " Yegappan Lakshmanan (Ver 0.2 -- Patches)
206 " The Vim Community, ofcourse :)
208 "=============================================================================
210 if !exists('loaded_cctree') && v:version >= 700
211 " First time loading the cctree plugin
212 let loaded_cctree = 1
217 " Line continuation used here
218 let s:cpo_save = &cpoptions
222 " Modify in .vimrc to modify default behavior
223 if !exists('CCTreeCscopeDb')
224 let CCTreeCscopeDb = "cscope.out"
226 if !exists('CCTreeRecursiveDepth')
227 let CCTreeRecursiveDepth = 3
229 if !exists('CCTreeMinVisibleDepth')
230 let CCTreeMinVisibleDepth = 3
232 if !exists('CCTreeOrientation')
233 let CCTreeOrientation = "topleft"
235 if !exists('CCTreeWindowVertical')
236 let CCTreeWindowVertical = 1
238 if !exists('CCTreeWindowWidth')
239 " -1 is auto select best width
240 let CCTreeWindowWidth = -1
242 if !exists('CCTreeWindowMinWidth')
243 let CCTreeWindowMinWidth = 40
245 if !exists('CCTreeWindowHeight')
246 let CCTreeWindowHeight = -1
248 if !exists('CCTreeDisplayMode')
249 let CCTreeDisplayMode = 1
251 if !exists('CCTreeHilightCallTree')
252 let CCTreeHilightCallTree = 1
255 " Plugin related local variables
256 let s:pluginname = 'CCTree'
257 let s:windowtitle = 'CCTree-Preview'
259 " There could be duplicate keywords on different lines
260 let s:CCTreekeyword = ''
261 let s:CCTreekeywordLine = -1
263 " Definition of a keyword...
264 let s:CCTreeKeywordRegEx = '[A-Za-z0-9_\\\.\/]\+'
266 " Other state variables
267 let s:currentkeyword = ''
268 let s:currentdirection = ''
270 let s:symhashtable = {}
271 let s:save_statusline = ''
272 let s:lastbufname = ''
278 " Use the Decho plugin for debugging
279 function! DBGecho(...)
285 function! DBGredir(...)
292 let s:symlistindex = 0
293 let s:symlisttable = []
295 function! s:CCTreeSymbolListAdd(name)
296 if !has_key(s:symhashtable, a:name)
297 let s:symhashtable[a:name] = s:symlistindex
298 call add(s:symlisttable, s:CCTreeSymbolDictCreate(a:name))
299 let s:symlistindex += 1
301 return s:symhashtable[a:name]
304 function! s:CCTreeSymbolDictCreate(name)
307 let retval['n'] = a:name
313 function! s:CCTreeSymbolMarkXRef(funcentryidx, newfuncidx)
314 let s:symlisttable[a:funcentryidx]['c'] .= (a:newfuncidx. ",")
315 let s:symlisttable[a:newfuncidx]['p'] .= (a:funcentryidx. ",")
319 function! s:CCTreeInitStatusLine()
320 let s:symlastprogress = 0
321 let s:symprogress = 0
323 let s:currentstatus = ''
324 let s:statusextra = ''
326 let s:save_statusline = &statusline
327 setlocal statusline=%{CCTreeStatusLine()}
330 function! s:CCTreeRestoreStatusLine()
331 let &statusline = s:save_statusline
334 function! s:CCTreeBusyStatusLineUpdate(msg)
335 let s:currentstatus = a:msg
339 function! s:CCTreeBusyStatusLineExtraInfo(msg)
340 let s:statusextra = a:msg
344 function! CCTreeStatusLine()
345 return s:pluginname. " ". s:currentstatus. " -- ". s:statusextra
349 let s:progresscurrent = 0
350 let s:progressmax = 0
352 function! s:CCTreeProgressBarInit(maxcount)
353 let s:progressmax = a:maxcount
354 let s:progress1percent = a:maxcount/100
355 let s:progresspercent = 0
359 function! s:CCTreeProgressBarTick(count)
360 let s:progresscurrent += a:count
361 if s:progress1percent < s:progresscurrent
362 let s:progresscurrent = 0
363 let s:progresspercent += 1
364 call s:CCTreeBusyStatusLineExtraInfo("Processing ". s:progresspercent .
365 \ "\%, total ". s:progressmax. " items")
370 function! s:CCTreeWarningMsg(msg)
376 function! s:CCTreePreprocessFilter (val)
377 call s:CCTreeProgressBarTick(1)
378 return a:val =~ "^\t[`#$}]|^\k"
382 function! s:CCTreeLoadDB(db_name)
383 call s:CCTreeLoadDBExt(a:db_name, 1)
386 function! s:CCTreeAppendDB(db_name)
387 call s:CCTreeLoadDBExt(a:db_name, 0)
391 function! s:CCTreeLoadDBExt(db_name, clear)
398 call s:CCTreeUnloadDB()
401 let cscope_db = a:db_name
403 let cscope_db = input('Cscope database: ', g:CCTreeCscopeDb, 'file')
409 if !filereadable(cscope_db)
410 call s:CCTreeWarningMsg('Cscope database ' . cscope_db . ' not found')
414 call add(s:loadedDBs, getcwd().'/'.a:db_name)
416 call s:CCTreeBusyStatusLineUpdate('Loading database')
417 let symbols = readfile(cscope_db)
419 call s:CCTreeWarningMsg("Failed to read cscope database")
420 call s:CCTreeRestoreStatusLine()
425 let symlocalstart = 0
426 let symlocalcount = 0
428 " Grab previous status line
429 call s:CCTreeInitStatusLine()
431 call s:CCTreeBusyStatusLineUpdate('Reading database')
432 " Check if database was built uncompressed
433 if symbols[0] !~ "cscope.*\-c"
434 let s:dbcompressed = 1
436 let s:dbcompressed = 0
438 " Filter-out lines that doesn't have relevant information
439 call filter(symbols, 'v:val =~ "^\t[`#$}@\~]"')
440 call s:CCTreeProgressBarInit(len(symbols))
442 call s:CCTreeBusyStatusLineUpdate('Analyzing database')
444 call s:CCTreeProgressBarTick(1)
448 let newfuncidx = s:CCTreeSymbolListAdd(a[2:])
449 call s:CCTreeSymbolMarkXRef(curfuncidx, newfuncidx)
452 let curfuncidx = s:CCTreeSymbolListAdd(a[2:])
454 call s:CCTreeSymbolListAdd(a[2:])
458 let newfileidx = s:CCTreeSymbolListAdd(a[3:])
459 call s:CCTreeSymbolMarkXRef(curfileidx, newfileidx)
462 let curfileidx = s:CCTreeSymbolListAdd(a[2:])
467 if s:dbcompressed == 1
468 call s:CCTreeBusyStatusLineUpdate('Uncompressing database')
469 " inplace uncompression
470 call s:Digraph_Uncompress(s:symlisttable, s:symhashtable)
473 call s:CCTreeRestoreStatusLine()
475 echomsg "Done building database"
478 function! s:CCTreeShowLoadedDBs()
480 echomsg "CCTree: List of loaded cscope databases"
481 echomsg "---------------------------------------"
482 for aDB in s:loadedDBs
488 function! s:CCTreeUnloadDB()
495 call garbagecollect()
497 let s:symlisttable = []
498 let s:symhashtable = {}
503 function! s:CCTreeGetSymbolXRef(symname, direction)
504 let symentryidx = s:symhashtable[a:symname]
505 let symidslist = split(s:symlisttable[symentryidx][a:direction], ",")
508 for asymid in symidslist
509 let xrefs[s:symlisttable[asymid]['n']] = 1
514 function! s:CCTreeGetCallsForSymbol(symname, depth, direction)
515 if (a:depth > g:CCTreeRecursiveDepth)
519 if !has_key(s:symhashtable, a:symname)
523 let calltree_dict = {}
524 let calltree_dict['entry'] = a:symname
526 for entry in keys(s:CCTreeGetSymbolXRef(a:symname, a:direction))
527 if !has_key(calltree_dict, 'childlinks')
528 let calltree_dict['childlinks'] = []
531 \s:CCTreeGetCallsForSymbol(entry, a:depth+1, a:direction)
532 call add(calltree_dict['childlinks'], tmpDict)
537 func! s:FindOpenBuffer(filename)
538 let bnrHigh = bufnr("$")
539 "tabpagebuflist(tabpagenr())
541 for bufnrs in range(1, bnrHigh)
542 if (bufexists(bufnrs) == 1 && bufname(bufnrs) == a:filename)
546 " Could not find the buffer
550 func! s:FindOpenWindow(filename)
551 let bufnr = s:FindOpenBuffer(a:filename)
553 let newWinnr = bufwinnr(bufnr)
555 exec newWinnr.'wincmd w'
559 " Could not find the buffer
563 function! s:CCTreePreviewWindowLeave()
564 call s:FindOpenWindow(s:lastbufname)
567 function! CCTreePreviewStatusLine()
568 let rtitle= s:windowtitle. ' -- '. s:currentkeyword.
569 \'[Depth: '. g:CCTreeRecursiveDepth.','
571 if s:currentdirection == 'p'
572 let rtitle .= "(Reverse)"
574 let rtitle .= "(Forward)"
580 function! s:CCTreePreviewWindowEnter()
581 let s:lastbufname = bufname("%")
582 if s:FindOpenWindow(s:windowtitle) == 0
583 if g:CCTreeWindowVertical == 1
584 exec g:CCTreeOrientation." vsplit ". s:windowtitle
587 exec g:CCTreeOrientation." split ". s:windowtitle
591 setlocal buftype=nofile
592 setlocal bufhidden=hide
595 setlocal statusline=%=%{CCTreePreviewStatusLine()}
598 syntax match CCTreePathMark /\s[|+]/ contained
599 syntax match CCTreeArrow /-*[<>]/ contained
600 syntax match CCTreeSymbol / [A-Za-z0-9_\.\\\/]\+/ contained
602 syntax region CCTreeSymbolLine start="^\s" end="$" contains=CCTreeArrow,CCTreePathMark,CCTreeSymbol oneline
604 syntax match CCTreeHiArrow /-*[<>]/ contained
605 syntax match CCTreeHiSymbol / [A-Za-z0-9_\.\\\/]\+/ contained
606 syntax match CCTreeHiPathMark /\s[|+]/ contained
608 syntax match CCTreeMarkExcl /^[!#]/ contained
609 syntax match CCTreeMarkTilde /@/ contained
610 syntax region CCTreeUpArrowBlock start="@" end=/[|+]/ contains=CCTreeMarkTilde contained oneline
612 syntax region CCTreeHiSymbolLine start="!" end="$" contains=CCTreeMarkExcl,
613 \ CCTreeUpArrowBlock,
614 \ CCTreeHiSymbol,CCTreeHiArrow,CCTreeHiPathMark oneline
616 syntax region CCTreeMarkedSymbolLine start="#" end="$" contains=CCTreeMarkExcl,
617 \ CCTreeMarkTilde,CCTreePathMark,
618 \ CCTreeArrow,CCTreeSymbol,CCTreeUpArrowBlock oneline
620 let cpo_save = &cpoptions
623 call s:CCTreeBufferKeyMappingsCreate()
624 nnoremap <buffer> <silent> <C-p> :CCTreePreviewBufferUsingTag<CR>
625 nnoremap <buffer> <silent> <CR> :CCTreeLoadBufferUsingTag<CR>
626 nnoremap <buffer> <silent> <2-LeftMouse> :CCTreeLoadBufferUsingTag<CR>
628 let &cpoptions = cpo_save
630 setlocal foldmethod=expr
631 setlocal foldexpr=s:CCTreeFoldExpr(getline(v:lnum))
632 setlocal foldtext=CCTreeFoldText()
633 let &l:foldlevel=g:CCTreeMinVisibleDepth
637 function! s:CCTreeBuildTreeForLevel(dict, level, treelist, lvllen)
638 if !has_key(a:dict, 'entry')
642 if g:CCTreeDisplayMode == 1
644 elseif g:CCTreeDisplayMode == 2
645 let curlevellen = a:level + 2
646 elseif g:CCTreeDisplayMode == 3
647 let curlevellen = strlen(a:dict['entry']) + a:level + 2
650 let a:lvllen[a:level] = min([a:lvllen[a:level], curlevellen])
653 call add(a:treelist, [a:dict['entry'], a:level])
654 if has_key(a:dict, 'childlinks')
655 for a in a:dict['childlinks']
656 call s:CCTreeBuildTreeForLevel(a, a:level+1, a:treelist, a:lvllen)
662 let s:calltreemaxdepth = 10
663 function! s:CCTreeBuildTreeDisplayItems(treedict, treesymlist)
664 let treexinfo = repeat([255], s:calltreemaxdepth)
665 call s:CCTreeBuildTreeForLevel(a:treedict, 0, a:treesymlist, treexinfo)
666 return s:CCTreeBuildDisplayPrependText(treexinfo)
670 function! s:CCTreeBuildDisplayPrependText(lenlist)
672 let treepptext = repeat([" "], s:calltreemaxdepth)
674 if s:currentdirection == 'p'
675 let directiontxt = "< "
676 elseif s:currentdirection == 'c'
677 let directiontxt = "> "
680 let treepptext[0] = pptxt."+".directiontxt
682 for idx in range(1, s:calltreemaxdepth-1)
683 if a:lenlist[idx] != 255
684 let pptxt .= repeat(" ", a:lenlist[idx-1])
685 let treepptext[idx] = pptxt."+"
687 if g:CCTreeDisplayMode == 1
689 elseif g:CCTreeDisplayMode >= 2
690 let arrows = repeat("-", idx)
693 let treepptext[idx] = pptxt."+".arrows.directiontxt
700 function! s:CCTreeDisplayTreeList(pptxtlst, treelst)
701 for aentry in a:treelst
702 call setline(".", a:pptxtlst[aentry[1]]. aentry[0])
703 let b:maxwindowlen = max([strlen(getline("."))+1, b:maxwindowlen])
709 " Provide dynamic call-tree highlighting using
710 " syntax highlight tricks
712 " There are 3 types of lines, marked with the start character [\s, !, #]
713 " Also @ is used to mark the path that is going up
715 function! s:CCTreeMarkCallTree(treelst, keyword)
718 for idx in range(line("."), 1, -1)
721 if a:treelst[idx-1][0] == a:keyword
722 let declevel = a:treelst[idx-1][1]
727 if declevel != -1 && foldclosed(idx) == -1
728 let curline = getline(idx)
729 if declevel == a:treelst[idx-1][1]
735 let pos = match(curline, '[+|]', 0, declevel+1)
736 " Unconventional change char
737 let curline = linemarker.strpart(curline, 1, pos-2).'@'.
738 \ strpart(curline, pos, 1). strpart(curline, pos+1)
739 call setline(idx, curline)
744 function! s:CCTreeDisplayWindowToggle()
745 if s:FindOpenWindow(s:windowtitle) == 1
748 let winbufnr = s:FindOpenBuffer(s:windowtitle)
750 call s:CCTreePreviewWindowEnter()
751 silent! exec "buf ".winbufnr
752 call s:CCTreeWindowResize()
753 silent! exec "wincmd p"
758 function! s:CCTreeWindowResize()
759 if g:CCTreeWindowVertical == 1
760 if g:CCTreeWindowWidth == -1
761 exec "vert resize". b:maxwindowlen
763 exec "vertical resize". g:CCTreeWindowWidth
766 if g:CCTreeWindowHeight != -1
767 let &winminheight = g:CCTreeWindowHeight
768 exec "resize".g:CCTreeWindowHeight
774 function! s:CCTreeDisplayTreeInWindow(atree)
776 if (bufname('%') != s:windowtitle)
777 call s:CCTreePreviewWindowEnter()
784 let b:maxwindowlen = g:CCTreeWindowMinWidth
785 let treemarkertxtlist = s:CCTreeBuildTreeDisplayItems(a:atree, b:treelist)
786 call s:CCTreeDisplayTreeList(treemarkertxtlist, b:treelist)
788 call s:CCTreeWindowResize()
791 " Need to force this again
792 let &l:foldlevel=g:CCTreeMinVisibleDepth
793 setlocal nomodifiable
794 if (incctreewin == 0)
795 call s:CCTreePreviewWindowLeave()
799 function! s:CCTreeFoldExpr(line)
800 let lvl = b:treelist[v:lnum-1][1]
808 function! CCTreeFoldText()
809 let line = substitute(getline(v:foldstart), '[!@#]', ' ' , 'g')
810 return line. " (+". (v:foldend - v:foldstart).
811 \ ')'. repeat(" ", winwidth(0))
815 function! s:CCTreeStoreState(symbol, direction)
816 let s:currentkeyword = a:symbol
817 let s:currentdirection = a:direction
820 function! s:CCTreeDBIsLoaded()
822 call s:CCTreeWarningMsg('CCTree database not loaded')
828 " Trick to get the current script ID
830 let s:sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$', '\1', '')
833 function! s:CCTreeTraceTreeForSymbol(sym_arg, direction)
834 if s:CCTreeDBIsLoaded() == 0
838 let symbol = a:sym_arg
840 let symbol = input('Trace symbol: ', expand('<cword>'),
841 \ 'customlist,<SNR>' . s:sid . 'CCTreeCompleteKwd')
847 let atree = s:CCTreeGetCallsForSymbol(symbol, 0, a:direction)
848 call s:CCTreeStoreState(symbol, a:direction)
849 call s:CCTreeUpdateForCurrentSymbol()
852 function! s:CCTreeUpdateForCurrentSymbol()
853 if s:currentkeyword != ''
854 let atree = s:CCTreeGetCallsForSymbol(s:currentkeyword, 0, s:currentdirection)
855 call s:CCTreeDisplayTreeInWindow(atree)
860 function! s:CCTreeGetCurrentKeyword()
861 let curline = line(".")
862 if foldclosed(curline) == -1
863 let curkeyword = matchstr(getline("."), s:CCTreeKeywordRegEx)
865 if curkeyword != s:CCTreekeyword || curline != s:CCTreekeywordLine
866 let s:CCTreekeyword = curkeyword
867 let s:CCTreekeywordLine = line(".")
875 function! s:CCTreeLoadBufferFromKeyword()
876 if s:CCTreeGetCurrentKeyword() == -1
883 call s:CCTreeWarningMsg('No buffer to load file')
885 if (cscope_connection() > 0)
887 exec "cs find g ".s:CCTreekeyword
890 exec "cs find f ".s:CCTreekeyword
894 " Ctags is smart enough to figure the path
895 exec "tag ".fnamemodify(s:CCTreekeyword, ":t")
896 catch /^Vim\%((\a\+)\)\=:E426/
897 call s:CCTreeWarningMsg('Tag '. s:CCTreekeyword .' not found')
904 function! s:CCTreePreviewBufferFromKeyword()
905 call s:CCTreeGetCurrentKeyword()
906 if s:CCTreekeyword == ''
913 exec "ptag ".s:CCTreekeyword
917 function! s:CCTreeSanitizeCallDepth()
919 if g:CCTreeRecursiveDepth >= s:calltreemaxdepth
920 g:CCTreeRecursiveDepth = s:calltreemaxdepth
922 elseif g:CCTreeRecursiveDepth < 1
923 g:CCTreeRecursiveDepth = 1
928 call s:CCTreeWarningMsg('Depth out of bounds')
933 function! s:CCTreeRecursiveDepthIncrease()
934 let g:CCTreeRecursiveDepth += 1
935 if s:CCTreeSanitizeCallDepth() == 0
936 call s:CCTreeUpdateForCurrentSymbol()
940 function! s:CCTreeRecursiveDepthDecrease()
941 let g:CCTreeRecursiveDepth -= 1
942 if s:CCTreeSanitizeCallDepth() == 0
943 call s:CCTreeUpdateForCurrentSymbol()
948 " Use this function to determine the correct "g" flag
950 function! s:CCTreeGetSearchFlag(gvalue)
951 let ret = (!a:gvalue)* (&gdefault) + (!&gdefault)*(a:gvalue)
958 function! s:CCTreeClearMarks()
959 let windict = winsaveview()
960 silent! exec "1,$s/[!#@]/ /e".s:CCTreeGetSearchFlag(1)
961 call winrestview(windict)
964 function! s:CCTreeCursorHoldHandle()
965 if g:CCTreeHilightCallTree && s:CCTreeGetCurrentKeyword() != -1
967 call s:CCTreeClearMarks()
968 call s:CCTreeMarkCallTree(b:treelist, s:CCTreekeyword)
969 setlocal nomodifiable
974 " Command line completion function to return names from the db
975 function! s:CCTreeCompleteKwd(arglead, cmdline, cursorpos)
977 return keys(s:symhashtable)
979 return filter(keys(s:symhashtable), 'v:val =~? a:arglead')
983 augroup CCTreeGeneral
985 autocmd CursorHold CCTree-Preview call s:CCTreeCursorHoldHandle()
991 highlight link CCTreeSymbol Function
992 highlight link CCTreeMarkers LineNr
993 highlight link CCTreeArrow CCTreeMarkers
994 highlight link CCTreePathMark CCTreeArrow
995 highlight link CCTreeHiPathMark CCTreePathMark
997 " highlighted display
998 highlight link CCTreeHiSymbol TODO
999 highlight link CCTreeHiMarkers StatusLine
1000 highlight link CCTreeHiArrow CCTreeHiMarkers
1001 highlight link CCTreeUpArrowBlock CCTreeHiArrow
1003 highlight link CCTreeMarkExcl Ignore
1004 highlight link CCTreeMarkTilde Ignore
1008 command! -nargs=? -complete=file CCTreeLoadDB call s:CCTreeLoadDB(<q-args>)
1009 command! -nargs=? -complete=file CCTreeAppendDB call s:CCTreeAppendDB(<q-args>)
1010 command! -nargs=0 CCTreeUnLoadDB call s:CCTreeUnloadDB()
1011 command! -nargs=0 CCTreeShowLoadedDBs call s:CCTreeShowLoadedDBs()
1012 command! -nargs=? -complete=customlist,s:CCTreeCompleteKwd
1013 \ CCTreeTraceForward call s:CCTreeTraceTreeForSymbol(<q-args>, 'c')
1014 command! -nargs=? -complete=customlist,s:CCTreeCompleteKwd CCTreeTraceReverse
1015 \ call s:CCTreeTraceTreeForSymbol(<q-args>, 'p')
1016 command! -nargs=0 CCTreeLoadBufferUsingTag call s:CCTreeLoadBufferFromKeyword()
1017 command! -nargs=0 CCTreePreviewBufferUsingTag call s:CCTreePreviewBufferFromKeyword()
1018 command! -nargs=0 CCTreeRecurseDepthPlus call s:CCTreeRecursiveDepthIncrease()
1019 command! -nargs=0 CCTreeRecurseDepthMinus call s:CCTreeRecursiveDepthDecrease()
1020 command! -nargs=0 CCTreeWindowToggle call s:CCTreeDisplayWindowToggle()
1023 function! s:CCTreeGetKeyword()
1024 let keyw = expand("<cword>")
1025 let keyf = expand("<cfile>")
1028 if has_key(s:symhashtable, keyf)
1030 elseif has_key(s:symhashtable, keyw)
1040 function! s:CCTreeBufferKeyMappingsCreate()
1041 let func_expr = '<SNR>'.s:sid.'CCTreeGetKeyword()'
1042 exec 'nnoremap <buffer> <silent> <C-\>< :CCTreeTraceReverse <C-R>='.func_expr.'<CR><CR>'
1043 exec 'nnoremap <buffer> <silent> <C-\>> :CCTreeTraceForward <C-R>='.func_expr.'<CR><CR>'
1044 exec 'nnoremap <silent> <C-\>w :CCTreeWindowToggle<CR>'
1046 nnoremap <buffer> <silent> <C-\>= :CCTreeRecurseDepthPlus<CR>
1047 nnoremap <buffer> <silent> <C-\>- :CCTreeRecurseDepthMinus<CR>
1052 " Header files get detected as cpp?
1053 " This is a bug in Vim 7.2, a patch needs to be applied to the runtime c
1055 " For now, use this hack to make *.h files work
1056 autocmd FileType * if &ft == 'c'|| &ft == 'cpp' |call s:CCTreeBufferKeyMappingsCreate()| endif
1060 " Cscope Digraph character compression/decompression routines
1061 " the logic of these routines are based off the Cscope source code
1063 let s:dichar1 = " teisaprnl(of)=c"
1064 let s:dichar2 = " tnerpla"
1066 function! s:Digraph_DictTable_Init ()
1070 for dc1 in range(strlen(s:dichar1))
1071 for dc2 in range(strlen(s:dichar2))
1072 call add(dicttable, s:dichar1[dc1].s:dichar2[dc2])
1079 function! s:Digraph_Uncompress_Slow (value, dicttable)
1081 for idx in range(strlen(a:value))
1082 let charext = char2nr(a:value[idx])-128
1084 let retval .= a:dicttable[charext]
1086 let retval .= a:value[idx]
1092 function! s:Digraph_Uncompress_Fast (value, dicttable)
1093 let dichar_list = split(a:value, '[^\d128-\d255]\{}')
1094 let retval = a:value
1095 for adichar in dichar_list
1096 let retval = substitute(retval, '\C'.adichar, a:dicttable[char2nr(adichar)-128], "g")
1102 function! s:Digraph_Uncompress_filter_loop(compressedsym, symlist, symhash, cmpdict)
1103 let idx = a:symhash[a:compressedsym]
1104 let uncmpname = s:Digraph_Uncompress_Fast(a:compressedsym, a:cmpdict)
1105 let a:symhash[uncmpname] = idx
1106 let a:symlist[idx]['n'] = uncmpname
1107 call s:CCTreeProgressBarTick(1)
1111 function! s:Digraph_Uncompress (symlist, symhash)
1112 let compressdict = s:Digraph_DictTable_Init()
1114 call s:CCTreeProgressBarInit(len(a:symhash))
1115 " The encoding needs to be changed to 8-bit, otherwise we can't swap special
1116 " 8-bit characters; restore after done
1117 let encoding_save=&encoding
1118 let &encoding="latin1"
1120 for compressedsym in keys(a:symhash)
1121 let idx = a:symhash[compressedsym]
1122 let uncmpname = s:Digraph_Uncompress_Fast(compressedsym, compressdict)
1123 let a:symhash[uncmpname] = idx
1124 " free the old entry
1125 unlet a:symhash[compressedsym]
1126 let a:symlist[idx]['n'] = uncmpname
1127 call s:CCTreeProgressBarTick(1)
1129 let &encoding=encoding_save
1133 function! s:Digraph_Compress(value, dicttable)
1137 while index < strlen(a:value)
1138 let dc1 = stridx(s:dichar1, a:value[index])
1140 let dc2 = stridx(s:dichar2, a:value[index+1])
1142 let retval .= nr2char(128 + (dc1*8) + dc2)
1148 let retval .= a:value[index]
1156 let &cpoptions = s:cpo_save