Dapat vim memantau perubahan waktu nyata ke file

104

Pertanyaan saya mirip dengan ini bagaimana memonitor file teks secara realtime tetapi saya ingin melakukannya di vim. Saya tahu saya dapat membaca file menggunakan file yang dibuka tail -f sample.xml, dan ketika konten baru ditulis ke file, itu juga akan menulis konten baru ke layar saya. Dapatkah saya meminta vim secara otomatis mengisi data baru ketika file diperbarui?

Patrick
sumber

Jawaban:

101

Kamu bisa :set autoread agar vim membaca file tersebut saat ada perubahan. Namun (tergantung pada platform Anda), Anda harus memberikan fokus.

Dari bantuan:

Ketika sebuah file terdeteksi telah diubah di luar Vim dan belum diubah di dalam Vim, secara otomatis membacanya lagi. Ketika file telah dihapus, ini tidak dilakukan.

Peter
sumber
5
Terima kasih atas petunjuknya! Kelihatannya cukup menjanjikan, tetapi tidak berhasil di sistem saya :( Saya menggunakan Mac10.6.2 iTerm dengan vim versi 7.2.303 yang dikompilasi dengan MacVim. Adakah komentar tambahan yang dapat saya coba?
Patrick
erm, itu sangat aneh. apakah Anda menggunakan macvim gui atau versi terminal? ini bekerja untuk saya dengan macvim gui yang diunduh sebelumnya. (Saya memang harus mengklik aplikasi untuk memberikan fokus, seperti yang saya sebutkan.)
Peter
1
Saya sedang menguji di terminal, setelah saya menggunakan gvim (MacVim GUI) fungsinya mulai berfungsi! Seperti yang Anda sebutkan, saya perlu memfokuskan gvim untuk memperbarui konten. Apakah Anda punya trik untuk memperbaruinya bahkan tanpa fokus? Sekali lagi terima kasih untuk bantuan anda.
Patrick
3
Sayangnya, saya tidak tahu solusi untuk itu. Saya akan tercengang jika vim bisa melakukannya tanpa perubahan fokus - ini akan membutuhkan vim untuk mengumpulkan sistem file untuk melihat kapan itu berubah. Saya pikir Anda membutuhkan plugin untuk itu.
Peter
2
@ Peter Saya membuat plugin seperti itu beberapa waktu yang lalu. Juga lihat pertanyaan ini dan jawaban saya untuk itu . untuk detail lebih lanjut tentang cara autoreadkerja dan batasannya.
Martin Tournoij
63

Tidak tahu tentang otomatis, tetapi Anda dapat mengetik:

:e!

untuk memuat ulang file

dimba
sumber
Meskipun pendekatan ini tidak memperbarui konten secara otomatis, pendekatan ini menampilkan konten yang diperbarui. Terima kasih atas jawaban anda!
Patrick
31

Letakkan yang berikut ini di .vimrc:

"periksa satu kali setelah 4 detik tidak ada aktivitas dalam mode normal
setel autoread                                                                                                                                                                                    
au CursorHold * waktu pemeriksaan                                                                                                                                                                       
Phan Hai Quang
sumber
Bagus! Berfungsi dengan baik, bahkan dengan peringatan jika Anda telah mengubah file itu sejak pemuatan ulang terakhir.
zoujyjs
1
Jawaban pertama tidak berhasil untuk saya, tetapi ini berhasil! :-)
Ionică Bizău
4
"Setiap 4 detik" tidak benar. Ini hanya akan memeriksa satu kali setelah 4 detik tidak ada aktivitas dalam mode normal. Jadi jika Anda tidak melakukan apa pun di buffer lain untuk waktu yang lama, buffer tersebut tidak akan diperbarui, tetapi akan dilakukan jika Anda hanya memindahkan kursor dan menunggu 4 detik. Pilihan lainnya adalah memanggil ": checktime" untuk memperbarui secara manual (setelah menyetel autoread). Sayangnya, tampaknya tidak ada dukungan polling dalam vim, jadi tidak ada jawaban yang benar untuk pertanyaan OP.
David Ljung Madison Stellar
1
Baru saja menemukan ini. Jika Anda mengubah waktu check-in untuk memanggil fungsi kustom dan menambahkan "call feedkeys (" lh ")" di akhir fungsi, maka fungsi akan diaktifkan setiap 4 detik.
flukus
@DavidLjungMadison Anda benar, saya akan menyunting kiriman untuk menghindari kesalahan ini
Phan Hai Quang
9

seperti yang dikatakan @flukus dalam komentar ke jawaban sebelumnya, Anda bisa call feedkeys["lh"](ini menggerakkan kursor ke kanan dan kembali ke kiri, yang biasanya tidak membahayakan saat melihat file log)

Jadi, jika Anda menggabungkan sisa jawaban yang Anda miliki, Anda dapat menjalankan dari ex (whithin vim) saat diperlukan:

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


(jika Anda ingin melompat (hampir) ke bagian akhir file, cukup gunakan "G", bukan "lh" dengan tombol umpan)

Penjelasan:
- autoread : membaca file ketika diubah dari luar (tetapi tidak berfungsi sendiri, tidak ada timer internal atau semacamnya. Ini hanya akan membaca file ketika vim melakukan tindakan, seperti perintah di ex :!
- CursorHold * checktime : ketika kursor tidak digerakkan oleh pengguna untuk waktu yang ditentukan dalam 'updatetime' (yang defaultnya adalah 4000 milidetik), waktu pemeriksaan dijalankan, yang memeriksa perubahan dari luar file
- panggil feedkeys ("lh") : kursor digerakkan sekali, ke kanan dan ke kiri. dan kemudian tidak ada yang terjadi (... yang berarti, CursorHold dipicu, yang berarti kita memiliki loop )

Selain itu Anda bisa :set syntax=logtalkmewarnai log

Untuk menghentikan pengguliran saat menggunakan call feedkeys("G"), jalankan :set noautoread- sekarang vim akan memberi tahu, bahwa file telah diubah dan tanyakan apakah ada yang ingin membaca perubahan atau tidak)

(Apakah ini memiliki efek samping?)

Edit: Saya melihat satu efek samping: jika seseorang menggunakan "G" sebagai feedkey, itu akan menggulir ke bawah setiap buffer yang saat ini dibuka ?! Jadi, tidak mungkin bekerja di buffer kiri jendela splittet sementara buffer kanan menggulir ke bawah file log secara otomatis

eli
sumber
4

Tempelkan ini di .vimrc Anda dan itu akan bekerja seperti bos. (Diambil dari: 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
sumber
1
Ini adalah jawaban yang lebih disukai untuk mengatasi kekurangan autoread terminal.
mcanfield
3
@mcanfield Tidak, ini tidak terjadi karena ini masih tidak "mengawasi perubahan". Anda masih perlu mengaktifkan Vim dan masih melakukan polling (tidak menonton) pada serangkaian acara terbatas. CursorHolddijalankan sekali . Jadi jika Anda pergi dan minum kopi, atau melakukan sesuatu di Jendela lain, itu tidak akan diperbarui.
Martin Tournoij
4
Skrip itu juga dibundel sebagai plugin Vim: vim-autoread .
stephen.hanson
1
@ stephen.hanson Terima kasih untuk tautannya, plugin itu bekerja dengan baik untuk saya!
Tropilio
3

Tail Bundle harus melakukan apa yang Anda inginkan. Catatan, belum pernah menggunakannya sendiri.

Alok Singhal
sumber
2

Jika unix + neovim

:term tail -f <filename>

Jelas ini tidak akan berhasil untuk semua orang, tapi begitulah cara saya melakukannya.

Jeb
sumber
0

VIM akan memperingatkan Anda ketika file telah diperbarui sehingga Anda tidak menimpa perubahan yang telah dibuat sejak Anda membukanya. Ini akan meminta Anda pada saat itu untuk memuat ulang file.

prestomation
sumber
1
Terima kasih atas jawaban Anda, tetapi vim tidak memperingatkan saya ketika file diubah di sistem saya :(
Patrick