Может ли vim отслеживать изменения файла в реальном времени


105

Мой вопрос аналогичен тому, как отслеживать текстовый файл в реальном времени, но я хочу сделать это в vim. Я знаю, что могу читать открытый файл использования tail -f sample.xmlфайла, и когда новый контент будет записан в файл, он также запишет новый контент на мой экран. Могу ли я сделать так, чтобы vim автоматически заполнял новые данные при обновлении файла?

Ответы:


101

Ты можешь :set autoread так, чтобы vim читал файл при его изменении. Однако (в зависимости от вашей платформы) вы должны сосредоточиться на ней.

Из справки:

Если было обнаружено, что файл был изменен вне Vim, но не был изменен внутри Vim, автоматически прочтите его снова. Когда файл был удален, этого не происходит.


5
Спасибо за подсказку! Это выглядит довольно многообещающе, но в моей системе это не работает :( Я использую Mac10.6.2 iTerm с vim версии 7.2.303, скомпилированный с MacVim. Могу я попробовать дополнительные комментарии?
Патрик

эм, это довольно странно. вы используете графический интерфейс macvim или терминальную версию? у меня он работает с предварительно скомпилированным macvim gui. (Как я уже упоминал, мне нужно нажать на приложение, чтобы сфокусировать его.)
Питер,

1
Я тестировал в терминале, после того, как я использовал gvim (MacVim GUI), функция начала работать! Однако, как вы упомянули, мне нужно сфокусировать gvim для обновления содержимого. У вас есть какие-нибудь хитрости, чтобы обновить его даже без фокусировки? Еще раз спасибо за вашу помощь.
Патрик

3
К сожалению, я не знаю решения этой проблемы. Я был бы ошеломлен, если бы vim мог сделать это без изменения фокуса - для этого потребовалось бы, чтобы vim опрашивал файловую систему, чтобы увидеть, когда она изменится. Думаю, для этого вам понадобится плагин.
Питер

2
@Peter Я сделал такой плагин некоторое время назад. Также смотрите этот вопрос и мой ответ на него . для получения более подробной информации о том, как autoreadработает и его ограничениях.
Мартин Турной, 03

63

Не знаю об автомате, но вы можете ввести:

:e!

перезагрузить файл


Хотя этот подход не обновляет содержимое автоматически, он отображает обновленное содержимое. Спасибо за Ваш ответ!
Патрик

31

Поместите следующее в свой .vimrc :

"проверка один раз после 4 секунд бездействия в нормальном режиме
установить автоматическое чтение                                                                                                                                                                                    
au CursorHold * checktime                                                                                                                                                                       

Большой! Работает хорошо, даже с предупреждением, если вы изменили этот файл с момента последней перезагрузки.
zoujyjs 02

1
Первый ответ у меня не сработал, но это работает! :-)
Ionică Bizău

4
«Каждые 4 секунды» не соответствует действительности. Это будет проверяться только один раз после 4 секунд бездействия в нормальном режиме. Поэтому, если вы долгое время ничего не делаете в другом буфере, он не будет обновляться, но это произойдет, если вы просто переместите курсор и подождите 4 секунды. Другой вариант - вручную вызвать ": checktime" для обновления (после установки авточитания). К сожалению, похоже, что в vim нет какой-либо поддержки опроса, поэтому нет верного ответа на вопрос OP.
Дэвид Люнг Мэдисон Стеллар

1
Только что наткнулся на это. Если вы измените время проверки для вызова пользовательской функции и добавите «call feedkeys (« lh »)» в конец функции, то она будет запускаться каждые 4 секунды.
flukus

@DavidLjungMadison, вы правы, я собираюсь отредактировать пост, чтобы избежать этой ошибки
Фан Хай Куанг

10

как @flukus сказал в комментарии к предыдущему ответу, вы можете call feedkeys["lh"](он перемещает курсор вправо и обратно влево, что обычно не вредит при просмотре файла журнала)

Итак, если вы объедините оставшуюся часть ответа, у вас есть oneliner, который вы можете запустить из ex (whithin vim) при необходимости:

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


(если вы хотите перейти (почти) к концу файла, просто используйте «G» вместо «lh» с клавишами подачи)

Объяснение:
- autoread : читает файл при изменении извне (но он не работает сам по себе, нет внутреннего таймера или чего-то подобного. Он будет читать файл только тогда, когда vim выполняет действие, например команду в ex :!
- CursorHold * checktime : когда курсор не перемещается пользователем в течение времени, указанного в 'updatetime' (которое по умолчанию составляет 4000 миллисекунд), выполняется checktime, который проверяет наличие изменений извне файла
- вызовите feedkeys («lh») : курсор перемещается один раз вправо и назад влево. а затем ничего не происходит (... это означает, что CursorHold срабатывает, что означает, что у нас есть цикл )

Дополнительно вы можете :set syntax=logtalkраскрасить журнал

Чтобы остановить прокрутку при использовании call feedkeys("G"), выполните :set noautoread- теперь vim сообщит, что файл был изменен, и спросит, хочет ли кто-то прочитать изменения или нет)

(Есть ли у этого побочные эффекты?)

Изменить: я вижу один побочный эффект: если использовать «G» в качестве клавиши подачи, он будет прокручивать вниз каждый текущий открытый буфер ?! Таким образом, невозможно работать в левом буфере разделенного окна, когда правый буфер автоматически прокручивает файл журнала вниз.


4

Вставьте это в свой .vimrc, и он должен работать как босс. (Взято с: http://vim.wikia.com/wiki/Have_Vim_check_automatically_if_the_file_has_changed_external )

" 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
Это предпочтительный ответ для устранения недостатков автоматического чтения терминала.
mcanfield

3
@mcanfield Нет, это не так, поскольку он все еще не «следит за изменениями». Вам все еще нужно, чтобы Vim был активным, и он все еще опрашивает (не просматривает) ограниченный набор событий. CursorHoldвыполняется один раз . Поэтому, если вы уходите и пьете кофе или делаете что-то в другом окне, оно не обновляется.
Мартин Турной, 03

4
Этот сценарий также входит в состав плагина Vim: vim-autoread .
stephen.hanson

1
@ stephen.hanson Спасибо за ссылку, этот плагин у меня работает хорошо!
Tropilio


2

Если unix + neovim

:term tail -f <filename>

Очевидно, это не сработает для всех, но я так делаю.



0

VIM предупредит вас, когда файл был обновлен, чтобы вы не перезаписали изменения, сделанные с момента его открытия. В этот момент вам будет предложено перезагрузить файл.


1
Спасибо за ответ, но vim не предупредил меня, когда файл был изменен в моей системе :(
Патрик
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.