Wie kann ich Vim zum automatischen Lesen einer Datei ohne Fokus veranlassen?

29

Ich verwende VIm für alle Arten von Dingen (oder in diesem Fall für gVim), einschließlich der Überwachung der in eine Datei geschriebenen Ausgabe. Ich autoreadveranlasse Vim, die Datei erneut zu lesen, was immer dann der Fall ist, wenn ich den Tastaturfokus darauf lege.

Gibt es eine Möglichkeit, Vim den Puffer aktualisieren zu lassen, auch wenn ich den Tastaturfokus nicht ändere? Ich habe versucht, Einstellungen vorzunehmen, checktimeaber es scheint keinen Effekt zu haben, wenn der Tastaturfokus an einer anderen Stelle liegt.

Die von mir überwachte Ausgabe ersetzt die Ausgabedatei vollständig. und ich freue mich nicht tail -fdarauf. Es gibt noch andere Möglichkeiten, wie zum Beispiel, jedes Mal in eine neue Instanz zu leiten oder in lessetwas, aber es wäre cool, wenn es mit VIm gemacht werden könnte.

falstro
quelle
@Carpetsmoker wie wäre es mit der CursorHoldVeranstaltung? Wenn Vim nicht fokussiert ist, sollte es alle n Sekunden ausgelöst werden.
muru
1
@muru Nein, CursorHoldwird nur einmal ausgeführt. Dies ist explizit dokumentiert als: "Feuert nicht jede 'Aktualisierungszeit' ms ab, wenn Sie Vim verlassen, um Kaffee zu
kochen
1
Ich habe das gvim- Tag wieder entfernt, ich hoffe, das ist in Ordnung ;-) Aus meiner Sicht handelt es sich bei diesen Fragen nicht wirklich um gVim, da der Fokuswechsel nur ein Ereignis ist, bei dem Vim prüft, ob die Datei geändert wurde (es gibt eine ganze Menge, siehe meine Antwort für Details). Die meisten, wenn nicht alle Möglichkeiten, dies zu verbessern, funktionieren sowohl in Vim als auch in gVim.
Martin Tournoij
@Carpetsmoker ah, ich hatte den Eindruck, dass gVim regelmäßig überprüft wurde, während es den Tastaturfokus hatte (was es zu einer gVim-Frage macht), aber anscheinend habe ich mich geirrt. Danke, dass Sie das geklärt haben.
Falstro

Antworten:

20

Update 25.06.2015 :

  • Ich habe die "Shell" -Methode abgeschafft, da sie zu dysfunktional war. Der Einfügemodus wurde beendet und die Zombie-Prozesse wurden beendet. Wenn Sie sich den Revisionsverlauf dieses Posts ansehen, möchten Sie ihn auf jeden Fall sehen.
  • Ich habe ein Plugin daraus gemacht: auto_autoread.vim . Im Moment ist es praktisch dasselbe wie der folgende Code, aber ich würde empfehlen, dass Sie das Plugin verwenden, da dies wahrscheinlich Updates erhalten wird.

Was macht autoreaddas?

Um diese Frage zu beantworten, müssen wir zuerst verstehen, was die autoreadOption bewirkt und was sie noch wichtiger macht .

Leider :help 'autoread' gibt es nicht viele Informationen dazu, sondern nur die Meldung "Es wurde festgestellt, dass eine Datei außerhalb von Vim geändert wurde" . Wie erkennt Vim, dass eine Datei geändert wurde? Bei bestimmten Aktionen überprüft Vim die Änderungszeit der Datei.

Wann:

  • :checktime wird genutzt;
  • ein Puffer wird eingegeben;
  • :diffupdate wird genutzt;
  • :e wird für eine Datei ausgegeben, die bereits einen Puffer hat;
  • Ausführen eines externen Befehls mit !;
  • Rückkehr in den Vordergrund ( ^Z, fgnur wenn die Shell die Job-Kontrolle hat);

Für gVim ist dies auch dann der Fall, wenn:

  • Schließen des "Rechtsklick" -Menüs (entweder durch Auswahl oder durch einfaches Schließen);
  • der Fokus wird geändert (das ist Ihnen bereits aufgefallen);
  • Schließen des Dateibrowser-Dialogfelds, das angezeigt wird, wenn Sie "Datei -> Öffnen", "Datei -> Speichern unter" im Menü (sowie an einigen anderen Stellen) verwenden.

Ich habe diese Informationen aus der Vim-Quelle gesammelt, indem ich alle Aufrufe von buf_check_timestamp(), check_timestamps()Funktionen und Speicherorte, auf die eingestellt need_check_timestampsist, lokalisiert habe TRUE.

Möglicherweise habe ich einige Ereignisse verpasst, aber das Wichtigste ist, dass Vim nur überprüft, ob die Datei unter bestimmten Umständen geändert wurde . Es "fragt" die Datei sicher nicht n Sekunden lang nach Änderungen ab , was im Grunde das ist, wonach Sie suchen.

Für Ihren Zweck set autoreadist das also nicht genug.

Verwenden von Python

Dadurch wird ein Python-Thread im Hintergrund ausgeführt, der :checktimealle n Sekunden ausgeführt wird. Wenn autoreadwird aktiviert , wird dies den Puffer von der Festplatte neu zu laden, sonst wird es nur warnen.

Dies setzt voraus, dass Vim +pythonoder +python3in hat :version. Es sollte auf allen Plattformen (einschließlich Windows) funktionieren.

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

Sie können dies mit starten :call AutoreadPython(); Sie können dies natürlich in einem Autocmd tun; beispielsweise:

autocmd *.c call AutoreadPython()

Nachwort

Es gibt tatsächlich mehr Methoden, zum Beispiel könnten Sie ein Tool wie entroder Python inotifyoder ein gaminModul verwenden, um eine Datei auf Änderungen zu überwachen. :checktimeAußerdem werden alle Puffer überprüft, wenn keine Argumente angegeben wurden. Dies kann durch Überprüfen nur eines einzelnen Puffers oder verbessert werden eine bestimmte Datei.
Diese Antwort ist jedoch schon ziemlich lang :-) Diese Methode sollte (hoffentlich!) Für die meisten Szenarien gut funktionieren oder sollte leicht an Ihr Szenario anpassbar sein.

PS. Ich habe auch versucht, Ruby zu verwenden, aber leider Threadlaufen Ruby-Threads (mit ) nicht im Hintergrund wie Python, so dass ich nicht in der Lage war, dies zum Laufen zu bringen (vielleicht gibt es aber einen anderen Weg?)

Martin Tournoij
quelle
2

Ich habe ein kleines Plugin vim-autoread erstellt , mit tail -fdem der Puffer im Hintergrund asynchron aktualisiert wird. Dies erfordert natürlich die Job-Funktion von Vim Version 8.

Verwenden Sie, :AutoReadum es einzuschalten und um :AutoRead!es auszuschalten.

Christian Brabandt
quelle
Eine NeoVim-kompatible Version wäre toll!
Andrew
@ AndrewMacFie Ich verstehe nicht, warum das bei Neovim nicht funktioniert.
Christian Brabandt
das Fehlen von Vim 8-Jobs in NeoVim, dachte ich?
Andrew
@ AndrewMacFie oh das ist wohl wahr. Da ich kein Neovim verwende, kann ich es nicht NeoVim-kompatibel machen. Allerdings wäre eine PR willkommen :)
Christian Brabandt
fair genug
Andrew
1

In Neovim können Sie den folgenden Befehl verwenden, der einen Terminalpuffer öffnet, in dem der Befehl tail ausgeführt wird.

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

Dies funktioniert auch dann weiter, wenn die Datei entfernt und neu erstellt wird.

Oder fügen Sie Folgendes zu Ihrer hinzu $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>)
Brett Y
quelle
1

Aus dieser Antwort (unter Bezugnahme auf eine Antwort von PhanHaiQuang und einen Kommentar von Flukus )

Dieser Oneliner kann bei Bedarf von ex (innerhalb von vim) ausgeführt werden (oder jeder Befehl in vimrc abgelegt werden, wenn Protokolldateien geöffnet werden.)

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

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

eli
quelle