Vim có thể theo dõi các thay đổi trong thời gian thực đối với một tệp tin không


104

Câu hỏi của tôi tương tự như câu hỏi này là làm thế nào để theo dõi một tệp văn bản trong thời gian thực nhưng tôi muốn làm điều đó trong vim. Tôi biết mình có thể đọc tệp sử dụng tệp đã mở tail -f sample.xmlvà khi nội dung mới được ghi vào tệp, nó cũng sẽ ghi nội dung mới vào màn hình của tôi. Tôi có thể có vim tự động điền dữ liệu mới khi tệp được cập nhật không?

Câu trả lời:


101

Bạn có thể :set autoreadđể vim đọc tệp khi nó thay đổi. Tuy nhiên (tùy thuộc vào nền tảng của bạn), bạn phải tập trung cho nó.

Từ sự trợ giúp:

Khi một tệp được phát hiện đã bị thay đổi bên ngoài Vim và nó không bị thay đổi bên trong Vim, hãy tự động đọc lại tệp đó. Khi tệp đã bị xóa, điều này không được thực hiện.


5
Cảm ơn vì gợi ý! Điều này có vẻ khá hứa hẹn, nhưng nó không hoạt động trên hệ thống của tôi: (Tôi đang sử dụng Mac10.6.2 iTerm với phiên bản vim 7.2.303 được biên dịch với MacVim. Tôi có thể thử thêm bất kỳ nhận xét nào?
Patrick

Ờm, điều đó khá kỳ lạ. bạn đang sử dụng macvim gui hay phiên bản đầu cuối? nó hoạt động với tôi với macvim gui được biên dịch sẵn. (Tôi phải nhấp vào ứng dụng để cung cấp cho nó tập trung tuy nhiên, như tôi đã đề cập.)
Peter

1
Tôi đang thử nghiệm trong thiết bị đầu cuối, sau khi tôi sử dụng gvim (MacVim GUI), chức năng bắt đầu hoạt động! Như bạn đã đề cập, tôi cần tập trung gvim để cập nhật nội dung. Bạn có thủ thuật nào để cập nhật nó ngay cả khi không lấy nét không? Cảm ơn vì sự giúp đỡ của bạn lần nữa!
Patrick

3
Tôi không biết một giải pháp cho điều đó, rất tiếc. Tôi sẽ rất ngạc nhiên nếu vim có thể làm điều đó mà không cần thay đổi trọng tâm - nó sẽ yêu cầu vim thăm dò hệ thống tệp để xem khi nào nó thay đổi. Tôi nghĩ bạn cần một plugin cho điều đó.
Peter

2
@Peter Tôi đã tạo một plugin như vậy một thời gian trước. Cũng xem câu hỏi này và câu trả lời của tôi cho nó . để biết thêm chi tiết về cách thức autoreadhoạt động và những hạn chế của nó.
Martin Tournoij

63

Không biết về tự động, nhưng bạn có thể nhập:

:e!

để tải lại tệp


Mặc dù cách tiếp cận này không tự động cập nhật nội dung nhưng nó hiển thị nội dung đã cập nhật. Cảm ơn câu trả lời của bạn!
Patrick

31

Đặt những điều sau vào của bạn .vimrc:

"kiểm tra một lần sau 4 giây không hoạt động ở chế độ bình thường
đặt autoread                                                                                                                                                                                    
au CursorHold * kiểm tra thời gian                                                                                                                                                                       

Tuyệt quá! Hoạt động tốt, ngay cả khi có cảnh báo nếu bạn đã thay đổi tệp đó kể từ lần tải lại cuối cùng.
zoujyjs

1
Câu trả lời đầu tiên không phù hợp với tôi, nhưng nó hoạt động! :-)
Ionică Bizău

4
"Cứ 4 giây một lần" không đúng. Điều này sẽ chỉ kiểm tra một lần sau 4 giây không hoạt động ở chế độ bình thường. Vì vậy, nếu bạn không làm bất cứ điều gì trong bộ đệm khác trong một thời gian dài, nó sẽ không được cập nhật, nhưng sẽ có nếu bạn chỉ di chuyển con trỏ và đợi 4 giây. Một tùy chọn khác là gọi thủ công ": checktime" để cập nhật (sau khi thiết lập autoread). Thật không may, dường như không có bất kỳ loại hỗ trợ thăm dò nào trong vim, vì vậy không có câu trả lời thực sự cho câu hỏi OPs.
David Ljung Madison Stellar

1
Chỉ cần xem qua điều này. Nếu bạn thay đổi thời gian kiểm tra để gọi một hàm tùy chỉnh và thêm "callkey feed (" lh ")" vào cuối hàm thì nó sẽ kích hoạt 4 giây một lần.
flukus

@DavidLjungMadison bạn nói đúng, mình sẽ chỉnh sửa bài để tránh sai sót này
Phan Hai Quang

9

như @flukus đã nói trong một nhận xét cho câu trả lời trước đó mà bạn có thể call feedkeys["lh"](nó di chuyển con trỏ sang phải và quay lại bên trái, điều này bình thường không gây hại khi xem tệp nhật ký)

Vì vậy, nếu bạn kết hợp phần còn lại của câu trả lời, bạn có một đường thẳng, bạn có thể chạy từ ex (whithin vim) khi cần:

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


(nếu bạn muốn chuyển (gần) đến cuối tệp, chỉ cần sử dụng "G" thay vì "lh" với phím nguồn cấp dữ liệu)

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

Ngoài ra, bạn có thể :set syntax=logtalktô màu nhật ký

Để dừng cuộn khi sử dụng call feedkeys("G"), hãy thực thi :set noautoread- bây giờ vim sẽ cho biết, tệp đã bị thay đổi. Hãy hỏi xem người ta có muốn đọc các thay đổi hay không)

(Điều này có bất kỳ tác dụng phụ nào không?)

Chỉnh sửa: Tôi thấy một tác dụng phụ: nếu một người sử dụng phím nguồn cấp dữ liệu "G", nó sẽ cuộn xuống mọi vùng đệm hiện đang mở ?! Vì vậy, không thể làm việc trong bộ đệm bên trái của cửa sổ splittet trong khi bộ đệm bên phải tự động cuộn xuống tệp nhật ký


4

Gắn cái này vào .vimrc của bạn và nó sẽ hoạt động như một ông chủ. (Lấy từ: 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)

1
Đây là câu trả lời ưa thích để giải quyết những thiếu sót trong autoread đầu cuối.
mcanfield

3
@mcanfield Không, không phải vì điều này vẫn không "theo dõi các thay đổi". Bạn vẫn cần phải kích hoạt Vim và nó vẫn đang thăm dò ý kiến ​​(không xem) trên một số sự kiện giới hạn. CursorHoldđược chạy một lần . Vì vậy, nếu bạn đi uống cà phê hoặc đang làm gì đó trong một Cửa sổ khác, nó sẽ không cập nhật.
Martin Tournoij

4
Tập lệnh đó cũng được đóng gói dưới dạng một plugin Vim: vim-autoread .
stephen.hanson 11/09/18

1
@ stephen.hanson Cảm ơn liên kết, plugin đó đang hoạt động tốt đối với tôi!
Tropilio


2

Nếu unix + neovim

:term tail -f <filename>

Rõ ràng là điều này sẽ không hiệu quả với tất cả mọi người, nhưng đó là cách tôi làm.



0

VIM sẽ cảnh báo bạn khi tệp đã được cập nhật để bạn không ghi đè lên những thay đổi đã được thực hiện kể từ khi bạn mở tệp. Tại thời điểm đó, nó sẽ nhắc bạn tải lại tệp.


1
Cảm ơn câu trả lời của bạn, nhưng vim đã không cảnh báo tôi khi tệp đã bị thay đổi trong hệ thống của tôi :(
Patrick
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.