" File: sco.vim " Author: Nickolay Golubev " Email: golubev.nikolay@gmail.com " " This script allow to work with cscope programm inside vim " You can easily store cscope results and filter them " " Please mail me problems if exists('g:sco_plugin_loaded') finish endif let g:sco_plugin_loaded = 1 if ! exists('g:sco_default_db') let g:sco_default_db = "cscope.out" endif if ! exists('g:sco_default_exe') let g:sco_default_exe = "cscope" endif let s:sco_settings = {} let s:sco_requests = {0:'C Symbol', 1:'Global Definition of',4:'Functions calling',5:'Text',6:'Grep', 8:'Files including file'} let s:last_sco_buffer = -1 let s:preview = 0 " Parse sco settings (% option:value) function! ParseSCOSettings() "{{{ let l:line_count = line("$") let s:sco_settings = {} if l:line_count == 0 return endif let l:line_number = 1 while l:line_number <= l:line_count let l:line = getline(l:line_number) let l:option_pattern = '^%\s\(\S\+\):\s\(\S\+\)' "echo 'test:'.l:line_number.' :'.l:line if l:line =~ l:option_pattern "echo 'pattern_match' let l:option_name = substitute(l:line, l:option_pattern, '\1', '') let l:option_value = substitute(l:line, l:option_pattern, '\2', '') "echo "otpname:".l:option_name." ; value:".l:option_value let s:sco_settings[ l:option_name ] = l:option_value else break endif let l:line_number = l:line_number + 1 endwhile endfunction "}}} " Put default option settings to sco buffer if not present function! DefaultSetting(name, value) "{{{ if has_key(s:sco_settings, a:name)==0 call append(0, '% '.a:name.': '.a:value) let s:sco_settings[a:name] = a:value endif endfunction "}}} function! SetSettings() call ParseSCOSettings() call DefaultSetting('cscope_db', g:sco_default_db) call DefaultSetting('cscope_exe', g:sco_default_exe) endfunction " open last sco buffer function! GoToLastScoBuffer() let l:last_sco_buffer_name = bufname(s:last_sco_buffer) if l:last_sco_buffer_name !~ "sco$" echohl WarningMsg | echo 'Last sco ['.s:last_sco_buffer.'] buffer not present' | echohl None "echo "" return 0 endif exec 'buffer '.s:last_sco_buffer return 1 endfunction " put results from cscope function! CScopeResult(type, word) "{{{ if ! GoToLastScoBuffer() return endif call SetSettings() let l:cmd_line = s:sco_settings['cscope_exe'] let l:data_base = s:sco_settings['cscope_db'] let l:cmd_line = l:cmd_line.' -d -L -'.a:type.' "'.a:word.'" -f '.l:data_base let l:request_line = s:sco_requests[ a:type ].' "'.a:word.'"' exec ':'.line("$") let l:first_line = line(".") exec 'r !'.l:cmd_line let l:last_line = line(".") if l:first_line == l:last_line echohl WarningMsg | echo l:request_line.' not found in '.l:data_base | echohl None echo "" return endif let l:failed = append(l:first_line, '>>> '.l:request_line) let l:failed = append(l:last_line+1, '<<<') let l:first_line = l:first_line + 2 let l:last_line = l:last_line + 1 let l:line_number = l:first_line let l:max_file_name_length = 0 let l:max_function_name_length = 0 let l:max_line_number_length = 0 let l:pattern = '^\(\S\+\)\s\(\S\+\)\s\(\d\+\)\s\(.*\)$' while l:line_number <= l:last_line let l:line = getline(l:line_number) let l:file_name = substitute(l:line, l:pattern, '\1', '') let l:function_name = substitute(l:line, l:pattern, '\2', '') let l:file_line_number = substitute(l:line, l:pattern, '\3', '') let l:body = substitute(l:line, l:pattern, '\4', '') if strlen(l:file_name) > l:max_file_name_length let l:max_file_name_length = strlen(l:file_name) endif if strlen(l:function_name) > l:max_function_name_length let l:max_function_name_length = strlen(l:function_name) endif if strlen(l:file_line_number) > l:max_line_number_length let l:max_line_number_length = strlen(l:file_line_number) endif let l:line_number = l:line_number + 1 endwhile let l:line_number = l:first_line while l:line_number <= l:last_line let l:line = getline(l:line_number) let l:file_name = substitute(l:line, l:pattern, '\1', '') let l:function_name = substitute(l:line, l:pattern, '\2', '') let l:file_line_number = substitute(l:line, l:pattern, '\3', '') let l:body = substitute(l:line, l:pattern, '\4', '') let l:new_line = printf('# %-'.max_file_name_length.'s %'.max_function_name_length.'s %'.max_line_number_length.'s %s', l:file_name, l:function_name, l:file_line_number, l:body) call setline(l:line_number, l:new_line) let l:line_number = l:line_number + 1 endwhile exec ':'.l:first_line endfunction "}}} " filter result inside >>> <<< function! FilterResult(delete_pattern, leave_pattern) let l:first_line_num = -1 let l:last_line_num = -1 let l:line_num = line('.') while l:line_num > 0 let l:line = getline(l:line_num) if line =~ '^>>>' let l:first_line_num = l:line_num break endif let l:line_num = l:line_num - 1 endwhile let l:line_num = line('.') let l:line_count = line('$') while l:line_num <= l:line_count let l:line = getline(l:line_num) if line =~ '^<<<' let l:last_line_num = l:line_num break endif let l:line_num = l:line_num + 1 endwhile if l:first_line_num < 0 || l:last_line_num < 0 return endif let l:line_num = l:first_line_num + 1 while l:line_num < l:last_line_num let l:line = getline(l:line_num) if l:line =~ a:delete_pattern && l:line !~ a:leave_pattern exec l:line_num.'d' let l:line_num = l:line_num - 1 let l:last_line_num = l:last_line_num - 1 endif let l:line_num = l:line_num + 1 endwhile endfunction " allign sco result function! AllignResult(first_line, last_line) let l:pattern = '^#\s\+\(\S\+\)\s\+\(\S\+\)\s\+\(\d\+\)\s\+\(.*\)$' let l:max_file_name_length = 0 let l:max_function_name_length = 0 let l:max_line_number_length = 0 let l:line_number = a:first_line while l:line_number <= a:last_line let l:line = getline(l:line_number) let l:file_name = substitute(l:line, l:pattern, '\1', '') let l:function_name = substitute(l:line, l:pattern, '\2', '') let l:file_line_number = substitute(l:line, l:pattern, '\3', '') let l:body = substitute(l:line, l:pattern, '\4', '') if strlen(l:file_name) > l:max_file_name_length let l:max_file_name_length = strlen(l:file_name) endif if strlen(l:function_name) > l:max_function_name_length let l:max_function_name_length = strlen(l:function_name) endif if strlen(l:file_line_number) > l:max_line_number_length let l:max_line_number_length = strlen(l:file_line_number) endif let l:line_number = l:line_number + 1 endwhile let l:line_number = a:first_line while l:line_number <= a:last_line let l:line = getline(l:line_number) let l:file_name = substitute(l:line, l:pattern, '\1', '') let l:function_name = substitute(l:line, l:pattern, '\2', '') let l:file_line_number = substitute(l:line, l:pattern, '\3', '') let l:body = substitute(l:line, l:pattern, '\4', '') let l:new_line = printf('# %-'.max_file_name_length.'s %'.max_function_name_length.'s %'.max_line_number_length.'s %s', l:file_name, l:function_name, l:file_line_number, l:body) call setline(l:line_number, l:new_line) let l:line_number = l:line_number + 1 endwhile endfunction " add mark from file function! AddMark() let l:line_number = line('.') let l:line = getline('.') let l:file_name = expand('%:p') if ! GoToLastScoBuffer() return endif let l:mark_line = '# '.l:file_name.' '.l:line_number.' '.l:line call append(line('$'), l:mark_line) let l:line_number = line('$') while l:line_number >= 0 let l:line = getline(l:line_number) if l:line !~ '' break endif let l:line_number = l:line_number - 1 endwhile call AllignResult(l:line_number+1, line('$')) endfunction " select file to edit function! EditFile() "{{{ let l:pattern = '^#\s\+\(\S\+\)\s\+\(\S\+\)\s\+\(\d\+\)\s\+\(.*\)$' let l:current_line = getline('.') if l:current_line !~ l:pattern return endif let l:file_name = substitute(l:current_line, l:pattern, '\1','') let l:line_number = substitute(l:current_line, l:pattern, '\3','') if s:preview exec 'pclose' endif exec 'edit +:'.l:line_number.' '.l:file_name endfunction "}}} " cursor move handler function! Cursor_move_handler() if ! s:preview return endif let l:pattern = '^#\s\+\(\S\+\)\s\+\(\S\+\)\s\+\(\d\+\)\s\+\(.*\)$' let l:current_line = getline('.') if l:current_line =~ l:pattern let l:file_name = substitute(l:current_line, l:pattern, '\1', '') let l:line_number = substitute(l:current_line, l:pattern, '\3', '') exec 'pedit +'.l:line_number.' '.l:file_name else exec 'pclose' endif endfunction " toggle preview function! TogglePreview() if s:preview let s:preview = 0 exec 'pclose' return endif if ! s:preview let s:preview = 1 call Cursor_move_handler() return endif endfunction " put help to sco buffer function! AddHelpLines() "{{{ let l:help_lines = [] call add(l:help_lines, '>>> sco help') call add(l:help_lines, '/Hot keys local to this buffer:/') call add(l:help_lines, ' - select file to edit from result') call add(l:help_lines, 'cp - Toggle preview mode') call add(l:help_lines, '/Global hot keys:/') call add(l:help_lines, 'cg - Find Global Definition of symbol under cursor') call add(l:help_lines, 'cc - Find C Symbol') call add(l:help_lines, 'cf - Find Files including this file') call add(l:help_lines, 'cw - Find Functions calling this function') call add(l:help_lines, 'cb - Open last sco buffer') call add(l:help_lines, 'cm - Mark current line') call add(l:help_lines, '/Commands local to this buffer:/') call add(l:help_lines, ":Delete 'pattern' - delete all rows which match 'pattern' inside folded result") call add(l:help_lines, ":Leave 'pattern' - leave only rows which match 'pattern' inside folded result") call add(l:help_lines, ":Filter 'delete_pattern', 'leave_pattern' - leave only rows which match 'pattern' inside folded result and delete rows with 'delete_pattern'") call add(l:help_lines, ':Preview - toggle preview mode') call add(l:help_lines, '/Global commands:/') call add(l:help_lines, ":SCOSymbol 'symbolname' - find C Symbol") call add(l:help_lines, ":SCOGlobal 'functionname' - find Global definition") call add(l:help_lines, ":SCOInclude 'filename' - find files including ") call add(l:help_lines, ":SCOWhoCall 'functionname' - find functions calling function") call add(l:help_lines, ":SCOText 'text' - find text") call add(l:help_lines, ":SCOGrep 'pattern' - find grep pattern") call add(l:help_lines, ":SCOBuffer - go to last sco buffer") call add(l:help_lines, ":SCOMark - mark current line") call add(l:help_lines, '<<< sco help') call add(l:help_lines, '>>> fold help') call add(l:help_lines, 'zj - move to next fold') call add(l:help_lines, 'zk - previous fold') call add(l:help_lines, 'zo - open fold') call add(l:help_lines, 'zc - close fold') call add(l:help_lines, '[z - top of fold') call add(l:help_lines, ']z - bottom of fold') call add(l:help_lines, 'zR - unfold all') call add(l:help_lines, 'zM - fold all') call add(l:help_lines, '<<< fold help') call append(line('$'), l:help_lines) endfunction "}}} function! EnterScoBuffer() let s:last_sco_buffer = bufnr('%') call Cursor_move_handler() endfunction " set highlight and commands - called when .sco file readed function! Prepare_sco_settings() "{{{ setlocal autowriteall setlocal filetype=sco setlocal foldmethod=marker setlocal foldmarker=>>>,<<< setlocal foldclose=all setlocal updatetime=500 call SetSettings() let s:last_sco_buffer = bufnr('%') command! -nargs=1 SCOSymbol call CScopeResult(0, ) command! -nargs=1 SCOGlobal call CScopeResult(1, ) command! -nargs=1 SCOWhoCall call CScopeResult(4, ) command! -nargs=1 SCOText call CScopeResult(5, ) command! -nargs=1 SCOGrep call CScopeResult(6, ) command! -nargs=1 SCOInclude call CScopeResult(8, ) command! SCOBuffer call GoToLastScoBuffer() command! SCOMark call AddMark() command! -buffer Preview call TogglePreview() command! -buffer -nargs=1 Delete call FilterResult(, '$^') command! -buffer -nargs=1 Leave call FilterResult('*', ) command! -buffer -nargs=1 -nargs=1 -complete=tag Filter call FilterResult() nnoremap :call EditFile() nnoremap cp :Preview nnoremap cg :SCOGlobal expand('') nnoremap cc :SCOSymbol expand('') nnoremap ct :SCOText expand('') nnoremap cw :SCOWhoCall expand('') nnoremap cf :SCOInclude expand('') nnoremap cb :SCOBuffer nnoremap cm :SCOMark syn match sco_header /^% cscope_db: / nextgroup=sco_header_param syn match sco_header /^% cscope_exe: / nextgroup=sco_header_param syn match sco_comment /^\/.\+\/$/ syn match sco_header_param /.*/ contained syn match sco />>>.*$/ syn match sco0 /<<<.*$/ syn match sco1 /^#/ nextgroup=sco2 skipwhite syn match sco2 /\s\S\+/ nextgroup=sco3 contained skipwhite syn match sco3 /\s\S\+/ nextgroup=sco4 contained skipwhite syn match sco4 /\s\S\+/ nextgroup=sco5 contained skipwhite syn region sco5 start="\s" end="$" contains=Comment,Number,Float contained keepend hi link sco_header Define hi link sco_header_param Identifier hi link sco_comment Comment hi link sco Comment hi link sco0 Comment hi link sco1 Comment hi link sco2 Conditional hi link sco3 Identifier hi link sco4 Underlined hi link sco5 String endfunction "}}} " set highlight and commands, put help - called when .sco file created function! Prepare_sco_settings_new_file() call Prepare_sco_settings() call AddHelpLines() endfunction augroup filetypedetect au! BufRead *.sco call Prepare_sco_settings() au! BufNewFile *.sco call Prepare_sco_settings_new_file() au! BufWinEnter *.sco call EnterScoBuffer() au! CursorMoved *.sco nested call Cursor_move_handler() augroup END " vim:ft=vim:fdm=marker:ff=unix:nowrap