Wednesday, June 23, 2010

Re: how to update cscope.out automatically ?

On 23/06/2010 3:03 AM, taco wrote:
hi, all
     After I have modified source files, I need to update cscope.out file by run "cscope -b -R" on shell then do ":cs reset" in vim. It is so inconvenience.
I want vim do it for me. how to reach this aim?

I guess I should really write either a TIP or a Plugin for this.

Below contains a bunch of stuff:
1.  Couple of functions to detect if a cscope.out is already active, what options it was started with and determine how to refresh it (ie. cscope -b).
2.  A pile of mappings to make my life a bit easier, since cscope is designed for C, but I use it for SQL and Perl and others.
3.  Some commands, the important one being - CSRefresh, it will stop cscope, re-run cscope -b and restart cscope with the same options.
4.  Some options you can set from your vimrc to control it's behaviour.
5.  An autocmd to detect if there is a cscope.out and automatically run :cs add

In a nutshell, on Windows I do this:
    dir /s/b *.sql  > cscope.files (create a file with all the files I want indexed)
    cscope -b (create the cscope database)

Open Vim:
    Edit a file
    Run :cs show, you should see cscope active.
    Update your source and :w
    Run :CSRefresh

I don't want to run CSRefresh all the time (for example in a autocmd on saving) since there could be lots of files and unless you are adding new methods or changing signatures, it is unnecessary.





I wrote the following and keep it in my .vimrc

" CScope support for VIM:/*{{{*/
if has("cscope")
    " See below about creating the cscope.files file.
    " This autocmd will remove the entries from within
    " a file that cscope cannot deal with, or does not
    " make sense indexing.
    autocmd BufReadPost cscope.files
                \ let before_lines = line('$') |
                \ silent! exec 'silent! g/\(cscope\|\.\(gif\|bmp\|png\|jpg\|swp\)\)/d' |
                \ silent! exec 'silent! v/\./d' |
                \ let before_lines = before_lines - line('$') |
                \ if before_lines > 0 |
                \   call confirm( 'Removed ' . before_lines . ' lines from file.  ' .
                \           'These were any of the following: ' .
                \           "\n".'- image and swap files ' .
                \           "\n".'- directories ' .
                \           "\n".'- any cscope files.' .
                \           "\n\n".'Press u to recover these lines.'
                \           ) |
                \ endif

    " Most often I find I need to recursively look at data
    " You cannot use (reports an error opening subdirs):
    "     cscope -R *.sql
    " You must use:
    "     cscope -R
    " But that only gets C/CPP files.
    " I have to do this:
    "     find -name *.sql > cscope.files
    "       or
    "     dir /s/b *.pl  > cscope.files
    "     dir /s/b *.pm >> cscope.files
    "     cscope -b (create the cscope database)
    "     cscope -C (queries this with case insensitivity)
    "
    " To open the same options in Vim:
    "     cs add cscope.out . -C  (for case insensitivity)
    "
    " For help on cscope and Vim:
    "     :cs
    "     :h cs

    " See below, CSReloadDB, which rebuilds the cscope database
    " if cscope.files is available.
    let g:cscope_rebuild_on_refresh = 1
    let g:cscope_options_default    = '-C'
   
    let &cscopeprg = expand('$VIM\Tools\cscope.exe')
    " If 'csto' is set to zero, cscope database(s) are searched first,
    " followed " by tag file(s) if cscope did not return any matches.
    set cscopetagorder=0
    " set cscopetag
    set nocscopeverbose
    " determines how many components of a file's path to display
    set cscopepathcomp=3
    " Use the quickfix window for the cscope query
    set cscopequickfix=s-,c-,d-,i-,t-,e-
    " add any database in current directory
   
    if filereadable("cscope.out")
        " cscope -C (queries this with case insensitivity)
        exec 'cs add '.getcwd().'/cscope.out "" '.g:cscope_options_default
        " else add database pointed to by environment
    elseif $CSCOPE_DB != ""
        cs add $CSCOPE_DB
    endif
    set csverb

    " Find this C symbol (0==s)
    nnoremap g<C-\> :silent! cs find 0 <C-R>=expand("<cword>")<CR><CR>:cwindow<CR>
    vnoremap <silent> g<c-\> :<C-U>
                  \:let old_reg=getreg('"')<bar>
                  \:let old_regmode=getregtype('"')<cr>
                  \gvy
                  \:silent! cs find s <C-R>=@"<cr><cr>
                  \:call setreg('"', old_reg, old_regmode)<cr>:cwindow<CR>
    " Find functions call this word (3==c)
    nnoremap g<C-]> :silent! cs find c <C-R>=expand("<cword>")<CR><CR>:cwindow<CR>
    vnoremap <silent> g<c-]> :<C-U>
                  \:let old_reg=getreg('"')<bar>
                  \:let old_regmode=getregtype('"')<cr>
                  \gvy
                  \:silent! cs find c <C-R>=@"<cr><cr>
                  \:call setreg('"', old_reg, old_regmode)<cr>:cwindow<CR>
    " Find this text string  (4==t)
    nnoremap g<C-[> :silent! cs find t <C-R>=expand("<cword>")<CR><CR>:cwindow<CR>
    vnoremap <silent> g<c-[> :<C-U>
                  \:let old_reg=getreg('"')<bar>
                  \:let old_regmode=getregtype('"')<cr>
                  \gvy
                  \:silent! cs find t <C-R>=@"<cr><cr>
                  \:call setreg('"', old_reg, old_regmode)<cr>:cwindow<CR>
    " Find this definition (1==g)
    nnoremap g<C-g> :silent! cs find g <C-R>=expand("<cword>")<CR><CR>:cwindow<CR>
    vnoremap <silent> g<c-g> :<C-U>
                  \:let old_reg=getreg('"')<bar>
                  \:let old_regmode=getregtype('"')<cr>
                  \gvy
                  \:silent! cs find g <C-R>=@"<cr><cr>
                  \:call setreg('"', old_reg, old_regmode)<cr>:cwindow<CR>
    " Find this text string  (4==t)
    " Use input() instead of inputdialog() so you can use <C-R> more
    " effectively when pasting in text to search for
    " nnoremap g/ :silent! cs find t <C-R>=input("Enter search string:", expand("<cword>"))<CR><CR>:cwindow<CR>
    nnoremap g/ :let find_text = input("Enter search string:", expand("<cword>")) <bar>
                \ :if find_text != '' \|
                \     exec('silent! cs find t '.find_text) \|
                \     exec('cwindow') \|
                \ endif<CR>

    function! CSRefreshAllConns()

        " Check if there are any cscope connections
        let saveA = @a
        redir  @a
        silent! exec 'cs show'
        redir END
        let cs_conns = @a
        let @a = saveA

        if cs_conns !~? 'no cscope connections'
            let match_regex = '\(\d\+\s\+\d\+\s\+\S\+\s\+\S\+\)'
            let index = match(cs_conns, match_regex)
           
            while index > -1
                " Retrieve the name of option
                let cs_conn_num = matchstr(cs_conns, '^\d\+', index)
                if strlen(cs_conn_num) > 0
                    let index = (index + strlen(cs_conn_num)) 
                    let cs_db_name = matchstr(cs_conns,
                                \ '\s\+\d\+\s\+\zs\S\+',
                                \ index
                                \ )
                    let index = index + strlen(cs_conn_num)
                                \     + strlen(cs_db_name)
                    let cs_db_path = matchstr(cs_conns,
                                \ '\s\+\zs\S\+',
                                \ index
                                \ )
                    if cs_db_path =~ "<none>" || cs_db_path =~ '""'
                        let cs_db_path = ''
                    endif
                    let index = index + strlen(cs_conn_num)
                                \     + strlen(cs_db_name)
                                \     + strlen(cs_db_path)
                                \     + 1
                    call CSReloadDB( cs_conn_num, cs_db_name, cs_db_path,
                                \ g:cscope_options_default )
                endif
                let index = index + 1
                let index = match(cs_conns, match_regex, index)
            endwhile
        else
            if filereadable("cscope.out")
                " cscope -C (queries this with case insensitivity)
                exec 'cs add '.getcwd().'/cscope.out "" '.g:cscope_options_default
            endif
        endif

    endfunction

    function! CSReloadDB( cs_conn_num, cs_db_name, cs_db_path, cs_options )
        exec 'cs kill ' . a:cs_conn_num

        let cs_db_fullpath = fnamemodify(a:cs_db_name,":p")

        let root_file = a:cs_db_path
        if root_file == ""
            let root_file = fnamemodify(a:cs_db_name,":p")
        endif
        " If no pre_path was specified (ie . = current directory)
        " Then assume the directory has not changed since cscope was started
        " let cs_db_path     = substitute(root_file, '^\.$',
        "             \ '\=expand("%:p:h")', '')
        " if has('win32')
        "     let cs_db_fullpath = substitute(cs_db_path, '\S\+\zs\\\?$', '&\', '') .
        "                 \ a:cs_db_name
        " else
        "     let cs_db_fullpath = substitute(cs_db_path, '\S\+\zs\\\?$', '&/', '') .
        "                 \ a:cs_db_name
        " endif

        if filereadable(cs_db_fullpath)
            if g:cscope_rebuild_on_refresh == 1
                call CSRebuildDB( cs_db_fullpath, a:cs_options )
            endif
            let cs_cmd = 'cs add '.
                        \ cs_db_fullpath.' '.
                        \ fnamemodify(cs_db_fullpath, ":p:h").' '.
                        \ a:cs_options
            exec cs_cmd
        else
            echohl WarningMsg
            echomsg 'CSReloadDB - Cannot find: '.cs_db_fullpath
            echohl None
        endif
    endfunction

    function! CSRebuildDB( cs_db_fullpath, cs_options )
        let cscope_files = fnamemodify(a:cs_db_fullpath,":p:h").'\cscope.files'
        if filereadable(cscope_files)
            let cs_cmd = 'cscope.exe -b '.
                        \ '-f '.a:cs_db_fullpath.
                        \ ' -i '.cscope_files
            let cs_out = system(cs_cmd)

            if v:shell_error
                echo cs_out
            else
                echo 'Rebuilt cscope database: ' . a:cs_db_fullpath
            endif
        endif
       
    endfunction

    command! CSRefresh :call CSRefreshAllConns()
endif
" /*}}}*/


If you have comments (good or bad) or think this would be worth a plugin, let me know.
Please post these suggests to the list.

Once cscope is active, you can also use Dr. Chips plugin to make using it easier:
cecscope : command and menu driven cscope interface
http://www.vim.org/scripts/script.php?script_id=1453


HTH,
Dave

No comments: