Може vim відстежувати зміни у файлі в режимі реального часу


104

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

Відповіді:


101

Ти можеш :set autoread зробити так, що vim читає файл, коли він змінюється. Однак (залежно від вашої платформи), ви повинні зосередитись на цьому.

З довідки:

Якщо виявлено, що файл був змінений поза Vim, і він не був змінений всередині Vim, автоматично прочитайте його ще раз. Коли файл буде видалено, цього не робиться.


5
Дякую за підказку! Це виглядає досить перспективно, але це не працює у моїй системі :( я використовую Mac10.6.2 iTerm з vim версією 7.2.303, скомпільованою з MacVim. Будь-який додатковий коментар я можу спробувати?
Патрік

ем, це досить дивно. ви використовуєте macvim gui або термінальну версію? це працює для мене з попередньо складеним macvim gui. (Мені доводиться натискати на додаток, щоб зосередити увагу, як я вже згадував.)
Петро,

1
Я тестував у терміналі, після того як я використав gvim (MacVim GUI), функція почала працювати! Як ви вже згадували, мені потрібно зосередити gvim, щоб оновити вміст. Чи є у вас якийсь трюк, щоб оновити його навіть без фокусування? Дякуємо за вашу допомогу ще раз.
Патрік

3
На жаль, не знаю рішення для цього. Я був би приголомшений, якби vim міг це зробити без зміни фокусу - він потребує опитування файлової системи, щоб побачити, коли вона змінюється. Думаю, для цього вам знадобиться плагін.
Пітер

2
@Peter Я зробив такий плагін деякий час тому. Дивіться також це питання та мою відповідь на нього . для отримання більш детальної інформації про те, як autoreadпрацює та обмежує їх.
Martin Tournoij

63

Не знаю про автоматично, але ви можете ввести:

:e!

перезавантажити файл


Хоча цей підхід не оновлює контент автоматично, він відображає оновлений вміст. Дякую за вашу відповідь!
Патрік

31

Помістіть у своєму .vimrc:

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

Чудово! Працює добре, навіть із попередженням, якщо ви змінили цей файл з моменту останнього перезавантаження.
zoujyjs

1
Перша відповідь не спрацювала для мене, але це працює! :-)
Ionică Bizău

4
"Кожні 4 секунди" не відповідає дійсності. Це перевірятиметься лише один раз після 4-х бездіяльності в звичайному режимі. Отже, якщо ви довго нічого не робите в іншому буфері, він не оновлюється, але це буде, якщо ви просто перемістите курсор і почекаєте 4 секунди. Інший варіант - вручну викликати ": checktime" для оновлення (після встановлення автопочитань). На жаль, начебто немає жодної підтримки опитування в vim, тому правдивої відповіді на питання ОП немає.
David Ljung Madison Stellar

1
Щойно натрапив на це. Якщо ви зміните контрольний час, щоб викликати користувацьку функцію, і додати в кінець функції "стрічки викликів (" lh ")", то вона запускатиметься кожні 4 секунди.
флюкус

@DavidLjungMadison Ви маєте рацію, я збираюся редагувати публікацію, щоб уникнути цієї помилки
Phan Hai Quang

9

як @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 мілісекунд), виконується контрольний час, який перевіряє зміни поза файлом
- виклики викликів ("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_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
Це кращий варіант відповіді на усунення недоліків автопослуг терміналу.
mcanfield

3
@mcanfield Ні, це не так, як це все ще не "спостерігає за змінами". Вам все ще потрібно активувати Vim, і він все ще опитується (не дивиться) на обмеженому наборі подій. CursorHoldзапускається один раз . Тож якщо ви вийдете і поп'єте каву, чи щось робите в іншому вікні, воно не оновиться.
Мартін Турнойж

4
Цей скрипт також поставляється як плагін Vim: vim-autoread .
stephen.hanson

1
@ stephen.hanson Дякую за посилання, що плагін добре працює для мене!
Тропіліо


2

Якщо unix + neovim

:term tail -f <filename>

Очевидно, що це буде працювати не для всіх, але це, як я це роблю.



0

VIM попередить вас, коли файл оновлено, щоб ви не перезаписали зміни, які були внесені з моменту його відкриття. Після цього він запропонує вам перезавантажити файл.


1
Дякую за вашу відповідь, але vim не попередив мене про зміну файлу в моїй системі :(
Патріку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.