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:

  1. 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.
  2. 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!

52
demandé sur cdleary 2008-10-01 02:47:30

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.

41
répondu Zathrus 2011-10-01 00:07:22

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:

  1. 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 .

  2. 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).

  3. 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 que ctags est invoqué sur juste le fichier juste sauvegardé, et le résultat est alors sort 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.

13
répondu Aristotle Pagaltzis 2009-01-29 19:24:01

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.

10
répondu xolox 2013-06-19 17:52:50

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.

7
répondu code933k 2010-11-30 05:46:46

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.

3
répondu tonylo 2008-09-30 23:01:38

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?

2
répondu zigdon 2008-09-30 22:55:34

pour supprimer l'invite" press enter", utiliser : muet .

2
répondu Greg Hewgill 2008-09-30 23:03:15

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.

2
répondu rand_acs 2011-09-01 10:45:09

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
1
répondu dimonomid 2011-05-13 05:37:29

il y a un plugin vim appelé AutoTag pour cela qui fonctionne vraiment bien.

si vous avez taglist installé il mettra également à jour cela pour vous.

1
répondu Marcus 2015-01-27 17:07:10

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,

1
répondu Luc Hermitte 2015-03-16 17:34:09

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.

0
répondu Greg Jandl 2011-10-26 22:15:27