Làm cách nào tôi có thể tạo Vim autoread một tệp trong khi nó không tập trung?


29

Tôi đang sử dụng VIm cho tất cả các loại (hoặc gVim trong trường hợp này), bao gồm cả đầu ra giám sát được ghi vào một tệp; Tôi sử dụng autoreadđể làm cho Vim đọc lại tập tin, nó thực hiện bất cứ khi nào tôi chuyển trọng tâm bàn phím sang nó.

Có cách nào để làm cho Vim cập nhật bộ đệm ngay cả khi tôi không chuyển trọng tâm bàn phím không? Tôi đã thử cài đặt checktimenhưng dường như không có bất kỳ ảnh hưởng nào trong khi tiêu điểm bàn phím ở nơi khác.

Đầu ra tôi đang theo dõi đang thay thế hoàn toàn tệp đầu ra; và tôi không tìm kiếm tail -fnó. Có các tùy chọn khác, như chuyển sang một phiên bản mới mỗi lần, hoặc chuyển sang lesshoặc một cái gì đó, nhưng sẽ rất tuyệt nếu nó có thể được thực hiện với VIm.


@Carpetsmoker thế nào về CursorHoldsự kiện này? Nếu Vim không có tiêu điểm, nó sẽ kích hoạt cứ sau n giây.
muru

1
@muru Không, chỉ CursorHoldđược thực hiện một lần, điều này được ghi lại rõ ràng là: "không kích hoạt mọi 'cập nhật' nếu bạn rời Vim để pha cà phê. :)"
Martin Tournoij

1
Tôi đã gỡ bỏ các gvim thẻ một lần nữa, tôi hy vọng đó là okay ;-) Như tôi đã nhìn thấy nó, câu hỏi này là không thực sự về gVim, như thay đổi tập trung chỉ là một sự kiện mà Vim kiểm tra nếu tập tin được thay đổi (có cả một bó, xem câu trả lời của tôi để biết chi tiết). Hầu hết, nếu không phải tất cả, các cách để cải thiện điều này sẽ hoạt động tốt trong cả Vim và gVim.
Martin Tournoij

@Carpetsmoker ah, tôi có ấn tượng rằng gVim đã kiểm tra thường xuyên trong khi nó có tiêu điểm bàn phím (do đó làm cho nó trở thành một câu hỏi gVim), nhưng có vẻ như tôi đã nhầm. Cám ơn giải thích rõ ràng.
falstro

Câu trả lời:


20

Cập nhật 2015-06-25 :

  • Tôi đã loại bỏ phương pháp "shell", vì nó quá rối loạn. Nó dừng chế độ chèn và để lại quá trình zombie. Nhìn vào lịch sử sửa đổi của bài viết này là bạn thực sự muốn xem nó.
  • Tôi đã tạo một plugin từ đây: auto_autoread.vim . Hiện tại, nó thực sự giống như mã bên dưới, nhưng tôi khuyên bạn nên sử dụng plugin vì điều này có khả năng nhận được cập nhật.

Không gì autoreadlàm gì?

Để trả lời câu hỏi này, trước tiên chúng ta phải hiểu autoreadtùy chọn này làm gì và quan trọng hơn là những gì nó không làm.

Thật không may :help 'autoread' , không có nhiều thông tin về điều này, nó chỉ nói rằng "một tệp đã được phát hiện đã bị thay đổi bên ngoài Vim" . Làm thế nào để Vim phát hiện ra rằng một tập tin được thay đổi? Trên một số hành động nhất định, Vim kiểm tra thời gian sửa đổi của tệp.

Khi nào:

  • :checktime Được sử dụng;
  • một bộ đệm được nhập vào;
  • :diffupdate Được sử dụng;
  • :e được cấp cho một tệp đã có bộ đệm;
  • thực hiện một lệnh bên ngoài với !;
  • trở về nền trước ( ^Z, fgchỉ khi vỏ có kiểm soát công việc);

đối với gVim, điều này cũng được thực hiện khi:

  • đóng menu "nhấp chuột phải" (bằng cách chọn một cái gì đó, hoặc chỉ bằng cách đóng nó);
  • trọng tâm được thay đổi (đây là những gì bạn đã nhận thấy);
  • đóng hộp thoại trình duyệt tệp bật lên nếu bạn sử dụng "tệp -> mở", "tệp -> lưu dưới dạng" từ menu (cũng như một số nơi khác).

Tôi đã thu thập thông tin này từ nguồn Vim bằng cách định vị tất cả các cuộc gọi đến buf_check_timestamp(), các check_timestamps()chức năng và vị trí need_check_timestampsđược đặt TRUE.

Tôi có thể đã bỏ lỡ một số sự kiện, nhưng điều quan trọng cần nhớ là Vim chỉ kiểm tra xem tệp có bị sửa đổi trong một tập hợp rất hạn chế của xơ gan hay không . Nó chắc chắn không "thăm dò" tệp cho các thay đổi trong n giây, về cơ bản là những gì bạn đang theo đuổi.

Vì vậy, cho mục đích của bạn, set autoreadlà không đủ.

Sử dụng Python

Điều này lên lịch một luồng Python để chạy trong nền, nó sẽ chạy :checktimemỗi n giây. Nếu autoreadđược bật , điều này sẽ tải lại bộ đệm từ đĩa, nếu không nó sẽ chỉ cảnh báo.

Điều này đòi hỏi Vim có +pythonhoặc +python3trong :version. Nó nên hoạt động trên tất cả các nền tảng (bao gồm cả 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

Bạn có thể bắt đầu điều này bằng cách sử dụng :call AutoreadPython(); tất nhiên bạn có thể làm điều này trong một autocmd; ví dụ:

autocmd *.c call AutoreadPython()

Lời bạt

Thực tế có nhiều phương thức hơn, ví dụ bạn có thể sử dụng một công cụ như entrhoặc Python inotifyhoặc gaminmô-đun để theo dõi tệp để thay đổi, :checktimecũng kiểm tra tất cả các bộ đệm nếu nó không đưa ra bất kỳ đối số nào, điều này có thể được cải thiện bằng cách chỉ kiểm tra một bộ đệm hoặc một tập tin nhất định
Tuy nhiên, câu trả lời này đã khá dài :-) Phương pháp này (hy vọng!) Hoạt động tốt cho hầu hết các kịch bản hoặc có thể dễ dàng thích ứng với kịch bản của bạn.

Tái bút Tôi cũng đã thử sử dụng Ruby, nhưng tiếc là các chủ đề của Ruby (không sử dụng Thread) không chạy trong nền như Python, vì vậy tôi không thể làm cho nó hoạt động (mặc dù có một cách khác?)


2

Tôi đã tạo một plugin vim-autoread nhỏ sử dụng tail -fđể cập nhật bộ đệm trong nền không đồng bộ. Điều này rõ ràng cần tính năng công việc của Vim Phiên bản 8.

Sử dụng :AutoReadđể bật và :AutoRead!tắt.


Một phiên bản tương thích NeoVim sẽ rất tuyệt!
Andrew

@AndrewMacFie Tôi không thấy, tại sao điều này sẽ không hoạt động trên Neovim.
Christian Brabandt

Tôi thiếu hỗ trợ việc làm Vim 8 trong NeoVim?
Andrew

@AndrewMacFie ồ điều đó có lẽ đúng. Vì tôi không sử dụng neovim, tôi không thể làm cho nó tương thích NeoVim. Tuy nhiên, một PR sẽ được hoan nghênh :)
Christian Brabandt

đủ công bằng :)
Andrew

1

Trong Neovim, bạn có thể sử dụng lệnh sau sẽ mở bộ đệm đầu cuối chạy lệnh đuôi.

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

Điều này sẽ tiếp tục hoạt động ngay cả khi tập tin được gỡ bỏ và tạo lại.

Hoặc thêm những điều sau đây vào $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>)

1

từ câu trả lời này (tham khảo câu trả lời của PhanHaiQuang và nhận xét của flukus )

Người ta có thể chạy oneliner này từ ex (whithin vim) khi cần (hoặc đặt từng lệnh trong vimrc, khi tệp log được mở.)

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

Giải thích:
- autoread : đọc tệp khi thay đổi từ bên ngoài (nhưng nó không hoạt động, không có bộ đếm thời gian bên trong hoặc một cái gì đó tương tự. Nó sẽ chỉ đọc tệp khi vim thực hiện một hành động, như một lệnh trong ex :!
- CoderHold * thời gian kiểm tra : khi con trỏ không di chuyển theo thời gian được chỉ định trong 'updatetime' (tức là 4000 milis giây theo mặc định), thời gian kiểm tra sẽ được thực hiện, kiểm tra các thay đổi từ bên ngoài tệp
- gọi feedkey ("lh") : con trỏ được di chuyển một lần, phải và quay lại bên trái. và sau đó không có gì xảy ra (... điều đó có nghĩa là CthonHold được kích hoạt, có nghĩa là chúng ta có một vòng lặp )

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.