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