Kann vim Echtzeitänderungen an einer Datei überwachen

104

Meine Frage ist ähnlich wie beim Überwachen einer Textdatei in Echtzeit, aber ich möchte dies in vim tun. Ich weiß, dass ich eine geöffnete Datei lesen kann tail -f sample.xml, und wenn neuer Inhalt in die Datei geschrieben wird, schreibt er auch den neuen Inhalt auf meinen Bildschirm. Kann ich vim die neuen Daten automatisch füllen lassen, wenn eine Datei aktualisiert wird?

Patrick
quelle

Antworten:

101

Sie können :set autoread damit vim die Datei lesen, wenn sie sich ändert. Allerdings müssen Sie (abhängig von Ihrer Plattform) den Fokus darauf legen.

Aus der Hilfe:

Wenn festgestellt wurde, dass eine Datei außerhalb von Vim geändert wurde und innerhalb von Vim nicht geändert wurde, lesen Sie sie automatisch erneut. Wenn die Datei gelöscht wurde, erfolgt dies nicht.

Peter
quelle
5
Danke für den Tipp! Das sieht ziemlich vielversprechend aus, funktioniert aber auf meinem System nicht :( Ich verwende Mac10.6.2 iTerm mit vim Version 7.2.303, kompiliert mit MacVim. Gibt es einen zusätzlichen Kommentar, den ich versuchen kann?
Patrick
ähm, das ist ziemlich komisch. Verwenden Sie die Macvim-GUI oder die Terminal-Version? es funktioniert bei mir mit macvim gui heruntergeladen vorkompiliert. (Ich muss jedoch auf die App klicken, um sie zu fokussieren, wie ich bereits erwähnte.)
Peter
1
Ich habe im Terminal getestet, nachdem ich gvim (MacVim GUI) verwendet hatte, begann die Funktion zu funktionieren! Wie Sie bereits erwähnt haben, muss ich mich auf gvim konzentrieren, um den Inhalt zu aktualisieren. Haben Sie einen Trick, um es auch ohne Fokussierung zu aktualisieren? Nochmals vielen Dank für Ihre Hilfe.
Patrick
3
Ich kenne leider keine Lösung dafür. Ich wäre fassungslos, wenn vim dies ohne Änderung des Fokus tun könnte - es würde erfordern, dass vim das Dateisystem abfragt, um zu sehen, wann es sich ändert. Ich denke, dafür brauchst du ein Plugin.
Peter
2
@ Peter Ich habe vor einiger Zeit so ein Plugin gemacht . Siehe auch diese Frage und meine Antwort darauf . Weitere Informationen zur Funktionsweise autoreadund den Einschränkungen.
Martin Tournoij
63

Ich weiß es nicht automatisch, aber Sie können Folgendes eingeben:

:e!

um die Datei neu zu laden

dimba
quelle
Obwohl dieser Ansatz den Inhalt nicht automatisch aktualisiert, wird der aktualisierte Inhalt angezeigt. Danke für deine Antwort!
Patrick
31

Geben Sie Folgendes in Ihre ein .vimrc:

"Überprüfen Sie einmal nach 4s Inaktivität im normalen Modus
Autoread einstellen                                                                                                                                                                                    
au CursorHold * Prüfzeit                                                                                                                                                                       
Phan Hai Quang
quelle
Toll! Funktioniert auch mit einer Warnung, wenn Sie diese Datei seit dem letzten Neuladen geändert haben.
Zoujyjs
1
Die erste Antwort hat bei mir nicht funktioniert, aber das funktioniert! :-)
Ionică Bizău
4
Das "alle 4 Sekunden" ist nicht wahr. Dies wird nur einmal nach 4 Sekunden Inaktivität im normalen Modus überprüft . Wenn Sie also längere Zeit nichts in einem anderen Puffer tun, wird es nicht aktualisiert, aber wenn Sie nur den Cursor bewegen und 4 Sekunden warten. Eine andere Möglichkeit besteht darin, ": checktime" manuell aufzurufen, um die Aktualisierung durchzuführen (nachdem die Autoread-Einstellung vorgenommen wurde). Leider scheint es in vim keine Unterstützung für Umfragen zu geben, daher gibt es keine echte Antwort auf die Frage der OP.
David Ljung Madison Stellar
1
Bin gerade darauf gestoßen. Wenn Sie die Prüfzeit ändern, um eine benutzerdefinierte Funktion aufzurufen, und am Ende der Funktion "Aufruf-Feedkeys (" lh ")" hinzufügen, wird diese alle 4 Sekunden ausgelöst.
Flukus
@ DavidLjungMadison Sie haben Recht, ich werde den Beitrag bearbeiten, um diesen Fehler zu vermeiden
Phan Hai Quang
9

Wie @flukus in einem Kommentar zu einer früheren Antwort sagte , können Sie call feedkeys["lh"](es bewegt den Cursor nach rechts und zurück nach links, was normalerweise beim Anzeigen einer Protokolldatei keinen Schaden anrichtet).

Wenn Sie also den Rest der Antwort kombinieren, haben Sie einen Oneliner, den Sie bei Bedarf von ex (innerhalb von vim) ausführen können:

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


(Wenn Sie (fast) zum Ende der Datei springen möchten, verwenden Sie einfach "G" anstelle von "lh" mit Feedkeys.)

Erläuterung:
- Autoread : Liest die Datei, wenn sie von außen geändert wird (aber sie funktioniert nicht von alleine, es gibt keinen internen Timer oder ähnliches. Sie liest die Datei nur, wenn vim eine Aktion ausführt, wie ein Befehl in ex :!
- CursorHold * checktime : Wenn der Cursor vom Benutzer für die in 'updatetime' angegebene Zeit (standardmäßig 4000 Millisekunden) nicht bewegt wird, wird checktime ausgeführt, die nach Änderungen von außerhalb der Datei sucht
- Feedkeys aufrufen ("lh") : Der Cursor wird einmal nach rechts und hinten nach links bewegt. Dann passiert nichts (... was bedeutet, dass CursorHold ausgelöst wird, was bedeutet, dass wir eine Schleife haben. )

Zusätzlich können Sie :set syntax=logtalkdas Protokoll einfärben

Um das Scrollen bei der Verwendung zu stoppen call feedkeys("G"), führen Sie aus :set noautoread- jetzt erkennt vim, dass die Datei geändert wurde, und fragt, ob man die Änderungen lesen möchte oder nicht.

(Hat dies irgendwelche Nebenwirkungen?)

Bearbeiten: Ich sehe einen Nebeneffekt: Wenn man den Feedkey "G" verwendet, wird jeder aktuell geöffnete Puffer nach unten gescrollt?! Es ist also nicht möglich, im linken Puffer eines Splittet-Fensters zu arbeiten, während der rechte Puffer automatisch eine Protokolldatei nach unten scrollt

eli
quelle
4

Stecke dies in deine .vimrc und es sollte wie ein Boss funktionieren. (Entnommen aus: 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)
Moeabdol
quelle
1
Dies ist die bevorzugte Antwort, um Mängel beim Autoread-Terminal zu beheben.
mcanfield
3
@mcanfield Nein, das ist es nicht, da dies immer noch nicht "auf Änderungen achtet". Sie noch brauchen , um Vim aktiv , und es ist nach wie vor Polling (nicht beobachtet) auf eine begrenzte Anzahl von Ereignissen. CursorHoldwird einmal ausgeführt . Wenn Sie also einen Kaffee trinken oder etwas in einem anderen Fenster tun, wird es nicht aktualisiert.
Martin Tournoij
4
Dieses Skript wird auch als Vim-Plugin gebündelt: vim-autoread .
stephen.hanson
1
@ stephen.hanson Danke für den Link, das Plugin funktioniert gut für mich!
Tropilio
3

Tail Bundle sollte machen was du willst. Beachten Sie, habe es nicht selbst verwendet.

Alok Singhal
quelle
2

Wenn Unix + Neovim

:term tail -f <filename>

Natürlich wird das nicht für alle funktionieren, aber so mache ich es.

Jeb
quelle
0

VIM warnt Sie, wenn eine Datei aktualisiert wurde, damit Sie keine Änderungen überschreiben, die seit dem Öffnen vorgenommen wurden. An dieser Stelle werden Sie aufgefordert, die Datei neu zu laden.

Prestomation
quelle
1
Vielen Dank für Ihre Antwort, aber vim hat mich nicht gewarnt, als die Datei in meinem System geändert wurde :(
Patrick