Vim автоматически создает теги ctags

Прямо сейчас у меня в .vimrc есть следующее:

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

С этим есть несколько проблем:

  1. Это медленно - регенерирует теги для файлов, которые не изменились с момента последнего создания тегов.
  2. Я должен нажать кнопку ввода еще раз после записи файла из-за неизбежного «нажмите Enter или введите команду, чтобы продолжить».

Когда вы объединяете эти две проблемы, я слишком рано нажимаю дополнительный ввод (до завершения ctags -R), затем вижу раздражающее сообщение об ошибке и мне приходится снова нажимать ввод.

Я знаю, что это не кажется большим делом, но из-за того количества файлов, которые я записываю в конкретный день, это очень раздражает. Должен быть способ сделать это лучше!


person cdleary    schedule 30.09.2008    source источник


Ответы (12)


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

Обратной стороной является то, что у вас не будет полезного файла тегов, пока он не будет завершен. Пока вы работаете в системе * nix, можно сделать несколько записей до того, как завершатся предыдущие ctags, но вы должны это проверить. В системе Windows он не будет помещать его в фоновый режим и будет жаловаться, что файл заблокирован до тех пор, пока не закончатся первые ctags (что не должно вызывать проблем в vim, но вы получите немного устаревший файл тегов ).

Обратите внимание: вы можете использовать параметр --append, как предлагает Тонило, но тогда вам придется отключить tagbsearch, что может означать, что поиск тегов займет намного больше времени, в зависимости от размера вашего файла тегов.

person Zathrus    schedule 30.09.2008
comment
Ах ... хорошее решение. Я использовал тишину! ctags -R и не понимал, почему ничего не происходит ... Думаю, вам нужен второй удар. - person cdleary; 01.10.2008
comment
В Windows вы всегда можете использовать 'start ctags -R'. Это запустит ctags в backgroud. - person devemouse; 01.09.2011
comment
У меня были проблемы с этим решением, когда файлы вызывали предупреждения ctags, поскольку эти предупреждения затем отображались в vim и испортили экран (например, ctags: Warning: ignoring null tag in public/jquery.form.js). Я просто перенаправил stderr на / dev / null, и это исправляет, но это означает, что я не буду знать о проблемах с тегами. autocmd BufWritePost *.rb,*.js silent! !/usr/local/bin/ctags -R 2> /dev/null & - person mmrobins; 02.05.2012
comment
@mmrobins какие-либо предложения, если это перенаправление на dev / null не работает? Я понимаю, что вы делаете, но Vim, похоже, не уважает это и все равно печатает на экране. - person New Alexandria; 07.03.2014

Изменить: решение, очень похожее на следующее, было опубликовано как the AutoTag сценарий vim. Обратите внимание, что скрипту требуется vim с поддержкой Python.

Вместо этого в моем решении используется 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, используемым для заключения имени файла в кавычки (путем преобразования любых встроенных одинарных кавычек в кавычки-escape-кавычки-кавычки).

  3. Таким образом, он запускает команду оболочки, которая проверяет, существует ли файл tags, и в этом случае его содержимое печатается за исключением строк, которые относятся к только что сохраненному файлу, в то время как ctags вызывается только для только что сохраненного файла, и результат затем sort удаляется и возвращается на место.

Предостережение разработчика: это предполагает, что все находится в одном каталоге и что это также текущий каталог, локальный в буфере. Я не думал о том, чтобы исказить путь.

person Aristotle Pagaltzis    schedule 02.10.2008

Я написал easytags.vim именно для этого: автоматически обновлять и выделять теги . Плагин можно настроить для обновления только редактируемого файла или всех файлов в каталоге редактируемого файла (рекурсивно). Он может использовать файл глобальных тегов, файлы тегов для конкретных типов файлов и файлы тегов для конкретных проектов.

person xolox    schedule 14.01.2012
comment
easytags - это хорошо и круто, но время срабатывания триггера vim по умолчанию слишком нетерпеливо ... чтобы предотвратить раздражающие срывы, добавьте это к своему f.e. /etc/vim/vimrc.local: set updatetime=30000 "trigger autocmds after half a minute of user inactivity instead of after 4 secondsset swapsync="" "disable swap file sync on user inactivity trigger - person eMPee584; 06.01.2013
comment
@ eMPee584: Я согласен, что временами это может сильно раздражать (прерывая рабочий процесс пользователя). В настоящее время я работаю над веткой, в которой Exuberant Ctags выполняется в асинхронном подпроцессе. Как только он будет работать надежно из коробки на всех платформах, я, вероятно, сделаю его по умолчанию. - person xolox; 19.06.2013

Однако я заметил, что это старый поток ... Используйте incron в * nix-подобных средах, поддерживающих inotify. Он всегда будет запускать команды при изменении файлов в каталоге. т.е.

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

Вот и все.

person code933k    schedule 30.11.2010

Возможно, используйте аргумент append для ctags, как показано:

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

Я не могу ручаться за это, поскольку я обычно использую анализ исходного кода для просмотра кода, но использую vim в качестве редактора ... поймите.

person tonylo    schedule 30.09.2008

Как насчет того, чтобы запускать ctags через crontab? Если ваше дерево проекта довольно стабильно по своей структуре, это должно быть выполнимо?

person zigdon    schedule 30.09.2008
comment
+1, ПОЦЕЛУЙ. Вот пример cronjob, который я только что настроил для запуска каждый день в 2:10. Очевидно, вы можете иметь столько, сколько захотите. Мои параметры ctags предназначены для drupal, что, вероятно, больше, чем вам нужно. 10 2 * * * cd / var / www / yoursite / && / usr / bin / ctags --langmap = php: .engine.inc.module.theme.install.php --php-types = cdf --languages ​​= php - рекурсивный - person roberttstephens; 09.08.2012

Чтобы подавить запрос «нажмите ввод», используйте : silent.

person Greg Hewgill    schedule 30.09.2008

В OSX эта команда не работает "из коробки", по крайней мере, для меня.

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

Я нашел сообщение, в котором объясняется, как получить стандартные ctags версия, содержащая параметр -R. Одно это не сработало для меня. Мне пришлось добавить / usr / local / bin в переменную PATH в .bash_profile, чтобы выбрать корзину, в которую Homebrew устанавливает программы.

person rand_acs    schedule 01.09.2011

По моему мнению, плагин Indexer лучше.

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

Это может быть:

1) надстройка для project.tar.gz

2) независимый плагин

  • генерация фоновых тегов (вам не нужно ждать, пока работают ctags)
  • поддерживается несколько проектов
person dimonomid    schedule 26.03.2011

Для этого есть плагин vim под названием AutoTag, который очень хорошо работает.

Если у вас установлен список тегов, он также обновит его.

person Marcus    schedule 10.02.2011

Вариант --append - действительно правильный выбор. Используя grep -v, мы можем обновить только один помеченный файл. Например, вот отрывок из неотредактированного плагина, который решает эту проблему. (NB: потребуется "внешний" плагин библиотеки)

" 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 для принудительного обновления базы тегов для текущего (несохраненного) файла;
  • автокоманда, обновляющая базу тегов каждый раз при сохранении файла; и он поддерживает множество опций для отключения автоматического обновления там, где оно нам не нужно, для настройки вызовов ctags в зависимости от типов файлов, ... Это не просто совет, а небольшой отрывок из плагина.

HTH,

person Luc Hermitte    schedule 01.10.2008

Auto Tag - это плагин vim, который обновляет существующие файлы тегов при сохранении.

Я использую его в течение многих лет без проблем, за исключением того, что он обеспечивает максимальный размер файлов тегов. Однако, если у вас нет действительно большого набора кода, индексированного в одном файле тегов, вы не должны достигать этого предела.

Обратите внимание, что Auto Tag требует поддержки Python в vim.

person Greg Jandl    schedule 26.10.2011