Rainbow
[my-vim-dotfolder.git] / plugin / srcexpl.vim
blob0a0596b41ce2aa0497e6faca43eaf0a11726022a
2 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
3 "                                                                              "
4 " File_Name__: srcexpl.vim                                                     "
5 " Abstract___: A (G)VIM plugin for exploring the source code based on 'tags'   "
6 "              and 'quickfix'. It works like the context window in 'Source     "
7 "              Insight'.                                                       "
8 " Author_____: Wenlong Che <chewenlong AT buaa.edu.cn>                         "
9 " Version____: 4.2                                                             "
10 " Last_Change: March 16, 2009                                                  "
11 " Licence____: This program is free software; you can redistribute it and / or "
12 "              modify it under the terms of the GNU General Public License as  "
13 "              published by the Free Software Foundation; either version 2, or "
14 "              any later version.                                              "
15 "                                                                              "
16 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
18 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
19 " NOTE: The graph below shows my work platform with some VIM plugins,          "
20 "       including 'Source Explorer', 'Taglist' and 'NERD tree'. And I usually  "
21 "       use a plugin named 'trinity.vim' to manage them.                       "
22 "                                                                              "
23 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
25 " +----------------------------------------------------------------------------+
26 " | File | Edit | Tools | Syntax | Buffers | Window | Help |                   |
27 " +----------------------------------------------------------------------------+
28 " |-demo.c-------- |-----------------------------------------|-/home/myprj/----|
29 " |function        | 1 void foo(void)     /* function 1 */   ||~ src/          |
30 " |  foo           | 2 {                                     || `-demo.c       |
31 " |  bar           | 3 }                                     |`-tags           |
32 " |                | 4 void bar(void)     /* function 2 */   |                 |
33 " |~ +----------+  | 5 {                                     |~ +-----------+  |
34 " |~ | Tag List |\ | 6 }                                     |~ | NERD Tree |\ |
35 " |~ +__________+ ||~        +-----------------+             |~ +___________+ ||
36 " |~ \___________\||~        | The Main Editor |\            |~ \____________\||
37 " |~               |~        +_________________+ |           |~                |
38 " |~               |~        \__________________\|           |~                |
39 " |~               |~                                        |~                |
40 " |-__Tag_List__---|-demo.c----------------------------------|-_NERD_tree_-----|
41 " |Source Explorer v4.2                                                        |
42 " |~                              +-----------------+                          |
43 " |~                              | Source Explorer |\                         |
44 " |~                              +_________________+ |                        |
45 " |~                              \__________________\|                        |
46 " |-Source_Explorer[Preview]---------------------------------------------------|
47 " |:TrinityToggleAll                                                           |
48 " +----------------------------------------------------------------------------+
50 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
51 "                                                                              "
52 " The_setting_example_in_my_vimrc_file:-)                                      "
53 "                                                                              "
54 " // The switch of the Source Explorer                                         "
55 " nmap <F8> :SrcExplToggle<CR>
56 "                                                                              "
57 " // Set the height of Source Explorer window                                  "
58 " let g:SrcExpl_winHeight = 8
59 "                                                                              "
60 " // Set 100 ms for refreshing the Source Explorer                             "
61 " let g:SrcExpl_refreshTime = 100
62 "                                                                              "
63 " // Set "Enter" key to jump into the exact definition context                 "
64 " let g:SrcExpl_jumpKey = "<ENTER>"
65 "                                                                              "
66 " // Set "Space" key for back from the definition context                      "
67 " let g:SrcExpl_gobackKey = "<SPACE>"
68 "                                                                              "
69 " // In order to Avoid conflicts, the Source Explorer should know what plugins "
70 " // are using buffers. And you need add their bufname into the list below     "
71 " // according to the command ":buffers!"                                      "
72 " let g:SrcExpl_pluginList = [
73 "         \ "__Tag_List__",
74 "         \ "_NERD_tree_",
75 "         \ "Source_Explorer"
76 "     \ ]
77 "                                                                              "
78 " // Enable/Disable the local definition searching, and note that this is not  "
79 " // guaranteed to work, the Source Explorer doesn't check the syntax for now. "
80 " // It only searches for a match with the keyword according to command 'gd'   "
81 " let g:SrcExpl_searchLocalDef = 1
82 "                                                                              "
83 " // Do not let the Source Explorer update the tags file when opening          "
84 " let g:SrcExpl_isUpdateTags = 0
85 "                                                                              "
86 " // Use program 'ctags' with argument '--sort=foldcase -R' to create or       "
87 " // update a tags file                                                        "
88 " let g:SrcExpl_updateTagsCmd = "ctags --sort=foldcase -R ."
89 "                                                                              "
90 " // Set "<F12>" key for updating the tags file artificially                   "
91 " let g:SrcExpl_updateTagsKey = "<F12>"
92 "                                                                              "
93 " Just_change_above_of_them_by_yourself:-)                                     "
94 "                                                                              "
95 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
97 " Avoid reloading {{{
99 if exists('loaded_srcexpl')
100     finish
101 endif
103 let loaded_srcexpl = 1
104 let s:save_cpo = &cpoptions
106 " }}}
108 " VIM version control {{{
110 " The VIM version control for running the Source Explorer
112 if v:version < 700
113     echohl ErrorMsg
114         echo "SrcExpl: Require VIM 7.0 or above for running the Source Explorer."
115     echohl None
116     finish
117 endif
119 set cpoptions&vim
121 " }}}
123 " User interfaces {{{
125 " User interface for opening the Source Explorer
127 command! -nargs=0 -bar SrcExpl 
128     \ call <SID>SrcExpl()
130 " User interface for closing the Source Explorer
132 command! -nargs=0 -bar SrcExplClose 
133     \ call <SID>SrcExpl_Close()
135 " User interface for switching the Source Explorer
137 command! -nargs=0 -bar SrcExplToggle 
138     \ call <SID>SrcExpl_Toggle()
140 " User interface for changing the height of the Source Explorer window
141 if !exists('g:SrcExpl_winHeight')
142     let g:SrcExpl_winHeight = 8
143 endif
145 " User interface for setting the update time interval for each refreshing
146 if !exists('g:SrcExpl_refreshTime')
147     let g:SrcExpl_refreshTime = 100
148 endif
150 " User interface to jump into the exact definition context
151 if !exists('g:SrcExpl_jumpKey')
152     let g:SrcExpl_jumpKey = '<CR>'
153 endif
155 " User interface to go back from the definition context
156 if !exists('g:SrcExpl_gobackKey')
157     let g:SrcExpl_gobackKey = '<SPACE>'
158 endif
160 " User interface for handling the conflicts between the 
161 " Source Explorer and other plugins
162 if !exists('g:SrcExpl_pluginList')
163     let g:SrcExpl_pluginList = [
164             \ "__Tag_List__", 
165             \ "_NERD_tree_", 
166             \ "Source_Explorer"
167         \ ]
168 endif
170 " User interface to enable local declaration searching 
171 " according to command 'gd'
172 if !exists('g:SrcExpl_searchLocalDef')
173     let g:SrcExpl_searchLocalDef = 1
174 endif
176 " User interface to control if update the 'tags' file when loading 
177 " the Source Explorer, 0 for false, others for true
178 if !exists('g:SrcExpl_isUpdateTags')
179     let g:SrcExpl_isUpdateTags = 1
180 endif
182 " User interface to create a 'tags' file using exact ctags
183 " utility, 'ctags --sort=foldcase -R .' as default
184 if !exists('g:SrcExpl_updateTagsCmd')
185     let g:SrcExpl_updateTagsCmd = "ctags --sort=foldcase -R ."
186 endif
188 " User interface to update tags file artificially
189 if !exists('g:SrcExpl_updateTagsKey')
190     let g:SrcExpl_updateTagsKey = ''
191 endif
193 " }}}
195 " Global variables {{{
197 " Buffer caption for identifying myself among all the plugins
198 let s:SrcExpl_pluginCaption = 'Source_Explorer'
200 " Plugin switch flag
201 let s:SrcExpl_isRunning = 0
203 " }}}
205 " SrcExpl_UpdateTags() {{{
207 " Update tags file with the 'ctags' utility
209 function! g:SrcExpl_UpdateTags()
211     " Go to the current work directory
212     silent! exe "cd " . expand('%:p:h')
213     " Get the amount of tags files
214     let l:tmp = len(tagfiles())
216     " No tags file or not found one
217     if l:tmp == 0
218         " Ask user if or not create a tags file
219         echohl Question
220             \ | let l:tmp = <SID>SrcExpl_GetInput("\nSrcExpl: "
221                 \ . "The 'tags' file was not found in your PATH.\n"
222             \ . "Create one in the current directory now? (y)es/(n)o?") | 
223         echohl None
224         " They do
225         if l:tmp == "y" || l:tmp == "yes"
226             " We tell user where we create a tags file
227             echohl Question
228                 echo "SrcExpl: Creating 'tags' file in (". expand('%:p:h') . ")"
229             echohl None
230             " Call the external 'ctags' utility program
231             exe "!" . g:SrcExpl_updateTagsCmd
232             " Rejudge the tags file if existed
233             if !filereadable("tags")
234                 " Tell them what happened
235                 call <SID>SrcExpl_ReportErr("Execute 'ctags' utility program failed")
236                 return -1
237             endif
238         " They don't
239         else
240             echo ""
241             return -2
242         endif
243     " More than one tags file
244     elseif l:tmp > 1
245         call <SID>SrcExpl_ReportErr("More than one tags file in your PATH")
246         return -3
247     " Found one successfully
248     else
249         " Is the tags file in the current directory ?
250         if tagfiles()[0] ==# "tags"
251             " Prompt the current work directory
252             echohl Question
253                 echo "SrcExpl: Updating 'tags' file in (". expand('%:p:h') . ")"
254             echohl None
255             " Call the external 'ctags' utility program
256             exe "!" . g:SrcExpl_updateTagsCmd
257         " Up to other directories
258         else
259             " Prompt the whole path of the tags file
260             echohl Question
261                 echo "SrcExpl: Updating 'tags' file in (". tagfiles()[0][:-6] . ")"
262             echohl None
263             " Store the current word directory at first
264             let l:tmp = getcwd()
265             " Go to the directory that contains the old tags file
266             silent! exe "cd " . tagfiles()[0][:-5]
267             " Call the external 'ctags' utility program
268             exe "!" . g:SrcExpl_updateTagsCmd
269            " Go back to the original work directory
270            silent! exe "cd " . l:tmp
271         endif
272     endif
274     " Done
275     return 0
277 endfunction " }}}
279 " SrcExpl_GoBack() {{{
281 " Move the cursor to the previous location in the mark history
283 function! g:SrcExpl_GoBack()
285     " If or not the cursor is on the main editor window
286     if &previewwindow || <SID>SrcExpl_AdaptPlugins()
287         return -1
288     endif
290     " Just go back to the previous position
291     return <SID>SrcExpl_GetMarkList()
293 endfunction " }}}
295 " SrcExpl_Jump() {{{
297 " Jump to the main editor window and point to the definition
299 function! g:SrcExpl_Jump()
301     " Only do the operation on the Source Explorer 
302     " window is valid
303     if !&previewwindow
304         return -1
305     endif
307     " Do we get the definition already?
308     if bufname("%") == s:SrcExpl_pluginCaption
309         " No such definition
310         if s:SrcExpl_status == 0
311             return -2
312         " Multiple definitions
313         elseif s:SrcExpl_status == 2
314             " If point to the jump list head, just avoid that
315             if line(".") == 1
316                 return -3
317             endif
318         endif
319     endif
321     if g:SrcExpl_searchLocalDef != 0
322         " We have already jumped to the main editor window
323         let s:SrcExpl_isJumped = 1
324     endif
325     " Indeed go back to the main editor window
326     silent! exe s:SrcExpl_editWin . "wincmd w"
327     " Set the mark for recording the current position
328     call <SID>SrcExpl_SetMarkList()
330     " We got multiple definitions
331     if s:SrcExpl_status == 2
332         " Select the exact one and jump to its context
333         call <SID>SrcExpl_SelToJump()
334         " Set the mark for recording the current position
335         call <SID>SrcExpl_SetMarkList()
336         return 0
337     endif
339     " Open the buffer using main editor window
340     exe "edit " . s:SrcExpl_currMark[0]
341     " Jump to the context line of that symbol
342     call cursor(s:SrcExpl_currMark[1], s:SrcExpl_currMark[2])
343     " Match the symbol of definition
344     call <SID>SrcExpl_MatchExpr()
345     " Set the mark for recording the current position
346     call <SID>SrcExpl_SetMarkList()
348     " We got one local definition
349     if s:SrcExpl_status == 3
350         " Get the cursor line number
351         let s:SrcExpl_csrLine = line(".")
352         " Try to tag the symbol again
353         let l:expr = '\<' . s:SrcExpl_symbol . '\>' . '\C'
354         " Try to tag something
355         call <SID>SrcExpl_TagSth(l:expr)
356     endif
358     " Done
359     return 0
361 endfunction " }}}
363 " SrcExpl_Refresh() {{{
365 " Refresh the Source Explorer window and update the status
367 function! g:SrcExpl_Refresh()
369     " Tab page must be invalid
370     if s:SrcExpl_tabPage != tabpagenr()
371         return -1
372     endif
374     " If or not the cursor is on the main editor window
375     if &previewwindow || <SID>SrcExpl_AdaptPlugins()
376         return -2
377     endif
379     " Avoid errors of multi-buffers
380     if &modified
381         call <SID>SrcExpl_ReportErr("This modified file is not saved")
382         return -3
383     endif
385     " Get the ID of main editor window
386     let s:SrcExpl_editWin = winnr()
388     " Get the symbol under the cursor
389     if <SID>SrcExpl_GetSymbol()
390         return -4
391     endif
393     let l:expr = '\<' . s:SrcExpl_symbol . '\>' . '\C'
395     " Try to Go to local declaration
396     if g:SrcExpl_searchLocalDef != 0
397         if !<SID>SrcExpl_GoDecl(l:expr)
398             return 0
399         endif
400     endif
402     " Try to tag something
403     call <SID>SrcExpl_TagSth(l:expr)
405     " Done
406     return 0
408 endfunction " }}}
410 " SrcExpl_AdaptPlugins() {{{
412 " The Source Explorer window will not work when the cursor on the 
414 " window of other plugins, such as 'Taglist', 'NERD tree' etc.
416 function! <SID>SrcExpl_AdaptPlugins()
418     " Traversal the list of other plugins
419     for item in g:SrcExpl_pluginList
420         " If they acted as a split window
421         if bufname("%") ==# item
422             " Just avoid this operation
423             return -1
424         endif
425     endfor
427     " Safe
428     return 0
430 endfunction " }}}
432 " SrcExpl_ReportErr() {{{
434 " Output the message when we get an error situation
436 function! <SID>SrcExpl_ReportErr(err)
438     " Highlight the error prompt
439     echohl ErrorMsg
440         echo "SrcExpl: " . a:err
441     echohl None
443 endfunction " }}}
445 " SrcExpl_EnterWin() {{{
447 " Operation when 'WinEnter' event happens
449 function! <SID>SrcExpl_EnterWin()
451     " In the Source Explorer window
452     if &previewwindow
453         if has("gui_running")
454             " Delete the SrcExplGoBack item in Popup menu
455             silent! nunmenu 1.01 PopUp.&SrcExplGoBack
456         endif
457         " Unmap the go-back key
458         if maparg(g:SrcExpl_gobackKey, 'n') == 
459             \ ":call g:SrcExpl_GoBack()<CR>"
460             exe "nunmap " . g:SrcExpl_gobackKey
461         endif
462         " Do the mapping for 'double-click'
463         if maparg('<2-LeftMouse>', 'n') == ''
464             nnoremap <silent> <2-LeftMouse> 
465                 \ :call g:SrcExpl_Jump()<CR>
466         endif
467         " Map the user's key to jump into the exact definition context
468         if g:SrcExpl_jumpKey != ""
469             exe "nnoremap " . g:SrcExpl_jumpKey . 
470                 \ " :call g:SrcExpl_Jump()<CR>"
471         endif
472     " In other plugin windows
473     elseif <SID>SrcExpl_AdaptPlugins()
474         if has("gui_running")
475             " Delete the SrcExplGoBack item in Popup menu
476             silent! nunmenu 1.01 PopUp.&SrcExplGoBack
477         endif
478         " Unmap the go-back key
479         if maparg(g:SrcExpl_gobackKey, 'n') == 
480             \ ":call g:SrcExpl_GoBack()<CR>"
481             exe "nunmap " . g:SrcExpl_gobackKey
482         endif
483         " Unmap the exact mapping of 'double-click'
484         if maparg("<2-LeftMouse>", "n") == 
485                 \ ":call g:SrcExpl_Jump()<CR>"
486             nunmap <silent> <2-LeftMouse>
487         endif
488         " Unmap the jump key
489         if maparg(g:SrcExpl_jumpKey, 'n') == 
490             \ ":call g:SrcExpl_Jump()<CR>"
491             exe "nunmap " . g:SrcExpl_jumpKey
492         endif
493     " In the main editor window
494     else
495         if has("gui_running")
496             " You can use SrcExplGoBack item in Popup menu
497             " to go back from the definition
498             silent! nnoremenu 1.01 PopUp.&SrcExplGoBack 
499                 \ :call g:SrcExpl_GoBack()<CR>
500         endif
501         " Map the user's key to go back from the definition context
502         if g:SrcExpl_gobackKey != ""
503             exe "nnoremap " . g:SrcExpl_gobackKey . 
504                 \ " :call g:SrcExpl_GoBack()<CR>"
505         endif
506         " Unmap the exact mapping of 'double-click'
507         if maparg("<2-LeftMouse>", "n") == 
508                 \ ":call g:SrcExpl_Jump()<CR>"
509             nunmap <silent> <2-LeftMouse>
510         endif
511         " Unmap the jump key
512         if maparg(g:SrcExpl_jumpKey, 'n') == 
513             \ ":call g:SrcExpl_Jump()<CR>"
514             exe "nunmap " . g:SrcExpl_jumpKey
515         endif
516     endif
518 endfunction " }}}
520 " SrcExpl_SetMarkList() {{{
522 " Set a new mark for back to the previous position
524 function! <SID>SrcExpl_SetMarkList()
526     " Add one new mark into the tail of Mark List
527     call add(s:SrcExpl_markList, [expand("%:p"), line("."), col(".")])
529 endfunction " }}}
531 " SrcExpl_GetMarkList() {{{
533 " Get the mark for back to the previous position
535 function! <SID>SrcExpl_GetMarkList()
537     " If or not the mark list is empty
538     if !len(s:SrcExpl_markList)
539         call <SID>SrcExpl_ReportErr("Mark stack is empty")
540         return -1
541     endif
543     " Avoid the same situation
544     if get(s:SrcExpl_markList, -1)[0] == expand("%:p") 
545       \ && get(s:SrcExpl_markList, -1)[1] == line(".")
546       \ && get(s:SrcExpl_markList, -1)[2] == col(".")
547         " Remove the latest mark
548         call remove(s:SrcExpl_markList, -1)
549         " Get the latest mark again
550         return <SID>SrcExpl_GetMarkList()
551     endif
553     " Load the buffer content into the main editor window
554     exe "edit " . get(s:SrcExpl_markList, -1)[0]
555     " Jump to the context position of that symbol
556     call cursor(get(s:SrcExpl_markList, -1)[1], get(s:SrcExpl_markList, -1)[2])
557     " Remove the latest mark now
558     call remove(s:SrcExpl_markList, -1)
560     " Done
561     return 0
563 endfunction " }}}
565 " SrcExpl_SelToJump() {{{
567 " Select one of multi-definitions, and jump to there
569 function! <SID>SrcExpl_SelToJump()
571     let l:index = 0
572     let l:fpath = ""
573     let l:excmd = ""
574     let l:expr  = ""
576     " If or not in the Source Explorer window
577     if !&previewwindow
578         silent! wincmd P
579     endif
581     " Get the item data that the user selected just now
582     let l:list = getline(".")
583     " Traverse the prompt string until get the file path
584     while !((l:list[l:index] == ']') && 
585         \ (l:list[l:index + 1] == ':'))
586         let l:index += 1
587     endwhile
588     " Done
589     let l:index += 3
591     " Get the whole file path of the exact definition
592     while !((l:list[l:index] == ' ') && 
593         \ (l:list[l:index + 1] == '['))
594         let l:fpath = l:fpath . l:list[l:index]
595         let l:index += 1
596     endwhile
597     " Done
598     let l:index += 2
600     " Traverse the prompt string until get the symbol
601     while !((l:list[l:index] == ']') && 
602         \ (l:list[l:index + 1] == ':'))
603         let l:index += 1
604     endwhile
605     " Done
606     let l:index += 3
608     " Get the EX command string
609     while l:list[l:index] != ''
610         let l:excmd = l:excmd . l:list[l:index]
611         let l:index += 1
612     endwhile
614     " Indeed go back to the main editor window
615     silent! exe s:SrcExpl_editWin . "wincmd w"
616     " Open the file containing the definition context
617     exe "edit " . l:fpath
619     " Modify the EX Command to locate the tag exactly
620     let l:expr = substitute(l:excmd, '/^', '/^\\C', 'g')
621     let l:expr = substitute(l:expr,  '\*',  '\\\*', 'g')
622     let l:expr = substitute(l:expr,  '\[',  '\\\[', 'g')
623     let l:expr = substitute(l:expr,  '\]',  '\\\]', 'g')
624     " Use EX Command to Jump to the exact position of the definition
625     silent! exe l:expr
627     " Match the symbol
628     call <SID>SrcExpl_MatchExpr()
630 endfunction " }}}
632 " SrcExpl_SetCurrMark() {{{
634 " Save the current buf-win file path, line number and column number
636 function! <SID>SrcExpl_SetCurrMark()
638     " Store the curretn position for exploring
639     let s:SrcExpl_currMark = [expand("%:p"), line("."), col(".")]
641 endfunction " }}}
643 " SrcExpl_ColorExpr() {{{
645 " Highlight the symbol of definition
647 function! <SID>SrcExpl_ColorExpr()
649     " Set the highlight color
650     hi SrcExpl_HighLight term=bold guifg=Black guibg=Magenta ctermfg=Black ctermbg=Magenta
651     " Highlight this
652     exe 'match SrcExpl_HighLight "\%' . line(".") . 'l\%' . 
653         \ col(".") . 'c\k*"'
655 endfunction " }}}
657 " SrcExpl_MatchExpr() {{{
659 " Match the symbol of definition
661 function! <SID>SrcExpl_MatchExpr()
663     call search("$", "b")
664     let s:SrcExpl_symbol = substitute(s:SrcExpl_symbol, 
665         \ '\\', '\\\\', '')
666     call search('\<' . s:SrcExpl_symbol . '\>' . '\C')
668 endfunction " }}}
670 " SrcExpl_PromptNoDef() {{{
672 " Tell users there is no tag that be found in your PATH
674 function! <SID>SrcExpl_PromptNoDef()
676     " Do the Source Explorer existed already?
677     let l:bufnum = bufnr(s:SrcExpl_pluginCaption)
678     " Not existed, create a new buffer
679     if l:bufnum == -1
680         " Create a new buffer
681         let l:wcmd = s:SrcExpl_pluginCaption
682     else
683         " Edit the existing buffer
684         let l:wcmd = '+buffer' . l:bufnum
685     endif
687     " Reopen the Source Explorer idle window
688     exe "silent " . "pedit " . l:wcmd
689     " Move to it
690     silent! wincmd P
692     " Done
693     if &previewwindow
694         " First make it modifiable
695         setlocal modifiable
696         " Not show its name on the buffer list
697         setlocal nobuflisted
698         " No exact file
699         setlocal buftype=nofile
700         " Report the reason why the Source Explorer
701         " can not point to the definition
702         " Delete all lines in buffer.
703         1,$d _
704         " Go to the end of the buffer put the buffer list
705         $
706         " Display the version of the Source Explorer
707         put! ='Definition Not Found'
708         " Cancel all the highlighted words
709         match none
710         " Delete the extra trailing blank line
711         $ d _
712         " Make it unmodifiable again
713         setlocal nomodifiable
714         " Go back to the main editor window
715         silent! exe s:SrcExpl_editWin . "wincmd w"
716     endif
718 endfunction " }}}
720 " SrcExpl_ListMultiDefs() {{{
722 " List multiple definitions into the preview window
724 function! <SID>SrcExpl_ListMultiDefs(list, len)
726     " The Source Explorer existed already ?
727     let l:bufnum = bufnr(s:SrcExpl_pluginCaption)
728     " Not existed, create a new buffer
729     if l:bufnum == -1
730         " Create a new buffer
731         let l:wcmd = s:SrcExpl_pluginCaption
732     else
733         " Edit the existing buffer
734         let l:wcmd = '+buffer' . l:bufnum
735     endif
737     " Is the tags file in the current directory ?
738     if tagfiles()[0] ==# "tags"
739         " We'll get the operating system environment 
740         " in order to judge the slash type
741         if s:SrcExpl_isWinOS == 1
742             " With the backward slash
743             let l:path = expand('%:p:h') . '\'
744         else
745             " With the forward slash
746             let l:path = expand('%:p:h') . '/'
747         endif
748     else
749         let l:path = ''
750     endif
752     " Reopen the Source Explorer idle window
753     exe "silent " . "pedit " . l:wcmd
754     " Return to the preview window
755     silent! wincmd P
756     " Done
757     if &previewwindow
758         " Reset the attribute of the Source Explorer
759         setlocal modifiable
760         " Not show its name on the buffer list
761         setlocal nobuflisted
762         " No exact file
763         setlocal buftype=nofile
764         " Delete all lines in buffer
765         1,$d _
766         " Get the tags dictionary array
767         " Begin build the Jump List for exploring the tags
768         put! = '[Jump List]: '. s:SrcExpl_symbol . ' (' . a:len . ') '
769         " Match the symbol
770         call <SID>SrcExpl_MatchExpr()
771         " Highlight the symbol
772         call <SID>SrcExpl_ColorExpr()
773         " Loop key & index
774         let l:indx = 0
775         " Loop for listing each tag from tags file
776         while 1
777             " First get each tag list
778             let l:dict = get(a:list, l:indx, {})
779             " There is one tag
780             if l:dict != {}
781                 " Go to the end of the buffer put the buffer list
782                 $
783                 " We should avoid the './' or '.\' in the whole file path
784                 if l:dict['filename'][0] == '.'
785                     put! ='[File Path]: ' . l:path . l:dict['filename'][2:]
786                         \ . ' ' . '[EX Command]: ' . l:dict['cmd']
787                 else
788                     put! ='[File Path]: ' . l:path . l:dict['filename']
789                         \ . ' ' . '[EX Command]: ' . l:dict['cmd']
790                 endif
791             " Traversal finished
792             else
793                 break
794             endif
795             let l:indx += 1
796         endwhile
797     endif
799     " Delete the extra trailing blank line
800     $ d _
801     " Move the cursor to the top of the Source Explorer window
802     exe "normal! " . "gg"
803     " Back to the first line
804     setlocal nomodifiable
805     " Go back to the main editor window
806     silent! exe s:SrcExpl_editWin . "wincmd w"
808 endfunction " }}}
810 " SrcExpl_ViewOneDef() {{{
812 " Display the definition of the symbol into the preview window
814 function! <SID>SrcExpl_ViewOneDef(fpath, excmd)
816     let l:expr = ""
818     " Is the tags file in the current directory ?
819     if tagfiles()[0] ==# "tags"
820         exe "silent " . "pedit " . expand('%:p:h') . '/' . a:fpath
821     " Up to other directories
822     else
823         exe "silent " . "pedit " . a:fpath
824     endif
826     " Go to the Source Explorer window
827     silent! wincmd P
828     " Indeed back to the preview window
829     if &previewwindow
830         " Modify the EX Command to locate the tag exactly
831         let l:expr = substitute(a:excmd, '/^', '/^\\C', 'g')
832         let l:expr = substitute(l:expr,  '\*',  '\\\*', 'g')
833         let l:expr = substitute(l:expr,  '\[',  '\\\[', 'g')
834         let l:expr = substitute(l:expr,  '\]',  '\\\]', 'g')
835         " Execute EX command according to the parameter
836         silent! exe l:expr
837         " Match the symbol
838         call <SID>SrcExpl_MatchExpr()
839         " Highlight the symbol
840         call <SID>SrcExpl_ColorExpr()
841         " Set the current buf-win attribute
842         call <SID>SrcExpl_SetCurrMark()
843         " Refresh all the screen
844         redraw
845         " Go back to the main editor window
846         silent! exe s:SrcExpl_editWin . "wincmd w"
847     endif
849 endfunction " }}}
851 " SrcExpl_TagSth() {{{
853 " Just try to find the tag under the cursor
855 function! <SID>SrcExpl_TagSth(expr)
857     let l:len = -1 
859     " Is the symbol valid ?
860     if a:expr != '\<\>\C'
861         " We get the tag list of the expression
862         let l:list = taglist(a:expr)
863         " Then get the length of taglist
864         let l:len = len(l:list)
865     endif
867     " One tag
868     if l:len == 1
869         " Get dictionary to load tag's file path and ex command
870         let l:dict = get(l:list, 0, {})
871         call <SID>SrcExpl_ViewOneDef(l:dict['filename'], l:dict['cmd'])
872         " One definition
873         let s:SrcExpl_status = 1
874     " Multiple tags
875     elseif l:len > 1
876         call <SID>SrcExpl_ListMultiDefs(l:list, l:len)
877         " Multiple definitions
878         let s:SrcExpl_status = 2
879     " No tag
880     else
881         " Ignore the repetitious situation
882         if s:SrcExpl_status > 0
883             call <SID>SrcExpl_PromptNoDef()
884             " No definition
885             let s:SrcExpl_status = 0
886         endif
887     endif
889 endfunction " }}}
891 " SrcExpl_GoDecl() {{{
893 " Search the local declaration using 'gd' command
895 function! <SID>SrcExpl_GoDecl(expr)
897     " Get the original cursor position
898     let l:oldline = line(".")
899     let l:oldcol = col(".")
901     " Try to search the local declaration
902     if searchdecl(a:expr, 0, 1) != 0
903         " Search failed
904         return -1
905     endif
907     " Get the new cursor position
908     let l:newline = line(".")
909     let l:newcol = col(".")
910     " Go back to the original cursor position
911     call cursor(l:oldline, l:oldcol)
913     " Preview the context
914     exe "silent " . "pedit " . expand("%:p")
915     " Go to the Preview window
916     silent! wincmd P
917     " Indeed in the Preview window
918     if &previewwindow
919         " Go to the new cursor position
920         call cursor(l:newline, l:newcol)
921         " Match the symbol
922         call <SID>SrcExpl_MatchExpr()
923         " Highlight the symbol
924         call <SID>SrcExpl_ColorExpr()
925         " Set the current buf-win attribute
926         call <SID>SrcExpl_SetCurrMark()
927         " Refresh all the screen
928         redraw
929         " Go back to the main editor window
930         silent! exe s:SrcExpl_editWin . "wincmd w"
931         " We got a local definition
932         let s:SrcExpl_status = 3
933     endif
935     " Done
936     return 0
938 endfunction " }}}
940 " SrcExpl_GetSymbol() {{{
942 " Get the valid symbol under the current cursor
944 function! <SID>SrcExpl_GetSymbol()
946     " Get the current character under the cursor
947     let l:cchar = getline(".")[col(".") - 1]
948     " Get the current word under the cursor
949     let l:cword = expand("<cword>")
951     " Judge that if or not the character is invalid,
952     " because only 0-9, a-z, A-Z, and '_' are valid
953     if l:cchar =~ '\w' && l:cword =~ '\w'
954         " If the key word symbol has been explored
955         " just now, we will not explore that again
956         if s:SrcExpl_symbol ==# l:cword
957             " Not in Local definition searching mode
958             if g:SrcExpl_searchLocalDef == 0
959                 return -1
960             else
961                 " Do not refresh when jumping to the main editor window
962                 if s:SrcExpl_isJumped == 1
963                     " Get the cursor line number
964                     let s:SrcExpl_csrLine = line(".")
965                     " Reset the jump flag
966                     let s:SrcExpl_isJumped = 0
967                     return -2
968                 endif
969                 " The cursor is not moved actually
970                 if s:SrcExpl_csrLine == line(".")
971                     return -3
972                 endif
973             endif
974         endif
975         " Get the cursor line number
976         let s:SrcExpl_csrLine = line(".")
977         " Get the symbol word under the cursor
978         let s:SrcExpl_symbol = l:cword
979     " Invalid character
980     else
981         if s:SrcExpl_symbol == ''
982             return -4 " Second, third ...
983         else " First
984             let s:SrcExpl_symbol = ''
985         endif
986     endif
988     " Done
989     return 0
991 endfunction " }}}
993 " SrcExpl_GetInput() {{{
995 " Get the word inputed by user on the command line window
997 function! <SID>SrcExpl_GetInput(note)
999     " Be sure synchronize
1000     call inputsave()
1001     " Get the input content
1002     let l:input = input(a:note)
1003     " Save the content
1004     call inputrestore()
1005     " Tell the Source Explorer
1006     return l:input
1008 endfunction " }}}
1010 " SrcExpl_GetEditWin() {{{
1012 " Get the main editor window index
1014 function! <SID>SrcExpl_GetEditWin()
1016     let l:i = 1
1017     let l:j = 1
1019     " Loop for searching the main editor window
1020     while 1
1021         " Traverse the plugin list for each sub-window
1022         for item in g:SrcExpl_pluginList
1023             if bufname(winbufnr(l:i)) ==# item
1024                 \ || getwinvar(l:i, '&previewwindow')
1025                 break
1026             else
1027                 let l:j += 1
1028             endif
1029         endfor
1030         " We've found one
1031         if j >= len(g:SrcExpl_pluginList)
1032             return l:i
1033         else
1034             let l:i += 1
1035             let l:j = 0
1036         endif
1037         " Not found finally
1038         if l:i > winnr("$")
1039             return -1
1040         endif
1041     endwhile
1043 endfunction " }}}
1045 " SrcExpl_InitVimEnv() {{{
1047 " Initialize Vim environment
1049 function! <SID>SrcExpl_InitVimEnv()
1051     " Not highlight the word that had been searched
1052     " Because execute EX command will active a search event
1053 "    exe "set nohlsearch"
1054     " Auto change current work directory
1055 "    exe "set autochdir"
1056     " Let Vim find the possible tags file
1057 "    exe "set tags=tags;" ZOMG
1059     " First set the height of preview window
1060     exe "set previewheight=". string(g:SrcExpl_winHeight)
1061     " Set the actual update time according to user's requestion
1062     " 100 milliseconds by default
1063     exe "set updatetime=" . string(g:SrcExpl_refreshTime)
1065     " Open all the folds
1066     if has("folding")
1067         " Open this file at first
1068         exe "normal " . "zR"
1069         " Let it works during the whole editing session
1070         exe "set foldlevelstart=" . "99"
1071     endif
1073 endfunction " }}}
1075 " SrcExpl_InitGlbVal() {{{
1077 " Initialize global variables
1079 function! <SID>SrcExpl_InitGlbVal()
1081     " We'll get the operating system environment 
1082     " in order to judge the slash type (backward 
1083     " or forward)
1084     if has("win16") || has("win32") 
1085         \ || has("win64")
1086         let s:SrcExpl_isWinOS = 1
1087     else
1088         let s:SrcExpl_isWinOS = 0
1089     endif
1090     " Have we jumped to the main editor window ?
1091     let s:SrcExpl_isJumped = 0
1092     " Line number of the current cursor
1093     let s:SrcExpl_csrLine = 0
1094     " The ID of main editor window
1095     let s:SrcExpl_editWin = 0
1096     " The tab page number
1097     let s:SrcExpl_tabPage = 0
1098     " Source Explorer status:
1099     " 0: Definition not found
1100     " 1: Only one definition 
1101     " 2: Multiple definitions
1102     " 3: Local declaration
1103     let s:SrcExpl_status = 0
1104     " The mark for the current position
1105     let s:SrcExpl_currMark = []
1106     " The mark list for exploring the source code
1107     let s:SrcExpl_markList = []
1108     " The key word symbol for exploring
1109     let s:SrcExpl_symbol = ''
1111 endfunction " }}}
1113 " SrcExpl_CloseWin() {{{
1115 " Close the Source Explorer window
1117 function! <SID>SrcExpl_CloseWin()
1119     " Just close the preview window
1120     pclose
1122 endfunction " }}}
1124 " SrcExpl_OpenWin() {{{
1126 " Open the Source Explorer window under the bottom of (G)Vim,
1127 " and set the buffer's attribute of the Source Explorer
1129 function! <SID>SrcExpl_OpenWin()
1131     " Get the ID of main editor window
1132     let s:SrcExpl_editWin = winnr()
1133     " Get the tab page number
1134     let s:SrcExpl_tabPage = tabpagenr()
1136     " Has the Source Explorer existed already?
1137     let l:bufnum = bufnr(s:SrcExpl_pluginCaption)
1138     " Not existed, create a new buffer
1139     if l:bufnum == -1
1140         " Create a new buffer
1141         let l:wcmd = s:SrcExpl_pluginCaption
1142     else
1143         " Edit the existing buffer
1144         let l:wcmd = '+buffer' . l:bufnum
1145     endif
1147     " Reopen the Source Explorer idle window
1148     exe "silent " . "pedit " . l:wcmd
1149     " Jump to the Source Explorer
1150     silent! wincmd P
1151     " Open successfully and jump to it indeed
1152     if &previewwindow
1153         " First make it modifiable
1154         setlocal modifiable
1155         " Not show its name on the buffer list
1156         setlocal nobuflisted
1157         " No exact file
1158         setlocal buftype=nofile
1159         " Delete all lines in buffer
1160         1,$d _
1161         " Go to the end of the buffer
1162         $
1163         " Display the version of the Source Explorer
1164         put! ='Source Explorer v4.2'
1165         " Delete the extra trailing blank line
1166         $ d _
1167         " Make it no modifiable
1168         setlocal nomodifiable
1169         " Put it on the bottom of (G)Vim
1170         silent! wincmd J
1171     endif
1173     " Indeed go back to the main editor window
1174     silent! exe s:SrcExpl_editWin . "wincmd w"
1176 endfunction " }}}
1178 " SrcExpl_CleanUp() {{{
1180 " Clean up the rubbish and free the mapping resources
1182 function! <SID>SrcExpl_CleanUp()
1184     " GUI version only
1185     if has("gui_running")
1186         " Delete the SrcExplGoBack item in Popup menu
1187         silent! nunmenu 1.01 PopUp.&SrcExplGoBack
1188     endif
1190     " Make the 'double-click' for nothing
1191     if maparg('<2-LeftMouse>', 'n') != ''
1192         nunmap <silent> <2-LeftMouse>
1193     endif
1195     " Unmap the jump key
1196     if maparg(g:SrcExpl_jumpKey, 'n') == 
1197         \ ":call g:SrcExpl_Jump()<CR>"
1198         exe "nunmap " . g:SrcExpl_jumpKey
1199     endif
1201     " Unmap the go-back key
1202     if maparg(g:SrcExpl_gobackKey, 'n') == 
1203         \ ":call g:SrcExpl_GoBack()<CR>"
1204         exe "nunmap " . g:SrcExpl_gobackKey
1205     endif
1207     " Unmap the update-tags key
1208     if maparg(g:SrcExpl_updateTagsKey, 'n') == 
1209         \ ":call g:SrcExpl_UpdateTags()<CR>"
1210         exe "nunmap " . g:SrcExpl_updateTagsKey
1211     endif
1213     " Unload the autocmd group
1214     silent! autocmd! SrcExpl_AutoCmd
1216 endfunction " }}}
1218 " SrcExpl_Init() {{{
1220 " Initialize the Source Explorer properties
1222 function! <SID>SrcExpl_Init()
1224     " Initialize script global variables
1225     call <SID>SrcExpl_InitGlbVal()
1227     " Initialize Vim environment
1228     call <SID>SrcExpl_InitVimEnv()
1230     " We must get the ID of main editor window
1231     let l:tmp = <SID>SrcExpl_GetEditWin()
1232     " Not found
1233     if l:tmp < 0
1234         " Can not find the main editor window
1235         call <SID>SrcExpl_ReportErr("Can not Found the editor window")
1236         return -1
1237     endif
1238     " Jump to that
1239     silent! exe l:tmp . "wincmd w"
1241     if g:SrcExpl_isUpdateTags != 0
1242         " Update the tags file right now
1243         if g:SrcExpl_UpdateTags()
1244             return -2
1245         endif
1246     endif
1248     if g:SrcExpl_updateTagsKey != ""
1249         exe "nnoremap " . g:SrcExpl_updateTagsKey . 
1250             \ " :call g:SrcExpl_UpdateTags()<CR>"
1251     endif
1253     " Then we set the routine function when the event happens
1254     augroup SrcExpl_AutoCmd
1255         autocmd!
1256         au! CursorHold * nested call g:SrcExpl_Refresh()
1257         au! WinEnter * nested call <SID>SrcExpl_EnterWin()
1258     augroup end
1260     " Done
1261     return 0
1263 endfunction " }}}
1265 " SrcExpl_Toggle() {{{
1267 " The user interface function to open / close the Source Explorer
1269 function! <SID>SrcExpl_Toggle()
1271     " Not yet running
1272     if s:SrcExpl_isRunning == 0
1273         " Initialize the properties
1274         if <SID>SrcExpl_Init()
1275             return -1
1276         endif
1277         " Create the window
1278         call <SID>SrcExpl_OpenWin()
1279         " We change the flag to true
1280         let s:SrcExpl_isRunning = 1
1281     else
1282         " Not in the exact tab page
1283         if s:SrcExpl_tabPage != tabpagenr()
1284             call <SID>SrcExpl_ReportErr("Not support multiple tab pages")
1285             return -2
1286         endif
1287         " Set the switch flag off
1288         let s:SrcExpl_isOpen = 0
1289         " Close the window
1290         call <SID>SrcExpl_CloseWin()
1291         " Do the cleaning work
1292         call <SID>SrcExpl_CleanUp()
1293         " We change the flag to false
1294         let s:SrcExpl_isRunning = 0
1295     endif
1297     " Done
1298     return 0
1300 endfunction " }}}
1302 " SrcExpl_Close() {{{
1304 " The user interface function to close the Source Explorer
1306 function! <SID>SrcExpl_Close()
1308     " Already running
1309     if s:SrcExpl_isRunning == 1
1310         " Not in the exact tab page
1311         if s:SrcExpl_tabPage != tabpagenr()
1312             call <SID>SrcExpl_ReportErr("Not support multiple tab pages")
1313             return -1
1314         endif
1315         " Close the window
1316         call <SID>SrcExpl_CloseWin()
1317         " Do the cleaning work
1318         call <SID>SrcExpl_CleanUp()
1319         " We change the flag to false
1320         let s:SrcExpl_isRunning = 0
1321     else
1322         " Tell users the reason
1323         call <SID>SrcExpl_ReportErr("Source Explorer is close")
1324         return -2
1325     endif
1327     " Done
1328     return 0
1330 endfunction " }}}
1332 " SrcExpl() {{{
1334 " The user interface function to open the Source Explorer
1336 function! <SID>SrcExpl()
1338     " Not yet running
1339     if s:SrcExpl_isRunning == 0
1340         " Initialize the properties
1341         if <SID>SrcExpl_Init()
1342             return -1
1343         endif
1344         " Create the window
1345         call <SID>SrcExpl_OpenWin()
1346         " We change the flag to true
1347         let s:SrcExpl_isRunning = 1
1348     else
1349         " Not in the exact tab page
1350         if s:SrcExpl_tabPage != tabpagenr()
1351             call <SID>SrcExpl_ReportErr("Not support multiple tab pages")
1352             return -2
1353         endif
1354         " Already running
1355         call <SID>SrcExpl_ReportErr("Source Explorer is running")
1356         return -3
1357     endif
1359     " Done
1360     return 0
1362 endfunction " }}}
1364 " Avoid side effects {{{
1366 set cpoptions&
1367 let &cpoptions = s:save_cpo
1368 unlet s:save_cpo
1370 " }}}
1372 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1373 "                                                                              "
1374 " vim:foldmethod=marker:tabstop=4
1375 "                                                                              "
1376 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""