Come posso fare in modo che Vim autoread un file mentre non ha lo stato attivo?


29

Sto usando VIm per tutti i tipi di cose (o gVim in questo caso), incluso il monitoraggio dell'output scritto in un file; Uso autoreadper far rileggere Vim al file, cosa che fa ogni volta che cambio lo stato attivo della tastiera.

Esiste un modo per fare in modo che Vim aggiorni il buffer anche se non cambio lo stato attivo della tastiera? Ho provato a impostare checktimema non sembra avere alcun effetto mentre la messa a fuoco della tastiera è altrove.

L'output che sto monitorando sta sostituendo completamente il file di output; e non ci sto guardando tail -f. Ci sono altre opzioni, come il piping in una nuova istanza ogni volta, o il piping in lesso qualcosa del genere, ma sarebbe bello se si potesse fare con VIm.


@Carpetsmoker che ne dici CursorHolddell'evento? Se Vim non ha lo stato attivo, dovrebbe attivarsi ogni n secondi.
muru,

1
@muru No, CursorHoldviene eseguito solo una volta, questo è esplicitamente documentato come: "non spara ogni" aggiornamento "ms se lasci Vim per fare un caffè. :)"
Martin Tournoij

1
Ho rimosso di nuovo il tag gvim , spero che vada bene ;-) A mio modo di vedere, questa domanda non riguarda davvero gVim, poiché il cambio di focus è solo un evento in cui Vim controlla se il file è cambiato (ce ne sono molti, vedi la mia risposta per i dettagli). La maggior parte, se non tutti, i modi per migliorarlo funzioneranno bene sia in Vim che in gVim.
Martin Tournoij,

@Carpetsmoker ah, avevo l'impressione che gVim controllasse regolarmente mentre aveva il focus sulla tastiera (rendendolo quindi una domanda gVim), ma sembra che mi sbagliassi. Grazie per averlo chiarito.
falstro,

Risposte:


20

Aggiornamento 25/06/2015 :

  • Ho eliminato il metodo "shell", poiché era troppo disfunzionale. Ha interrotto la modalità di inserimento e ha lasciato i processi di zombi. Guarda la cronologia delle revisioni di questo post se vuoi davvero vederla comunque.
  • Da questo ho creato un plug-in: auto_autoread.vim . Al momento, è effettivamente lo stesso del codice seguente, ma ti consiglio di utilizzare il plug-in poiché è probabile che questo riceva aggiornamenti.

Cosa fa autoread?

Per rispondere a questa domanda, dobbiamo prima capire cosa fa l' autoreadopzione e, cosa più importante, cosa non fa.

Sfortunatamente :help 'autoread' non ci sono molte informazioni al riguardo, dice solo "è stato rilevato che un file è stato modificato al di fuori di Vim" . In che modo Vim rileva che un file è cambiato? Su alcune azioni, Vim controlla il tempo di modifica del file.

Quando:

  • :checktime viene usato;
  • viene inserito un buffer;
  • :diffupdate viene usato;
  • :e viene emesso per un file che ha già un buffer;
  • eseguire un comando esterno con !;
  • tornare in primo piano ( ^Z, fgsolo se la shell ha il controllo del lavoro);

per gVim, questo viene fatto anche quando:

  • chiudendo il menu "tasto destro" (selezionando qualcosa o semplicemente chiudendolo);
  • lo stato attivo è cambiato (questo è quello che hai già notato);
  • chiudendo la finestra di dialogo dei browser di file che si apre se si utilizza "file -> apri", "file -> salva come" dal menu (così come in altri luoghi).

Ho raccolto queste informazioni dalla fonte Vim individuando tutte le chiamate a buf_check_timestamp(), check_timestamps()funzioni e posizioni su cui need_check_timestampsè impostata TRUE.

Potrei aver perso alcuni eventi, ma la cosa fondamentale da ricordare è che Vim verifica solo se il file viene modificato in una serie molto limitata di circostanze . Certamente non "poll" il file per le modifiche mai n secondi, che è fondamentalmente quello che stai cercando.

Quindi, per il tuo scopo, set autoreadnon è abbastanza.

Usando Python

Questo programma l'esecuzione di un thread Python in background, verrà eseguito :checktimeogni n secondi. Se autoreadviene attivato , questo ricaricherà il buffer dal disco, altrimenti sarà solo avvertire.

Ciò richiede che Vim abbia +pythono +python3dentro :version. Dovrebbe funzionare su tutte le piattaforme (incluso Windows).

fun! AutoreadPython()
python << EOF
import time, vim
try: import thread
except ImportError: import _thread as thread # Py3

def autoread():
    vim.command('checktime')  # Run the 'checktime' command
    vim.command('redraw')     # Actually update the display

def autoread_loop():
    while True:
        time.sleep(1)
        autoread()

thread.start_new_thread(autoread_loop, ())
EOF
endfun

Puoi iniziare usando :call AutoreadPython(); puoi ovviamente farlo in un autocmd; per esempio:

autocmd *.c call AutoreadPython()

postfazione

Esistono in realtà più metodi, ad esempio è possibile utilizzare uno strumento come entro Python inotifyo il gaminmodulo per monitorare un file per le modifiche, :checktimecontrolla anche tutti i buffer se non viene fornito alcun argomento, questo può essere migliorato controllando solo un singolo buffer o un certo file.
Tuttavia, questa risposta è già piuttosto lunga :-) Questi metodi dovrebbero (si spera!) Funzionare bene per la maggior parte degli scenari o dovrebbero essere facilmente adattabili al tuo scenario.

PS. Ho anche provato a usare Ruby, ma sfortunatamente i thread di Ruby (usando Thread) non funzionano in background come fa Python, quindi non sono riuscito a farlo funzionare (forse c'è un altro modo, però?)


2

Ho creato un piccolo plugin vim-autoread che utilizza tail -fper aggiornare il buffer in background in modo asincrono. Ciò richiede ovviamente la funzione di lavoro di Vim versione 8.

Utilizzare :AutoReadper accenderlo e :AutoRead!per spegnerlo.


Una versione compatibile con NeoVim sarebbe fantastica!
Andrew,

@AndrewMacFie Non vedo, perché questo non funzionerebbe su Neovim.
Christian Brabandt,

la mancanza del supporto per Vim 8 lavori in NeoVim ho pensato?
Andrew,

@AndrewMacFie oh, probabilmente è vero. Dal momento che non utilizzo Neovim, non riesco a renderlo compatibile con NeoVim. Comunque un PR sarebbe il benvenuto :)
Christian Brabandt,

abbastanza giusto:)
Andrew

1

In Neovim potresti usare il seguente comando che aprirà un buffer terminale che esegue il comando tail.

:enew | call termopen('tail --follow=name --retry /path/to/file.log')

Ciò continuerà a funzionare anche se il file viene rimosso e ricreato.

Oppure aggiungi quanto segue al tuo $MYVIMRC

" :Tail /path/to/file
function! Tail(file)
  enew
  call termopen('tail --follow=name --retry ' . fnameescape(a:file))
endfunction
command! -nargs=1 Tail call Tail(<f-args>)

1

da questa risposta (riferendosi a una risposta di PhanHaiQuang e un commento di flukus )

È possibile eseguire questo oneliner da ex (con vim) quando necessario (o mettere ogni comando in vimrc, per quando vengono aperti i file di registro).

:set autoread | au CursorHold * checktime | call feedkeys("lh")

Spiegazione:
- Autoread : legge il file quando viene modificato dall'esterno (ma non funziona da solo, non esiste un timer interno o qualcosa del genere. Leggerà il file solo quando vim esegue un'azione, come un comando in ex :!
- CursorHold * checktime : quando il cursore non viene spostato dall'utente per il tempo specificato in 'updatetime' (che è di default 4000 millisecondi) viene eseguito il checktime, che controlla le modifiche al di fuori del file
- call feedkeys ("lh") : il cursore viene spostato una volta, a destra e indietro a sinistra. E poi non succede nulla (... il che significa che viene attivato CursorHold, il che significa che abbiamo un loop )

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.