" vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab foldmethod=marker " Copyright: Copyright (C) 2012-2015 Brook Hong " License: The MIT License " if !exists('g:cscope_silent') let g:cscope_silent = 0 endif if !exists('g:cscope_auto_update') let g:cscope_auto_update = 1 endif if !exists('g:cscope_open_location') let g:cscope_open_location = 1 endif if !exists('g:cscope_split_threshold') let g:cscope_split_threshold = 10000 endif function! s:echo(msg) if g:cscope_silent == 0 echo a:msg endif endfunction function! ToggleLocationList() let l:own = winnr() lw let l:cwn = winnr() if(l:cwn == l:own) if &buftype == 'quickfix' lclose elseif len(getloclist(winnr())) > 0 lclose else echohl WarningMsg | echo "No location list." | echohl None endif endif endfunction if !exists('g:cscope_cmd') if executable('cscope') let g:cscope_cmd = 'cscope' else call echo('cscope: command not found') finish endif endif if !exists('g:cscope_interested_files') let files = readfile(expand(":p:h")."/interested.txt") let g:cscope_interested_files = join(map(files, 'v:val."$"'), '\|') endif let s:cscope_vim_dir = substitute($HOME,'\\','/','g')."/.cscope.vim" let s:index_file = s:cscope_vim_dir.'/index' function! s:GetBestPath(dir) let f = substitute(a:dir,'\\','/','g') let bestDir = "" for d in keys(s:dbs) if stridx(f, d) == 0 && len(d) > len(bestDir) let bestDir = d endif endfor return bestDir endfunction function! s:ListFiles(dir) let d = [] let f = [] let cwd = a:dir let sl = &l:stl try while cwd != '' let a = split(globpath(cwd, "*"), "\n") for fn in a if getftype(fn) == 'dir' if !exists('g:cscope_ignored_dir') || fn !~? g:cscope_ignored_dir call add(d, fn) endif elseif getftype(fn) != 'file' continue elseif fn !~? g:cscope_interested_files continue else if stridx(fn, ' ') != -1 let fn = '"'.fn.'"' endif call add(f, fn) endif endfor let cwd = len(d) ? remove(d, 0) : '' sleep 1m | let &l:stl = 'Found '.len(f).' files, finding in '.cwd | redrawstatus endwhile catch /^Vim:Interrupt$/ catch echo "caught" v:exception endtry sleep 1m | let &l:stl = sl | redrawstatus return f endfunction function! s:RmDBfiles() let odbs = split(globpath(s:cscope_vim_dir, "*"), "\n") for f in odbs call delete(f) endfor endfunction function! s:FlushIndex() let lines = [] for d in keys(s:dbs) call add(lines, d.'|'.s:dbs[d]['id'].'|'.s:dbs[d]['loadtimes'].'|'.s:dbs[d]['dirty']) endfor call writefile(lines, s:index_file) endfunction function! s:CheckNewFile(dir, newfile) let id = s:dbs[a:dir]['id'] let cscope_files = s:cscope_vim_dir."/".id.".files" let files = readfile(cscope_files) if len(files) > g:cscope_split_threshold let cscope_files = s:cscope_vim_dir."/".id."_inc.files" if filereadable(cscope_files) let files = readfile(cscope_files) else let files = [] endif endif if count(files, a:newfile) == 0 call add(files, a:newfile) call writefile(files, cscope_files) endif endfunction function! s:_CreateDB(dir, init) let id = s:dbs[a:dir]['id'] let cscope_files = s:cscope_vim_dir."/".id."_inc.files" let cscope_db = s:cscope_vim_dir.'/'.id.'_inc.db' if ! filereadable(cscope_files) || a:init let cscope_files = s:cscope_vim_dir."/".id.".files" let cscope_db = s:cscope_vim_dir.'/'.id.'.db' if ! filereadable(cscope_files) let files = ListFiles(a:dir) call writefile(files, cscope_files) endif endif exec 'cs kill '.cscope_db redir @x exec 'silent !'.g:cscope_cmd.' -b -i '.cscope_files.' -f'.cscope_db redi END if @x =~ "\nCommand terminated\n" echohl WarningMsg | echo "Failed to create cscope database for ".a:dir.", please check if " | echohl None else let s:dbs[a:dir]['dirty'] = 0 exec 'cs add '.cscope_db endif endfunction function! s:CheckAbsolutePath(dir, defaultPath) let d = a:dir while 1 if !isdirectory(d) echohl WarningMsg | echo "Please input a valid path." | echohl None let d = input("", a:defaultPath, 'dir') elseif (len(d) < 2 || (d[0] != '/' && d[1] != ':')) echohl WarningMsg | echo "Please input an absolute path." | echohl None let d = input("", a:defaultPath, 'dir') else break endif endwhile let d = substitute(d,'\\','/','g') let d = substitute(d,'/\+$','','') return d endfunction function! s:InitDB(dir) let id = localtime() let s:dbs[a:dir] = {} let s:dbs[a:dir]['id'] = id let s:dbs[a:dir]['loadtimes'] = 0 let s:dbs[a:dir]['dirty'] = 0 call _CreateDB(a:dir, 1) call FlushIndex() endfunction function! s:LoadDB(dir) cs kill -1 exe 'cs add '.s:cscope_vim_dir.'/'.s:dbs[a:dir]['id'].'.db' if filereadable(s:cscope_vim_dir.'/'.s:dbs[a:dir]['id'].'_inc.db') exe 'cs add '.s:cscope_vim_dir.'/'.s:dbs[a:dir]['id'].'_inc.db' endif let s:dbs[a:dir]['loadtimes'] = s:dbs[a:dir]['loadtimes']+1 call FlushIndex() endfunction " 0 -- loaded " 1 -- cancelled function! s:AutoloadDB(dir) let ret = 0 let m_dir = GetBestPath(a:dir) if m_dir == "" echohl WarningMsg | echo "Can not find proper cscope db, please input a path to generate cscope db for." | echohl None let m_dir = input("", a:dir, 'dir') if m_dir != '' let m_dir = CheckAbsolutePath(m_dir, a:dir) call InitDB(m_dir) call LoadDB(m_dir) else let ret = 1 endif else let id = s:dbs[m_dir]['id'] if cscope_connection(2, s:cscope_vim_dir.'/'.id.'.db') == 0 call LoadDB(m_dir) endif endif return ret endfunction function! s:updateDBs(dirs) for d in a:dirs call _CreateDB(d, 0) endfor call FlushIndex() endfunction function! s:clearDBs(dir) cs kill -1 if a:dir == "" let s:dbs = {} call RmDBfiles() else let id = s:dbs[a:dir]['id'] call delete(s:cscope_vim_dir."/".id.".files") call delete(s:cscope_vim_dir.'/'.id.'.db') call delete(s:cscope_vim_dir."/".id."_inc.files") call delete(s:cscope_vim_dir.'/'.id.'_inc.db') unlet s:dbs[a:dir] endif call FlushIndex() endfunction function! s:listDBs() let dirs = keys(s:dbs) if len(dirs) == 0 echo "You have no cscope dbs now." else let s = [' ID LOADTIMES PATH'] for d in dirs let id = s:dbs[d]['id'] if cscope_connection(2, s:cscope_vim_dir.'/'.id.'.db') == 1 let l = printf("*%d %10d %s", id, s:dbs[d]['loadtimes'], d) else let l = printf(" %d %10d %s", id, s:dbs[d]['loadtimes'], d) endif call add(s, l) endfor echo join(s, "\n") endif endfunction function! s:loadIndex() let s:dbs = {} if ! isdirectory(s:cscope_vim_dir) call mkdir(s:cscope_vim_dir) elseif filereadable(s:index_file) let idx = readfile(s:index_file) for i in idx let e = split(i, '|') if len(e) == 0 call delete(s:index_file) call RmDBfiles() else let db_file = s:cscope_vim_dir.'/'.e[1].'.db' if filereadable(db_file) if isdirectory(e[0]) let s:dbs[e[0]] = {} let s:dbs[e[0]]['id'] = e[1] let s:dbs[e[0]]['loadtimes'] = e[2] let s:dbs[e[0]]['dirty'] = (len(e) > 3) ? e[3] :0 else call delete(db_file) endif endif endif endfor else call RmDBfiles() endif endfunction function! s:preloadDB() let dirs = split(g:cscope_preload_path, ';') for m_dir in dirs let m_dir = CheckAbsolutePath(m_dir, m_dir) if ! has_key(s:dbs, m_dir) call InitDB(m_dir) endif call LoadDB(m_dir) endfor endfunction function! CscopeFind(action, word) let dirtyDirs = [] for d in keys(s:dbs) if s:dbs[d]['dirty'] == 1 call add(dirtyDirs, d) endif endfor if len(dirtyDirs) > 0 call updateDBs(dirtyDirs) endif let dbl = AutoloadDB(expand('%:p:h')) if dbl == 0 try exe ':lcs f '.a:action.' '.a:word if g:cscope_open_location == 1 lw endif catch echohl WarningMsg | echo 'Can not find '.a:word.' with querytype as '.a:action.'.' | echohl None endtry endif endfunction function! CscopeFindInteractive(pat) call inputsave() let qt = input("\nChoose a querytype for '".a:pat."'(:help cscope-find)\n c: functions calling this function\n d: functions called by this function\n e: this egrep pattern\n f: this file\n g: this definition\n i: files #including this file\n s: this C symbol\n t: this text string\n\n or\n to query `pattern` instead of '".a:pat."' as `querytype`, Ex. `smain` to query a C symbol named 'main'.\n> ") call inputrestore() if len(qt) > 1 call CscopeFind(qt[0], qt[1:]) elseif len(qt) > 0 call CscopeFind(qt, a:pat) endif call feedkeys("\") endfunction function! s:onChange() if expand('%:t') =~? g:cscope_interested_files let m_dir = GetBestPath(expand('%:p:h')) if m_dir != "" let s:dbs[m_dir]['dirty'] = 1 call FlushIndex() call CheckNewFile(m_dir, expand('%:p')) redraw call echo('Your cscope db will be updated automatically, you can turn off this message by setting g:cscope_silent 1.') endif endif endfunction function! CscopeUpdateDB() call updateDBs(keys(s:dbs)) endfunction if exists('g:cscope_preload_path') call preloadDB() endif if g:cscope_auto_update == 1 au BufWritePost * call onChange() endif set cscopequickfix=s-,g-,d-,c-,t-,e-,f-,i- function! s:listDirs(A,L,P) return keys(s:dbs) endfunction com! -nargs=? -complete=customlist,listDirs CscopeClear call clearDBs("") com! -nargs=0 CscopeList call listDBs() call loadIndex()