Bagaimana saya bisa membuat Vim autoread file sementara itu tidak memiliki fokus?

29

Saya menggunakan VIm untuk semua hal (atau gVim dalam hal ini), termasuk memantau keluaran yang ditulis ke file; Saya menggunakan autoreaduntuk membuat Vim membaca ulang file, yang ia lakukan setiap kali saya mengalihkan fokus keyboard untuk itu.

Apakah ada cara untuk membuat Vim memperbarui buffer bahkan jika saya tidak mengganti fokus keyboard? Saya sudah mencoba pengaturan checktimetetapi tampaknya tidak berpengaruh apa pun saat fokus keyboard ada di tempat lain.

Output yang saya pantau adalah mengganti file output sepenuhnya; dan aku tidak melihatnya tail -f. Ada opsi lain, seperti memipet ke instance baru setiap saat, atau memipis ke lessatau sesuatu, tapi itu akan keren jika itu bisa dilakukan dengan VIm.

Falstro
sumber
@Carpetsmoker bagaimana dengan CursorHoldacara ini? Jika Vim tidak memiliki fokus, itu harus memicu setiap n detik.
muru
1
@muru Tidak, CursorHolddijalankan hanya sekali, ini secara eksplisit didokumentasikan sebagai: "tidak memecat setiap 'waktu pembaruan' ms jika Anda meninggalkan Vim untuk membuat kopi. :)"
Martin Tournoij
1
Saya dihapus gvim tag lagi, saya berharap bahwa apa-apa ;-) Seperti yang saya lihat, pertanyaan ini tidak benar-benar tentang gvim, seperti perubahan fokus adalah salah satu acara yang Vim memeriksa apakah file tersebut berubah (ada sejumlah, lihat jawaban saya untuk lebih jelasnya). Sebagian besar, jika tidak semua, cara untuk memperbaiki ini akan bekerja dengan baik di Vim dan gVim.
Martin Tournoij
@Carpetsmoker ah, saya mendapat kesan bahwa gVim memeriksa secara teratur sementara itu memiliki fokus keyboard (sehingga membuatnya menjadi pertanyaan gVim), tetapi tampaknya saya salah. Terima kasih sudah membereskannya.
falstro

Jawaban:

20

Pembaruan 2015-06-25 :

  • Saya telah membatalkan metode "shell", karena terlalu disfungsional. Itu menghentikan mode penyisipan dan meninggalkan proses zombie. Lihatlah riwayat revisi posting ini apakah Anda benar-benar ingin melihatnya.
  • Saya telah membuat sebuah plugin dari ini: auto_autoread.vim . Saat ini, secara efektif sama dengan kode di bawah ini, tetapi saya sarankan Anda menggunakan plugin karena ini kemungkinan akan menerima pembaruan.

Apa yang autoreadharus dilakukan

Untuk menjawab pertanyaan ini, pertama-tama kita harus memahami apa yang dilakukan autoreadopsi, dan yang lebih penting, apa yang tidak dilakukan.

Sayangnya :help 'autoread' tidak memiliki banyak informasi tentang ini, hanya mengatakan "file telah terdeteksi telah diubah di luar Vim" . Bagaimana Vim mendeteksi bahwa suatu file diubah? Pada tindakan tertentu, Vim memeriksa waktu modifikasi file.

Kapan:

  • :checktime digunakan;
  • buffer dimasukkan;
  • :diffupdate digunakan;
  • :e dikeluarkan untuk file yang sudah memiliki buffer;
  • mengeksekusi perintah eksternal dengan !;
  • kembali ke latar depan ( ^Z, fg, hanya jika shell memiliki kontrol pekerjaan);

untuk gVim, ini juga dilakukan ketika:

  • menutup menu "klik kanan" (baik dengan memilih sesuatu, atau hanya dengan menutupnya);
  • fokus diubah (ini yang sudah Anda perhatikan);
  • menutup dialog browser file yang muncul jika Anda menggunakan "file -> open", "file -> save as" dari menu (dan juga beberapa tempat lain).

Saya mengumpulkan informasi ini dari sumber Vim dengan mencari semua panggilan ke buf_check_timestamp(), check_timestamps()fungsi, dan lokasi di mana need_check_timestampsdiatur ke TRUE.

Saya mungkin telah melewatkan beberapa peristiwa, tetapi hal utama yang perlu diingat adalah bahwa Vim hanya memeriksa apakah file tersebut dimodifikasi dalam serangkaian keadaan yang sangat terbatas . Itu tentu tidak "polling" file untuk perubahan n setiap detik, yang pada dasarnya apa yang Anda cari.

Jadi, untuk tujuan Anda, set autoreadtidak cukup.

Menggunakan Python

Ini menjadwalkan utas Python untuk dijalankan di latar belakang, ini akan berjalan :checktimesetiap n detik. Jika autoreadsudah diaktifkan , ini akan reload buffer dari disk, yang lain itu hanya akan memperingatkan.

Ini mengharuskan Vim memiliki +pythonatau +python3dalam :version. Ini harus bekerja pada semua platform (termasuk 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

Anda dapat memulai ini dengan menggunakan :call AutoreadPython(); Anda tentu saja dapat melakukan ini dalam autocmd; sebagai contoh:

autocmd *.c call AutoreadPython()

Kata penutup

Sebenarnya ada lebih banyak metode, misalnya Anda dapat menggunakan alat seperti entratau Python inotifyatau gaminmodul untuk memantau file untuk perubahan, :checktimejuga memeriksa semua buffer jika tidak diberikan argumen, ini dapat ditingkatkan dengan hanya memeriksa satu buffer atau file tertentu.
Namun, jawaban ini sudah agak lama :-) Metode ini seharusnya (mudah-mudahan!) Berfungsi dengan baik untuk sebagian besar skenario, atau harus mudah beradaptasi dengan skenario Anda.

PS. Saya juga mencoba menggunakan Ruby, tapi sayangnya utas Ruby (menggunakan Thread) tidak berjalan di latar belakang seperti yang dilakukan oleh Python, jadi saya tidak bisa menjalankannya (mungkin ada cara lain, sih?)

Martin Tournoij
sumber
2

Saya membuat sedikit plugin vim-autoread yang digunakan tail -funtuk memperbarui buffer di latar belakang secara tidak sinkron. Ini jelas membutuhkan fitur pekerjaan Vim Versi 8.

Gunakan :AutoReaduntuk menyalakannya dan :AutoRead!mematikannya.

Christian Brabandt
sumber
Versi yang kompatibel dengan NeoVim akan sangat bagus!
Andrew
@AndrewMacFie Saya tidak mengerti, mengapa ini tidak berhasil pada Neovim.
Christian Brabandt
kurangnya dukungan pekerjaan Vim 8 di NeoVim saya pikir?
Andrew
@AndrewMacFie oh itu mungkin benar. Karena saya tidak menggunakan neovim, saya tidak dapat membuatnya NeoVim kompatibel. Namun seorang PR akan disambut :)
Christian Brabandt
cukup adil:)
Andrew
1

Di Neovim Anda bisa menggunakan perintah berikut yang akan membuka terminal buffer menjalankan perintah tail.

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

Ini akan terus berfungsi bahkan jika file dihapus dan diciptakan kembali.

Atau tambahkan berikut ini ke $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
sumber
1

dari jawaban ini (merujuk pada jawaban oleh PhanHaiQuang dan komentar oleh flukus )

Seseorang dapat menjalankan oneliner ini dari ex (whithin vim) saat dibutuhkan (atau menempatkan setiap perintah dalam vimrc, untuk saat file log dibuka.)

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

Penjelasan:
- autoread : membaca file ketika diubah dari luar (tetapi tidak bekerja sendiri, tidak ada timer internal atau sesuatu seperti itu. Itu hanya akan membaca file ketika vim melakukan suatu tindakan, seperti perintah dalam ex :!
- CursorHold * checktime : ketika cursor tidak dipindahkan oleh pengguna untuk waktu yang ditentukan dalam 'updatetime' (yang secara default 4000 milidetik) dijalankan, yang memeriksa perubahan dari luar file
- panggilan feedkeys ("lh") : kursor dipindahkan satu kali, kanan dan kiri kiri. dan kemudian tidak ada yang terjadi (... yang berarti, bahwa CursorHold dipicu, yang berarti kita memiliki loop )

eli
sumber