Può vim monitorare le modifiche in tempo reale a un file


104

La mia domanda è simile a questa su come monitorare un file di testo in tempo reale, ma voglio farlo in vim. So di poter leggere un file aperto usa il tail -f sample.xmlfile e quando viene scritto un nuovo contenuto nel file, scriverà anche il nuovo contenuto sul mio schermo. Posso fare in modo che vim riempia automaticamente i nuovi dati quando un file viene aggiornato?

Risposte:


101

Puoi :set autoreadcosì che vim legga il file quando cambia. Tuttavia (a seconda della piattaforma), devi concentrarti.

Dall'aiuto:

Quando viene rilevato che un file è stato modificato al di fuori di Vim e non è stato modificato all'interno di Vim, leggerlo di nuovo automaticamente. Quando il file è stato cancellato, ciò non viene fatto.


5
Grazie per il suggerimento! Sembra piuttosto promettente, ma non funziona sul mio sistema :( Sto usando Mac10.6.2 iTerm con vim versione 7.2.303 compilata con MacVim. Qualche commento aggiuntivo che posso provare?
Patrick

Ehm, è piuttosto strano. stai usando la GUI macvim o la versione terminale? funziona per me con macvim gui scaricato precompilato. (Devo fare clic sull'app per concentrarla, come ho già detto.)
Peter,

1
Stavo testando nel terminale, dopo aver usato gvim (MacVim GUI) la funzione ha iniziato a funzionare! Come hai detto, però, devo concentrarmi su gvim per aggiornare il contenuto. Hai qualche trucco per aggiornarlo anche senza mettere a fuoco? Grazie ancora per il tuo aiuto.
Patrick

3
Non conosco una soluzione a questo, purtroppo. Sarei sbalordito se vim potesse farlo senza il cambio di focus - richiederebbe a vim di interrogare il filesystem per vedere quando cambia. Penso che avresti bisogno di un plugin per questo.
Peter

2
@Peter Ho creato un plugin del genere qualche tempo fa. Vedi anche questa domanda e la mia risposta . per maggiori dettagli su come autoreadfunziona e sui suoi limiti.
Martin Tournoij

63

Non so automaticamente, ma puoi digitare:

:e!

per ricaricare il file


Sebbene questo approccio non aggiorni automaticamente il contenuto, visualizza il contenuto aggiornato. Grazie per la tua risposta!
Patrick

31

Metti quanto segue nel tuo .vimrc:

"selezionare una volta dopo 4 secondi di inattività in modalità normale
imposta la lettura automatica                                                                                                                                                                                    
au CursorHold * checktime                                                                                                                                                                       

Grande! Funziona bene, anche con un avviso se hai modificato quel file dall'ultimo ricaricamento.
zoujyjs

1
La prima risposta non ha funzionato per me, ma funziona! :-)
Ionică Bizău

4
"Ogni 4 secondi" non è vero. Questo controllerà solo una volta dopo 4 secondi di inattività in modalità normale. Quindi, se non fai nulla in un altro buffer per molto tempo, non verrà aggiornato, ma lo sarebbe se sposti il ​​cursore e attendi 4 secondi. Un'altra opzione è chiamare manualmente ": checktime" per aggiornare (dopo aver impostato la lettura automatica). Sfortunatamente non sembra esserci alcun tipo di supporto per i sondaggi in vim, quindi non c'è una vera risposta alla domanda dei PO.
David Ljung Madison Stellar

1
Mi sono appena imbattuto in questo. Se modifichi checktime per chiamare una funzione personalizzata e aggiungi "call feedkeys (" lh ")" alla fine della funzione, verrà attivata ogni 4 secondi.
flukus

@DavidLjungMadison hai ragione, modificherò il post per evitare questo errore
Phan Hai Quang

9

come ha detto @flukus in un commento a una risposta precedente puoi call feedkeys["lh"](sposta il cursore a destra e di nuovo a sinistra, il che normalmente non fa male durante la visualizzazione di un file di registro)

Quindi, se combini il resto della risposta hai un oneliner che puoi eseguire da ex (all'interno di vim) quando necessario:

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


(se vuoi saltare (quasi) alla fine del file, usa semplicemente "G" invece di "lh" con i feedkeys)

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 è 4000 millisecondi per impostazione predefinita) viene eseguito il checktime, che controlla le modifiche dall'esterno del file
- chiama feedkeys ("lh") : il cursore viene spostato una volta, a destra e indietro a sinistra. e poi non accade nulla (... il che significa che CursorHold è attivato, il che significa che abbiamo un ciclo )

Inoltre puoi :set syntax=logtalkcolorare il registro

Per interrompere lo scorrimento durante l'uso call feedkeys("G"), eseguire :set noautoread- ora vim dirà che il file è stato modificato e chiedere se si desidera leggere o meno le modifiche)

(Questo ha effetti collaterali?)

Modifica: vedo un effetto collaterale: se si usa "G" come feedkey, scorrerà verso il basso ogni buffer attualmente aperto ?! Quindi, non è possibile lavorare nel buffer sinistro di una finestra suddivisa mentre il buffer destro fa scorrere automaticamente un file di registro verso il basso


4

Inseriscilo nel tuo .vimrc e dovrebbe funzionare come un boss. (Tratto da: http://vim.wikia.com/wiki/Have_Vim_check_automatically_if_the_file_has_changed_externally )

" Function to Watch for changes if buffer changed on disk
function! WatchForChanges(bufname, ...)
  " Figure out which options are in effect
  if a:bufname == '*'
    let id = 'WatchForChanges'.'AnyBuffer'
    " If you try to do checktime *, you'll get E93: More than one match for * is given
    let bufspec = ''
  else
    if bufnr(a:bufname) == -1
      echoerr "Buffer " . a:bufname . " doesn't exist"
      return
    end
    let id = 'WatchForChanges'.bufnr(a:bufname)
    let bufspec = a:bufname
  end
  if len(a:000) == 0
    let options = {}
  else
    if type(a:1) == type({})
      let options = a:1
    else
      echoerr "Argument must be a Dict"
    end
  end
  let autoread    = has_key(options, 'autoread')    ? options['autoread']    : 0
  let toggle      = has_key(options, 'toggle')      ? options['toggle']      : 0
  let disable     = has_key(options, 'disable')     ? options['disable']     : 0
  let more_events = has_key(options, 'more_events') ? options['more_events'] : 1
  let while_in_this_buffer_only = has_key(options, 'while_in_this_buffer_only') ? options['while_in_this_buffer_only'] : 0
  if while_in_this_buffer_only
    let event_bufspec = a:bufname
  else
    let event_bufspec = '*'
  end
  let reg_saved = @"
  "let autoread_saved = &autoread
  let msg = "\n"
  " Check to see if the autocommand already exists
  redir @"
    silent! exec 'au '.id
  redir END
  let l:defined = (@" !~ 'E216: No such group or event:')
  " If not yet defined...
  if !l:defined
    if l:autoread
      let msg = msg . 'Autoread enabled - '
      if a:bufname == '*'
        set autoread
      else
        setlocal autoread
      end
    end
    silent! exec 'augroup '.id
      if a:bufname != '*'
        "exec "au BufDelete    ".a:bufname . " :silent! au! ".id . " | silent! augroup! ".id
        "exec "au BufDelete    ".a:bufname . " :echomsg 'Removing autocommands for ".id."' | au! ".id . " | augroup! ".id
        exec "au BufDelete    ".a:bufname . " execute 'au! ".id."' | execute 'augroup! ".id."'"
      end
        exec "au BufEnter     ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHold   ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHoldI  ".event_bufspec . " :checktime ".bufspec
      " The following events might slow things down so we provide a way to disable them...
      " vim docs warn:
      "   Careful: Don't do anything that the user does
      "   not expect or that is slow.
      if more_events
        exec "au CursorMoved  ".event_bufspec . " :checktime ".bufspec
        exec "au CursorMovedI ".event_bufspec . " :checktime ".bufspec
      end
    augroup END
    let msg = msg . 'Now watching ' . bufspec . ' for external updates...'
  end
  " If they want to disable it, or it is defined and they want to toggle it,
  if l:disable || (l:toggle && l:defined)
    if l:autoread
      let msg = msg . 'Autoread disabled - '
      if a:bufname == '*'
        set noautoread
      else
        setlocal noautoread
      end
    end
    " Using an autogroup allows us to remove it easily with the following
    " command. If we do not use an autogroup, we cannot remove this
    " single :checktime command
    " augroup! checkforupdates
    silent! exec 'au! '.id
    silent! exec 'augroup! '.id
    let msg = msg . 'No longer watching ' . bufspec . ' for external updates.'
  elseif l:defined
    let msg = msg . 'Already watching ' . bufspec . ' for external updates'
  end
  echo msg
  let @"=reg_saved
endfunction

let autoreadargs={'autoread':1}
execute WatchForChanges("*",autoreadargs)

1
Questa è la risposta preferita per affrontare le carenze della lettura automatica del terminale.
mcanfield

3
@mcanfield No, non lo è perché ancora non "osserva i cambiamenti". Devi ancora avere Vim attivo e sta ancora interrogando (non guardando) su un insieme limitato di eventi. CursorHoldviene eseguito una volta . Quindi, se esci e prendi un caffè o stai facendo qualcosa in un'altra finestra, non si aggiornerà.
Martin Tournoij

4
Lo script è anche fornito in bundle come plugin Vim: vim-autoread .
stephen.hanson

1
@ stephen.hanson Grazie per il collegamento, quel plugin funziona bene per me!
Tropilio


2

Se unix + neovim

:term tail -f <filename>

Ovviamente questo non funzionerà per tutti, ma è come lo faccio io.



0

VIM ti avviserà quando un file è stato aggiornato in modo da non sovrascrivere le modifiche apportate da quando lo hai aperto. A quel punto ti verrà chiesto di ricaricare il file.


1
Grazie per la tua risposta, ma vim non mi ha avvisato quando il file è stato modificato nel mio sistema :(
Patrick
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.