web-dev-qa-db-fra.com

Vim ctags auto-générés

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 ceci:

  1. C'est lent - régénère les balises pour les fichiers qui n'ont pas changé depuis la dernière génération de balises.
  2. Je dois appuyer sur le bouton Entrée à nouvea après avoir écrit le fichier en raison d'une inévitable "appuyez sur Entrée ou tapez la commande pour continuer".

Lorsque vous combinez ces deux problèmes, je finis par pousser l'entrée supplémentaire trop tôt (avant ctags -R est terminé), puis voyez le message d'erreur gênant et appuyez de nouveau sur Entrée.

Je sais que cela ne semble pas être un gros problème, mais avec la quantité d'écritures de fichiers que je fais un jour donné, cela a tendance à devenir vraiment ennuyeux. Il doit y avoir une meilleure façon de le faire!

53
cdleary

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

L'inconvénient est que vous n'aurez pas de fichier de balises utile jusqu'à ce qu'il soit terminé. Tant que vous êtes sur un système * nix, il devrait être possible de faire plusieurs écritures avant la fin des ctags précédents, mais vous devriez le tester. Sur un système Windows, il ne le mettra pas en arrière-plan et se plaindra que le fichier est verrouillé jusqu'à la fin des premiers ctags (ce qui ne devrait pas causer de problèmes dans vim, mais vous vous retrouverez avec un fichier de balises légèrement obsolète). ).

Notez que vous pouvez utiliser le --append comme le suggère tonylo, mais vous devrez ensuite désactiver tagbsearch, ce qui pourrait signifier que les recherches de balises prennent beaucoup plus de temps, selon la taille de votre fichier de balises.

43
Zathrus

Éditer: Une solution très similaire à la suivante a été publiée sous la forme du script vim AutoTag. Notez que le script a cependant besoin d'un vim avec Python ).

Ma solution se résume à awk à la place, elle devrait donc fonctionner sur de nombreux autres systèmes.


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

Notez que vous ne pouvez l'écrire de cette façon que dans un script, sinon il doit aller sur une seule ligne.

Il se passe beaucoup de choses là-dedans:

  1. Cette commande automatique se déclenche lorsqu'un fichier a été détecté comme étant C ou C++, et ajoute à son tour une commande automatique de tampon local qui est déclenchée par l'événement BufWritePost.

  2. Il utilise le % espace réservé qui est remplacé par le nom de fichier du tampon au moment de l'exécution, avec le :gs modificateur utilisé pour citer entre guillemets le nom de fichier (en transformant les guillemets simples incorporés en guillemets-d'échappement-guillemets).

  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é à l'exception des lignes qui se réfèrent au fichier qui vient d'être enregistré, tandis que ctags est invoqué sur juste le fichier qui vient d'être enregistré, et le résultat est alors sorted et remis en place.

Implémenteur Caveat: cela suppose que tout se trouve dans le même répertoire et que c'est également le répertoire courant du tampon local. Je n'ai pas songé au cheminement.

14

J'ai écrit easytags.vim pour faire exactement cela: mettre à jour et surligner automatiquement les balises. Le plug-in peut être configuré pour mettre à jour uniquement le fichier en cours de modification ou tous les fichiers du répertoire du fichier en cours de modification (récursivement). Il peut utiliser un fichier de balises global, des fichiers de balises spécifiques au type de fichier et des fichiers de balises spécifiques au projet.

11
xolox

J'ai remarqué que c'est un vieux fil, cependant ... Utilisez incron dans * nix comme des environnements supportant inotify. Il lancera toujours des commandes chaque fois que les 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 tout.

7
code933k

Utilisez peut-être l'argument append pour ctags comme démontré par:

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

Je ne peux pas vraiment garantir cela car j'utilise généralement les informations de source pour la navigation dans le code, mais j'utilise vim comme éditeur ... allez comprendre.

3
tonylo

Que diriez-vous d'avoir des ctags planifiés pour s'exécuter via crontab? Si votre arborescence de projet est assez stable dans sa structure, cela devrait être faisable?

2
zigdon

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 de ctags qui contient l'option -R. Cela seul n'a pas fonctionné pour moi. J'ai dû ajouter/usr/local/bin à la variable PATH dans .bash_profile afin de récupérer le bac où Homebrew installe les programmes.

2
rand_acs

Pour supprimer l'invite "appuyez sur Entrée", utilisez : silencieux .

2
Greg Hewgill

Le --append l'option est en effet la voie à suivre. Utilisé avec un grep -v, nous ne pouvons mettre à jour qu'un seul fichier balisé . Par exemple, voici un extrait d'un plugin non poli qui résout ce problème. (NB: Il faudra un "externe" plugin de bibliothèque )

" 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 balises pour tous les fichiers du projet en cours;
  • ^Xtc pour forcer la mise à jour de la base de balises pour le fichier actuel (non enregistré);
  • une autocommande qui met à jour la base de balises chaque fois qu'un fichier est enregistré; et il prend en charge et de nombreuses options pour désactiver la mise à jour automatique là où nous ne le voulons pas, pour régler les appels ctags en fonction des types de fichiers, ... Ce n'est pas seulement une astuce, mais un petit extrait d'un plugin.

HTH,

1
Luc Hermitte

Il existe un plugin vim appelé AutoTag pour cela qui fonctionne vraiment bien.

Si vous avez installé la liste de balises, elle sera également mise à jour pour vous.

1
Marcus

À mon avis, le plugin Indexer est meilleur.

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

Ça peut être:

1) un module complémentaire pour project.tar.gz

2) un plugin indépendant

  • génération de balises d'arrière-plan (vous n'avez pas attendu que ctags fonctionne)
  • plusieurs projets soutenus
1
dimonomid

Auto Tag est un plugin vim qui met à jour les fichiers de balises existants lors de l'enregistrement.

Je l'utilise depuis des années sans problème, à l'exception qu'il impose une taille maximale sur les fichiers de balises. À moins que vous n'ayez un très grand ensemble de code indexé dans le même fichier de balises, vous ne devriez pas atteindre cette limite.

Notez que la balise automatique nécessite Python support dans vim.

0
Greg Jandl