cctree.vim 111 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513
  1. " C Call-Tree Explorer (CCTree) <CCTree.vim>
  2. "
  3. "
  4. " Script Info and Documentation
  5. "=============================================================================
  6. " Copyright: Copyright (C) August 2008 - 2011, 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.
  14. "
  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: June 10, 2012
  20. " Version: 1.61
  21. "
  22. "=============================================================================
  23. "
  24. " {{{ Description:
  25. " Plugin generates dependency-trees for symbols using a cscope database
  26. " in Vim.
  27. " }}}
  28. " {{{ Requirements: 1) Vim 7.xx , 2) Cscope
  29. "
  30. " Tested on Unix and the following Win32 versions:
  31. " + Cscope, mlcscope (WIN32)
  32. " http://code.google.com/p/cscope-win32/
  33. " http://www.bell-labs.com/project/wwexptools/packages.html
  34. " }}}
  35. " {{{ Installation:
  36. " Copy this file to ~/.vim/plugins/
  37. " or to /vimfiles/plugins/ (on Win32 platforms)
  38. "
  39. " It might also be possible to load it as a filetype plugin
  40. " ~/.vim/ftplugin/c/
  41. "
  42. " Need to set :filetype plugin on
  43. "
  44. " }}}
  45. " {{{ Usage:
  46. " Build cscope database, for example:
  47. " > cscope -b -i cscope.files
  48. " [Tip: add -c option to build uncompressed databases for faster
  49. " load speeds]
  50. "
  51. " Load database with command ":CCTreeLoadDB"
  52. " (Please note that it might take a while depending on the
  53. " database size)
  54. "
  55. " Append database with command ":CCTreeAppendDB"
  56. " Allows multiple cscope files to be loaded and cross-referenced
  57. " Illustration:
  58. " :CCTreeAppendDB ./cscope.out
  59. " :CCTreeAppendDB ./dir1/cscope.out
  60. " :CCTreeAppendDB ./dir2/cscope.out
  61. "
  62. " A database name, i.e., my_cscope.out, can be specified with
  63. " the command. If not provided, a prompt will ask for the
  64. " filename; default is cscope.out.
  65. "
  66. " To show loaded databases, use command ":CCTreeShowLoadedDBs"
  67. "
  68. " To unload all databases, use command ":CCTreeUnLoadDB"
  69. " Note: There is no provision to unload databases individually
  70. "
  71. " To save the current set of databases loaded in to memory onto disk
  72. " in native CCTree XRef format, use command ":CCTreeSaveXRefDB"
  73. "
  74. " To load a saved native CCTree XRef format file, use
  75. " command ":CCTreeLoadXRefDB"
  76. "
  77. " To load a saved native CCTree XRef format file, use
  78. " command ":CCTreeLoadXRefDBFromDisk"
  79. "
  80. " Notes: No merging database support for CCTree native DB's [at present].
  81. "
  82. "
  83. " To have multiple CCTree preview windows, use ":CCTreeWindowSaveCopy"
  84. " Note: Once saved, only the depth of the preview window can be changed
  85. "
  86. " Default Mappings:
  87. " Get reverse call tree for symbol <C-\><
  88. " Get forward call tree for symbol <C-\>>
  89. " Increase depth of tree and update <C-\>=
  90. " Decrease depth of tree and update <C-\>-
  91. "
  92. " Open symbol in other window <CR>
  93. " Preview symbol in other window <Ctrl-P>
  94. "
  95. " Save copy of preview window <C-\>y
  96. " Highlight current call-tree flow <C-l>
  97. " Compress(Fold) call tree view zs
  98. " (This is useful for viewing long
  99. " call trees which span across
  100. " multiple pages)
  101. "
  102. " Custom user-mappings:
  103. " Users can custom-map the short-cut keys by
  104. " overriding the following variables in their
  105. " Vim start-up configuration
  106. "
  107. " g:CCTreeKeyTraceForwardTree = '<C-\>>'
  108. " g:CCTreeKeyTraceReverseTree = '<C-\><'
  109. " g:CCTreeKeyHilightTree = '<C-l>' " Static highlighting
  110. " g:CCTreeKeySaveWindow = '<C-\>y'
  111. " g:CCTreeKeyToggleWindow = '<C-\>w'
  112. " g:CCTreeKeyCompressTree = 'zs' " Compress call-tree
  113. " g:CCTreeKeyDepthPlus = '<C-\>='
  114. " g:CCTreeKeyDepthMinus = '<C-\>-'
  115. "
  116. " Command List:
  117. " CCTreeLoadDB <dbname>
  118. " CCTreeAppendDB <dbname>
  119. " CCTreeLoadXRefDB <dbname>
  120. " CCTreeSaveXRefDB <dbname>
  121. " CCTreeLoadXRefDBFromDisk <dbname>
  122. "
  123. " CCTreeUnLoadDB
  124. " CCTreeShowLoadedDBs
  125. "
  126. " CCTreeTraceForward <symbolname>
  127. " CCTreeTraceReverse <symbolname>
  128. " CCTreeRecurseDepthPlus
  129. " CCTreeRecurseDepthMinus
  130. " CCTreeWindowSaveCopy
  131. "
  132. " Only in preview window:
  133. " CCTreeWindowHiCallTree (same as <C-l> shorcut)
  134. " Highlight calling tree for keyword at cursor
  135. "
  136. " Dynamic configuration:
  137. " CCTreeOptsEnable <option> (<tab> for auto-complete)
  138. " CCTreeOptsDisable <option> (<tab> for auto-complete)
  139. " CCTreeOptsToggle <option> (<tab> for auto-complete)
  140. " Options:
  141. " DynamicTreeHiLights: Control dynamic tree highlighting
  142. " UseUnicodeSymbols: Use of UTF-8 special characters for
  143. " tree
  144. " UseConceal: Use (+Conceal) feature instead of 'ignore'
  145. " syntax highlighting. Allows CCTree window
  146. " to be exported in HTML without syntax markup
  147. " characters. (Vim 7.3+ only)
  148. " EnhancedSymbolProcessing: Cross-reference enums, macros,
  149. " global variables, typedefs (Warning: Database
  150. " processing speeds will be slow).
  151. "
  152. "
  153. "
  154. " Settings:
  155. " Customize behavior by changing the variable settings
  156. "
  157. " UTF-8 usage:
  158. " UTF-8 symbols should work fine on the majority of
  159. " X11 systems; however, some terminals might cause problems.
  160. "
  161. " To use symbols for drawing the tree, this option can be enabled.
  162. " g:CCTreeUseUTF8Symbols = 1
  163. " The options interface (CCTreeOptsxxx) can be used to
  164. " modify options on-the-fly.
  165. "
  166. " Cscope database file, g:CCTreeCscopeDb = "cscope.out"
  167. " Maximum call levels, g:CCTreeRecursiveDepth = 3
  168. " Maximum visible(unfolded) level, g:CCTreeMinVisibleDepth = 3
  169. " Orientation of window, g:CCTreeOrientation = "topleft"
  170. " (standard vim options for split: [right|left][above|below])
  171. "
  172. " Use Vertical window, g:CCTreeWindowVertical = 1
  173. " Min width for window, g:CCTreeWindowMinWidth = 40
  174. " g:CCTreeWindowWidth = -1, auto-select best width to fit
  175. "
  176. " Horizontal window, g:CCTreeWindowHeight, default is -1
  177. "
  178. "
  179. " Display format, g:CCTreeDisplayMode, default 1
  180. "
  181. " Values: 1 -- Ultra-compact (takes minimum screen width)
  182. " 2 -- Compact (Takes little more space)
  183. " 3 -- Wide (Takes copious amounts of space)
  184. "
  185. " For vertical splits, 1 and 2 are good, while 3 is good for
  186. " horizontal displays
  187. "
  188. " NOTE: To get older behavior, add the following to your vimrc
  189. " let g:CCTreeDisplayMode = 3
  190. " let g:CCTreeWindowVertical = 0
  191. "
  192. " Syntax Coloring:
  193. " CCTreeSymbol is the symbol name
  194. " CCTreeMarkers include "|","+--->"
  195. "
  196. " CCTreeHiSymbol is the highlighted call tree functions
  197. " CCTreeHiMarkers is the same as CCTreeMarkers except
  198. " these denote the highlighted call-tree
  199. "
  200. "
  201. " CCTreeHiXXXX allows dynamic highlighting of the call-tree.
  202. " To observe the effect, move the cursor to the function to
  203. " highlight the current call-tree. This option can be
  204. " turned off using the setting, g:CCTreeHilightCallTree.
  205. " For faster highlighting, the value of 'updatetime' can be
  206. " changed.
  207. "
  208. " Support for large database files:
  209. " Vimscript does not have an API for reading files line-by-line. This
  210. " becomes a problem when parsing large databases. CCTree can overcome
  211. " the limitation using an external utility (i.e., GNU coreutils: split)
  212. " or VimScript's perl interpreter interface (:version must indicate +perl)
  213. "
  214. " The following settings are tailored to suit GNU coreutils split; the default
  215. " settings should work with no changes on typical linux/unix distros
  216. " (Monopoly OSes will require installation of unixutils or equivalent)
  217. "
  218. " External command is setup with the following parameters:
  219. " g:CCTreeSplitProgCmd = 'PROG_SPLIT SPLIT_OPT SPLIT_SIZE IN_FILE OUT_FILE_PREFIX'
  220. "
  221. " Break-down of individual parameters:
  222. " The split utility is assumed to be on the path; otherwise, specify full path
  223. " g:CCTreeSplitProg = 'split'
  224. "
  225. " Option for splitting files (-C or -l)
  226. " g:CCTreeSplitProgOption = '-C'
  227. " If split program does not support -C, then this parameter must be set to
  228. " the number of lines in the split files
  229. " g:CCTreeDbFileSplitLines = -1
  230. " Largest filesize Vimscript can handle; file sizes greater than this will
  231. " be temporarily split
  232. " g:CCTreeDbFileMaxSize = 40000000 (40 Mbytes)
  233. "
  234. " Sample system command:
  235. " Typical:
  236. " split -C 40000000 inputFile outputFilePrefix
  237. "
  238. " When g:CCTreeDbFileSplitLines is set to 10000 (-C options will be ignored)
  239. " split -l 10000 inputFile outputFilePrefix
  240. "
  241. "
  242. " Using perl interface:
  243. " By default, perl usage is disabled. Set
  244. " g:CCTreeUsePerl = 1 to enable the perl interface.
  245. "
  246. " Perl interface is typically faster than native Vimscript.
  247. " This option can be used independent of the file size
  248. "
  249. " For more info on setting up perl interface
  250. " :help perl-using or :help perl-dynamic
  251. "
  252. " Writing large Xref Databases:
  253. " CCTree can use external utilities to write extremely large files beyond
  254. " VimScripts capabilities. It requires the use of an external tool that can
  255. " join text files (i.e., 'cat' in unix). This utility is triggered if the size
  256. " of the file being written exceeds g:CCTreeDbFileMaxSize (40 Mb or as configured)
  257. "
  258. " The join utility command is configured by default as follows:
  259. " let CCTreeJoinProgCmd = 'PROG_JOIN JOIN_OPT IN_FILES > OUT_FILE'
  260. "
  261. " let g:CCTreeJoinProg = 'cat' " PROG_JOIN
  262. " let g:CCTreeJoinProgOpts = "" " JOIN_OPT
  263. "
  264. "
  265. " }}}
  266. " {{{ Limitations:
  267. " Basic Symbol Processing:
  268. " The accuracy of the call-tree will only be as good as the cscope
  269. " database generation.
  270. " NOTE: Different flavors of Cscope have some known
  271. " limitations due to the lexical analysis engine. This results
  272. " in incorrectly identified function blocks, etc.
  273. " Enhanced Symbol Processing:
  274. " (1) Cscope does not mark-up nameless enums correctly; hence,
  275. " CCTree cannot recognize nameless enum symbols.
  276. " }}}
  277. " {{{ History:
  278. " Version 1.61: June 10, 2012
  279. " 1. Compability patch for change in tag file format starting
  280. " from ccglue version 0.6.0
  281. " Version 1.60: July 14, 2011
  282. " 1. Speed-up call-tree depth manipulation using incremental
  283. " updates
  284. " Version 1.55: June 20, 2011
  285. " 1. Speed-up syntax highlighting by restricting to visible
  286. " area (Note: To export to HTML, run TOhtml command on cctree window
  287. " copy to get complete highlighted call-tree)
  288. " Version 1.53: June 17, 2011
  289. " 1. Bug fix related to appending cscope databases
  290. " 2. Bug fix related to loading xref databases
  291. " Version 1.51: May 18, 2011
  292. " 1. Robust error reporting when external (split/cat) utils fail
  293. " Version 1.50: May 6, 2011
  294. " 1. Support cross-referencing of global variables, macros,
  295. " enums, and typedefs.
  296. " Version 1.40: April 22, 2011
  297. " 1. Maintain order of functions called during forward tracing
  298. " Version 1.39: April 18, 2011
  299. " 1. Use +Conceal feature for highlighting (only Vim 7.3)
  300. " Version 1.33: April 5, 2011
  301. " 1. Load and trace CCTree native XRefDb directly from disk
  302. " 2. Fix AppendDB command when 'ignorecase' is set
  303. " Version 1.26: March 28, 2011
  304. " 1. Fix macro cross-referencing limitation
  305. " 2. Correct native xref file format
  306. " Version 1.21: March 21, 2011
  307. " 1. Support serialization of loaded
  308. " cscope databases (for faster loading)
  309. " Version 1.07: March 09, 2011
  310. " 1. Fix new keymaps incorrectly applied to buffer
  311. " 2. CCTreeOptsToggle command for toggling options
  312. "
  313. " Version 1.04: March 06, 2011
  314. " 1. Customization for key mappings
  315. " 2. Dynamic configuration of UI variables
  316. " 3. Folding long call-trees to show current path dynamically
  317. "
  318. " Version 1.01: March 04, 2011
  319. " 1. Make UTF-8 symbols for tree optional
  320. "
  321. " Version 1.00: March 02, 2011
  322. " 1. Staging release for upcoming features
  323. " - Complete refactoring of code to take
  324. " advantage of VimScript's OO features
  325. " 2. Faster decompression of symbols
  326. " 3. Display related changes
  327. " - Use of unicode symbols for tree
  328. " 4. Bugfixes related to multi-database loading
  329. "
  330. " Version 0.90: February 18, 2011
  331. " 1. Support for large databases using external split utility or perl
  332. " interface
  333. "
  334. " Version 0.85: February 9, 2011
  335. " 1. Significant increase in database loading and decompression speeds
  336. "
  337. " Version 0.80: February 4, 2011
  338. " 1. Reduce memory usage by removing unused xref symbols
  339. "
  340. " Version 0.75: June 23, 2010
  341. " 1. Support for saving CCTree preview window; multiple
  342. " CCTree windows can now be open
  343. "
  344. " Version 0.71: May 11, 2010
  345. " 1. Fix script bug
  346. " Version 0.70: May 8, 2010
  347. " 1. Functionality to load multiple cscope databases
  348. "
  349. " Version 0.65: July 12, 2009
  350. " 1. Toggle preview window
  351. "
  352. " Version 0.61: December 24, 2008
  353. " 1. Fixed bug when processing include files
  354. " 2. Remove 'set ruler' option
  355. "
  356. " Version 0.60: November 26, 2008
  357. " 1. Added support for source-file dependency tree
  358. "
  359. " Version 0.50: October 17, 2008
  360. " 1. Optimizations for compact memory foot-print and
  361. " improved compressed-database load speeds
  362. "
  363. " Version 0.41: October 6, 2008
  364. " 1. Minor fix: Compressed cscope databases will load
  365. " incorrectly if encoding is not 8-bit
  366. "
  367. " Version 0.4: September 28, 2008
  368. " 1. Rewrite of "tree-display" code
  369. " 2. New syntax hightlighting
  370. " 3. Dynamic highlighting for call-trees
  371. " 4. Support for new window modes (vertical, horizontal)
  372. " 5. New display format option for compact or wide call-trees
  373. " NOTE: defaults for tree-orientation set to vertical
  374. "
  375. " Version 0.3:
  376. " September 21, 2008
  377. " 1. Support compressed cscope databases
  378. " 2. Display window related bugs fixed
  379. " 3. More intuitive display and folding capabilities
  380. "
  381. " Version 0.2:
  382. " September 12, 2008
  383. " (Patches from Yegappan Lakshmanan, thanks!)
  384. " 1. Support for using the plugin in Vi-compatible mode.
  385. " 2. Filtering out unwanted lines before processing the db.
  386. " 3. Command-line completion for the commands.
  387. " 4. Using the cscope db from any directory.
  388. "
  389. " Version 0.1:
  390. " August 31,2008
  391. " 1. Cross-referencing support for only functions and macros
  392. " Functions inside macro definitions will be incorrectly
  393. " attributed to the top level calling function
  394. "
  395. " }}}
  396. " {{{ Thanks:
  397. "
  398. " Ben Fritz (ver 1.53 -- Bug reports on database append/load)
  399. " Qaiser Durrani (ver 1.51 -- Reporting issues with SunOS)
  400. " Ben Fritz (ver 1.39 -- Suggestion/Testing for conceal feature)
  401. " Ben Fritz (ver 1.26 -- Bug report)
  402. " Frank Chang (ver 1.0x -- testing/UI enhancement ideas/bug fixes)
  403. " Arun Chaganty/Timo Tiefel (Ver 0.60 -- bug report)
  404. " Michael Wookey (Ver 0.4 -- Testing/bug report/patches)
  405. " Yegappan Lakshmanan (Ver 0.2 -- Patches)
  406. "
  407. " The Vim Community, ofcourse :)
  408. "=============================================================================
  409. " }}}
  410. " {{{ Init
  411. if !exists('loaded_cctree') && v:version >= 700
  412. " First time loading the cctree plugin
  413. let loaded_cctree = 1
  414. else
  415. "finish
  416. endif
  417. " Line continuation used here
  418. let s:cpo_save = &cpoptions
  419. set cpoptions&vim
  420. " Trick to get the current script ID
  421. map <SID>xx <SID>xx
  422. let s:sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$', '\1', '')
  423. unmap <SID>xx
  424. "}}}
  425. " {{{ Global variables; Modify in .vimrc to modify default behavior
  426. " {{{General
  427. if !exists('CCTreeCscopeDb')
  428. let CCTreeCscopeDb = "cscope.out"
  429. endif
  430. " revisit
  431. if !exists('CCTreeDb')
  432. let CCTreeDb = "cctree.out"
  433. endif
  434. if !exists('CCTreeRecursiveDepth')
  435. let CCTreeRecursiveDepth = 3
  436. endif
  437. if !exists('CCTreeMinVisibleDepth')
  438. let CCTreeMinVisibleDepth = 3
  439. endif
  440. if !exists('CCTreeEnhancedSymbolProcessing')
  441. let CCTreeEnhancedSymbolProcessing = 0
  442. endif
  443. " }}}
  444. " {{{ Custom user-key mappings
  445. if !exists('CCTreeKeyTraceForwardTree')
  446. let g:CCTreeKeyTraceForwardTree = '<C-\>>'
  447. endif
  448. if !exists('CCTreeKeyTraceReverseTree')
  449. let g:CCTreeKeyTraceReverseTree = '<C-\><'
  450. endif
  451. if !exists('CCTreeKeyHilightTree')
  452. let g:CCTreeKeyHilightTree = '<C-l>' " Static highlighting
  453. endif
  454. if !exists('CCTreeKeySaveWindow ')
  455. let g:CCTreeKeySaveWindow = '<C-\>y'
  456. endif
  457. if !exists('CCTreeKeyToggleWindow ')
  458. let g:CCTreeKeyToggleWindow = '<C-\>w'
  459. endif
  460. if !exists('CCTreeKeyCompressTree ')
  461. let g:CCTreeKeyCompressTree = 'zs' " Compress call-tree
  462. endif
  463. if !exists('CCTreeKeyDepthPlus')
  464. let g:CCTreeKeyDepthPlus = '<C-\>='
  465. endif
  466. if !exists('CCTreeKeyDepthMinus')
  467. let g:CCTreeKeyDepthMinus = '<C-\>-'
  468. endif
  469. " }}}
  470. " {{{ CCTree UI settings
  471. if !exists('CCTreeOrientation')
  472. let CCTreeOrientation = "topleft"
  473. endif
  474. if !exists('CCTreeWindowVertical')
  475. let CCTreeWindowVertical = 1
  476. endif
  477. if !exists('CCTreeWindowWidth')
  478. " -1 is auto select best width
  479. let CCTreeWindowWidth = -1
  480. endif
  481. if !exists('CCTreeWindowMinWidth')
  482. let CCTreeWindowMinWidth = 25
  483. endif
  484. if !exists('CCTreeWindowHeight')
  485. let CCTreeWindowHeight = -1
  486. endif
  487. if !exists('CCTreeDisplayMode')
  488. let CCTreeDisplayMode = 1
  489. endif
  490. if !exists('CCTreeHilightCallTree')
  491. let CCTreeHilightCallTree = 1
  492. endif
  493. " }}}
  494. " {{{ Split prog
  495. if !exists('CCTreeSplitProgCmd')
  496. let CCTreeSplitProgCmd = 'PROG_SPLIT SPLIT_OPT SPLIT_SIZE IN_FILE OUT_FILE_PREFIX'
  497. endif
  498. if !exists('CCTreeSplitProg')
  499. "PROG_SPLIT
  500. let CCTreeSplitProg = 'split'
  501. endif
  502. if !exists('CCTreeSplitProgOption')
  503. "SPLIT_OPT
  504. let CCTreeSplitProgOption = '-C'
  505. endif
  506. if !exists('CCTreeDbFileSplitLines')
  507. " if SPLIT_OPT is -l
  508. " If split program does not support -C, then this parameter must be set to
  509. " the number of lines in the split files
  510. let CCTreeDbFileSplitLines = -1
  511. endif
  512. if !exists('CCTreeSplitProgCmd')
  513. let CCTreeSplitProgCmd = 'PROG_SPLIT SPLIT_OPT SPLIT_SIZE IN_FILE OUT_FILE_PREFIX'
  514. endif
  515. if !exists('CCTreeDbFileMaxSize')
  516. " if SPLIT_OPT is -C
  517. let CCTreeDbFileMaxSize = 40000000 "40 Mbytes
  518. endif
  519. " }}}
  520. " {{{ Join/Cat prog
  521. if !exists('CCTreeJoinProgCmd')
  522. let CCTreeJoinProgCmd = 'PROG_JOIN JOIN_OPT IN_FILES > OUT_FILE'
  523. endif
  524. if !exists('CCTreeJoinProg')
  525. "PROG_JOIN
  526. let CCTreeJoinProg = 'cat'
  527. endif
  528. if !exists('CCTreeJoinProgOpts')
  529. let CCTreeJoinProgOpts = ""
  530. endif
  531. " }}}
  532. " {{{ Misc (perl)
  533. if !exists('CCTreeUsePerl')
  534. " Disabled by default
  535. let CCTreeUsePerl = 0
  536. if 0 " Auto-detect perl interface (Experimental code)
  537. if has('perl)
  538. perl << PERL_EOF
  539. VIM::DoCommand("let CCTreeUsePerl = 1");
  540. PERL_EOF
  541. endif
  542. endif
  543. endif
  544. if has('conceal')
  545. let s:CCTreeUseConceal = 1
  546. else
  547. let s:CCTreeUseConceal = 0
  548. endif
  549. if !exists('CCTreeUseUTF8Symbols')
  550. let CCTreeUseUTF8Symbols = 0
  551. endif
  552. " }}}
  553. " }}}
  554. " {{{ Plugin related local variables
  555. let s:pluginname = 'CCTree'
  556. let s:windowtitle = 'CCTree-View'
  557. let s:windowsavetitle = 'CCTree-View-Copy'
  558. let s:DBClasses = { 'cscopeid': 'Cscope', 'cctreexref' : 'CCTree XRef'}
  559. let s:DBStorage = { 'memory': 'Memory', 'disk' : 'Disk'}
  560. " }}}
  561. " {{{ Turn on/off debugs
  562. let s:tag_debug=0
  563. " Use the Decho plugin for debugging
  564. function! DBGecho(...)
  565. if s:tag_debug
  566. Decho(a:000)
  567. endif
  568. endfunction
  569. function! DBGredir(...)
  570. if s:tag_debug
  571. Decho(a:000)
  572. endif
  573. endfunction
  574. function! Pause()
  575. call input("sasasD", "asdads")
  576. endfunction
  577. " }}}
  578. " {{{ Progress bar (generic, numeric, rolling)
  579. let s:GenericProgressBar= {
  580. \ 'depth': 0,
  581. \ 'depthChar': '',
  582. \ 'currentChar': 0,
  583. \ 'updateTime': 0,
  584. \ 'rangeChars': [],
  585. \ 'formatStr' : '',
  586. \ 'units' : ''
  587. \ }
  588. function! s:GenericProgressBar.mCreate(rangechars, depthchar, fmtStr)
  589. let pbr = deepcopy(s:GenericProgressBar)
  590. unlet pbr.mCreate
  591. let pbr.rangeChars = a:rangechars
  592. let pbr.depthChar = a:depthchar
  593. let pbr.formatStr = a:fmtStr
  594. return pbr
  595. endfunction
  596. function! s:GenericProgressBar.mSetDepth(val) dict
  597. let self.depth = a:val
  598. endfunction
  599. function! s:GenericProgressBar.mUpdate() dict
  600. let staticchars = repeat(self.depthChar, self.depth)
  601. let displayStr = substitute(self.formatStr, "\@PROGRESS\@",
  602. \ staticchars . self.rangeChars[self.currentChar], "")
  603. call s:StatusLine.mSetExtraInfo(displayStr)
  604. endfunction
  605. function! s:GenericProgressBar.mDone()
  606. call s:StatusLine.mSetExtraInfo("")
  607. endfunction
  608. let s:ProgressBarRoll = {
  609. \ 'updateTime' : 0,
  610. \ 'curTime' : 0
  611. \}
  612. function! s:ProgressBarRoll.mCreate(rollchars, depthChar) dict
  613. let gpbr = s:GenericProgressBar.mCreate(a:rollchars, a:depthChar, "\@PROGRESS\@")
  614. let pbr = extend(gpbr, deepcopy(s:ProgressBarRoll))
  615. unlet pbr.mCreate
  616. let pbr.curTime = localtime()
  617. return pbr
  618. endfunction
  619. function! s:ProgressBarRoll.mTick(count) dict
  620. if (localtime() - self.curTime) > self.updateTime
  621. let self.currentChar += 1
  622. if self.currentChar == len(self.rangeChars)
  623. let self.currentChar = 0
  624. endif
  625. let self.curTime = localtime()
  626. call self.mUpdate()
  627. endif
  628. endfunction
  629. let s:ProgressBarNumeric = {
  630. \ 'progress1current' : 0,
  631. \ 'progressmax' : 0,
  632. \ 'progress1percent' : 0,
  633. \ 'progresspercent' : 0,
  634. \}
  635. function! s:ProgressBarNumeric.mCreate(maxcount, unit) dict
  636. let gpbr = s:GenericProgressBar.mCreate(range(0,200), '',
  637. \ "Processing \@PROGRESS\@\%, total ". a:maxcount . " " . a:unit)
  638. let progressbar = extend(gpbr, deepcopy(s:ProgressBarNumeric))
  639. unlet progressbar.mCreate
  640. let progressbar.progressmax = a:maxcount
  641. let progressbar.progress1percent = a:maxcount/100
  642. let progressbar.units = a:unit
  643. return progressbar
  644. endfunction
  645. function! s:ProgressBarNumeric.mTick(count) dict
  646. let self.progress1current += a:count
  647. if self.progress1percent <= self.progress1current
  648. let tmp = (self.progress1current/self.progress1percent)
  649. let self.progresspercent += tmp
  650. let self.progress1current -= tmp * self.progress1percent
  651. let self.currentChar += 1
  652. call self.mUpdate()
  653. endif
  654. endfunction
  655. " }}}
  656. " {{{ Status line
  657. let s:StatusLine = {
  658. \ 'symlastprogress' : 0,
  659. \ 'symprogress' : 0,
  660. \ 'cursym' : 0,
  661. \ 'savedStatusLine' : '',
  662. \ 'statusextra' : '',
  663. \ 'local':0
  664. \}
  665. function! s:StatusLine.mInit() dict
  666. let self.savedStatusLine = &l:statusline
  667. setlocal statusline=%{CCTreeStatusLine()}
  668. endfunction
  669. function! s:StatusLine.mRestore() dict
  670. let self.currentstatus = ''
  671. let self.statusextra = ''
  672. let &l:statusline = s:StatusLine.savedStatusLine
  673. redrawstatus
  674. endfunction
  675. function! s:StatusLine.mSetInfo(msg) dict
  676. let s:StatusLine.currentstatus = a:msg
  677. redrawstatus
  678. endfunction
  679. function! s:StatusLine.mSetExtraInfo(msg) dict
  680. let s:StatusLine.statusextra = a:msg
  681. redrawstatus
  682. endfunction
  683. function! CCTreeStatusLine()
  684. return s:pluginname. " ".
  685. \ s:StatusLine.currentstatus . " -- ".
  686. \ s:StatusLine.statusextra
  687. endfunction
  688. "}}}
  689. " {{{ Shell command interface
  690. let s:ShellCmds = {'shellOutput': ''}
  691. function! s:ShellCmds.mSplit(inFile, outFile)
  692. let cmdEx = substitute(g:CCTreeSplitProgCmd, "PROG_SPLIT", g:CCTreeSplitProg,"")
  693. let cmdEx = substitute(cmdEx, "SPLIT_OPT", g:CCTreeSplitProgOption,"")
  694. if g:CCTreeDbFileSplitLines != -1
  695. let cmdEx = substitute(cmdEx, "SPLIT_SIZE", g:CCTreeDbFileSplitLines,"")
  696. else
  697. let cmdEx = substitute(cmdEx, "SPLIT_SIZE", g:CCTreeDbFileMaxSize,"")
  698. endif
  699. let cmdEx = substitute(cmdEx, "IN_FILE", a:inFile,"")
  700. let cmdEx = substitute(cmdEx, "OUT_FILE_PREFIX", a:outFile,"")
  701. return cmdEx
  702. endfunction
  703. function! s:ShellCmds.mJoin(inFileList, outFile)
  704. let cmdEx = substitute(g:CCTreeJoinProgCmd, "PROG_JOIN", g:CCTreeJoinProg,"")
  705. let cmdEx = substitute(cmdEx, "JOIN_OPT", g:CCTreeJoinProgOpts,"")
  706. let cmdEx = substitute(cmdEx, "IN_FILES", a:inFileList,"")
  707. let cmdEx = substitute(cmdEx, "OUT_FILE", a:outFile,"")
  708. return cmdEx
  709. endfunction
  710. function! s:ShellCmds.mExec(cmd)
  711. let s:shellOutput= system(a:cmd)
  712. if s:shellOutput != ''
  713. " Failed
  714. return s:CCTreeRC.Error
  715. endif
  716. return s:CCTreeRC.Success
  717. endfunction
  718. " }}}
  719. " {{{ Virtual file interface
  720. let s:vFile = {}
  721. function! s:vFile.mCreate(fname, mode)
  722. if a:mode == 'r'
  723. return s:vFileR.mCreate(a:fname)
  724. elseif a:mode == 'w'
  725. return s:vFileW.mCreate(a:fname)
  726. endif
  727. return -1
  728. endfunction
  729. let s:vFileW = {
  730. \ 'splitfiles' : [],
  731. \ 'totSplits' : 0,
  732. \ 'lines' : [],
  733. \ 'fileSize' : 0
  734. \}
  735. function! s:vFileW.mCreate(fname) dict
  736. let vfile = deepcopy(s:vFileW)
  737. unlet vfile.mCreate
  738. let vfile.link = a:fname
  739. return vfile
  740. endfunction
  741. function! s:vFileW.mCreateSplit() dict
  742. " first split, create name
  743. if self.totSplits == 0
  744. let self.tlink = tempname()
  745. endif
  746. let fname = self.tlink .'_'. self.totSplits
  747. call writefile(self.lines, fname)
  748. call add(self.splitfiles, fname)
  749. let self.lines = []
  750. let self.totSplits += 1
  751. endfunction
  752. function! s:vFileW.mTestForSplit() dict
  753. if self.fileSize > g:CCTreeDbFileMaxSize
  754. call self.mCreateSplit()
  755. endif
  756. endfunction
  757. function! s:vFileW.mAddFileSize(size) dict
  758. let self.fileSize += a:size
  759. endfunction
  760. function! s:vFileW.mWriteList(linelist) dict
  761. call extend(self.lines, a:linelist)
  762. call self.mTestForSplit()
  763. endfunction
  764. function! s:vFileW.mWriteLine(line) dict
  765. call add(self.lines, a:line)
  766. call self.mAddFileSize(len(a:line))
  767. call self.mTestForSplit()
  768. endfunction
  769. function! s:vFileW.mClose() dict
  770. if self.totSplits == 0
  771. call writefile(self.lines, self.link)
  772. else
  773. " force remaining lines into a new split
  774. call self.mCreateSplit()
  775. " now join all of them
  776. let filelist = join(self.splitfiles, " ")
  777. let cmdEx = s:ShellCmds.mJoin(filelist, self.link)
  778. if s:ShellCmds.mExec(cmdEx) != s:CCTreeRC.Success
  779. let msg = s:shellOutput ."Shell command: ".cmdEx. " failed!".
  780. \ " Refer help to setup split/join utils."
  781. call s:CCTreeUtils.mWarningPrompt(msg)
  782. endif
  783. endif
  784. for afile in self.splitfiles
  785. call delete(afile)
  786. endfor
  787. return 0
  788. endfunction
  789. let s:vFileR = {
  790. \ 'splitfiles' : [],
  791. \ 'currentSplitIdx' : 0,
  792. \ 'totSplits' : 0,
  793. \ 'lines' : [],
  794. \ 'valid' : 0,
  795. \ 'mode' : ""
  796. \}
  797. function! s:vFileR.mIsLargeFile() dict
  798. if (getfsize(self.link) > g:CCTreeDbFileMaxSize)
  799. return 1
  800. endif
  801. return 0
  802. endfunction
  803. function! s:vFileR.mCreate(fname) dict
  804. let vfile = deepcopy(s:vFileR)
  805. unlet vfile.mCreate
  806. let vfile.link = a:fname
  807. let vfile.valid = filereadable(a:fname)
  808. let vfile.size = getfsize(a:fname)
  809. return vfile
  810. endfunction
  811. function! s:vFileR.mOpen() dict
  812. if self.mode == 'w'
  813. " no need to do anything
  814. return 0
  815. endif
  816. if self.mIsLargeFile() == 0
  817. "little trick to keep interface uniform when we don't split
  818. call add(self.splitfiles, self.link)
  819. let self.totSplits = 1
  820. else
  821. let tmpDb = tempname()
  822. let cmdEx = s:ShellCmds.mSplit(self.link, tmpDb)
  823. if s:ShellCmds.mExec(cmdEx) != s:CCTreeRC.Success
  824. let msg = s:shellOutput ."Shell command: ".cmdEx. " failed!".
  825. \ " Refer help to setup split/join utils."
  826. call s:CCTreeUtils.mWarningPrompt(msg)
  827. return -1
  828. else
  829. let self.splitfiles = split(expand(tmpDb."*"), "\n")
  830. endif
  831. if empty(self.splitfiles)
  832. return -1
  833. endif
  834. endif
  835. let self.totSplits = len(self.splitfiles)
  836. return 0
  837. endfunction
  838. function! s:vFileR.mRead() dict
  839. if (self.currentSplitIdx >= len(self.splitfiles))
  840. " out of bounds
  841. return -1
  842. endif
  843. let self.lines = readfile(self.splitfiles[self.currentSplitIdx])
  844. let self.currentSplitIdx += 1
  845. return 0
  846. endfunction
  847. function! s:vFileR.mRewind() dict
  848. let self.currentSplitIdx = 0
  849. let self.lines = []
  850. endfunction
  851. function! s:vFileR.mClose() dict
  852. if self.totSplits == 1
  853. return
  854. endif
  855. for afile in self.splitfiles
  856. call delete(afile)
  857. endfor
  858. endfunction
  859. "}}}
  860. " {{{Stop watch
  861. let s:StopWatch = {
  862. \ 'text' : "(no reltime feature)",
  863. \}
  864. function! s:StopWatch.mCreate() dict
  865. let stopWatch = deepcopy(s:StopWatch)
  866. unlet stopWatch.mCreate
  867. call stopWatch.mReset()
  868. return stopWatch
  869. endfunction
  870. function! s:StopWatch.mReset() dict
  871. if has('reltime')
  872. let self.startRTime = reltime()
  873. else
  874. let self.startRTime = localtime()
  875. endif
  876. endfunction
  877. function! s:StopWatch.mSnapElapsed() dict
  878. if has('reltime')
  879. let self.text = reltimestr(reltime(self.startRTime))
  880. else
  881. let self.text = localtime() - self.startRTime
  882. endif
  883. endfunction
  884. function! s:StopWatch.mGetText() dict
  885. return self.text
  886. endfunction
  887. "}}}
  888. " {{{ Digraph character compression/decompression routines
  889. let s:CharMaps = {
  890. \'savedEncoding' : '',
  891. \'mapkind' : ''
  892. \}
  893. " The encoding needs to be changed to 8-bit, otherwise we can't swap special
  894. " 8-bit characters; restore after done
  895. function! s:CharMaps.mInitTranslator() dict
  896. if self.mapkind == 'Alpha'
  897. let self.savedEncoding = &encoding
  898. let &encoding="latin1"
  899. endif
  900. endfunction
  901. function! s:CharMaps.mDoneTranslator() dict
  902. if self.mapkind == 'Alpha'
  903. let &encoding=self.savedEncoding
  904. endif
  905. endfunction
  906. function! s:CharMaps.CrossProduct(seq1, seq2) dict
  907. let cpSeq = []
  908. for dc1 in range(strlen(a:seq1))
  909. for dc2 in range(strlen(a:seq2))
  910. call add(cpSeq, a:seq1[dc1].a:seq2[dc2])
  911. endfor
  912. endfor
  913. return cpSeq
  914. endfunction
  915. let s:TranslateMap = {}
  916. function! s:TranslateMap.mCreate (srcsym, destsym, mapkind, regex) dict
  917. let dicttable = extend(deepcopy(s:CharMaps), deepcopy(s:TranslateMap))
  918. unlet dicttable.CrossProduct
  919. let dicttable.mappings = {}
  920. " map lower
  921. let maxsym = min([len(a:srcsym),len (a:destsym)])
  922. let index = 0
  923. while (index < maxsym)
  924. let dicttable.mappings[a:srcsym[index]] = a:destsym[index]
  925. let index += 1
  926. endwhile
  927. " Need mapping lens, we assume it's constant across the board
  928. let dicttable.mapsrclen = len(a:srcsym[0])
  929. let dicttable.regex = a:regex
  930. if a:mapkind == 'Alpha'
  931. let dicttable.mTranslate = dicttable.mTranslateAlpha
  932. elseif a:mapkind == 'Numeric'
  933. let dicttable.mTranslate = dicttable.mTranslateNumeric
  934. endif
  935. let dicttable.mapkind = a:mapkind
  936. unlet dicttable.mTranslateNumeric
  937. unlet dicttable.mTranslateAlpha
  938. return dicttable
  939. endfunction
  940. function! s:TranslateMap.mTranslateNumeric(value) dict
  941. let index = 0
  942. let retval = ""
  943. " remember to deal with multi-byte characters
  944. while index < len(a:value)
  945. let char1 = char2nr(a:value[index])
  946. if has_key(self.mappings, char1)
  947. let newmap = self.mappings[char1]
  948. else
  949. " take only the first character
  950. let newmap = a:value[index]
  951. endif
  952. let retval .= newmap
  953. let index += 1
  954. endwhile
  955. return retval
  956. endfunction
  957. function! s:TranslateMap.mTranslateAlpha(value) dict
  958. let retval = substitute(a:value, self.regex, '\=self.mappings[submatch(1)]', "g")
  959. return retval
  960. endfunction
  961. function! s:CCTreeGetXRefDbMaps(maptype, mapkind)
  962. let dichar1 = "|0123456789"
  963. let dichar2 = ",0123456789"
  964. return s:CCTreeCreateGenericMaps(a:maptype, a:mapkind, dichar1, dichar2)
  965. endfunction
  966. function! s:CCTreeGetCscopeMaps(maptype, mapkind)
  967. let dichar1 = " teisaprnl(of)=c"
  968. let dichar2 = " tnerpla"
  969. return s:CCTreeCreateGenericMaps(a:maptype, a:mapkind, dichar1, dichar2)
  970. endfunction
  971. function! s:CCTreeCreateGenericMaps(maptype, mapkind, dichar1, dichar2)
  972. let s:CharMaps.mapkind = a:mapkind
  973. call s:CharMaps.mInitTranslator()
  974. if a:mapkind == 'Numeric'
  975. let ab = map(range(128,255), 'v:val')
  976. elseif a:mapkind == 'Alpha'
  977. let ab = map(range(128,255), 'nr2char(v:val)')
  978. else
  979. return {}
  980. endif
  981. let ac = s:CharMaps.CrossProduct(a:dichar1, a:dichar2)
  982. if a:maptype == 'Compress'
  983. let maps = s:TranslateMap.mCreate(ac, ab, a:mapkind,
  984. \'\(['.a:dichar1.']['.a:dichar2.']\)\C')
  985. elseif a:maptype == 'Uncompress'
  986. let maps = s:TranslateMap.mCreate(ab, ac, a:mapkind,
  987. \'\([\d128-\d255]\)')
  988. endif
  989. call s:CharMaps.mDoneTranslator()
  990. return maps
  991. endfunction
  992. " }}}
  993. " {{{ Unique list filter object
  994. let s:UniqList = {}
  995. function! s:UniqList.mFilterEntries(lstval) dict
  996. let valdict = {}
  997. let reslist = ''
  998. for aval in a:lstval
  999. let rval = split(aval, "|")
  1000. let bval = rval[0]
  1001. if !has_key(valdict, bval)
  1002. let valdict[bval] = ''
  1003. let reslist .= (bval . ",")
  1004. endif
  1005. endfor
  1006. " strip out the last comma
  1007. let reslist = reslist[:-2]
  1008. return reslist
  1009. endfunction
  1010. let s:CCTreeUniqListFilter = deepcopy(s:UniqList)
  1011. function! s:CCTreeMakeCommaListUnique(clist)
  1012. let entries = split(a:clist, ",")
  1013. if len(entries) > 0
  1014. return s:CCTreeUniqListFilter.mFilterEntries(entries)
  1015. endif
  1016. return ""
  1017. endfunction
  1018. " }}}
  1019. " {{{ Buffer/Window
  1020. func! s:FindOpenBuffer(filename)
  1021. let bnrHigh = bufnr("$")
  1022. "tabpagebuflist(tabpagenr())
  1023. for bufnrs in range(1, bnrHigh)
  1024. if (bufexists(bufnrs) == 1 && bufname(bufnrs) == a:filename && bufloaded(bufnrs) != 0 )
  1025. return bufnrs
  1026. endif
  1027. endfor
  1028. " Could not find the buffer
  1029. return 0
  1030. endfunction
  1031. func! s:FindOpenWindow(filename)
  1032. let bufnr = s:FindOpenBuffer(a:filename)
  1033. if (bufnr > 0)
  1034. let newWinnr = bufwinnr(bufnr)
  1035. if newWinnr != -1
  1036. exec newWinnr.'wincmd w'
  1037. return 1
  1038. endif
  1039. endif
  1040. " Could not find the buffer
  1041. return 0
  1042. endfunction
  1043. " }}}
  1044. " {{{ Utils library
  1045. let s:Utils = {}
  1046. " Use this function to determine the correct "g" flag
  1047. " for substitution
  1048. function! s:Utils.mGetSearchFlag(gvalue)
  1049. let ret = (!a:gvalue)* (&gdefault) + (!&gdefault)*(a:gvalue)
  1050. if ret == 1
  1051. return 'g'
  1052. endif
  1053. return ''
  1054. endfunc
  1055. " Strlen works for multibyte characters
  1056. function! s:Utils.mStrlenEx(val)
  1057. return strlen(substitute(a:val, ".", "x", "g"))
  1058. endfunc
  1059. " }}}
  1060. " {{{ Generic db loader interface
  1061. let s:GenericDbLdr = {
  1062. \ 'fDBName' : '',
  1063. \ 'class' : 'Generic',
  1064. \ }
  1065. function! s:GenericDbLdr.mCreate(fname) dict
  1066. let gdb = deepcopy(s:GenericDbLdr)
  1067. unlet gdb.mCreate
  1068. let gdb.fDBName = a:fname
  1069. if !filereadable(a:fname)
  1070. return s:CCTreeRC.Error
  1071. endif
  1072. return gdb
  1073. endfunction
  1074. function! s:GenericDbLdr.mParseDbHeader(gRdr)
  1075. let header = readfile(self.fDBName, "", a:gRdr.headerLines)
  1076. return a:gRdr.mParseDbHeader(header)
  1077. endfunction
  1078. let s:XRefMemDbLdr = {
  1079. \ 'class' : s:DBStorage.memory
  1080. \}
  1081. function! s:XRefMemDbLdr.mCreate(fname) dict
  1082. let gdb = s:GenericDbLdr.mCreate(a:fname)
  1083. if type(gdb) != type({})
  1084. return gdb
  1085. endif
  1086. let mdb = extend(gdb, deepcopy(s:XRefMemDbLdr))
  1087. unlet mdb.mCreate
  1088. return mdb
  1089. endfunction
  1090. if has('perl') && g:CCTreeUsePerl == 1
  1091. " Perl function
  1092. function! s:XRefMemDbLdr.mLoadFileIntoXRefDb(xRefDb, gRdr) dict
  1093. let stage = 1
  1094. for afltr in a:gRdr.opts
  1095. let stageidxstr = 'Stage ('.stage.'/'.len(a:gRdr.opts).') '
  1096. call s:StatusLine.mSetInfo(stageidxstr. ': (PERL) Loading database ')
  1097. call a:gRdr.mProcessingStateInit()
  1098. let pBar = s:ProgressBarNumeric.mCreate(getfsize(self.fDBName), "bytes")
  1099. echomsg 'filtering '. afltr
  1100. perl << PERL_EOF
  1101. #use strict;
  1102. #use warnings FATAL => 'all';
  1103. #use warnings NONFATAL => 'redefine';
  1104. my $filebytes = 0;
  1105. my $filterpat = VIM::Eval("afltr");
  1106. open (CSCOPEDB, VIM::Eval("self.fDBName")) or die "File trouble!";
  1107. #VIM::DoCommand("echomsg '".$filterpat."'");
  1108. while (<CSCOPEDB>) {
  1109. $filebytes += length($_);
  1110. chomp($_);
  1111. if ($_ !~ $filterpat) {
  1112. next;
  1113. }
  1114. VIM::DoCommand("call pBar.mTick(".$filebytes.")");
  1115. $filebytes = 0;
  1116. VIM::DoCommand("call a:gRdr.mProcessSymbol(a:xRefDb, '".$_."')");
  1117. }
  1118. VIM::DoCommand("call pBar.mDone()");
  1119. close(CSCOPEDB);
  1120. PERL_EOF
  1121. call a:gRdr.mProcessingStateDone()
  1122. let stage += 1
  1123. endfor
  1124. endfunction
  1125. else
  1126. " Native Vim function
  1127. function! s:XRefMemDbLdr.mLoadFileIntoXRefDb(xRefDb, gRdr) dict
  1128. let vDbFile = s:vFile.mCreate(self.fDBName, "r")
  1129. if vDbFile.valid == 0
  1130. return -1
  1131. endif
  1132. if vDbFile.mIsLargeFile() == 1
  1133. call s:StatusLine.mSetExtraInfo('Database '
  1134. \.' >'.g:CCTreeDbFileMaxSize .' bytes. Splitting '.
  1135. \'into smaller chunks... (this may take some time)')
  1136. endif
  1137. try
  1138. if vDbFile.mOpen() == 0
  1139. call self.mReadFileIntoXRefDb(vDbFile,
  1140. \ a:xRefDb,
  1141. \ a:gRdr)
  1142. endif
  1143. finally
  1144. call vDbFile.mClose()
  1145. endtry
  1146. endfunction
  1147. endif
  1148. function! s:XRefMemDbLdr.mReadFileIntoXRefDb(vDbFile, xrefdb, gRdr)
  1149. let stage = 0
  1150. for afltr in a:gRdr.opts
  1151. call a:vDbFile.mRewind()
  1152. let stage += 1
  1153. call a:gRdr.mProcessingStateInit()
  1154. while 1 == 1
  1155. if a:vDbFile.mRead() == -1
  1156. break
  1157. endif
  1158. let stageidxstr = 'Stage ('.stage.'/'.len(a:gRdr.opts).') '
  1159. let fileidxstr = '('.a:vDbFile.currentSplitIdx.'/'.a:vDbFile.totSplits.') '
  1160. call s:StatusLine.mSetInfo(stageidxstr. ': Reading database chunk '.fileidxstr)
  1161. " Filter-out lines that doesn't have relevant information
  1162. let plist = a:gRdr.mReadLinesFromFile(a:vDbFile, afltr)
  1163. let pBar = s:ProgressBarNumeric.mCreate(len(plist), "items")
  1164. call s:StatusLine.mSetInfo(stageidxstr.': Analyzing database chunk '.fileidxstr)
  1165. call self.mProcessListIntoXrefDb(plist, a:gRdr, a:xrefdb, pBar)
  1166. call pBar.mDone()
  1167. " clean-up memory
  1168. call garbagecollect()
  1169. endwhile
  1170. call a:gRdr.mProcessingStateDone()
  1171. endfor
  1172. endfunction
  1173. function! s:XRefMemDbLdr.mProcessListIntoXrefDb(symbols, rdr, xrefdb, pbar)
  1174. for a in a:symbols
  1175. call a:pbar.mTick(1)
  1176. call a:rdr.mProcessSymbol(a:xrefdb, a)
  1177. endfor
  1178. endfunction
  1179. function! s:GenericDbLdr.mParseDbHeader(gRdr)
  1180. let header = readfile(self.fDBName, "", a:gRdr.headerLines)
  1181. return a:gRdr.mParseDbHeader(header)
  1182. endfunction
  1183. " }}}
  1184. " {{{ Generic Disk DB Ldr
  1185. let s:XRefDiskDbLdr = {
  1186. \ 'class' : s:DBStorage.disk
  1187. \ }
  1188. function! s:XRefDiskDbLdr.mCreate(fname) dict
  1189. let gdb = s:GenericDbLdr.mCreate(a:fname)
  1190. if type(gdb) != type({})
  1191. return gdb
  1192. endif
  1193. let mdb = extend(gdb, deepcopy(s:XRefDiskDbLdr))
  1194. unlet mdb.mCreate
  1195. return mdb
  1196. endfunction
  1197. function! s:XRefDiskDbLdr.mLoadFileIntoXRefDb(xRefDb, gRdr) dict
  1198. call a:xRefDb.mSetLink(self.fDBName)
  1199. endfunction
  1200. "}}}
  1201. " {{{ Xref disk DB
  1202. let s:XRefDiskDb = {
  1203. \ 'link':'',
  1204. \ 'savedTags': '',
  1205. \ 'class' : s:DBStorage.disk
  1206. \ }
  1207. function! s:XRefDiskDb.mCreate() dict
  1208. let fdb = deepcopy(s:XRefDiskDb)
  1209. unlet fdb.mCreate
  1210. let fdb.maps = s:CCTreeGetXRefDbMaps('Uncompress', 'Numeric')
  1211. return fdb
  1212. endfunction
  1213. function! s:XRefDiskDb.mSetLink(filedb) dict
  1214. let self.link = a:filedb
  1215. " revisit, do parse header here
  1216. endfunction
  1217. function! s:XRefDiskDb.mClear() dict
  1218. " do nothing
  1219. endfunction
  1220. function! s:XRefDiskDb.mInitState() dict
  1221. let self.savedTags = &tags
  1222. let &tags = self.link
  1223. endfunction
  1224. function! s:XRefDiskDb.mRestoreState() dict
  1225. let &tags = self.savedTags
  1226. endfunction
  1227. function! s:XRefDiskDb.mDecodeTagEntry(tagentry) dict
  1228. let itms = split(a:tagentry.name, "#")
  1229. let a:tagentry.n = itms[1]
  1230. let a:tagentry.idx = itms[0]
  1231. " Vim taglist() drops empty fields, so need to protect
  1232. if has_key(a:tagentry, 'c')
  1233. let a:tagentry.c = self.maps.mTranslate(a:tagentry.c)
  1234. else
  1235. let a:tagentry.c = ''
  1236. endif
  1237. if has_key(a:tagentry, 'p')
  1238. let a:tagentry.p = self.maps.mTranslate(a:tagentry.p)
  1239. else
  1240. let a:tagentry.p = ''
  1241. endif
  1242. return a:tagentry
  1243. endfunction
  1244. function! s:XRefDiskDb.mGetSymbolIdFromName(symname) dict
  1245. let symtagline = taglist('\#'.a:symname.'$')
  1246. let asym = self.mDecodeTagEntry(symtagline[0])
  1247. return asym.idx
  1248. endfunction
  1249. function! s:XRefDiskDb.mGetSymbolFromId(symid) dict
  1250. let symtagline = taglist('^'.a:symid.'\#')
  1251. if empty(symtagline)
  1252. echomsg "Failed to locate ".a:symid
  1253. else
  1254. return self.mDecodeTagEntry(symtagline[0])
  1255. endif
  1256. return {}
  1257. endfunction
  1258. function! s:XRefDiskDb.mGetSymbolIds() dict
  1259. " illegal
  1260. let symtaglines = taglist('^.')
  1261. return keys(self.symidhash)
  1262. endfunction
  1263. function! s:XRefDiskDb.mGetSymbolNames(lead) dict
  1264. if empty(a:lead)
  1265. let symtaglines = taglist('^.')
  1266. else
  1267. let symtaglines = taglist('#'.a:lead)
  1268. endif
  1269. let alist = []
  1270. for atag in symtaglines
  1271. let acctreesym = self.mDecodeTagEntry(atag)
  1272. call add(alist, acctreesym.n)
  1273. endfor
  1274. return alist
  1275. endfunction
  1276. " }}}
  1277. " {{{ TagFile utils
  1278. let s:CCTreeTagDbRdr = {'class': 'CCTreeXrefDb',
  1279. \ 'headerLines' : 4,
  1280. \ 'compressed' : 0,
  1281. \ 'opts': ['v:val !~ "^[\!]"'],
  1282. \ 'perl_opts': "^[^\!]",
  1283. \ 'mapPreKeys': {'c':'','p':''},
  1284. \ 'mapPostKeys': {'c':'','p':''}
  1285. \ }
  1286. function! s:CCTreeTagDbRdr.mCreate(fname) dict
  1287. let cctxdbrdr = deepcopy(s:CCTreeTagDbRdr)
  1288. unlet cctxdbrdr.mCreate
  1289. return cctxdbrdr
  1290. endfunction
  1291. function! s:CCTreeTagDbRdr.mRequirePreProcessing() dict
  1292. return s:CCTreeRC.False
  1293. endfunction
  1294. function! s:CCTreeTagDbRdr.mRequirePostProcessing() dict
  1295. return s:CCTreeRC.True
  1296. endfunction
  1297. function! s:CCTreeTagDbRdr.mRequireCleanup() dict
  1298. " Clean-up all symbols [never]
  1299. return s:CCTreeRC.False
  1300. endfunction
  1301. function! s:CCTreeTagDbRdr.mGetPreProcessingMaps() dict
  1302. return s:CCTreeGetXRefDbMaps('Compress', 'Alpha')
  1303. endfunction
  1304. function! s:CCTreeTagDbRdr.mGetPostProcessingMaps() dict
  1305. return s:CCTreeGetXRefDbMaps('Uncompress', 'Alpha')
  1306. endfunction
  1307. function! s:CCTreeTagDbRdr.mParseDbHeader(hdr) dict
  1308. " just check line 3 for sanity
  1309. if a:hdr[2] =~ "CCTree"
  1310. return s:CCTreeRC.Success
  1311. endif
  1312. return s:CCTreeRC.Error
  1313. endfunction
  1314. function! s:CCTreeTagDbRdr.mProcessingStateInit() dict
  1315. endfunction
  1316. function! s:CCTreeTagDbRdr.mProcessingStateDone() dict
  1317. endfunction
  1318. function! s:CCTreeTagDbRdr.mReadLinesFromFile(vdbFile, filtercmds) dict
  1319. " Hard-coded assumptions here about format for performance
  1320. if empty(get(a:vdbFile.lines, 0)) != 1 && a:vdbFile.lines[0][0] == "!"
  1321. " filter out the first few lines starting with "!"
  1322. call remove(a:vdbFile.lines, 0, self.headerLines-1)
  1323. endif
  1324. return a:vdbFile.lines
  1325. endfunction
  1326. function! s:CCTreeTagDbRdr.mProcessSymbol(xrefdb, aline) dict
  1327. let cctreesym = self.mDecodeTagLine(a:aline)
  1328. call a:xrefdb.mInsertSym(cctreesym.idx, cctreesym)
  1329. " we really don't need idx any longer
  1330. unlet cctreesym.idx
  1331. endfunction
  1332. function! s:CCTreeTagDbRdr.mDecodeTagLine(tagline) dict
  1333. let items = split(a:tagline, "\t")
  1334. let newsym = s:CCTreeSym.mCreate("", "")
  1335. try
  1336. let [newsym.idx, newsym.n] = split(items[0], '#')
  1337. catch
  1338. echomsg "problem decoding ". a:tagline
  1339. endtry
  1340. "let newsym.idx = strpart(items[0], 0, idxBr)
  1341. "let newsym.n = items[0][ idxBr+1 : -2] "strpart(items[0], idxBr+1, strlen(items[0])-1)
  1342. if empty(get(items, 3)) != 1
  1343. let newsym.c = items[3][2:]
  1344. endif
  1345. if empty(get(items, 4)) != 1
  1346. let newsym.p = items[4][2:]
  1347. endif
  1348. return newsym
  1349. endfunction
  1350. " }}}
  1351. " {{{ Generic Db Serializer
  1352. let s:GenericDbSerializer = {}
  1353. function! s:GenericDbSerializer.mCreate(xrefdb) dict
  1354. let gDbSerializer = deepcopy(s:GenericDbSerializer)
  1355. let gDbSerializer.xrefdb = a:xrefdb
  1356. return gDbSerializer
  1357. endfunction
  1358. function! s:GenericDbSerializer.mWriteXRefDbToFile(fname,
  1359. \ gWriter) dict
  1360. call s:StatusLine.mInit()
  1361. try
  1362. call s:StatusLine.mSetInfo('Writing XRefDb')
  1363. let vDbFile = s:vFile.mCreate(a:fname, "w")
  1364. call vDbFile.mWriteList(a:gWriter.mBuildHeader())
  1365. call self.mWriteSymsToFile(vDbFile, a:gWriter)
  1366. finally
  1367. call vDbFile.mClose()
  1368. call s:StatusLine.mRestore()
  1369. endtry
  1370. endfunction
  1371. function! s:GenericDbSerializer.mWriteSymsToFile(dstVFile,
  1372. \ gWriter) dict
  1373. let pBar = s:ProgressBarNumeric.mCreate(self.xrefdb.mGetSymbolCount(),
  1374. \ "items")
  1375. call a:gWriter.mInitWriting()
  1376. " write syms
  1377. for asymid in sort(self.xrefdb.mGetSymbolIds())
  1378. let acctreesym = self.xrefdb.mGetSymbolFromId(asymid)
  1379. call a:dstVFile.mWriteLine(a:gWriter.mBuildTagLine(acctreesym,
  1380. \ asymid))
  1381. call pBar.mTick(1)
  1382. endfor
  1383. call pBar.mDone()
  1384. call a:gWriter.mDoneWriting()
  1385. endfunction
  1386. " }}}
  1387. " {{{ CCTreeTagDb Writer
  1388. let s:CCTreeTagDbWriter = {}
  1389. function! s:CCTreeTagDbWriter.mCreate(tmaps) dict
  1390. let dbwriter = deepcopy(s:CCTreeTagDbWriter)
  1391. unlet dbwriter.mCreate
  1392. let dbwriter.tmaps = a:tmaps
  1393. return dbwriter
  1394. endfunction
  1395. function! s:CCTreeTagDbWriter.mInitWriting() dict
  1396. call self.tmaps.mInitTranslator()
  1397. endfunction
  1398. function! s:CCTreeTagDbWriter.mDoneWriting() dict
  1399. call self.tmaps.mDoneTranslator()
  1400. endfunction
  1401. function! s:CCTreeTagDbWriter.mBuildHeader() dict
  1402. let hdr = []
  1403. call add(hdr, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/")
  1404. call add(hdr, "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/")
  1405. call add(hdr, "!_TAG_PROGRAM_NAME\t\tCCTree (Vim plugin)//")
  1406. call add(hdr, "!_TAG_PROGRAM_URL\thttp://vim.sourceforge.net/scripts/script.php?script_id=2368\t/site/")
  1407. return hdr
  1408. endfunction
  1409. function! s:CCTreeTagDbWriter.mBuildTagLine(sym, symid) dict
  1410. let basetag = a:symid .'#'. a:sym.n."\t"."\t"."/^\$/".";\""
  1411. let cm = self.tmaps.mTranslate(a:sym.c)
  1412. let pm = self.tmaps.mTranslate(a:sym.p)
  1413. let basetag .= "\tc:". self.tmaps.mTranslate(a:sym.c)
  1414. let basetag .= "\tp:". self.tmaps.mTranslate(a:sym.p)
  1415. return basetag
  1416. endfunction
  1417. " }}}
  1418. " {{{ CCTree constants
  1419. let s:CCTreeRC = {
  1420. \ 'Error' : -1,
  1421. \ 'True' : 1,
  1422. \ 'False' : 0,
  1423. \ 'Success' : 2
  1424. \ }
  1425. "}}}
  1426. " {{{ CCTree DB Obj
  1427. " Symbol definition
  1428. let s:CCTreeSym = {
  1429. \'k': "",
  1430. \'n': "",
  1431. \'c': "",
  1432. \'p': ""
  1433. \}
  1434. function! s:CCTreeSym.mCreate(name, kind)
  1435. let sym = deepcopy(s:CCTreeSym)
  1436. unlet sym.mCreate
  1437. let sym.n = a:name
  1438. let sym.k = a:kind
  1439. return sym
  1440. endfunction
  1441. " }}}
  1442. " {{{ GenericXref, XrefDb
  1443. let s:GenericXRef = {}
  1444. function! s:GenericXRef.mCreate(filedb) dict
  1445. let gxref = deepcopy(s:GenericXRef)
  1446. return gxref
  1447. endfunction
  1448. function! s:GenericXRef.mInitState() dict
  1449. endfunction
  1450. function! s:GenericXRef.mRestoreState() dict
  1451. endfunction
  1452. " {{{ XRef Database object
  1453. let s:xRefMemDb = {
  1454. \ 'symuniqid': 0,
  1455. \ 'symidhash' : {},
  1456. \ 'symnamehash' : {},
  1457. \ 'class' : s:DBStorage.memory
  1458. \}
  1459. function s:xRefMemDb.mCreate() dict
  1460. let dbObj = deepcopy(s:xRefMemDb)
  1461. unlet dbObj.mCreate
  1462. return dbObj
  1463. endfunction
  1464. function s:xRefMemDb.mInitState() dict
  1465. endfunction
  1466. function s:xRefMemDb.mRestoreState() dict
  1467. endfunction
  1468. function s:xRefMemDb.mClear() dict
  1469. let self.symidhash = {}
  1470. let self.symnamehash = {}
  1471. let self.symuniqid = 0
  1472. endfunction
  1473. function! s:xRefMemDb.mInsertSym(idx, cctreesym) dict
  1474. let self.symuniqid = max([self.symuniqid, a:idx])
  1475. let self.symidhash[a:idx] = a:cctreesym
  1476. let self.symnamehash[a:cctreesym.n] = a:idx
  1477. endfunction
  1478. function! s:xRefMemDb.mRemoveSymById(symidx) dict
  1479. call self.mRemoveSymByName(acctreesym.n)
  1480. call remove(self.symidhash, a:symidx)
  1481. endfunction
  1482. function! s:xRefMemDb.mRemoveSymByName(symname) dict
  1483. call remove(self.symnamehash, a:symname)
  1484. endfunction
  1485. function! s:xRefMemDb.mAddSym(name, kind) dict
  1486. if !has_key(self.symnamehash, a:name)
  1487. let self.symnamehash[a:name] = self.symuniqid
  1488. let self.symidhash[self.symuniqid] =
  1489. \s:CCTreeSym.mCreate(a:name, a:kind)
  1490. let self.symuniqid += 1
  1491. endif
  1492. let asymid = self.symnamehash[a:name]
  1493. if a:kind != ""
  1494. let asym = self.symidhash[asymid]
  1495. let asym.k = a:kind
  1496. endif
  1497. return asymid
  1498. endfunction
  1499. function! s:xRefMemDb.mMarkXRefSyms(funcentryidx, newfuncidx) dict
  1500. let self.symidhash[a:funcentryidx]['c'] .= (",". a:newfuncidx)
  1501. let self.symidhash[a:newfuncidx]['p'] .= (",". a:funcentryidx)
  1502. endfunction
  1503. function! s:xRefMemDb.mGetSymbolFromName(symname) dict
  1504. return self.symidhash[self.symnamehash[a:symname]]
  1505. endfunction
  1506. function! s:xRefMemDb.mGetSymbolIdFromName(symname) dict
  1507. if has_key(self.symnamehash, a:symname)
  1508. return self.symnamehash[a:symname]
  1509. else
  1510. return s:CCTreeRC.Error
  1511. endif
  1512. endfunction
  1513. function! s:xRefMemDb.mGetSymbolFromId(symid) dict
  1514. return self.symidhash[a:symid]
  1515. endfunction
  1516. function! s:xRefMemDb.mGetSymbolIds() dict
  1517. return keys(self.symidhash)
  1518. endfunction
  1519. function! s:xRefMemDb.mGetSymbolNames(lead) dict
  1520. let syms = keys(self.symnamehash)
  1521. if empty(a:lead) != 1
  1522. return filter(syms, 'v:val =~? a:lead')
  1523. endif
  1524. return syms
  1525. endfunction
  1526. function! s:xRefMemDb.mGetSymbolCount() dict
  1527. return len(self.symnamehash)
  1528. endfunction
  1529. function! s:xRefMemDb.mTranslateSymbols(map, tkeys) dict
  1530. call a:map.mInitTranslator()
  1531. let pBar = s:ProgressBarNumeric.mCreate(len(self.symnamehash), "items")
  1532. for asym in keys(self.symnamehash)
  1533. let idx = self.symnamehash[asym]
  1534. let val = self.symidhash[idx]
  1535. if has_key(a:tkeys, 'n')
  1536. let uncmpname = a:map.mTranslate(asym)
  1537. if (asym != uncmpname)
  1538. "Set up new entry
  1539. let self.symnamehash[uncmpname] = idx
  1540. " free the old entry
  1541. call remove(self.symnamehash, asym)
  1542. " Set uncompressed name
  1543. let val.n = uncmpname
  1544. endif
  1545. endif
  1546. if has_key(a:tkeys, 'p')
  1547. let val.p = a:map.mTranslate(val.p)
  1548. endif
  1549. if has_key(a:tkeys, 'c')
  1550. let val.c = a:map.mTranslate(val.c)
  1551. endif
  1552. call pBar.mTick(1)
  1553. endfor
  1554. call pBar.mDone()
  1555. call a:map.mDoneTranslator()
  1556. endfunction
  1557. function! s:xRefMemDb.mCleanSymbols () dict
  1558. let pBar = s:ProgressBarNumeric.mCreate(len(self.symnamehash), "items")
  1559. for asym in keys(self.symnamehash)
  1560. let idx = self.symnamehash[asym]
  1561. let val = self.symidhash[idx]
  1562. if empty(val.p) && empty(val.c)
  1563. call remove(self.symnamehash, asym)
  1564. call remove(self.symidhash, idx)
  1565. else
  1566. let val.p = s:CCTreeMakeCommaListUnique(val.p)
  1567. let val.c = s:CCTreeMakeCommaListUnique(val.c)
  1568. endif
  1569. call pBar.mTick(1)
  1570. endfor
  1571. call pBar.mDone()
  1572. endfunction
  1573. "}}}
  1574. "}}} End of Xref
  1575. " {{{ Tracer
  1576. let s:CallTreeNode = {
  1577. \ 'symname' : "",
  1578. \ 'symid' : ""
  1579. \ }
  1580. function! s:CallTreeNode.mCreate(name, id) dict
  1581. let ct = deepcopy(s:CallTreeNode)
  1582. unlet ct.mCreate
  1583. let ct.symname = a:name
  1584. let ct.symid = a:id
  1585. return ct
  1586. endfunction
  1587. let s:CallTreeUtils = {}
  1588. function! s:CallTreeUtils.mAddChildLink(callTreeNode, childTree) dict
  1589. if !has_key(a:callTreeNode, 'childlinks')
  1590. let a:callTreeNode.childlinks = []
  1591. endif
  1592. call add(a:callTreeNode.childlinks, a:childTree)
  1593. endfunction
  1594. let s:XRefTracer = {
  1595. \}
  1596. function! s:XRefTracer.mCreate(xrefdb) dict
  1597. let xreftracer = deepcopy(s:XRefTracer)
  1598. let xreftracer.xrefdb = a:xrefdb
  1599. return xreftracer
  1600. endfunction
  1601. function! s:XRefTracer.mInitTracing() dict
  1602. call self.xrefdb.mInitState()
  1603. endfunction
  1604. function! s:XRefTracer.mDoneTracing() dict
  1605. call self.xrefdb.mRestoreState()
  1606. endfunction
  1607. function! s:XRefTracer.mGetSymbolIdXRef(symid, direction) dict
  1608. let acctreesym = self.xrefdb.mGetSymbolFromId(a:symid)
  1609. let symidslist = split(
  1610. \s:CCTreeMakeCommaListUnique(acctreesym[a:direction]), ",")
  1611. return symidslist
  1612. endfunction
  1613. function! s:XRefTracer.mGrowTree(rtree,
  1614. \ direction, pbar) dict
  1615. if !has_key(a:rtree, 'childlinks')
  1616. call self.mBuildTree(a:rtree, 1, 1,
  1617. \ a:direction, a:pbar)
  1618. else
  1619. for entry in a:rtree['childlinks']
  1620. call self.mGrowTree(entry,
  1621. \ a:direction, a:pbar)
  1622. endfor
  1623. endif
  1624. endfunction
  1625. function! s:XRefTracer.mPruneTree(rtree,
  1626. \ direction, pbar) dict
  1627. if !has_key(a:rtree, 'childlinks')
  1628. return -1
  1629. else
  1630. for entry in a:rtree['childlinks']
  1631. if (self.mPruneTree(entry,
  1632. \ a:direction, a:pbar) == -1)
  1633. call remove(a:rtree['childlinks'], 0)
  1634. endif
  1635. endfor
  1636. endif
  1637. if empty(a:rtree['childlinks']) == 1
  1638. call remove(a:rtree, 'childlinks')
  1639. endif
  1640. return 0
  1641. endfunction
  1642. function! s:XRefTracer.mBuildTree(rtree, curdepth, maxdepth,
  1643. \ direction, pbar) dict
  1644. if (a:curdepth > a:maxdepth)
  1645. return {}
  1646. endif
  1647. call a:pbar.mSetDepth(a:curdepth)
  1648. for entry in self.mGetSymbolIdXRef(a:rtree.symid, a:direction)
  1649. call a:pbar.mTick(1)
  1650. let symname = self.xrefdb.mGetSymbolFromId(entry)
  1651. let ctree = s:CallTreeNode.mCreate(symname['n'], entry)
  1652. call self.mBuildTree(ctree, a:curdepth+1, a:maxdepth,
  1653. \a:direction, a:pbar)
  1654. call s:CallTreeUtils.mAddChildLink(a:rtree, ctree)
  1655. endfor
  1656. endfunction
  1657. function! s:XRefTracer.mBuildForSymbol(symid, curdepth, maxdepth,
  1658. \ direction, pbar) dict
  1659. let symname = self.xrefdb.mGetSymbolFromId(a:symid)
  1660. " revisit
  1661. if empty(symname)
  1662. return {}
  1663. endif
  1664. let rtree = s:CallTreeNode.mCreate(symname['n'], a:symid)
  1665. call self.mBuildTree(rtree, a:curdepth, a:maxdepth, a:direction,
  1666. \ a:pbar)
  1667. return rtree
  1668. endfunction
  1669. " }}}
  1670. " {{{ Cscope Reader
  1671. let s:CscopeDbRdrState = {
  1672. \'curfuncidx': -1,
  1673. \'curfileidx': -1,
  1674. \'curmacroidx': -1,
  1675. \'curenumidx': -1,
  1676. \ }
  1677. function! s:CscopeDbRdrState.mCreate() dict
  1678. return deepcopy(s:CscopeDbRdrState)
  1679. endfunction
  1680. let s:CscopeDbRdrSymTags = {
  1681. \'func' : '$}',
  1682. \'macro' : '#\)',
  1683. \'file' : '@\~',
  1684. \'enum' : 'em',
  1685. \'global' : 'g',
  1686. \'typedef' : 't',
  1687. \}
  1688. let s:CscopeDbSymFilter = ['v:val =~ "^\t[#`$}@\~\)]"']
  1689. let s:CscopeDbSymEnhFilter = ['v:val =~ "^\t[emgt#`$}@~)]"',
  1690. \ 'v:val =~ "^\\a\\|^\t[)$}#]"']
  1691. let s:CscopeDbSymFilterPerl = ['^\t[\`\#\$\}\@\~\)]']
  1692. let s:CscopeDbSymEnhFilterPerl = ['^\t[\`\#\$\}\@\~\)emgt]',
  1693. \ '^[A-Za-z]|^\t[\#\$\}\)]']
  1694. let s:CscopeDbRdr = {
  1695. \ 'class': 'Cscope',
  1696. \ 'headerLines' : 1,
  1697. \ 'compressed' : 0,
  1698. \ 'opts': [],
  1699. \ 'perl_opts': '',
  1700. \ 'mapPreKeys': {'n':''},
  1701. \ 'mapPostKeys': {'n':''}
  1702. \}
  1703. function! s:CscopeDbRdr.mCreate(fname, enhanced) dict
  1704. let csdbrdr = deepcopy(s:CscopeDbRdr)
  1705. unlet csdbrdr.mCreate
  1706. if a:enhanced == 1
  1707. if g:CCTreeUsePerl == 1
  1708. let csdbrdr.opts = s:CscopeDbSymEnhFilterPerl
  1709. else
  1710. let csdbrdr.opts = s:CscopeDbSymEnhFilter
  1711. endif
  1712. else
  1713. if g:CCTreeUsePerl == 1
  1714. let csdbrdr.opts = s:CscopeDbSymFilterPerl
  1715. else
  1716. let csdbrdr.opts = s:CscopeDbSymFilter
  1717. endif
  1718. endif
  1719. return csdbrdr
  1720. endfunction
  1721. function! s:CscopeDbRdr.mProcessingStateInit() dict
  1722. let self.iState = s:CscopeDbRdrState.mCreate()
  1723. endfunction
  1724. function! s:CscopeDbRdr.mProcessingStateDone() dict
  1725. " discard state
  1726. unlet self.iState
  1727. endfunction
  1728. function! s:CscopeDbRdr.mReadLinesFromFile(vDbFile, filtercmds) dict
  1729. return s:CCTreeUtils.mFilter(a:vDbFile.lines, a:filtercmds)
  1730. endfunction
  1731. function! s:CscopeDbRdr.mParseDbHeader(dbHeader) dict
  1732. if a:dbHeader[0] =~ "cscope"
  1733. if (a:dbHeader[0] !~ "cscope.*\-c")
  1734. let self.compressed = s:CCTreeRC.True
  1735. else
  1736. let self.compressed = s:CCTreeRC.False
  1737. endif
  1738. return s:CCTreeRC.Success
  1739. endif
  1740. return s:CCTreeRC.Error
  1741. endfunction
  1742. function! s:CscopeDbRdr.mRequirePreProcessing() dict
  1743. return (self.compressed == 1)? s:CCTreeRC.True : s:CCTreeRC.False
  1744. endfunction
  1745. function! s:CscopeDbRdr.mRequirePostProcessing() dict
  1746. return (self.compressed == 1)? s:CCTreeRC.True : s:CCTreeRC.False
  1747. endfunction
  1748. function! s:CscopeDbRdr.mRequireCleanup() dict
  1749. " Clean-up all symbols [always]
  1750. return s:CCTreeRC.True
  1751. endfunction
  1752. function! s:CscopeDbRdr.mGetPreProcessingMaps() dict
  1753. return s:CCTreeGetCscopeMaps('Compress', 'Alpha')
  1754. endfunction
  1755. function! s:CscopeDbRdr.mGetPostProcessingMaps() dict
  1756. return s:CCTreeGetCscopeMaps('Uncompress', 'Alpha')
  1757. endfunction
  1758. function! s:CscopeDbRdr.mProcessSymbol(xrefdb, symbol) dict
  1759. try
  1760. if a:symbol[0] == "\t"
  1761. return self.mProcessTaggedSymbol(a:xrefdb, a:symbol)
  1762. else
  1763. return self.mProcessUnTaggedSymbol(a:xrefdb, a:symbol)
  1764. endif
  1765. catch
  1766. echomsg 'Problem with '. a:symbol
  1767. endtry
  1768. endfunction
  1769. function! s:CscopeDbRdr.mProcessUnTaggedSymbol(xrefdb, symbol) dict
  1770. let cursymidx = a:xrefdb.mGetSymbolIdFromName(a:symbol)
  1771. if cursymidx != s:CCTreeRC.Error
  1772. if self.iState.curfuncidx != -1
  1773. call a:xrefdb.mMarkXRefSyms(self.iState.curfuncidx, cursymidx)
  1774. elseif self.iState.curmacroidx != -1
  1775. call a:xrefdb.mMarkXRefSyms(self.iState.curmacroidx, cursymidx)
  1776. endif
  1777. endif
  1778. endfunction
  1779. function! s:CscopeDbRdr.mProcessTaggedSymbol(xrefdb, symbol) dict
  1780. if self.iState.curmacroidx != -1
  1781. if a:symbol[1] == "`"
  1782. call a:xrefdb.mMarkXRefSyms(self.iState.curmacroidx,
  1783. \ a:xrefdb.mAddSym(a:symbol[2:], ""))
  1784. elseif a:symbol[1] == ')'
  1785. let self.iState.curmacroidx = -1
  1786. endif
  1787. elseif self.iState.curfuncidx != -1
  1788. " inside function
  1789. if a:symbol[1] == "`"
  1790. call a:xrefdb.mMarkXRefSyms(self.iState.curfuncidx,
  1791. \ a:xrefdb.mAddSym(a:symbol[2:], ""))
  1792. elseif a:symbol[1] == "}"
  1793. let self.iState.curfuncidx = -1
  1794. elseif a:symbol[1] == "#"
  1795. let self.iState.curmacroidx = a:xrefdb.mAddSym(a:symbol[2:], 'm')
  1796. endif
  1797. elseif self.iState.curenumidx != -1
  1798. if a:symbol[1] == "m"
  1799. call a:xrefdb.mMarkXRefSyms(self.iState.curenumidx,
  1800. \ a:xrefdb.mAddSym(a:symbol[2:], "em"))
  1801. else
  1802. " just reprocess the symbol after changing state
  1803. let self.iState.curenumidx = -1
  1804. call self.mProcessTaggedSymbol(a:xrefdb, a:symbol)
  1805. endif
  1806. elseif a:symbol[1] == "$"
  1807. let self.iState.curfuncidx = a:xrefdb.mAddSym(a:symbol[2:], "f")
  1808. elseif a:symbol[1] == "#"
  1809. let self.iState.curmacroidx = a:xrefdb.mAddSym(a:symbol[2:], "d")
  1810. elseif a:symbol[1] == "~"
  1811. call a:xrefdb.mMarkXRefSyms(self.iState.curfileidx,
  1812. \a:xrefdb.mAddSym(a:symbol[3:], "i"))
  1813. elseif a:symbol[1] == "e"
  1814. let self.iState.curenumidx = a:xrefdb.mAddSym(a:symbol[2:], "e")
  1815. elseif a:symbol[1] == "g"
  1816. call a:xrefdb.mAddSym(a:symbol[2:], "g")
  1817. elseif a:symbol[1] == "@"
  1818. if a:symbol[2] != ""
  1819. let self.iState.curfileidx =
  1820. \a:xrefdb.mAddSym(a:symbol[2:], "F")
  1821. endif
  1822. endif
  1823. endfunction
  1824. " }}}
  1825. " {{{ CCTree helper library
  1826. let s:CCTreeUtils = {}
  1827. function! s:CCTreeUtils.mDetectDB(class)
  1828. if a:class == s:DBClasses.cctreexref
  1829. if filereadable(g:CCTreeDb)
  1830. return g:CCTreeDb
  1831. endif
  1832. elseif a:class == s:DBClasses.cscopeid
  1833. if filereadable(g:CCTreeCscopeDb)
  1834. return g:CCTreeCscopeDb
  1835. endif
  1836. endif
  1837. return ''
  1838. endfunction
  1839. function! s:CCTreeUtils.mFilter(lines, filtercmd) dict
  1840. let retlst = []
  1841. let progr = len(a:lines)/100
  1842. let pBar = s:ProgressBarNumeric.mCreate(len(a:lines), "items")
  1843. while len(a:lines) > 0
  1844. if progr <= len(a:lines)
  1845. let tmplist = remove(a:lines, 0, progr)
  1846. else
  1847. let tmplist = remove(a:lines, 0, len(a:lines)-1)
  1848. endif
  1849. call filter(tmplist, a:filtercmd)
  1850. call pBar.mTick(progr)
  1851. call extend(retlst, tmplist)
  1852. endwhile
  1853. call pBar.mDone()
  1854. return retlst
  1855. endfunction
  1856. function! s:CCTreeUtils.mWarningPrompt(msg) dict
  1857. echohl WarningMsg
  1858. let a = input(s:pluginname. ": ". a:msg)
  1859. echohl None
  1860. endfunction
  1861. function! s:CCTreeUtils.mWarningMsg(msg) dict
  1862. echohl WarningMsg
  1863. echomsg s:pluginname. ": ". a:msg
  1864. echohl None
  1865. endfunction
  1866. function! s:CCTreeUtils.mInfoMsg(msg) dict
  1867. echohl Title
  1868. echomsg s:pluginname. ": ". a:msg
  1869. echohl None
  1870. endfunction
  1871. function! s:CCTreeUtils.mWrite(msg) dict
  1872. echo s:pluginname. ": ". a:msg
  1873. endfunction
  1874. " }}}
  1875. " {{{ CCTree DB management
  1876. let s:CCTreeXrefDbEntry = {
  1877. \ 'type': '',
  1878. \ 'fname' : '',
  1879. \ 'fsize' : 0,
  1880. \ 'fdate' : 0
  1881. \}
  1882. function! s:CCTreeXrefDbEntry.mCreate(fname, type) dict
  1883. let xrefdbent = deepcopy(s:CCTreeXrefDbEntry)
  1884. unlet xrefdbent.mCreate
  1885. let xrefdbent.type = a:type
  1886. let xrefdbent.fname = simplify(getcwd().'/'.a:fname)
  1887. let xrefdbent.fsize = getfsize(a:fname)
  1888. let xrefdbent.fdate = strftime("%c", getftime(a:fname))
  1889. return xrefdbent
  1890. endfunction
  1891. let s:CCTreeDBList = {
  1892. \'loadedDBs' : []
  1893. \ }
  1894. function! s:CCTreeDBList.mCreate() dict
  1895. let dbList = deepcopy(s:CCTreeDBList)
  1896. unlet dbList.mCreate
  1897. return dbList
  1898. endfunction
  1899. function! s:CCTreeDBList.mShowLoaded() dict
  1900. let i = 1
  1901. call s:CCTreeUtils.mWrite(s:pluginname.": List of loaded cscope databases")
  1902. call s:CCTreeUtils.mWrite("---------------------------------------")
  1903. for aDBEnt in self.loadedDBs
  1904. call s:CCTreeUtils.mWrite(i." ".aDBEnt.fname. " ".
  1905. \ " (".aDBEnt.type.") ".
  1906. \ aDBEnt.fsize. " bytes ".
  1907. \ aDBEnt.fdate)
  1908. let i = i + 1
  1909. endfor
  1910. endfunction
  1911. function! s:CCTreeDBList.mClearAll() dict
  1912. let self.loadedDBs = []
  1913. endfunction
  1914. function! s:CCTreeDBList.mIsEmpty() dict
  1915. if empty(self.loadedDBs)
  1916. return s:CCTreeRC.True
  1917. endif
  1918. return s:CCTreeRC.False
  1919. endfunction
  1920. " Load the cscope db into the global cctree xref db
  1921. function! s:CCTreeDBList.mCreateDbLoaderAndReader(dbName, dbclass, storageclass) dict
  1922. let dbUser = s:CCTreeCmdLine.mInputDBName('Load', a:dbName, a:dbclass)
  1923. if dbUser == ''
  1924. call s:CCTreeUtils.mWarningMsg('Filename required')
  1925. "User cancel, do nothing
  1926. return
  1927. endif
  1928. " Create generic Db loader object
  1929. if a:storageclass == s:DBStorage.disk
  1930. let gDbLdr = s:XRefDiskDbLdr.mCreate(dbUser)
  1931. elseif a:storageclass == s:DBStorage.memory
  1932. let gDbLdr = s:XRefMemDbLdr.mCreate(dbUser)
  1933. endif
  1934. if type(gDbLdr) != type({})
  1935. call s:CCTreeUtils.mWarningMsg(a:dbclass.' database ' . a:dbName .
  1936. \ ' not found.')
  1937. return s:CCTreeRC.Error
  1938. endif
  1939. " Create new DB reader object
  1940. if a:storageclass == s:DBStorage.memory
  1941. if a:dbclass == s:DBClasses.cscopeid
  1942. let gDbRdr = s:CscopeDbRdr.mCreate(dbUser, g:CCTreeEnhancedSymbolProcessing)
  1943. elseif a:dbclass == s:DBClasses.cctreexref
  1944. let gDbRdr = s:CCTreeTagDbRdr.mCreate(dbUser)
  1945. else
  1946. return s:CCTreeRC.Error
  1947. endif
  1948. if gDbLdr.mParseDbHeader(gDbRdr) == s:CCTreeRC.Error
  1949. call s:CCTreeUtils.mWarningMsg(gDbRdr.class.' database ' . a:dbName .
  1950. \ ' format is not parseable.')
  1951. return s:CCTreeRC.Error
  1952. endif
  1953. else
  1954. let gDbRdr = {}
  1955. endif
  1956. return {'loader': gDbLdr, 'reader': gDbRdr}
  1957. endfunction
  1958. function! s:CCTreeDBList.mAddDbToList(dbName, type)
  1959. let aDBEnt = s:CCTreeXrefDbEntry.mCreate(a:dbName, a:type)
  1960. call add(self.loadedDBs, aDBEnt)
  1961. endfunction
  1962. " Merge the cscope db into the global cctree xref db
  1963. function! s:CCTreeDBList.mMerge(dbName, xRefDb, class)
  1964. " Check if merge can be supported
  1965. if self.loadedDBs[0].type == s:DBStorage.disk
  1966. call s:CCTreeUtils.mInfoMsg("Cannot merge with DBs traced from disk")
  1967. return
  1968. endif
  1969. " Create db loader, reader
  1970. let gObjs = self.mCreateDbLoaderAndReader(a:dbName, a:class, s:DBStorage.memory)
  1971. if type(gObjs) == type({})
  1972. " if Db is compressed, then we need to compress our symbols first
  1973. let swatch = s:StopWatch.mCreate()
  1974. if self.mLoadDB(gObjs.loader, a:xRefDb,
  1975. \ gObjs.reader) != s:CCTreeRC.Error
  1976. call self.mAddDbToList(gObjs.loader.fDBName, gObjs.loader.class)
  1977. call swatch.mSnapElapsed()
  1978. let msg = "Done merging databases. xRef Symbol Count: "
  1979. \.a:xRefDb.mGetSymbolCount()
  1980. \.". Time taken: ".swatch.mGetText()." secs"
  1981. call s:CCTreeUtils.mInfoMsg(msg)
  1982. endif
  1983. " Load will auto decompress the symbols
  1984. endif
  1985. endfunction
  1986. " Load the cscope db into the global cctree xref db
  1987. function! s:CCTreeDBList.mAddNew(dbName, xRefDb, dbclass, storageclass)
  1988. " Create db loader, reader
  1989. let gObjs = self.mCreateDbLoaderAndReader(a:dbName, a:dbclass, a:storageclass)
  1990. if type(gObjs) == type({})
  1991. let swatch = s:StopWatch.mCreate()
  1992. if self.mLoadDB(gObjs.loader, a:xRefDb,
  1993. \ gObjs.reader) != s:CCTreeRC.Error
  1994. call self.mAddDbToList(gObjs.loader.fDBName, gObjs.loader.class)
  1995. call swatch.mSnapElapsed()
  1996. if a:storageclass == s:DBStorage.memory
  1997. let msg = "Done loading database. xRef Symbol Count: "
  1998. \.a:xRefDb.mGetSymbolCount()
  1999. \.". Time taken: ".swatch.mGetText()." secs"
  2000. else
  2001. let msg = "Disk Xref database loaded for tracing"
  2002. endif
  2003. call s:CCTreeUtils.mInfoMsg(msg)
  2004. endif
  2005. endif
  2006. endfunction
  2007. function! s:CCTreeDBList.mLoadDB(gDbLdr, xRefDb, gRdr)
  2008. let rc = s:CCTreeRC.Success
  2009. try
  2010. let swatch = s:StopWatch.mCreate()
  2011. call s:StatusLine.mInit()
  2012. " if compression, then we need to compress our symbols first
  2013. if !empty(a:gRdr) && a:gRdr.mRequirePreProcessing() == s:CCTreeRC.True
  2014. call s:StatusLine.mSetInfo('Pre-processing existing symbols')
  2015. call a:xRefDb.mTranslateSymbols(a:gRdr.mGetPreProcessingMaps(),
  2016. \ a:gRdr.mapPreKeys)
  2017. endif
  2018. call garbagecollect()
  2019. call s:StatusLine.mSetInfo('Loading database')
  2020. call a:gDbLdr.mLoadFileIntoXRefDb(a:xRefDb, a:gRdr)
  2021. if !empty(a:gRdr) && a:gRdr.mRequireCleanup() == s:CCTreeRC.True
  2022. call s:StatusLine.mSetInfo('Symbol clean-up')
  2023. call a:xRefDb.mCleanSymbols()
  2024. endif
  2025. call garbagecollect()
  2026. if !empty(a:gRdr) && a:gRdr.mRequirePostProcessing() == s:CCTreeRC.True
  2027. call s:StatusLine.mSetInfo('Post-processing loaded symbols')
  2028. call a:xRefDb.mTranslateSymbols(a:gRdr.mGetPostProcessingMaps(),
  2029. \ a:gRdr.mapPostKeys)
  2030. endif
  2031. call swatch.mSnapElapsed()
  2032. " restore normalcy
  2033. call garbagecollect()
  2034. redraw
  2035. catch /^Vim:Interrupt$/ " catch interrupts (CTRL-C)
  2036. call s:CCTreeUtils.mWarningMsg('Loading aborted.')
  2037. let rc = s:CCTreeRC.Error
  2038. finally
  2039. call s:StatusLine.mRestore()
  2040. endtry
  2041. return rc
  2042. endfunction
  2043. "}}}
  2044. " {{{ UI Input related
  2045. let s:CCTreeUI = {}
  2046. function! s:CCTreeUI.mInputDBName(dbName, class, action)
  2047. let dbUser = a:dbName
  2048. let dbUser = input(a:action. ' database ('. a:class. '): ', a:dbName, 'file')
  2049. return dbUser
  2050. endfunction
  2051. " }}}
  2052. " {{{ CCTree Markers
  2053. let s:TreeMarkers_UTF8 = {
  2054. \ 'splitT' : nr2char(0x251c),
  2055. \ 'arrowR' : nr2char(0x25c0),
  2056. \ 'arrowF' : nr2char(0x25B6),
  2057. \ 'extV' : nr2char(0x2502),
  2058. \ 'extH': nr2char(0x2500),
  2059. \ 'depth': nr2char(0x25BC)
  2060. \}
  2061. let s:TreeMarkers_Text = {
  2062. \ 'splitT' : '+',
  2063. \ 'arrowF' : '>',
  2064. \ 'arrowR' : '<',
  2065. \ 'extV' : '|',
  2066. \ 'extH': '-',
  2067. \ 'depth': 'depth:'
  2068. \}
  2069. let s:CCTreeMarkers = {
  2070. \ 'icons':{}
  2071. \ }
  2072. function! s:CCTreeMarkers.mCreate() dict
  2073. let treeMarkers = deepcopy(s:CCTreeMarkers)
  2074. if &encoding == 'utf-8' && g:CCTreeUseUTF8Symbols == 1
  2075. let treeMarkers.icons = deepcopy(s:TreeMarkers_UTF8)
  2076. else
  2077. " default choice
  2078. let treeMarkers.icons = deepcopy(s:TreeMarkers_Text)
  2079. endif
  2080. let treeMarkers.icons.arrowSyms = treeMarkers.icons.arrowF . treeMarkers.icons.arrowR
  2081. let treeMarkers.icons.vertSyms = treeMarkers.icons.splitT . treeMarkers.icons.extV
  2082. return treeMarkers
  2083. endfunction
  2084. function! s:CCTreeMarkers.mGetArrow(direction) dict
  2085. if a:direction == 'p'
  2086. return self.icons.arrowR
  2087. elseif a:direction == 'c'
  2088. return self.icons.arrowF
  2089. endif
  2090. return '?'
  2091. endfunction
  2092. " }}}
  2093. " {{{ User key mappings
  2094. let s:CCTreeKeyMappings = {
  2095. \ 'CTreeF': g:CCTreeKeyTraceForwardTree,
  2096. \ 'CTreeR': g:CCTreeKeyTraceReverseTree,
  2097. \ 'CTreeHilight': g:CCTreeKeyHilightTree,
  2098. \ 'CTreeWSave': g:CCTreeKeySaveWindow,
  2099. \ 'CTreeWToggle': g:CCTreeKeyToggleWindow,
  2100. \ 'CTreeCompress': g:CCTreeKeyCompressTree,
  2101. \ 'CTreeDepthMinus': g:CCTreeKeyDepthMinus,
  2102. \ 'CTreeDepthPlus': g:CCTreeKeyDepthPlus
  2103. \}
  2104. " }}}
  2105. " {{{ CCTreeWindow
  2106. let s:CCTreeWindow = {
  2107. \ 'hiKeyword': '',
  2108. \ 'hiKeywordLine':'',
  2109. \ 'lastbufname':'',
  2110. \ 'treeMarkers': s:CCTreeMarkers.mCreate()}
  2111. function! s:CCTreeWindow.mCreate() dict
  2112. let win = deepcopy(s:CCTreeWindow)
  2113. unlet win.mCreate
  2114. return win
  2115. endfunction
  2116. function! s:CCTreeWindow.mLeave()
  2117. call s:FindOpenWindow(self.lastbufname)
  2118. endfunction
  2119. " Definition of a keyword...
  2120. let s:CCTreeKeywordRegEx = '[A-Za-z0-9_\\\.\/]\+'
  2121. function! s:CCTreeWindow.mGetKeywordAtCursor() dict
  2122. let curline = line(".")
  2123. let self.hiKeyword = ''
  2124. if foldclosed(curline) == -1
  2125. let curkeyword = matchstr(getline("."), s:CCTreeKeywordRegEx)
  2126. if curkeyword != ''
  2127. if curkeyword != self.hiKeyword || curline != self.hiKeywordLine
  2128. let self.hiKeyword = curkeyword
  2129. let self.hiKeywordLine = line(".")
  2130. return s:CCTreeRC.Success
  2131. endif
  2132. else
  2133. return s:CCTreeRC.Error
  2134. endif
  2135. endif
  2136. if self.hiKeyword == ''
  2137. return s:CCTreeRC.Error
  2138. endif
  2139. return s:CCTreeRC.Success
  2140. endfunction
  2141. function! s:CCTreeWindow.mBuildStatusLine(pState, title, items)
  2142. let needcomma = 0
  2143. let rtitle = a:title. ' ('. a:pState.keyword
  2144. let rtitle .= '['
  2145. if has_key(a:items, "depth")
  2146. let rtitle .= self.treeMarkers.icons.depth
  2147. let rtitle .= a:pState.depth
  2148. let needcomma = 1
  2149. endif
  2150. if has_key(a:items, "direction")
  2151. if needcomma == 1
  2152. let rtitle .= ','
  2153. endif
  2154. let rtitle .= self.treeMarkers.mGetArrow(a:pState.direction)
  2155. endif
  2156. let rtitle .= '])'
  2157. return rtitle
  2158. endfunction
  2159. function! CCTreeWindowPreviewStatusLine()
  2160. " get global
  2161. " this is a hack
  2162. let pState = s:CCTreeGlobals.PreviewState
  2163. let tMarkers = s:CCTreeGlobals.Window.treeMarkers
  2164. return s:CCTreeGlobals.Window.mBuildStatusLine(
  2165. \ s:CCTreeGlobals.PreviewState,
  2166. \ s:windowtitle,
  2167. \ {'depth':''}
  2168. \)
  2169. endfunction
  2170. function! s:CCTreeWindow.mPreviewSave(savetitle) dict
  2171. if s:FindOpenWindow(s:windowtitle) == 1
  2172. setlocal modifiable
  2173. call self.mClearMarksAll(b:displayTree)
  2174. call self.mMarkCallTreeAll(b:displayTree,
  2175. \ self.hiKeyword)
  2176. setlocal nomodifiable
  2177. setlocal statusline=%-F
  2178. silent! exec ":f ". a:savetitle
  2179. setlocal buflisted
  2180. return s:CCTreeRC.Success
  2181. endif
  2182. return s:CCTreeRC.Error
  2183. endfunction
  2184. function! s:CCTreeWindow.mIsOpen() dict
  2185. if s:FindOpenBuffer(s:windowtitle) > 0
  2186. return s:CCTreeRC.True
  2187. endif
  2188. return s:CCTreeRC.False
  2189. endfunction
  2190. function! s:CCTreeWindow.mClose() dict
  2191. if s:FindOpenWindow(s:windowtitle) == 1
  2192. silent! q!
  2193. endif
  2194. endfunction
  2195. function! s:CCTreeWindow.mDisplayToggle() dict
  2196. if s:FindOpenWindow(s:windowtitle) == 1
  2197. silent! hide
  2198. else
  2199. let winbufnr = s:FindOpenBuffer(s:windowtitle)
  2200. if winbufnr > 0
  2201. call self.mEnter()
  2202. silent! exec "buf ".winbufnr
  2203. call self.mResize()
  2204. silent! wincmd p
  2205. else
  2206. call s:CCTreeUtils.mWarningMsg(" No active window found.")
  2207. endif
  2208. endif
  2209. endfunction
  2210. function! s:CCTreeWindow.mResize() dict
  2211. if g:CCTreeWindowVertical == 1
  2212. if g:CCTreeWindowWidth == -1
  2213. exec "vertical resize ". b:maxwindowlen
  2214. else
  2215. exec "vertical resize ". g:CCTreeWindowWidth
  2216. endif
  2217. else
  2218. if g:CCTreeWindowHeight != -1
  2219. let &winminheight = g:CCTreeWindowHeight
  2220. exec "resize".g:CCTreeWindowHeight
  2221. endif
  2222. endif
  2223. endfunction
  2224. function! s:CCTreeWindow.mDisplayTree(atree, direction) dict
  2225. let incctreewin = 1
  2226. if (bufname('%') != s:windowtitle)
  2227. let incctreewin = self.mEnter()
  2228. endif
  2229. setlocal modifiable
  2230. silent 1,$d
  2231. let b:maxwindowlen = g:CCTreeWindowMinWidth
  2232. let b:displayTree = s:DisplayTree.mCreate(a:atree,
  2233. \ a:direction, self.treeMarkers)
  2234. call s:CCTreeDisplay.mPopulateTreeInCurrentBuffer(b:displayTree)
  2235. exec "normal gg"
  2236. " Need to force this again
  2237. let &l:foldlevel=g:CCTreeMinVisibleDepth
  2238. setlocal nomodifiable
  2239. call self.mResize()
  2240. if (incctreewin == 0)
  2241. call s:CCTreeWindow.mLeave()
  2242. endif
  2243. endfunction
  2244. function! s:CCTreeWindow.mExtractTreeSymbols(dtree)
  2245. let symlist = {}
  2246. for aentry in a:dtree.entries
  2247. let symlist[aentry.symbol] = 0
  2248. endfor
  2249. return symlist
  2250. endfunction
  2251. function! s:CCTreeWindow.mEnter() dict
  2252. let self.lastbufname = bufname("%")
  2253. let foundWindow = s:FindOpenWindow(s:windowtitle)
  2254. if foundWindow == 0
  2255. if g:CCTreeWindowVertical == 1
  2256. exec g:CCTreeOrientation." vsplit ". s:windowtitle
  2257. set winfixwidth
  2258. else
  2259. exec g:CCTreeOrientation." split ". s:windowtitle
  2260. set winfixheight
  2261. endif
  2262. setlocal buftype=nofile
  2263. setlocal bufhidden=hide
  2264. setlocal noswapfile
  2265. setlocal nonumber
  2266. setlocal nowrap
  2267. setlocal nobuflisted
  2268. if s:CCTreeUseConceal == 1
  2269. setlocal cole=3
  2270. setlocal cocu=nv
  2271. endif
  2272. setlocal statusline=%=%{CCTreeWindowPreviewStatusLine()}
  2273. call self.mInitSyntax(self.treeMarkers.icons)
  2274. let cpo_save = &cpoptions
  2275. set cpoptions&vim
  2276. call s:CCTreeBufferKeyMappingsCreate(s:CCTreeKeyMappings)
  2277. command! -buffer -nargs=0 CCTreeWindowHiCallTree
  2278. \ call s:CCTreeGlobals.mCursorHoldHandleEvent()
  2279. exec 'nnoremap <buffer> <silent> '.s:CCTreeKeyMappings.CTreeHilight.
  2280. \' :CCTreeWindowHiCallTree<CR>'
  2281. exec 'nnoremap <buffer> <silent> '.s:CCTreeKeyMappings.CTreeCompress.
  2282. \ ' :2,.foldclose!<CR>zv'
  2283. nnoremap <buffer> <silent> <C-p> :CCTreePreviewBufferUsingTag<CR>
  2284. nnoremap <buffer> <silent> <CR> :CCTreeLoadBufferUsingTag<CR>
  2285. nnoremap <buffer> <silent> <2-LeftMouse> :CCTreeLoadBufferUsingTag<CR>
  2286. let &cpoptions = cpo_save
  2287. endif
  2288. setlocal foldmethod=expr
  2289. setlocal foldexpr=CCTreeFoldExpr(getline(v:lnum))
  2290. setlocal foldtext=CCTreeFoldText()
  2291. let &l:foldlevel=g:CCTreeMinVisibleDepth
  2292. return foundWindow
  2293. endfunction
  2294. " }}}
  2295. " {{{ Dynamic call-tree highlighting using
  2296. " syntax highlight tricks
  2297. "
  2298. " There are 3 types of lines, marked with the start character [\s, !, #]
  2299. " Also @ is used to mark the path that is going up
  2300. function! s:CCTreeWindow.mMarkCallTreeVisible(dtree, keyword) dict
  2301. call self.mMarkCallTree(a:dtree, a:keyword, line("w0"))
  2302. endfunction
  2303. function! s:CCTreeWindow.mMarkCallTreeAll(dtree, keyword) dict
  2304. call self.mMarkCallTree(a:dtree, a:keyword, 1)
  2305. endfunction
  2306. function! s:CCTreeWindow.mMarkCallTree(dtree, keyword, firstLine) dict
  2307. let declevel = -1
  2308. let treelst = a:dtree.entries
  2309. let curLine = line(".")
  2310. let declevel = treelst[curLine-1].level
  2311. let targetlevel = declevel
  2312. for idx in range(curLine, a:firstLine, -1)
  2313. let aentry = treelst[idx-1]
  2314. " Find our keyword
  2315. let linemarker = 0
  2316. " Skip folds
  2317. if declevel != -1 && foldclosed(idx) == -1
  2318. if targetlevel == aentry.level
  2319. let linemarker = 1
  2320. let targetlevel -= 1
  2321. endif
  2322. let aline = a:dtree.mGetNotationalTxt(aentry.level, targetlevel+1, linemarker, 1)
  2323. \ . s:DisplayTreeUtils.mGetSymName(aentry)
  2324. call setline(idx, aline)
  2325. endif
  2326. endfor
  2327. endfunction
  2328. function! s:CCTreeWindow.mClearMarksVisible(dtree) dict
  2329. call self.mClearMarks(a:dtree, line("w$"), 1)
  2330. endfunction
  2331. function! s:CCTreeWindow.mClearMarksAll(dtree) dict
  2332. call self.mClearMarks(a:dtree, line("$"), 0)
  2333. endfunction
  2334. function! s:CCTreeWindow.mClearMarks(dtree, lastLine, noskip) dict
  2335. let curLine = line(".")
  2336. for idx in range(curLine+1, a:lastLine)
  2337. if a:noskip == 0
  2338. " be smart, breakout when we are done
  2339. let breakout = (getline(idx)[0] !~ "[!#]")
  2340. if breakout == 1
  2341. break
  2342. endif
  2343. endif
  2344. let aentry = a:dtree.entries[idx-1]
  2345. let aline = a:dtree.mGetNotationalTxt(aentry.level, -1, 0, 0)
  2346. \ . s:DisplayTreeUtils.mGetSymName(aentry)
  2347. call setline(idx, aline)
  2348. endfor
  2349. endfunction
  2350. function! s:CCTreeWindow.mInitSyntax(markers) dict
  2351. "syntax match CCTreePathMark /\s[|+]/ contained
  2352. exec 'syntax match CCTreePathMark /\s['. a:markers.vertSyms . ']/ contained'
  2353. "syntax match CCTreeArrow /-*[<>]/ contained
  2354. exec 'syntax match CCTreeArrow /'.a:markers.extH.'*['. a:markers.arrowSyms .']/ contained'
  2355. syntax match CCTreeSymbol / [A-Za-z0-9_\.\\\/]\+/ contained
  2356. syntax region CCTreeSymbolLine start="^\s" end="$" contains=CCTreeArrow,CCTreePathMark,CCTreeSymbol oneline
  2357. "syntax match CCTreeHiArrow /-*[<>]/ contained
  2358. exec 'syntax match CCTreeHiArrow /'. a:markers.extH .'*['. a:markers.arrowSyms .']/ contained'
  2359. syntax match CCTreeHiSymbol / [A-Za-z0-9_\.\\\/]\+/ contained
  2360. "syntax match CCTreeHiPathMark /\s[|+]/ contained
  2361. exec 'syntax match CCTreeHiPathMark /\s[' . a:markers.vertSyms . ']/ contained'
  2362. if s:CCTreeUseConceal == 1
  2363. syntax match CCTreeMarkExcl /^[!#]/ contained conceal
  2364. syntax match CCTreeMarkTilde /@/ contained conceal
  2365. else
  2366. syntax match CCTreeMarkExcl /^[!#]/ contained
  2367. syntax match CCTreeMarkTilde /@/ contained
  2368. endif
  2369. "syntax region CCTreeUpArrowBlock start="@" end=/[|+]/ contains=CCTreeMarkTilde contained oneline
  2370. exec 'syntax region CCTreeUpArrowBlock start="@" end=/['. a:markers.vertSyms .']/ contains=CCTreeMarkTilde contained oneline'
  2371. syntax region CCTreeHiSymbolLine start="!" end="$" contains=CCTreeMarkExcl,
  2372. \ CCTreeUpArrowBlock,
  2373. \ CCTreeHiSymbol,CCTreeHiArrow,CCTreeHiPathMark oneline
  2374. syntax region CCTreeMarkedSymbolLine start="#" end="$" contains=CCTreeMarkExcl,
  2375. \ CCTreeMarkTilde,CCTreePathMark,
  2376. \ CCTreeArrow,CCTreeSymbol,CCTreeUpArrowBlock oneline
  2377. endfunction
  2378. " }}}
  2379. " {{{ CCTreeDisplay
  2380. let s:CCTreeDisplay = {}
  2381. function! s:CCTreeDisplay.mPopulateTreeInCurrentBuffer(dtree)
  2382. let linelist = []
  2383. for aentry in a:dtree.entries
  2384. let aline = a:dtree.mGetNotationalTxt(aentry.level, -1, 0, 0)
  2385. \ . s:DisplayTreeUtils.mGetSymName(aentry)
  2386. let len = s:Utils.mStrlenEx(aline)
  2387. let b:maxwindowlen = max([len+1, b:maxwindowlen])
  2388. call add(linelist, aline)
  2389. endfor
  2390. call setline(".", linelist)
  2391. endfunction
  2392. " }}}
  2393. " {{{ CCTree command line interface
  2394. let s:CCTreeCmdLine = {}
  2395. function! s:CCTreeCmdLine.mLoadDBFromDisk(dbName) dict
  2396. call s:CCTreeGlobals.mUnLoadDBs()
  2397. let s:CCTreeGlobals.XRefDb = s:XRefDiskDb.mCreate()
  2398. call s:CCTreeGlobals.DbList.mAddNew(a:dbName,
  2399. \ s:CCTreeGlobals.XRefDb, s:DBClasses.cctreexref, "Disk")
  2400. endfunction
  2401. " Unload current db's and load new one
  2402. " There is no selective unloading
  2403. function! s:CCTreeCmdLine.mLoadDB(db_name, class) dict
  2404. call s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(0)
  2405. call s:CCTreeGlobals.mUnLoadDBs()
  2406. let s:CCTreeGlobals.XRefDb = s:xRefMemDb.mCreate()
  2407. call s:CCTreeGlobals.DbList.mAddNew(a:db_name,
  2408. \ s:CCTreeGlobals.XRefDb, a:class, s:DBStorage.memory)
  2409. call s:CCTreeGlobals.mSetupAutoCmds()
  2410. endfunction
  2411. function! s:CCTreeCmdLine.mInputDBName(action, dbName, class) dict
  2412. if a:dbName == ''
  2413. let dbUser = s:CCTreeUI.mInputDBName(
  2414. \ s:CCTreeUtils.mDetectDB(a:class),
  2415. \ a:class, a:action)
  2416. else
  2417. let dbUser = a:dbName
  2418. endif
  2419. return dbUser
  2420. endfunction
  2421. function! s:CCTreeCmdLine.mSaveDB(dbName, class) dict
  2422. let dbUser = self.mInputDBName('Save', a:dbName, a:class)
  2423. if dbUser == ''
  2424. call s:CCTreeUtils.mWarningMsg('Filename required')
  2425. return
  2426. endif
  2427. call s:CCTreeGlobals.Window.mClose()
  2428. call s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(0)
  2429. call s:CCTreeGlobals.mWriteXRefDbToFile(dbUser)
  2430. call s:CCTreeGlobals.mSetupAutoCmds()
  2431. call s:CCTreeGlobals.mUpdateForCurrentSymbol()
  2432. endfunction
  2433. " Merge current db with new one
  2434. function! s:CCTreeCmdLine.mMergeDB(db_name, class) dict
  2435. "call s:CCTreeGlobals.Window.mClose()
  2436. call s:CCTreeGlobals.DbList.mMerge(a:db_name, s:CCTreeGlobals.XRefDb, a:class)
  2437. endfunction
  2438. " }}}
  2439. " {{{ CCTree Buffer mappings
  2440. function! s:CCTreeWindowGetHiKeyword()
  2441. let keyw = expand("<cword>")
  2442. let keyf = expand("<cfile>")
  2443. let syms = s:CCTreeGlobals.mGetPreviewTreeSymbols()
  2444. if keyw != keyf
  2445. if has_key(syms, keyf)
  2446. return keyf
  2447. elseif has_key(syms, keyw)
  2448. return keyw
  2449. endif
  2450. else
  2451. return keyw
  2452. endif
  2453. return ''
  2454. endfunction
  2455. " Keymappings used common to source files and CCTree window
  2456. function! s:CCTreeBufferKeyMappingsCreate(kmaps)
  2457. let func_expr = '<SNR>'.s:sid.'CCTreeWindowGetHiKeyword()'
  2458. exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeR.' :CCTreeTraceReverse <C-R>='.
  2459. \ func_expr.'<CR><CR>'
  2460. exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeF.' :CCTreeTraceForward <C-R>='
  2461. \ .func_expr.'<CR><CR>'
  2462. exec 'nnoremap <silent> '.a:kmaps.CTreeWSave. ' :CCTreeWindowSaveCopy<CR>'
  2463. exec 'nnoremap <silent> '.a:kmaps.CTreeWToggle. ' :CCTreeWindowToggle<CR>'
  2464. exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeDepthPlus.
  2465. \ ' :CCTreeRecurseDepthPlus<CR>'
  2466. exec 'nnoremap <buffer> <silent> '.a:kmaps.CTreeDepthMinus.
  2467. \ ' :CCTreeRecurseDepthMinus<CR>'
  2468. endfunction
  2469. augroup CCTreeMaps
  2470. au!
  2471. " Header files get detected as cpp?
  2472. " This is a bug in Vim 7.2, a patch needs to be applied to the runtime c
  2473. " syntax files
  2474. " For now, use this hack to make *.h files work
  2475. autocmd FileType * if &ft == 'c'|| &ft == 'cpp' |
  2476. \ call s:CCTreeBufferKeyMappingsCreate(s:CCTreeKeyMappings)|
  2477. \ endif
  2478. augroup END
  2479. " }}}
  2480. " {{{ Tree building
  2481. let s:DisplayTreeEntry = {
  2482. \ 'symlink': "",
  2483. \ 'level': -1
  2484. \ }
  2485. function! s:DisplayTreeEntry.mCreate(sym, level) dict
  2486. let te = deepcopy(s:DisplayTreeEntry)
  2487. let te.symlink = a:sym
  2488. let te.level = a:level
  2489. unlet te.mCreate
  2490. return te
  2491. endfunction
  2492. let s:DisplayTreeUtils = {}
  2493. function! s:DisplayTreeUtils.mGetSymName(DTEntry) dict
  2494. return a:DTEntry.symlink.symname
  2495. endfunction
  2496. function! s:DisplayTreeUtils.mGetSymLevel(DTEntry) dict
  2497. return a:DTEntry.level
  2498. endfunction
  2499. let s:calltreemaxdepth = 10
  2500. let s:DisplayTree = {
  2501. \ 'entries': [],
  2502. \ 'levelMaxLen': repeat([255], s:calltreemaxdepth),
  2503. \ 'notTxt': {}
  2504. \ }
  2505. function! s:DisplayTree.mCreate(calltree, direction, markers) dict
  2506. let dt = deepcopy(s:DisplayTree)
  2507. call dt.mBuildTreeForLevel(a:calltree, 0)
  2508. call dt.mBuildNotationalTxtMarkers(a:direction, a:markers.icons)
  2509. unlet dt.mBuildTreeForLevel
  2510. unlet dt.mCreate
  2511. return dt
  2512. endfunction
  2513. function! s:DisplayTree.mBuildTreeForLevel(ctree, level)
  2514. if !has_key(a:ctree, 'symname')
  2515. return
  2516. endif
  2517. if g:CCTreeDisplayMode == 3
  2518. let curlevellen = strlen(a:ctree.symbol) + a:level + 2
  2519. let self.levelMaxLen[a:level] = min([self.levelMaxLen[a:level],
  2520. \ curlevellen])
  2521. endif
  2522. let aentry = s:DisplayTreeEntry.mCreate(a:ctree, a:level)
  2523. call add(self.entries, aentry)
  2524. if has_key(a:ctree, 'childlinks')
  2525. for alink in a:ctree['childlinks']
  2526. call self.mBuildTreeForLevel(alink, a:level+1)
  2527. endfor
  2528. endif
  2529. endfunction
  2530. function! s:DisplayTree.mBuildNotationalTxtMarkers(direction, markerSyms) dict
  2531. " REVISIT
  2532. if a:direction == 'p'
  2533. let directiontxt = a:markerSyms.arrowR . " "
  2534. elseif a:direction == 'c'
  2535. let directiontxt = a:markerSyms.arrowF . " "
  2536. endif
  2537. let self.notTxt.arrowHead = a:markerSyms.splitT
  2538. let self.notTxt.arrow = directiontxt
  2539. let self.notTxt.arrowLead = a:markerSyms.extH
  2540. let self.notTxt.sep = a:markerSyms.extV
  2541. if s:CCTreeUseConceal == 1
  2542. let concealspace = " "
  2543. else
  2544. let concealspace = ""
  2545. endif
  2546. let self.notTxt.symHighlighter= concealspace . "@"
  2547. let self.notTxt.hiSymbolMarker = "!".concealspace
  2548. let self.notTxt.hiBranchMarker = "#".concealspace
  2549. let self.notTxt.cache = {}
  2550. endfunction
  2551. function! s:DisplayTree.mGetNotationalTxt(depth, hiDepth, hiSym, hiPath) dict
  2552. let notkey = join(a:000, ":")
  2553. if has_key(self.notTxt.cache,notkey) == 1
  2554. return self.notTxt.cache[notkey]
  2555. else
  2556. return self.mBuildNotationalTxt(a:depth, a:hiDepth, a:hiSym, a:hiPath)
  2557. endif
  2558. endfunction
  2559. function! s:DisplayTree.mBuildNotationalTxt(depth, hiDepth, hiSym, hiPath) dict
  2560. let hiBranch = 0
  2561. let curDepth = a:depth
  2562. if 0
  2563. let Aspace = "A"
  2564. let Bspace = "B"
  2565. let Cspace = "C"
  2566. let Sspace = "S"
  2567. let Xspace = "X"
  2568. let Zspace = "Z"
  2569. let Fspace = "1"
  2570. else
  2571. let Aspace = " "
  2572. let Bspace = " "
  2573. let Cspace = " "
  2574. let Sspace = " "
  2575. let Xspace = " "
  2576. let Zspace = " "
  2577. let Fspace = " "
  2578. endif
  2579. if g:CCTreeDisplayMode == 1
  2580. let arrowLeads = self.notTxt.arrowLead
  2581. elseif g:CCTreeDisplayMode >= 2
  2582. let arrowLeads = repeat(self.notTxt.arrowLead, a:depth)
  2583. endif
  2584. let indentSpace = ""
  2585. if g:CCTreeDisplayMode == 2
  2586. if curDepth > 0
  2587. let indentSpace = repeat(Aspace, curDepth)
  2588. endif
  2589. elseif g:CCTreeDisplayMode == 3
  2590. if curDepth > 0
  2591. let indentSpace = repeat(Aspace, self.levelMaxLen[curDepth-1])
  2592. endif
  2593. endif
  2594. let notTxt = self.notTxt.arrowHead. arrowLeads . self.notTxt.arrow
  2595. if a:hiDepth == a:depth
  2596. let notTxt = indentSpace . self.notTxt.symHighlighter . notTxt
  2597. let hiBranch = 1
  2598. else
  2599. let notTxt = indentSpace. Cspace. notTxt
  2600. endif
  2601. let curDepth -= 1
  2602. let indentSpace = ""
  2603. while (curDepth > 0)
  2604. if g:CCTreeDisplayMode == 2
  2605. let indentSpace = repeat(Bspace, curDepth)
  2606. elseif g:CCTreeDisplayMode == 3
  2607. let indentSpace = repeat(Bspace, self.levelMaxLen[curDepth-1])
  2608. endif
  2609. let notTxt = self.notTxt.sep . notTxt
  2610. if a:hiDepth == curDepth && a:hiPath == 1
  2611. let notTxt = indentSpace . self.notTxt.symHighlighter . notTxt
  2612. let hiBranch = 1
  2613. else
  2614. let notTxt = indentSpace. Cspace. notTxt
  2615. endif
  2616. let curDepth -= 1
  2617. endwhile
  2618. if curDepth == 0
  2619. " curdepth is 0
  2620. if a:hiDepth == curDepth && a:hiPath == 1
  2621. let notTxt = self.notTxt.symHighlighter . notTxt
  2622. let hiBranch = 1
  2623. else
  2624. let notTxt = Fspace . notTxt
  2625. endif
  2626. let curDepth -= 1
  2627. endif
  2628. " adjust space
  2629. if a:depth > 0
  2630. let notTxt = Xspace . notTxt
  2631. endif
  2632. if hiBranch == 1
  2633. if a:hiSym == 1
  2634. let notTxt = self.notTxt.hiSymbolMarker . notTxt
  2635. else
  2636. let notTxt = self.notTxt.hiBranchMarker . notTxt
  2637. endif
  2638. else
  2639. let notTxt = Sspace . notTxt
  2640. endif
  2641. return notTxt
  2642. endfunction
  2643. "}}}
  2644. " {{{ Preview window Folding
  2645. function! CCTreeFoldExpr(line)
  2646. if !exists('b:displayTree') || v:lnum > len(b:displayTree.entries)
  2647. return 0
  2648. endif
  2649. let lvl = b:displayTree.entries[v:lnum-1].level
  2650. if lvl == 0
  2651. let lvl = 1
  2652. endif
  2653. return '>'.lvl
  2654. endfunction
  2655. function! CCTreeFoldText()
  2656. if s:CCTreeUseConceal == 1
  2657. let line = substitute(getline(v:foldstart), '[!@#]', '' , 'g')
  2658. else
  2659. let line = substitute(getline(v:foldstart), '[!@#]', ' ' , 'g')
  2660. endif
  2661. return line. " (+". (v:foldend - v:foldstart).
  2662. \ ')'. repeat(" ", winwidth(0))
  2663. endfunction
  2664. " }}}
  2665. " {{{ Syntax coloring definitions
  2666. "Standard display
  2667. highlight default link CCTreeSymbol Function
  2668. highlight default link CCTreeMarkers LineNr
  2669. highlight default link CCTreeArrow CCTreeMarkers
  2670. highlight default link CCTreePathMark CCTreeArrow
  2671. highlight default link CCTreeHiPathMark CCTreePathMark
  2672. " highlighted display
  2673. highlight default link CCTreeHiKeyword Macro
  2674. highlight default link CCTreeHiSymbol TODO
  2675. highlight default link CCTreeHiMarkers NonText
  2676. highlight default link CCTreeHiArrow CCTreeHiMarkers
  2677. highlight default link CCTreeUpArrowBlock CCTreeHiArrow
  2678. highlight default link CCTreeMarkExcl Ignore
  2679. highlight default link CCTreeMarkTilde Ignore
  2680. "}}}
  2681. " {{{ CCTree global state
  2682. let s:CCTreePreviewState = {
  2683. \ 'keyword':'',
  2684. \ 'direction': '',
  2685. \ 'depth' : ''
  2686. \}
  2687. function! s:CCTreePreviewState.mCreate()
  2688. let state = deepcopy(s:CCTreePreviewState)
  2689. unlet state.mCreate
  2690. return state
  2691. endfunction
  2692. function! s:CCTreePreviewState.mStore(symbol, direction)
  2693. let self.keyword = a:symbol
  2694. let self.direction = a:direction
  2695. endfunction
  2696. " }}}
  2697. " {{{ CCTree global objects
  2698. let s:CCTreeGlobals = {
  2699. \ 'XRefDb': {},
  2700. \ 'DbList': s:CCTreeDBList.mCreate(),
  2701. \ 'PreviewState': s:CCTreePreviewState.mCreate(),
  2702. \ 'Window': s:CCTreeWindow.mCreate()
  2703. \}
  2704. let g:CCTreeGlobals = s:CCTreeGlobals
  2705. function! s:CCTreeGlobals.mEnable(opt) dict
  2706. if (has_key(s:CCTreeOptions, a:opt))
  2707. call s:CCTreeOptions[a:opt](1)
  2708. else
  2709. call s:CCTreeUtils.mWarningMsg('Invalid option')
  2710. endif
  2711. endfunction
  2712. function! s:CCTreeGlobals.mDisable(opt) dict
  2713. if (has_key(s:CCTreeOptions, a:opt))
  2714. call s:CCTreeOptions[a:opt](0)
  2715. else
  2716. call s:CCTreeUtils.mWarningMsg('Invalid option')
  2717. endif
  2718. endfunction
  2719. function! s:CCTreeGlobals.mToggle(opt) dict
  2720. if (has_key(s:CCTreeOptions, a:opt))
  2721. call s:CCTreeOptions[a:opt](-1)
  2722. else
  2723. call s:CCTreeUtils.mWarningMsg('Invalid option')
  2724. endif
  2725. endfunction
  2726. function! s:CCTreeGlobals.mGetSymNames(lead) dict
  2727. call self.XRefDb.mInitState()
  2728. let syms = self.XRefDb.mGetSymbolNames(a:lead)
  2729. call self.XRefDb.mRestoreState()
  2730. return syms
  2731. endfunction
  2732. function! s:CCTreeGlobals.mGetCallsForSymbol(name, depth, direction) dict
  2733. let rtree = s:CallTreeNode.mCreate(a:name, -1)
  2734. call self.mGetCallsForTreeNode(rtree, 'build',
  2735. \ self.PreviewState.depth, a:direction)
  2736. return rtree
  2737. endfunction
  2738. function! s:CCTreeGlobals.mGetCallsForTreeNode(rtree, action, depth, direction) dict
  2739. call s:StatusLine.mInit()
  2740. let pbar = s:ProgressBarRoll.mCreate(['-','\','|','/'], '*')
  2741. call s:StatusLine.mSetInfo('Building ')
  2742. redrawstatus!
  2743. " Create tracer
  2744. let xtracer = s:XRefTracer.mCreate(self.XRefDb)
  2745. call xtracer.mInitTracing()
  2746. let a:rtree.symid = self.XRefDb.mGetSymbolIdFromName(a:rtree.symname)
  2747. if a:action == 'build'
  2748. call xtracer.mBuildTree(a:rtree, 0, a:depth,
  2749. \ a:direction, pbar)
  2750. elseif a:action == 'expand'
  2751. call xtracer.mGrowTree(a:rtree,
  2752. \ a:direction, pbar)
  2753. elseif a:action == 'prune'
  2754. call xtracer.mPruneTree(a:rtree,
  2755. \ a:direction, pbar)
  2756. endif
  2757. call xtracer.mDoneTracing()
  2758. call s:StatusLine.mRestore()
  2759. endfunction
  2760. function! s:CCTreeGlobals.mShowLoadedDBs() dict
  2761. call self.DbList.mShowLoaded()
  2762. endfunction
  2763. function! s:CCTreeGlobals.mUnLoadDBs() dict
  2764. call s:CCTreeGlobals.Window.mClose()
  2765. if !empty(s:CCTreeGlobals.XRefDb)
  2766. call s:CCTreeGlobals.XRefDb.mClear()
  2767. endif
  2768. call s:CCTreeGlobals.DbList.mClearAll()
  2769. endfunction
  2770. function! s:CCTreeGlobals.mSetPreviewState(name, depth, direction) dict
  2771. let self.PreviewState.keyword = a:name
  2772. let self.PreviewState.direction = a:direction
  2773. let self.PreviewState.depth = a:depth
  2774. endfunction
  2775. function! s:CCTreeGlobals.mUpdateForCurrentSymbol() dict
  2776. if self.DbList.mIsEmpty() == s:CCTreeRC.True
  2777. return s:CCTreeRC.Error
  2778. endif
  2779. if self.PreviewState.keyword != ''
  2780. let swatch = s:StopWatch.mCreate()
  2781. " Move this function to globals?
  2782. let atree = self.mGetCallsForSymbol(self.PreviewState.keyword,
  2783. \ 0,
  2784. \ self.PreviewState.direction)
  2785. " May change in the future
  2786. let self.PreviewState.rootNode = atree
  2787. call self.Window.mDisplayTree(atree, self.PreviewState.direction)
  2788. call swatch.mSnapElapsed()
  2789. endif
  2790. endfunction
  2791. function! s:CCTreeGlobals.mGetPreviewTreeSymbols()
  2792. " REVIST
  2793. if exists('b:displayTree')
  2794. return self.Window.mExtractTreeSymbols(b:displayTree)
  2795. end
  2796. return {}
  2797. endfunction
  2798. function! s:CCTreeGlobals.mSanitizeCallDepth() dict
  2799. let error = 0
  2800. if self.PreviewState.depth >= s:calltreemaxdepth
  2801. self.PreviewState.depth = s:calltreemaxdepth
  2802. let error = 1
  2803. elseif self.PreviewState.depth < 1
  2804. let self.PreviewState.depth = 1
  2805. let error = 1
  2806. endif
  2807. if error == 1
  2808. call s:CCTreeUtils.mWarningMsg('Depth out of bounds')
  2809. endif
  2810. return error
  2811. endfunction
  2812. function! s:CCTreeGlobals.mRecursiveDepthModify(action) dict
  2813. call self.mGetCallsForTreeNode(self.PreviewState.rootNode,
  2814. \ a:action, 1, self.PreviewState.direction)
  2815. call self.Window.mDisplayTree(self.PreviewState.rootNode,
  2816. \ self.PreviewState.direction)
  2817. endfunction
  2818. function! s:CCTreeGlobals.mRecursiveDepthIncrease() dict
  2819. let self.PreviewState.depth += 1
  2820. if self.mSanitizeCallDepth() == 0
  2821. call self.mRecursiveDepthModify('expand')
  2822. endif
  2823. endfunction
  2824. function! s:CCTreeGlobals.mRecursiveDepthDecrease() dict
  2825. let self.PreviewState.depth -= 1
  2826. if self.mSanitizeCallDepth() == 0
  2827. call self.mRecursiveDepthModify('prune')
  2828. endif
  2829. endfunction
  2830. function! s:CCTreeGlobals.mDisplayToggle() dict
  2831. call self.Window.mDisplayToggle()
  2832. endfunction
  2833. function! s:CCTreeGlobals.mSetupAutoCmds() dict
  2834. augroup CCTreeGeneral
  2835. au!
  2836. augroup END
  2837. call s:CCTreeGlobals.mSetupCursorMoveAutoCmd(g:CCTreeHilightCallTree)
  2838. call s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(g:CCTreeUseUTF8Symbols)
  2839. endfunction
  2840. function! s:CCTreeGlobals.mSetupCursorMoveAutoCmd(enable) dict
  2841. if a:enable == 1
  2842. exec 'autocmd CCTreeGeneral CursorMoved '.s:windowtitle.' call s:CCTreeGlobals.mCursorHoldHandleEvent()'
  2843. else
  2844. exec 'autocmd! CCTreeGeneral CursorMoved '.s:windowtitle
  2845. endif
  2846. endfunction
  2847. function! s:CCTreeGlobals.mSetupEncodingChangeAutoCmd(enable) dict
  2848. return
  2849. if a:enable == 1
  2850. autocmd CCTreeGeneral EncodingChanged * call s:CCTreeGlobals.mEncodingChangedHandleEvent()
  2851. else
  2852. autocmd! CCTreeGeneral EncodingChanged *
  2853. endif
  2854. endfunction
  2855. function! s:CCTreeGlobals.mPreviewSave() dict
  2856. let rtitle = s:CCTreeGlobals.Window.mBuildStatusLine(
  2857. \ s:CCTreeGlobals.PreviewState,
  2858. \ s:windowsavetitle,
  2859. \ {'depth':'', 'direction':''}
  2860. \)
  2861. if self.Window.mPreviewSave(rtitle) == s:CCTreeRC.Success
  2862. call s:CCTreeUtils.mInfoMsg('Window saved as '. rtitle .
  2863. \ '. New window will be opened on next usage.')
  2864. else
  2865. call s:CCTreeUtils.mWarningMsg('No active window found to be saved.')
  2866. endif
  2867. endfunction
  2868. function! s:CCTreeGlobals.mWriteXRefDbToFile(fname) dict
  2869. " create db serializer and writer
  2870. let gDbSz = s:GenericDbSerializer.mCreate(self.XRefDb)
  2871. let gDbWriter = s:CCTreeTagDbWriter.mCreate(
  2872. \ s:CCTreeGetXRefDbMaps('Compress', 'Alpha'))
  2873. call gDbSz.mWriteXRefDbToFile(a:fname, gDbWriter)
  2874. endfunction
  2875. function! s:CCTreeGlobals.mReadToXRefDb(fname) dict
  2876. call s:StatusLine.mInit()
  2877. call s:StatusLine.mSetInfo('Reading XRefDb')
  2878. let vDbFile = s:vFile.mCreate(a:fname, "r")
  2879. if vDbFile.mIsLargeFile() == 1
  2880. call s:StatusLine.mSetExtraInfo('Xref DB '
  2881. \.' >'.g:CCTreeDbFileMaxSize .' bytes. Splitting '.
  2882. \'into smaller chunks... (this may take some time)')
  2883. endif
  2884. try
  2885. if vDbFile.mOpen() == 0
  2886. call s:TagFile.mReadToXRefDb(self.XRefDb, vDbFile)
  2887. endif
  2888. finally
  2889. call vDbFile.mClose()
  2890. call s:StatusLine.mRestore()
  2891. call self.DbList.mAddDbToList(a:fname, s:DBStorage.memory)
  2892. endtry
  2893. endfunction
  2894. function! s:CCTreeGlobals.mCursorHoldHandleEvent() dict
  2895. if self.Window.mGetKeywordAtCursor() != s:CCTreeRC.Error
  2896. setlocal modifiable
  2897. call self.Window.mClearMarksVisible(b:displayTree)
  2898. call self.Window.mMarkCallTreeVisible(b:displayTree,
  2899. \ self.Window.hiKeyword)
  2900. setlocal nomodifiable
  2901. endif
  2902. endfunction
  2903. function! s:CCTreeGlobals.mEncodingChangedHandleEvent() dict
  2904. let self.Window.treeMarkers = s:CCTreeMarkers.mCreate()
  2905. if self.Window.mIsOpen() == s:CCTreeRC.True
  2906. call self.Window.mClose()
  2907. call self.mUpdateForCurrentSymbol()
  2908. endif
  2909. endfunction
  2910. function! s:CCTreeGlobals.mInit() dict
  2911. call self.mSetupAutoCmds()
  2912. endfunction
  2913. " }}}
  2914. " {{{ CCTree options
  2915. function! s:CCTreeSetUseCallTreeHiLights(val)
  2916. if a:val == -1
  2917. let g:CCTreeHilightCallTree = !g:CCTreeHilightCallTree
  2918. else
  2919. let g:CCTreeHilightCallTree = a:val
  2920. endif
  2921. call s:CCTreeGlobals.mSetupAutoCmds()
  2922. endfunction
  2923. function! s:CCTreeSetUseUtf8Symbols(val)
  2924. if a:val == -1
  2925. let g:CCTreeUseUTF8Symbols = !g:CCTreeUseUTF8Symbols
  2926. else
  2927. let g:CCTreeUseUTF8Symbols = a:val
  2928. endif
  2929. call s:CCTreeGlobals.mEncodingChangedHandleEvent()
  2930. endfunction
  2931. function! s:CCTreeSetUseConceal(val)
  2932. if a:val == -1
  2933. let s:CCTreeUseConceal = !s:CCTreeUseConceal
  2934. else
  2935. let s:CCTreeUseConceal = a:val
  2936. endif
  2937. if !has('conceal')
  2938. call s:CCTreeUtils.mWarningMsg('+conceal feature not available')
  2939. let s:CCTreeUseConceal = 0
  2940. endif
  2941. endfunction
  2942. function! s:CCTreeSetEnhancedSymbolProcessing(val)
  2943. if a:val == -1
  2944. let g:CCTreeEnhancedSymbolProcessing = !g:CCTreeEnhancedSymbolProcessing
  2945. else
  2946. let g:CCTreeEnhancedSymbolProcessing = a:val
  2947. endif
  2948. endfunction
  2949. function! s:CCTreeOptionsList(arglead, cmdline, cursorpos)
  2950. let opts = keys(s:CCTreeOptions)
  2951. if a:arglead == ''
  2952. return opts
  2953. else
  2954. return filter(opts, 'v:val =~? a:arglead')
  2955. endif
  2956. endfunction
  2957. let s:CCTreeOptions = {'UseUnicodeSymbols': function('s:CCTreeSetUseUtf8Symbols'),
  2958. \ 'DynamicTreeHiLights': function('s:CCTreeSetUseCallTreeHiLights'),
  2959. \ 'UseConceal': function('s:CCTreeSetUseConceal'),
  2960. \ 'EnhancedSymbolProcessing': function('s:CCTreeSetEnhancedSymbolProcessing')
  2961. \}
  2962. " }}}
  2963. " {{{ Vim tags interface
  2964. " CCTreeCompleteKwd
  2965. " Command line completion function to return names from the db
  2966. function! s:CCTreeCompleteKwd(arglead, cmdline, cursorpos)
  2967. let syms = s:CCTreeGlobals.mGetSymNames(a:arglead)
  2968. if a:arglead == ''
  2969. return syms
  2970. else
  2971. return filter(syms, 'v:val =~? a:arglead')
  2972. endif
  2973. endfunction
  2974. function! s:CCTreeTraceTreeForSymbol(sym_arg, direction)
  2975. if s:CCTreeGlobals.DbList.mIsEmpty() == s:CCTreeRC.True
  2976. call s:CCTreeUtils.mWarningMsg('No database loaded')
  2977. return
  2978. endif
  2979. let symbol = a:sym_arg
  2980. if symbol == ''
  2981. let symbol = input('Trace symbol: ', expand('<cword>'),
  2982. \ 'customlist,<SNR>' . s:sid . 'CCTreeCompleteKwd')
  2983. if symbol == ''
  2984. return
  2985. endif
  2986. endif
  2987. let symmatch = s:CCTreeGlobals.mGetSymNames(symbol)
  2988. if len(symmatch) > 0 && index(symmatch, symbol) >= 0
  2989. call s:CCTreeGlobals.mSetPreviewState(symbol,
  2990. \ g:CCTreeRecursiveDepth,
  2991. \ a:direction)
  2992. call s:CCTreeGlobals.mUpdateForCurrentSymbol()
  2993. else
  2994. call s:CCTreeUtils.mWarningMsg('Symbol not found')
  2995. endif
  2996. endfunction
  2997. function! s:CCTreeGlobals.mLoadBufferFromKeyword()
  2998. " REVISIT
  2999. if s:CCTreeGlobals.Window.mGetKeywordAtCursor() == s:CCTreeRC.Error
  3000. call s:CCTreeUtils.mWarningMsg('No keyword at cursor')
  3001. return
  3002. endif
  3003. let hiKeyword = s:CCTreeGlobals.Window.hiKeyword
  3004. try
  3005. wincmd p
  3006. catch
  3007. call s:CCTreeUtils.mWarningMsg('No buffer to load file')
  3008. finally
  3009. if (cscope_connection() > 0)
  3010. try
  3011. exec "cs find g ". hiKeyword
  3012. catch
  3013. " cheap hack
  3014. exec "cs find f ". hiKeyword
  3015. endtry
  3016. else
  3017. try
  3018. " Ctags is smart enough to figure the path
  3019. exec "tag ".fnamemodify(hiKeyword, ":t")
  3020. catch /^Vim\%((\a\+)\)\=:E433/
  3021. call s:CCTreeUtils.mWarningMsg('Tag file not found')
  3022. catch /^Vim\%((\a\+)\)\=:E426/
  3023. call s:CCTreeUtils.mWarningMsg('Tag '. hiKeyword .' not found')
  3024. wincmd p
  3025. endtry
  3026. endif
  3027. endtry
  3028. endfunction
  3029. function! s:CCTreeGlobals.mPreviewBufferFromKeyword()
  3030. if self.Window.mGetKeywordAtCursor() == s:CCTreeRC.Error
  3031. call s:CCTreeUtils.mWarningMsg('No keyword found')
  3032. return
  3033. endif
  3034. let hiKeyword = s:CCTreeGlobals.Window.hiKeyword
  3035. silent! wincmd P
  3036. if !&previewwindow
  3037. wincmd p
  3038. endif
  3039. try
  3040. exec "ptag ". hiKeyword
  3041. catch
  3042. call s:CCTreeUtils.mWarningMsg('Tag '.hiKeyword. ' not found')
  3043. endtry
  3044. endfunction
  3045. " }}}
  3046. " {{{ Define commands
  3047. command! -nargs=? -complete=file CCTreeLoadXRefDBFromDisk
  3048. \ call s:CCTreeCmdLine.mLoadDBFromDisk(<q-args>)
  3049. command! -nargs=? -complete=file CCTreeLoadDB call s:CCTreeCmdLine.mLoadDB(<q-args>, s:DBClasses.cscopeid)
  3050. command! -nargs=? -complete=file CCTreeLoadXRefDB call s:CCTreeCmdLine.mLoadDB(<q-args>, s:DBClasses.cctreexref)
  3051. command! -nargs=? -complete=file CCTreeSaveXRefDB call s:CCTreeCmdLine.mSaveDB(<q-args>, s:DBClasses.cctreexref)
  3052. command! -nargs=? -complete=file CCTreeAppendDB call s:CCTreeCmdLine.mMergeDB(<q-args>, s:DBClasses.cscopeid)
  3053. command! -nargs=0 CCTreeUnLoadDB call s:CCTreeGlobals.mUnLoadDBs()
  3054. command! -nargs=0 CCTreeShowLoadedDBs call s:CCTreeGlobals.mShowLoadedDBs()
  3055. command! -nargs=? -complete=customlist,s:CCTreeCompleteKwd
  3056. \ CCTreeTraceForward call s:CCTreeTraceTreeForSymbol(<q-args>, 'c')
  3057. command! -nargs=? -complete=customlist,s:CCTreeCompleteKwd CCTreeTraceReverse
  3058. \ call s:CCTreeTraceTreeForSymbol(<q-args>, 'p')
  3059. command! -nargs=0 CCTreeLoadBufferUsingTag call s:CCTreeGlobals.mLoadBufferFromKeyword()
  3060. command! -nargs=0 CCTreePreviewBufferUsingTag call s:CCTreeGlobals.mPreviewBufferFromKeyword()
  3061. command! -nargs=0 CCTreeRecurseDepthPlus call s:CCTreeGlobals.mRecursiveDepthIncrease()
  3062. command! -nargs=0 CCTreeRecurseDepthMinus call s:CCTreeGlobals.mRecursiveDepthDecrease()
  3063. " Preview Window
  3064. command! -nargs=0 CCTreeWindowToggle call s:CCTreeGlobals.mDisplayToggle()
  3065. command! -nargs=0 CCTreeWindowSaveCopy call s:CCTreeGlobals.mPreviewSave()
  3066. " Run-time dynamic options
  3067. command! -nargs=1 -complete=customlist,s:CCTreeOptionsList CCTreeOptsEnable call s:CCTreeGlobals.mEnable(<q-args>)
  3068. command! -nargs=1 -complete=customlist,s:CCTreeOptionsList CCTreeOptsDisable call s:CCTreeGlobals.mDisable(<q-args>)
  3069. command! -nargs=1 -complete=customlist,s:CCTreeOptionsList CCTreeOptsToggle call s:CCTreeGlobals.mToggle(<q-args>)
  3070. "}}}
  3071. " {{{ finish (and init)
  3072. call s:CCTreeGlobals.mInit()
  3073. " restore 'cpo'
  3074. let &cpoptions = s:cpo_save
  3075. unlet s:cpo_save
  3076. " vim: ts=8 sw=4 sts=4 et foldenable foldmethod=marker foldcolumn=1
  3077. " }}}