Как я могу заставить Vim автоматически читать файл, пока он не имеет фокуса?

29

Я использую VIm для всех видов вещей (или gVim в данном случае), включая мониторинг вывода, записанного в файл; Я использую autoreadVim для перечитывания файла, что он делает всякий раз, когда я переключаю фокус клавиатуры на него.

Есть ли способ заставить Vim обновлять буфер, даже если я не переключаю фокус клавиатуры? Я попытался установить, checktimeно это не имеет никакого эффекта, в то время как клавиатура фокусируется в другом месте.

Вывод, который я отслеживаю, полностью заменяет выходной файл; и я не смотрю на tail -fэто. Существуют и другие варианты, например, каждый раз добавление нового экземпляра или добавление lessчего-либо, но было бы здорово, если бы это можно было сделать с помощью VIm.

falstro
источник
@Carpetsmoker как насчет CursorHoldмероприятия? Если Vim не имеет фокуса, он должен запускаться каждые n секунд.
Муру
1
@muru Нет, CursorHoldвыполняется только один раз, это явно задокументировано как: «не срабатывает каждые« время обновления »мс, если вы покидаете Vim, чтобы приготовить кофе. :)»
Мартин Турной
1
Я снова удалил тег gvim , я надеюсь, что все в порядке ;-) Как я понимаю, этот вопрос на самом деле не относится к gVim, поскольку изменение фокуса - это всего лишь одно событие, в котором Vim проверяет, не был ли изменен файл (существует целая куча, см. мой ответ для деталей). Большинство, если не все, способов улучшить это будет хорошо работать как в Vim, так и в gVim.
Мартин Турной
@Carpetsmoker ах, у меня сложилось впечатление, что gVim регулярно проверял, когда у него была фокусировка на клавиатуре (что делало его вопросом gVim), но, похоже, я ошибся. Спасибо за разъяснение этого.
Фальстро

Ответы:

20

Обновление 2015-06-25 :

  • Я отказался от метода «shell», так как он был слишком нефункциональным. Он остановил режим вставки и оставил процессы зомби. Посмотрите на историю изменений в этих постах, вы действительно хотите увидеть это в любом случае.
  • Я сделал плагин из этого: auto_autoread.vim . На данный момент он фактически совпадает с приведенным ниже кодом, но я бы порекомендовал вам использовать плагин, поскольку он может получать обновления.

Что делает autoread?

Чтобы ответить на этот вопрос, мы должны сначала понять, что autoreadделает опция, и что более важно, что она не делает.

К сожалению :help 'autoread' , не имеет много информации по этому поводу, он просто говорит, что «был обнаружен файл, который был изменен за пределами Vim» . Как Vim обнаруживает, что файл изменен? При определенных действиях Vim проверяет время модификации файла.

Когда:

  • :checktime используется;
  • буфер введен;
  • :diffupdate используется;
  • :e выдается для файла, который уже имеет буфер;
  • выполнение внешней команды с помощью !;
  • возвращение на передний план ( ^Z, fgтолько если оболочка имеет управление заданиями);

для gVim это также делается, когда:

  • закрытие меню «щелкнуть правой кнопкой мыши» (либо выбрав что-либо, либо просто закрыв его);
  • фокус изменен (это то, что вы уже заметили);
  • закрытие диалогового окна файловых браузеров, которое появляется, если вы используете «файл -> открыть», «файл -> сохранить как» из меню (а также некоторые другие места).

Я собрал эту информацию из источника Vim, найдя все вызовы buf_check_timestamp(), check_timestamps()функции и места, где need_check_timestampsустановлено TRUE.

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

Так что для ваших целей set autoreadэтого недостаточно.

Использование Python

Это запланирует поток Python для запуска в фоновом режиме, он будет запускаться :checktimeкаждые n секунд. Если autoreadбудет включена , это будет перезагрузить буфер с диска, иначе это будет просто предупредить.

Это требует, чтобы Vim имел +pythonили +python3в :version. Он должен работать на всех платформах (включая 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

Вы можете начать это с помощью :call AutoreadPython(); Вы, конечно, можете сделать это в autocmd; например:

autocmd *.c call AutoreadPython()

Послесловие

На самом деле существует больше методов, например, вы можете использовать инструмент, такой как entrPython inotifyили gaminмодуль, для отслеживания изменений в файле, а :checktimeтакже проверять все буферы, если ему не дано никаких аргументов, это можно улучшить, проверяя только один буфер или определенный файл.
Однако этот ответ уже довольно длинный :-) Этот метод должен (надеюсь!) Работать нормально для большинства сценариев или должен легко адаптироваться к вашему сценарию.

PS. Я также пытался использовать Ruby, но, к сожалению, потоки (использующие Thread) Ruby не работают в фоновом режиме, как это делает Python, поэтому я не смог заставить это работать (хотя, возможно, есть другой способ?)

Мартин Турной
источник
2

Я сделал небольшой плагин vim-autoread, который используется tail -fдля асинхронного обновления буфера в фоновом режиме. Это, очевидно, требует особой работы Vim версии 8.

Используйте, :AutoReadчтобы включить и :AutoRead!выключить его.

Кристиан Брабандт
источник
NeoVim-совместимая версия была бы отличной!
Андрей
@ AndrewMacFie Не понимаю, почему это не сработает на Neovim.
Кристиан Брабандт
отсутствие поддержки Vim 8 рабочих мест в NeoVim я думал?
Андрей
@AndrewMacFie О, это, вероятно, правда. Поскольку я не использую neovim, я не могу сделать его совместимым с NeoVim. Однако пиар приветствуется :)
Кристиан Брабандт
достаточно справедливо
Андрей
1

В Neovim вы можете использовать следующую команду, которая откроет буфер терминала, выполняющий команду tail.

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

Это продолжит работать, даже если файл будет удален и создан заново.

Или добавьте следующее к вашему $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>)
Бретт Y
источник
1

из этого ответа (ссылаясь на ответ от PhanHaiQuang и комментарий от flukus )

При необходимости можно запустить этот oneliner из ex (с vim) (или поместить каждую команду в vimrc, когда открываются лог-файлы).

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

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

Eli
источник