Vim автоматически генерирует ctags
-
03-07-2019 - |
Вопрос
Прямо сейчас у меня есть следующее в моем .vimrc
:
au BufWritePost *.c,*.cpp,*.h !ctags -R
С этим связано несколько проблем:
- Это медленно - восстанавливает теги для файлов, которые не менялись с момента последнего создания тегов.
- Я должен нажать кнопку ввода снова после записи файла из-за неизбежного "нажмите Enter или введите команду для продолжения".
Когда вы объединяете эти две проблемы, я в конечном итоге нажимаю дополнительный ввод слишком рано (до ctags -R
завершено), затем увидите раздражающее сообщение об ошибке и должны снова нажать enter.
Я знаю, это не кажется чем-то особенным, но из-за количества записей в файл, которые я делаю в данный день, это, как правило, становится действительно раздражающим.Должен быть лучший способ сделать это!
Решение
au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &
Недостатком является то, что у вас не будет полезного файла тегов, пока он не будет завершен.Пока вы используете систему * nix, должно быть нормально выполнять несколько записей до завершения предыдущих ctags, но вы должны это протестировать.В системе Windows он не переведет его в фоновый режим и будет жаловаться, что файл заблокирован до завершения выполнения первых ctags (что не должно вызвать проблем в vim, но в итоге вы получите слегка устаревший файл tags).
Обратите внимание, что вы могли бы использовать --append
вариант, как предлагает tonylo, но тогда вам придется отключить tagbsearch
это может означать, что поиск по тегам займет намного больше времени, в зависимости от размера вашего файла тегов.
Другие советы
Редактировать:Решение, очень похожее на следующее, было опубликовано как тот самый АвтоТег 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
Обратите внимание, что вы можете написать это таким образом только в скрипте, в противном случае это должно быть в одной строке.
Там много чего происходит:
Эта автоматическая команда запускается, когда было обнаружено, что файл является C или C ++, и добавляет, в свою очередь, автоматическую команду для локального буфера, которая запускается
BufWritePost
событие.Он использует
%
заполнитель, который заменяется именем файла буфера во время выполнения, вместе с:gs
модификатор, используемый для ввода имени файла в оболочечные кавычки (путем превращения любых встроенных одинарных кавычек в кавычки-escape-quote-цитата).Таким образом, он запускает команду оболочки, которая проверяет, есть ли
tags
файл существует, и в этом случае печатается его содержимое, за исключением строк, которые ссылаются на только что сохраненный файл, между темctags
вызывается только для только что сохраненного файла, и тогда результатом будетsort
отредактируйте и поставьте на место.
Исполнитель предостережения:это предполагает, что все находится в одном каталоге и что это также текущий каталог buffer-local.Я не задумывался о том, чтобы исказить дорожку.
Я написал easytags.vim чтобы сделать именно это:автоматически обновляйте и выделяйте теги.Подключаемый модуль может быть настроен на обновление только редактируемого файла или всех файлов в каталоге редактируемого файла (рекурсивно).Он может использовать глобальный файл тегов, файлы тегов определенного типа и файлы тегов конкретного проекта.
Однако я заметил, что это старая тема...Использование инкрон в *nix-подобных средах поддерживается inotify.Он всегда будет запускать команды всякий раз, когда файлы в каталоге изменяются.т. е.,
/home/me/Code/c/that_program IN_DELETE,IN_CLOSE_WRITE ctags --sort=yes *.c
Вот и все.
Возможно, используйте аргумент append к ctags, как показано в:
http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file
Я не могу за это ручаться, так как обычно использую source insight для просмотра кода, но использую vim в качестве редактора...пойди разберись.
Как насчет того, чтобы запланировать запуск ctags через crontab?Если дерево вашего проекта достаточно стабильно по своей структуре, это должно быть выполнимо?
Чтобы отключить запрос "нажмите enter", используйте :бесшумный.
В OSX эта команда не будет работать "из коробки", по крайней мере, для меня.
au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &
Я нашел Публикация, в котором объясняется, как получить стандартную версию ctags, содержащую опцию -R.Само по себе это у меня не сработало.Мне пришлось добавить /usr/local/bin в переменную PATH в .bash_profile, чтобы выбрать папку, в которую Homebrew устанавливает программы.
На мой взгляд, индексатор плагинов лучше.
http://www.vim.org/scripts/script.php?script_id=3221
Это может быть:
1) дополнение для project.tar.gz
2) независимый плагин
- генерация фоновых тегов (вам не нужно ждать, пока ctags заработает)
- поддерживается несколько проектов
Существует плагин vim, который называется АвтоТег для этого это работает действительно хорошо.
Если у вас установлен список тегов, он также обновит его для вас.
Тот Самый --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
принудительно обновить базу тегов для текущего (несохраненного) файла ;- автокоманда, которая обновляет базу тегов каждый раз при сохранении файла ;и он поддерживает множество опций для отключения автоматического обновления там, где мы этого не хотим, для настройки вызовов ctags в зависимости от типов файлов, ...Это не просто совет, а небольшая выдержка из плагина.
HTH,
Auto Tag - это плагин vim, который обновляет существующие файлы тегов при сохранении.
Я использую его в течение многих лет без проблем, за исключением того, что он устанавливает максимальный размер файлов тегов.Однако, если у вас нет действительно большого набора кода, проиндексированного в одном файле тегов, вы не должны превышать этот предел.
Обратите внимание, что для автоматического тегирования требуется поддержка Python в vim.