Vim auto-générer ctags
en ce moment j'ai ce qui suit dans mon .vimrc
:
au BufWritePost *.c,*.cpp,*.h !ctags -R
il y a quelques problèmes avec cela:
- c'est lent -- régénère les tags pour les fichiers qui n'ont pas changé depuis la dernière génération de tags.
- je dois appuyer sur le bouton enter encore après avoir écrit le fichier en raison d'une inévitable"appuyez sur Entrée ou type commande pour continuer".
lorsque vous combinez ces deux problèmes, je finis par pousser l'entrée supplémentaire trop tôt (avant que ctags -R
ait terminé), puis voir le message d'erreur ennuyeux, et doivent pousser entrée à nouveau.
je sais que ça n'a pas l'air d'être une grosse affaire, mais avec la quantité de fichiers écrits que je fais un jour donné, ça a tendance à devenir vraiment ennuyeux. Il doit y avoir une meilleure façon de le faire!
12 réponses
au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &
l'inconvénient est que vous n'aurez pas de fichier tags utile tant qu'il ne sera pas terminé. Tant que vous êtes sur un système *nix, vous pouvez effectuer plusieurs Écritures avant que les ctags précédents ne soient terminés, mais vous devez tester cela. Sur un système Windows, il ne le mettra pas en arrière-plan et il se plaindra que le fichier est verrouillé jusqu'à ce que les premiers ctags se termine (ce qui ne devrait pas causer de problèmes dans vim, mais vous finirez avec un fichier tags légèrement périmé).
notez que vous pouvez utiliser l'option --append
comme le suggère tonylo, mais ensuite vous devrez désactiver tagbsearch
ce qui pourrait signifier que les recherches d'étiquettes prennent beaucoup plus de temps, en fonction de la taille de votre fichier d'étiquettes.
Edit : une solution très proche de ce qui suit a été publiée sous le titre le AutoTag vim script . Notez que le script a besoin d'un vim avec le support de Python , cependant.
ma solution se décompose à awk à la place, donc il devrait fonctionner sur beaucoup plus de systèmes.
au FileType {c,cpp} au BufWritePost <buffer> silent ! [ -e tags ] &&
\ ( awk -F'\t' '\!="%:gs/'/'\''/"{print}' tags ; ctags -f- '%:gs/'/'\''/' )
\ | sort -t$'\t' -k1,1 -o tags.new && mv tags.new tags
Notez que vous ne pouvez écrire c'est comme ça dans un script, Sinon ça doit aller sur une seule ligne.
il se passe beaucoup de choses là-dedans:
-
cette auto-commande déclenche lorsqu'un fichier a été détecté comme étant C ou C++, et ajoute à son tour une auto-commande buffer-local qui est déclenchée par l'événement
BufWritePost
. -
il utilise le paramètre
%
qui est remplacé par le nom du fichier du tampon lors de l'exécution time, ainsi que le modificateur:gs
utilisé pour shell-quote le nom de fichier (en transformant n'importe quel single-quotes incorporé en quote-escape-quote). -
de cette façon, il exécute une commande shell qui vérifie si un fichier
tags
existe, auquel cas son contenu est imprimé sauf pour les lignes qui se réfèrent au fichier juste sauvegardé, pendant quectags
est invoqué sur juste le fichier juste sauvegardé, et le résultat est alorssort
ed et remis dans lieu.
Caveat implementor: cela suppose que tout est dans le même répertoire et que c'est aussi le répertoire courant Local. Je n'ai pas donné toute la pensée de chemin de déformation.
j'ai écrit easytags.vim pour ce faire: mettre à jour et surligner automatiquement les balises. Le plug-in peut être configuré pour mettre à jour uniquement le fichier en cours d'édition ou tous les fichiers du répertoire du fichier en cours d'édition (de façon récursive). Il peut utiliser un fichier Global tags, des fichiers de type de fichier tags spécifiques et des fichiers de projet tags spécifiques.
j'ai remarqué que c'est un vieux fil, cependant... Utilisez incron dans des environnements similaires à ceux de nix supportant inotify. Il lancera toujours des commandes chaque fois que des fichiers d'un répertoire changent. c'est à dire,
/home/me/Code/c/that_program IN_DELETE,IN_CLOSE_WRITE ctags --sort=yes *.c
C'est ça.
peut-être utiliser l'argument d'ajout aux ctags comme démontré par:
http://vim.wikia.com/wiki/Autocmd_to_update_ctags_file
Je ne peux pas vraiment me porter garant pour cela car j'utilise généralement source insight pour la navigation de code, mais utiliser vim comme un éditeur... aller à la figure.
Que Diriez-vous d'avoir des ctags programmés pour fonctionner via crontab? Si votre arbre de projet est assez stable dans sa structure, cela devrait être faisable?
sur OSX cette commande ne fonctionnera pas hors de la boîte, du moins pas pour moi.
au BufWritePost *.c,*.cpp,*.h silent! !ctags -R &
j'ai trouvé un post , qui explique comment obtenir la version standard ctags qui contient l'option-r. Seul, cela n'a pas fonctionné pour moi. J'ai dû ajouter /usr/local / bin à la variable PATH in .bash_profile afin de récupérer la corbeille où Homebrew installe les programmes.
dans mon opninion, indexeur de plugin est mieux.
http://www.vim.org/scripts/script.php?script_id=3221
Il peut être:
1) un add-on pour le projet.tar.gz
2) Un plugin indépendant
- arrière-plan balises génération (vous n'avez pas attendre que ctags œuvres)
- projets multiples soutenus
l'option --append
est en effet la voie à suivre. Utilisé avec un grep -v
, nous ne pouvons mettre à jour qu'un seul fichier étiqueté . Par exemple, voici un extrait d'un plugin non poli qui traite de cette question. (NB: Il faudra un "external" bibliothèque plugin )
" 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
ce code définit:"
-
^Xta
pour forcer la mise à jour de la base de tags pour tous les fichiers du projet en cours; -
^Xtc
pour forcer la mise à jour de la base des tags pour le fichier courant (non enregistré); - un autocommand qui met à jour la base des tags chaque fois qu'un fichier est sauvegardé ; et il supporte et de nombreuses options pour désactiver la mise à jour automatique là où nous ne le voulons pas, pour accorder les appels ctags en fonction des types de fichiers, ... Il n'est pas juste un conseil, mais un petit extrait d'un plugin.
HTH,
Auto Tag est un plugin vim qui met à jour les fichiers de tag existants sur save.
Je l'utilise depuis des années sans problème, à l'exception qu'il impose une taille maximale sur les fichiers tags. Sauf si vous avez un très grand ensemble de code tous indexés dans le même fichier tags, vous ne devriez pas frapper cette limite, cependant.
notez que la balise automatique nécessite le support Python dans vim.