programing

Vim은 ctag를 자동 생성합니다.

sourcetip 2021. 1. 14. 23:45
반응형

Vim은 ctag를 자동 생성합니다.


지금은 다음과 같습니다 .vimrc.

au BufWritePost *.c,*.cpp,*.h !ctags -R

여기에는 몇 가지 문제가 있습니다.

  1. 느립니다-마지막 태그 생성 이후 변경되지 않은 파일에 대한 태그를 다시 생성합니다.
  2. 필연적으로 "계속하려면 Enter를 누르거나 명령을 입력하십시오"라는 이유로 파일을 작성한 후 다시 Enter 버튼을 눌러야 합니다 .

이 두 가지 문제를 결합하면 너무 빨리 ( ctags -R완료 되기 전에) 추가 입력을 밀고 성가신 오류 메시지가 표시되고 다시 입력해야합니다.

나는 그것이 큰 문제처럼 들리지 않는다는 것을 알고 있지만, 내가 주어진 날에하는 파일 쓰기의 양으로 인해 정말 짜증나는 경향이 있습니다. 더 나은 방법이 있어야합니다!


au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &

단점은 완료 될 때까지 유용한 태그 파일이 없다는 것입니다. * nix 시스템을 사용하는 한 이전 ctag가 완료되기 전에 여러 번 쓰기를해도 괜찮지 만 테스트해야합니다. Windows 시스템에서는 백그라운드에 배치하지 않고 첫 번째 ctag가 완료 될 때까지 파일이 잠겨 있다고 불평합니다 (vim에서 문제를 일으키지는 않지만 약간 오래된 태그 파일로 끝납니다) ).

--appendtonylo가 제안한대로 옵션을 사용할 수 있지만 비활성화 tagbsearch해야 태그 파일의 크기에 따라 태그 검색이 훨씬 오래 걸릴 수 있습니다.


편집 : 다음과 같은 솔루션 AutoTag vim 스크립트 로 게시되었습니다 . 그러나 스크립트 에는 Python을 지원하는 vim이 필요합니다 .

내 솔루션은 대신 awk를 사용하므로 더 많은 시스템에서 작동합니다.


au FileType {c,cpp} au BufWritePost <buffer> silent ! [ -e tags ] &&
    \ ( awk -F'\t' '$2\!="%:gs/'/'\''/"{print}' tags ; ctags -f- '%:gs/'/'\''/' )
    \ | sort -t$'\t' -k1,1 -o tags.new && mv tags.new tags

스크립트에서 이런 식으로 만 작성할 수 있습니다. 그렇지 않으면 한 줄로 작성해야합니다.

거기에 많은 일이 있습니다.

  1. 이 자동 명령은 파일이 C 또는 C ++로 감지 될 때 트리거되고 BufWritePost이벤트 에 의해 트리거되는 버퍼 로컬 자동 명령을 차례로 추가합니다 .

  2. 그것은 사용 %투게더와, 실행 시간에 상기 버퍼의 파일명으로 대체 자리 :gs개질제 (인용 탈출 인용 인용에 임베디드 작은 따옴표 돌려) 파일명 쉘 인용 사용.

  3. 그런 식으로 tags파일이 존재 하는지 확인하는 셸 명령을 실행합니다 .이 경우 방금 저장된 파일을 참조하는 행을 제외하고 내용이 인쇄되고 방금 저장된 파일 ctags에서만 호출되며 결과는 다음과 같습니다. sort에드 및 제자리에 다시 넣습니다.

경고 구현 자 : 이것은 모든 것이 동일한 디렉토리에 있고 버퍼 로컬 현재 디렉토리라고 가정합니다. 나는 경로 맹 글링에 대해 전혀 생각하지 않았습니다.


이 작업을 수행하기 위해 easytags.vim작성 했습니다. 자동으로 태그를 업데이트하고 강조 표시합니다. 플러그인은 편집중인 파일 만 업데이트하거나 편집중인 파일의 디렉토리에있는 모든 파일을 (재귀 적으로) 업데이트하도록 구성 할 수 있습니다. 글로벌 태그 파일, 파일 유형별 태그 파일 및 프로젝트 별 태그 파일을 사용할 수 있습니다.


나는 이것이 오래된 쓰레드라는 것을 알아 챘지만 ... inotify를 지원하는 환경과 같은 * nix에서 incron사용하라 . 디렉토리의 파일이 변경 될 때마다 항상 명령을 실행합니다. 즉,

/home/me/Code/c/that_program IN_DELETE,IN_CLOSE_WRITE ctags --sort=yes *.c

그게 다야.


다음과 같이 ctags에 append 인수를 사용할 수 있습니다.

http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file

나는 일반적으로 코드 브라우징에 소스 통찰력을 사용하기 때문에 이것을 보증 할 수는 없지만 vim을 편집기로 사용합니다.


crontab을 통해 실행되도록 ctag를 예약하는 것은 어떻습니까? 프로젝트 트리가 구조상 상당히 안정적이라면 가능해야합니까?


"press enter"프롬프트를 표시하지 않으려면 : silent를 사용 하십시오 .


OSX에서이 명령은 적어도 나를 위해 작동하지 않습니다.

au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &

-R 옵션이 포함 된 표준 ctags 버전을 얻는 방법을 설명하는 게시물을 찾았 습니다 . 이것만으로는 효과가 없었습니다. Homebrew가 프로그램을 설치하는 bin을 선택하기 위해 .bash_profile의 PATH 변수에 / usr / local / bin을 추가해야했습니다.


내 의견에서 플러그인 Indexer가 더 좋습니다.

http://www.vim.org/scripts/script.php?script_id=3221

그것은 될 수 있습니다:

1) project.tar.gz에 대한 추가 기능

2) 독립 플러그인

  • 백그라운드 태그 생성 (ctags가 작동하는 동안 기다리지 않음)
  • 여러 프로젝트 지원

정말 잘 작동하는 AutoTag 라는 vim 플러그인 이 있습니다.

taglist가 설치되어있는 경우에도 업데이트됩니다.


--append옵션은 실제로 길을 가야하는 것입니다. 와 함께 사용하면 태그가 지정된 파일을 grep -v하나만 업데이트 할 수 있습니다 . 예를 들어, 다음은 이 문제를 해결 하는 닦지 않은 플러그인 의 일부입니다 . (주의 : "외부" 라이브러리 플러그인 이 필요합니다. )

" Options {{{1
let g:tags_options_cpp = '--c++-kinds=+p --fields=+imaS --extra=+q'

function! s:CtagsExecutable()
  let tags_executable = lh#option#Get('tags_executable', s:tags_executable, 'bg')
  return tags_executable
endfunction

function! s:CtagsOptions()
  let ctags_options = lh#option#Get('tags_options_'.&ft, '')
  let ctags_options .= ' '.lh#option#Get('tags_options', '', 'wbg')
  return ctags_options
endfunction

function! s:CtagsDirname()
  let ctags_dirname = lh#option#Get('tags_dirname', '', 'b').'/'
  return ctags_dirname
endfunction

function! s:CtagsFilename()
  let ctags_filename = lh#option#Get('tags_filename', 'tags', 'bg')
  return ctags_filename
endfunction

function! s:CtagsCmdLine(ctags_pathname)
  let cmd_line = s:CtagsExecutable().' '.s:CtagsOptions().' -f '.a:ctags_pathname
  return cmd_line
endfunction


" ######################################################################
" Tag generating functions {{{1
" ======================================================================
" Interface {{{2
" ======================================================================
" Mappings {{{3
" inoremap <expr> ; <sid>Run('UpdateTags_for_ModifiedFile',';')

nnoremap <silent> <Plug>CTagsUpdateCurrent :call <sid>UpdateCurrent()<cr>
if !hasmapto('<Plug>CTagsUpdateCurrent', 'n')
  nmap <silent> <c-x>tc  <Plug>CTagsUpdateCurrent
endif

nnoremap <silent> <Plug>CTagsUpdateAll     :call <sid>UpdateAll()<cr>
if !hasmapto('<Plug>CTagsUpdateAll', 'n')
  nmap <silent> <c-x>ta  <Plug>CTagsUpdateAll
endif


" ======================================================================
" Auto command for automatically tagging a file when saved {{{3
augroup LH_TAGS
  au!
  autocmd BufWritePost,FileWritePost * if ! lh#option#Get('LHT_no_auto', 0) | call s:Run('UpdateTags_for_SavedFile') | endif
aug END

" ======================================================================
" Internal functions {{{2
" ======================================================================
" generate tags on-the-fly {{{3
function! UpdateTags_for_ModifiedFile(ctags_pathname)
  let source_name    = expand('%')
  let temp_name      = tempname()
  let temp_tags      = tempname()

  " 1- purge old references to the source name
  if filereadable(a:ctags_pathname)
    " it exists => must be changed
    call system('grep -v "  '.source_name.' " '.a:ctags_pathname.' > '.temp_tags.
      \ ' && mv -f '.temp_tags.' '.a:ctags_pathname)
  endif

  " 2- save the unsaved contents of the current file
  call writefile(getline(1, '$'), temp_name, 'b')

  " 3- call ctags, and replace references to the temporary source file to the
  " real source file
  let cmd_line = s:CtagsCmdLine(a:ctags_pathname).' '.source_name.' --append'
  let cmd_line .= ' && sed "s#\t'.temp_name.'\t#\t'.source_name.'\t#" > '.temp_tags
  let cmd_line .= ' && mv -f '.temp_tags.' '.a:ctags_pathname
  call system(cmd_line)
  call delete(temp_name)

  return ';'
endfunction

" ======================================================================
" generate tags for all files {{{3
function! s:UpdateTags_for_All(ctags_pathname)
  call delete(a:ctags_pathname)
  let cmd_line  = 'cd '.s:CtagsDirname()
  " todo => use project directory
  "
  let cmd_line .= ' && '.s:CtagsCmdLine(a:ctags_pathname).' -R'
  echo cmd_line
  call system(cmd_line)
endfunction

" ======================================================================
" generate tags for the current saved file {{{3
function! s:UpdateTags_for_SavedFile(ctags_pathname)
  let source_name    = expand('%')
  let temp_tags      = tempname()

  if filereadable(a:ctags_pathname)
    " it exists => must be changed
    call system('grep -v "  '.source_name.' " '.a:ctags_pathname.' > '.temp_tags.' && mv -f '.temp_tags.' '.a:ctags_pathname)
  endif
  let cmd_line = 'cd '.s:CtagsDirname()
  let cmd_line .= ' && ' . s:CtagsCmdLine(a:ctags_pathname).' --append '.source_name
  " echo cmd_line
  call system(cmd_line)
endfunction

" ======================================================================
" (public) Run a tag generating function {{{3
function! LHTagsRun(tag_function)
  call s:Run(a:tag_function)
endfunction

" ======================================================================
" (private) Run a tag generating function {{{3
" See this function as a /template method/.
function! s:Run(tag_function)
  try
    let ctags_dirname  = s:CtagsDirname()
    if strlen(ctags_dirname)==1
      throw "tags-error: empty dirname"
    endif
    let ctags_filename = s:CtagsFilename()
    let ctags_pathname = ctags_dirname.ctags_filename
    if !filewritable(ctags_dirname) && !filewritable(ctags_pathname)
      throw "tags-error: ".ctags_pathname." cannot be modified"
    endif

    let Fn = function("s:".a:tag_function)
    call Fn(ctags_pathname)
  catch /tags-error:/
    " call lh#common#ErrorMsg(v:exception)
    return 0
  finally
  endtry

  echo ctags_pathname . ' updated.'
  return 1
endfunction

function! s:Irun(tag_function, res)
  call s:Run(a:tag_function)
  return a:res
endfunction

" ======================================================================
" Main function for updating all tags {{{3
function! s:UpdateAll()
  let done = s:Run('UpdateTags_for_All')
endfunction

" Main function for updating the tags from one file {{{3
" @note the file may be saved or "modified".
function! s:UpdateCurrent()
  if &modified
    let done = s:Run('UpdateTags_for_ModifiedFile')
  else
    let done = s:Run('UpdateTags_for_SavedFile')
  endif
endfunction

이 코드는 다음을 정의합니다.

  • ^Xta 현재 프로젝트의 모든 파일에 대한 태그 기반 업데이트를 강제합니다.
  • ^Xtc 현재 (저장되지 않은) 파일에 대한 태그 기반 업데이트를 강제합니다.
  • an autocommand that updates the tags base every time a file is saved ; and it supports and many options to disable the automatic update where we don't want it, to tune ctags calls depending on filetypes, ... It is not just a tip, but a small excerpt of a plugin.

HTH,


Auto Tag is a vim plugin that updates existing tag files on save.

I've been using it for years without problems, with the exception that it enforces a maximum size on the tags files. Unless you have a really large set of code all indexed in the same tags file, you shouldn't hit that limit, though.

Note that Auto Tag requires Python support in vim.

ReferenceURL : https://stackoverflow.com/questions/155449/vim-auto-generate-ctags

반응형