Czy vim może monitorować zmiany w pliku w czasie rzeczywistym

104

Moje pytanie jest podobne do tego, jak monitorować plik tekstowy w czasie rzeczywistym, ale chcę to zrobić w vimie. Wiem, że mogę odczytać otwarty plik użycia tail -f sample.xmlpliku, a gdy nowa zawartość zostanie zapisana w pliku, zapisze również nową zawartość na moim ekranie. Czy mogę pozwolić, aby vim automatycznie wypełnił nowe dane, gdy plik jest aktualizowany?

Patrick
źródło

Odpowiedzi:

101

Możesz :set autoreadtak, aby vim czytał plik, gdy się zmieni. Jednak (w zależności od platformy) musisz skupić się na tym.

Z pomocy:

Kiedy wykryto, że plik został zmieniony poza Vimem i nie został zmieniony wewnątrz Vima, automatycznie przeczytaj go ponownie. Po usunięciu pliku nie jest to wykonywane.

Piotr
źródło
5
Dzięki za podpowiedź! Wygląda to całkiem obiecująco, ale nie działa w moim systemie :( Używam Maca 10.6.2 iTerm z vimem w wersji 7.2.303 skompilowanej z MacVimem. Jakieś dodatkowe komentarze, które mogę wypróbować?
Patrick
erm, to dość dziwne. czy używasz macvim gui czy wersji terminalowej? działa dla mnie z macvim gui pobranym prekompilowanym. (Muszę jednak kliknąć aplikację, aby ją skupić, jak wspomniałem).
Peter
1
Testowałem w terminalu, po użyciu gvim (MacVim GUI) funkcja zaczęła działać! Jak wspomniałeś, muszę skupić się na gvim, aby zaktualizować zawartość. Czy masz jakąś sztuczkę, aby zaktualizować ją nawet bez skupiania się? Jeszcze raz dziękuję za pomoc.
Patrick,
3
Niestety nie znam rozwiązania tego problemu. Byłbym zszokowany, gdyby vim mógł to zrobić bez zmiany punktu skupienia - wymagałoby to od vima sondowania systemu plików, aby zobaczyć, kiedy się zmienia. Myślę, że potrzebujesz do tego wtyczki.
Peter
2
@Peter Taką wtyczkę zrobiłem jakiś czas temu. Zobacz także to pytanie i moją odpowiedź . aby uzyskać więcej informacji na temat sposobu autoreaddziałania i jego ograniczeń.
Martin Tournoij
63

Nie wiem automatycznie, ale możesz wpisać:

:e!

aby ponownie załadować plik

dimba
źródło
Chociaż to podejście nie powoduje automatycznej aktualizacji treści, wyświetla zaktualizowaną zawartość. Dziękuję za odpowiedź!
Patrick,
31

Umieść w swoim .vimrc:

"sprawdź raz po 4 s bezczynności w trybie normalnym
ustaw autoread                                                                                                                                                                                    
au CursorHold * checktime                                                                                                                                                                       
Phan Hai Quang
źródło
Wspaniały! Działa dobrze, nawet z ostrzeżeniem, jeśli zmieniłeś ten plik od ostatniego ponownego załadowania.
zoujyjs
1
Pierwsza odpowiedź mi nie pomogła, ale to działa! :-)
Ionică Bizău
4
„Co 4 sekundy” nie jest prawdą. Pozwoli to sprawdzić tylko jeden raz po 4s bezczynności w trybie normalnym. Więc jeśli nie robisz nic w innym buforze przez długi czas, nie zostanie on zaktualizowany, ale tak by się stało, gdybyś po prostu przesunął kursor i poczekał 4 sekundy. Inną opcją jest ręczne wywołanie „: checktime” w celu aktualizacji (po ustawieniu automatycznego odczytu). Niestety, wygląda na to, że vim nie obsługuje ankiet, więc nie ma prawdziwej odpowiedzi na pytanie dotyczące PO.
David Ljung Madison Stellar
1
Właśnie to spotkałem. Jeśli zmienisz czas sprawdzania, aby wywołać funkcję niestandardową i dodasz „call feedkeys („ lh ”)” na końcu funkcji, będzie ona uruchamiana co 4 sekundy.
flukus
@DavidLjungMadison masz rację, zamierzam edytować post, aby uniknąć tego błędu
Phan Hai Quang
9

jak @flukus powiedział w komentarzu do poprzedniej odpowiedzi , możesz call feedkeys["lh"](przesuwa kursor w prawo iz powrotem w lewo, co normalnie nie szkodzi podczas przeglądania pliku dziennika)

Tak więc, jeśli połączysz resztę odpowiedzi , masz oneliner, który możesz w razie potrzeby uruchomić z ex (whithin vim):

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


(jeśli chcesz przeskoczyć (prawie) na koniec pliku, po prostu użyj „G” zamiast „lh” z kluczami kanałów)

Objaśnienie:
- autoread : czyta plik po zmianie z zewnątrz (ale nie działa samodzielnie, nie ma wewnętrznego timera lub czegoś podobnego. Czyta plik tylko wtedy, gdy vim wykona akcję, jak polecenie w ex :!
- CursorHold * checktime : gdy kursor nie jest przesuwany przez użytkownika przez czas określony w 'updatetime' (który domyślnie wynosi 4000 milisekund) wykonywany jest checktime, który sprawdza zmiany spoza pliku
- wywołaj feedkeys ("lh") : kursor jest przesuwany raz, w prawo iz powrotem w lewo. i wtedy nic się nie dzieje (... co oznacza, że ​​wyzwalany jest CursorHold, co oznacza, że ​​mamy pętlę )

Dodatkowo możesz :set syntax=logtalkpokolorować dziennik

Aby zatrzymać przewijanie podczas używania call feedkeys("G"), wykonaj :set noautoread- teraz vim powie, że plik został zmieniony i zapyta, czy chcesz odczytać zmiany, czy nie)

(Czy ma to jakieś skutki uboczne?)

Edycja: Widzę jeden efekt uboczny: jeśli użyje się "G" es klucz kanału, przewinie się w dół każdy aktualnie otwarty bufor ?! Tak więc nie można pracować w lewym buforze podzielonego okna, podczas gdy prawy bufor automatycznie przewija plik dziennika

eli
źródło
4

Umieść to w swoim .vimrc i powinno działać jak szef. (Zaczerpnięte z: 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
źródło
1
Jest to preferowana odpowiedź na niedociągnięcia w automatycznym odczytywaniu terminala.
mcanfield
3
@mcanfield Nie, nie jest, ponieważ to nadal nie „oczekuje zmian”. Państwo nadal trzeba mieć Vim aktywny i jest nadal sondowania (nie oglądanie) na ograniczonej wydarzeń. CursorHoldjest uruchamiany raz . Więc jeśli zgaśnie i napić się kawy, albo robią coś innego okna będzie nie aktualizować.
Martin Tournoij
4
Ten skrypt jest również dołączony jako wtyczka Vima: vim-autoread .
stephen.hanson
1
@ stephen.hanson Dzięki za link, ta wtyczka działa dobrze dla mnie!
Tropilio
3

Tail Bundle powinien robić, co chcesz. Uwaga, sam z tego nie korzystałem.

Alok Singhal
źródło
2

Jeśli unix + neovim

:term tail -f <filename>

Oczywiście to nie zadziała dla wszystkich, ale tak to robię.

Jeb
źródło
0

VIM ostrzeże Cię, gdy plik zostanie zaktualizowany, abyś nie nadpisał zmian, które zostały wprowadzone od czasu jego otwarcia. W tym momencie wyświetli się monit o ponowne załadowanie pliku.

prestomation
źródło
1
Dziękuję za odpowiedź, ale vim nie ostrzegł mnie, kiedy plik został zmieniony w moim systemie :(
Patrick