2009-07-21 13 views
32

Uso il file di tag vim C++ per la navigazione con Ctrl-]. Il problema è che ogni volta che un file viene modificato, i collegamenti non sono più validi e devo rieseguire i ctags e aggiornare il file dei tag. La nostra base di codice è enorme e ci vuole un po 'di tempo per generare file di tag.Come aggiornare automaticamente il file di tag in vim?

C'è uno strumento che aggiorna periodicamente il file di tag in background? Posso configurare VIM per fare lo stesso?

Io uso gvim sotto Windows.

risposta

25

seguito alla risposta di Blixtor, avrete bisogno di pensare un po 'attentamente la progettazione dello script. Suggerirei di separare la progettazione in modo che l'autocomando utilizzi il comando "start" di Windows o simile per eseguire uno script esterno sullo sfondo: impedendo così a Vim di non rispondere mentre viene generato il file di tag.

Questo script potrebbe quindi generare il file di tag utilizzando un nome di file diverso (vale a dire non "tag": ctags -R -o newtags .) e, quando ctags è completa, eliminare e rinominare tagsnewtags-tags. Ciò impedirà che il file di tag non sia disponibile in Vim mentre la generazione è terminata.

+2

ulteriori punti importanti! – Blixtor

+0

@ AI, c'è una soluzione simile per Linux ?! – Rafid

+0

Per Linux, immagino che potresti eseguire il comando con & per inserirlo in background, no? –

9

Un'idea:

autocomandi uso Vim (: help autocomando) per attivare l'esecuzione di uno script ogni volta che un buffer viene salvato utilizzando l'evento BufWritePost.

Questo script avvia la generazione di ctags e contiene alcune piccole logiche aggiuntive per non essere eseguito mentre è già in esecuzione (o per essere eseguito al massimo ogni 10 minuti, ecc.).

Edit:

Qualcosa di simile è stato chiesto qui in precedenza, vedere Vim auto-generate ctags

1

Questa logica funziona per la maggior parte dei casi: quando si apre un nuovo file in vim, passare alla directory di quel file e generare lì un file di tag se non esiste già. Quando si salva un buffer cambiato, generare un file tag nella directory del file viene salvato:


function! GenerateTagsFile() 
    if (!filereadable("tags")) 
    exec ":!start /min ctags -R --c++-kinds=+p --fields=+iaS --extra=+q --sort=foldcase ." 
    endif 
endfunction 

" Always change to directory of the buffer currently in focus. 
autocmd! bufenter *.* :cd %:p:h 
autocmd! bufread *.* :cd %:p:h 

" Generate tags on opening an existing file. 
autocmd! bufreadpost *.cpp :call GenerateTagsFile() 
autocmd! bufreadpost *.c :call GenerateTagsFile() 
autocmd! bufreadpost *.h :call GenerateTagsFile() 

" Generate tags on save. Note that this regenerates tags for all files in current folder. 
autocmd! bufwritepost *.cpp :call GenerateTagsFile() 
autocmd! bufwritepost *.c :call GenerateTagsFile() 
autocmd! bufwritepost *.h :call GenerateTagsFile() 
+0

si potrebbe voler usare: call system() invece, in questo modo sarebbe portatile, è possibile ottenere qualsiasi output tramite 'let l: lines = system ("cmdline")' e il codice di ritorno è restituito in v: shell_error. – osirisgothra

18

ho scritto il vim-easytags plug-in per fare esattamente questo. Inizializzo il mio file di tag una volta scansionando un intero progetto (usando il comando :UpdateTags **/*.[hc] per esempio) e in seguito il plug-in aggiornerà automaticamente il file dei tag mentre modificherò e i file del codice sorgente :update in Vim. Mentre aggiorna il file dei tag, blocca Vim, ma poiché esegue solo la scansione del file corrente non richiede molto tempo.

Aggiornamento (2014-07-30): Ancora lavorando al plug-in vim-easytags :-). Al giorno d'oggi supporta una modalità asincrona per evitare il blocco di Vim. Nel momento in cui scrivo questo, la modalità asincrona non è ancora la modalità predefinita, ma dopo un po 'più di feedback probabilmente cambierò la modalità predefinita.

+0

Hmmm modifica dal futuro. (Mentre sono qui ...) come si confronta a [AutoTag] (http://www.vim.org/scripts/script.php?script_id=1343). – FDinoff

+0

@FDinoff: AutoTag sembra molto più semplice, quindi un fattore di differenziazione è la completezza/configurabilità/complessità. Un'altra differenza è che i vim-easytags possono aggiornare * ed evidenziare * i tag mentre AutoTag sembra concentrarsi solo sulla parte di aggiornamento. Inoltre, AutoTag richiede Python mentre vim-easytags può funzionare senza. – xolox

+0

"Questo plug-in crea automaticamente un file di tag globale e lo aggiorna man mano che si modificano i file in Vim." Come posso mantenere tag separati per progetti diversi anziché uno globale singolo? @xolox – Tmx

10

Ho già scritto un plugin per fare tutto il duro lavoro con ctags: Indexer.

Fornisce una generazione automatica di tag automatici per l'intero progetto (i) e mantiene i tag aggiornati. I tag vengono generati nello sfondo, quindi non è necessario attendere mentre i tag ctags generano tag. Puoi utilizzarlo indipendentemente o come componente aggiuntivo per un altro plug-in project.tar.gz.

Nel primo modo, è possibile dichiarare i vostri progetti in ~/.indexer_files come questo:

[CoolProject] 

/home/user/cool_project 

[AnotherProject] 
option:ctags_params = "--languages=c++" 

/home/user/another_project/src 
/home/user/another_project/lib 

E poi, quando si apre un file da /home/user/cool_project, tutto questo progetto verrà indicizzato da ctags. Quando apri tag da un altro progetto, anche i tag vengono generati. I tag di diversi progetti non sono mai mescolati. Quando salvi il file dal progetto, i tag vengono aggiornati silenziosamente. Non devi preoccupartene, funziona e basta.

Per informazioni dettagliate, vedere l'articolo: Vim: convenient code navigation for your projects, che spiega a fondo l'utilizzo di Indexer + Vimprj.

E 'testato con successo su Vim 7.3, sui seguenti sistemi:

  • Archlinux

  • Ubuntu 10.4

  • Windows XP

  • Mac OS X Lion

1

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

function! DelTagOfFile(file) 
    let fullpath = a:file 
    let cwd = getcwd() 
    let tagfilename = cwd . "/tags" 
    let f = substitute(fullpath, cwd . "/", "", "") 
    let f = escape(f, './') 
    let cmd = 'sed -i "/' . f . '/d" "' . tagfilename . '"' 
    let resp = system(cmd) 
endfunction 

function! UpdateTags() 
    let f = expand("%:p") 
    let cwd = getcwd() 
    let tagfilename = cwd . "/tags" 
    let cmd = 'ctags -a -f ' . tagfilename . ' --c++-kinds=+p --fields=+iaS --extra=+q ' . '"' . f . '"' 
    call DelTagOfFile(f) 
    let resp = system(cmd) 
endfunction 
autocmd BufWritePost *.cpp,*.h,*.c call UpdateTags() 
Problemi correlati