Jak sprawić, by Vim automatycznie czytał plik, gdy nie jest aktywny?

29

Używam VIm do wszelkiego rodzaju rzeczy (w tym przypadku gVim), w tym monitorowania wyników zapisanych do pliku; Używam, autoreadaby Vim ponownie czytał plik, co dzieje się za każdym razem, gdy przełączam na niego fokus klawiatury.

Czy jest jakiś sposób, aby Vim zaktualizował bufor, nawet jeśli nie przełączę fokusu na klawiaturze? Próbowałem ustawienia, checktimeale wydaje się, że nie ma to żadnego wpływu, gdy klawiatura jest gdzie indziej.

Dane wyjściowe, które monitoruję, całkowicie zastępują plik wyjściowy; i nie patrzę na tail -fto. Istnieją inne opcje, takie jak przesyłanie do nowej instancji za każdym razem, przesyłanie do lesslub coś w tym stylu, ale byłoby fajnie, gdyby można to zrobić za pomocą VIm.

falstro
źródło
@Carpetsmoker co powiesz na CursorHoldwydarzenie? Jeśli Vim nie ma fokusa, powinien uruchamiać się co n sekund.
muru
1
@muru Nie, CursorHoldjest wykonywany tylko raz, jest to wyraźnie udokumentowane jako: „nie odpala każdego ms aktualizacji, jeśli zostawisz Vima na kawę. :)”
Martin Tournoij
1
Znów usunąłem tag gvim , mam nadzieję, że jest w porządku ;-) Jak widzę, te pytania tak naprawdę nie dotyczą gVim, ponieważ zmiana fokusu jest tylko jednym zdarzeniem, na którym Vim sprawdza, czy plik został zmieniony (jest cała masa, szczegóły znajdują się w mojej odpowiedzi). Większość, jeśli nie wszystkie, sposoby na poprawienie tego będą dobrze działać zarówno w Vimie, jak i gVimie.
Martin Tournoij,
@Carpetsmoker ah, miałem wrażenie, że gVim sprawdzał regularnie, gdy był skupiony na klawiaturze (co czyniło z niego pytanie gVim), ale wygląda na to, że się myliłem. Dzięki za wyjaśnienie.
falstro

Odpowiedzi:

20

Aktualizacja 2015-06-25 :

  • Złomowałem metodę „powłoki”, ponieważ była ona zbyt dysfunkcyjna. Zatrzymał tryb wstawiania i opuścił procesy zombie. Spójrz na historię zmian tego postu, czy naprawdę chcesz to zobaczyć.
  • Z tego zrobiłem wtyczkę: auto_autoread.vim . W tej chwili jest on faktycznie taki sam, jak poniższy kod, ale polecam korzystanie z wtyczki, ponieważ prawdopodobnie będzie otrzymywać aktualizacje.

Co ma autoreadzrobić?

Aby odpowiedzieć na to pytanie, musimy najpierw zrozumieć, co autoreadrobi ta opcja, a co ważniejsze, czego nie robi.

Niestety :help 'autoread' nie ma dużo informacji na ten temat, po prostu mówi „wykryto , że plik został zmieniony poza Vimem” . Jak Vim wykrywa zmianę pliku? W przypadku niektórych akcji Vim sprawdza czas modyfikacji pliku.

Kiedy:

  • :checktime Jest używane;
  • wprowadzono bufor;
  • :diffupdate Jest używane;
  • :e jest wydawany dla pliku, który już ma bufor;
  • wykonanie polecenia zewnętrznego za pomocą !;
  • powrót na pierwszy plan ( ^Z, fgtylko jeśli powłoka ma kontrolę zadań);

w przypadku gVim jest to również wykonywane, gdy:

  • zamykanie menu „kliknij prawym przyciskiem myszy” (albo przez wybranie czegoś, albo po prostu zamknięcie go);
  • fokus został zmieniony (to już zauważyłeś);
  • zamykanie okna dialogowego przeglądarki plików, które wyskakuje, jeśli użyjesz „menu -> otwórz”, „plik -> zapisz jako” z menu (a także niektórych innych miejsc).

Zebrałem te informacje ze źródła Vima, lokalizując wszystkie wywołania do buf_check_timestamp(), check_timestamps()funkcji i lokalizacji, w których need_check_timestampsjest ustawiony TRUE.

Mogłem przeoczyć pewne wydarzenia, ale kluczową rzeczą do zapamiętania jest to, że Vim sprawdza tylko, czy plik jest zmodyfikowany w bardzo ograniczonym zestawie okoliczności . Z pewnością nie „sonduje” pliku w poszukiwaniu zmian co n sekund, a właściwie tego właśnie szukasz.

Zatem dla twojego celu set autoreadto za mało.

Korzystanie z Pythona

Zaplanuje to uruchomienie wątku Python w tle, będzie on działał :checktimeco n sekund. Jeśli autoreadjest włączony , spowoduje to ponowne załadowanie bufora z dysku, w przeciwnym razie po prostu ostrzeże.

Wymaga to, że Vim posiada +pythonlub +python3w :version. Powinien działać na wszystkich platformach (w tym 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

Możesz zacząć od tego, używając :call AutoreadPython(); oczywiście możesz to zrobić w autocmd; na przykład:

autocmd *.c call AutoreadPython()

Posłowie

W rzeczywistości jest więcej metod, na przykład możesz użyć narzędzia takiego jak entrPython inotifylub gaminmoduł do monitorowania pliku pod kątem zmian, :checktimesprawdza również wszystkie bufory, jeśli nie podano żadnych argumentów, można to poprawić, sprawdzając tylko pojedynczy bufor lub pewien plik.
Jednak ta odpowiedź jest już dość długa :-) Te metody powinny (mam nadzieję!) Działać dobrze w większości scenariuszy lub powinny być łatwe do dostosowania do twojego scenariusza.

PS. Próbowałem także użyć Ruby, ale niestety wątki Ruby (używanie Thread) nie działają w tle tak jak Python, więc nie byłem w stanie uruchomić tego (może jest jednak inny sposób?)

Martin Tournoij
źródło
2

Zrobiłem małą wtyczkę vim-autoread, która wykorzystuje tail -fasynchronicznie aktualizację bufora w tle. To oczywiście wymaga funkcji zadania Vima w wersji 8.

Użyj, :AutoReadaby włączyć i :AutoRead!wyłączyć.

Christian Brabandt
źródło
Wersja kompatybilna z NeoVim byłaby świetna!
Andrew
@AndrewMacFie Nie rozumiem, dlaczego to nie działałoby na Neovim.
Christian Brabandt,
brak wsparcia dla Vim 8 miejsc pracy w NeoVim Myślałem?
Andrew
@AndrewMacFie, och, to chyba prawda. Ponieważ nie używam neovim, nie mogę uczynić go kompatybilnym z NeoVim. Jednak PR byłby mile widziany :)
Christian Brabandt
wystarczy
Andrew
1

W Neovim możesz użyć następującego polecenia, które otworzy bufor terminala z uruchomionym poleceniem tail.

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

Będzie to nadal działać, nawet jeśli plik zostanie usunięty i ponownie utworzony.

Lub dodaj następujące elementy do swojego $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
źródło
1

z tej odpowiedzi (odnosząc się do odpowiedzi PhanHaiQuang i komentarza flukus )

Można uruchomić ten oneliner z ex (whithin vim) w razie potrzeby (lub umieścić każde polecenie w vimrc, na wypadek, gdy pliki dziennika są otwarte).

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

Objaśnienie:
- autoread : czyta plik po zmianie z zewnątrz (ale nie działa samodzielnie, nie ma wewnętrznego timera ani czegoś takiego. Odczyta plik tylko wtedy, gdy vim wykona akcję, jak polecenie w ex :!
- CursorHold * checktime : gdy kursor nie zostanie przesunięty przez użytkownika na czas określony w „updatetime” (domyślnie jest to 4000 milisekund), wykonywany jest checktime, który sprawdza zmiany spoza pliku
- wywołuje klawisze feed ((lh)) : kursor przesuwa się raz, w prawo i wstecz w lewo. i wtedy nic się nie dzieje (... co oznacza, że ​​uruchamiane jest CursorHold, co oznacza, że ​​mamy pętlę )

eli
źródło