Як я можу змусити Vim автоматично читати файл, якщо він не має фокусу?


29

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

Чи є спосіб змусити Vim оновлювати буфер, навіть якщо я не перемикаю фокус клавіатури? Я спробував налаштування, checktimeале, схоже, це не має ніякого ефекту, коли фокус клавіатури знаходиться в іншому місці.

Моніторинг результатів я повністю замінюю вихідний файл; і я не дивлюсь на tail -fце. Є й інші варіанти, такі як підключення кожного разу до нового екземпляра, або підключення до lessчогось іншого, але було б здорово, якби це можна було зробити з VIm.


@Carpetsmoker як щодо CursorHoldподії? Якщо Vim не має фокусу, він повинен спрацьовувати кожні n секунд.
муру

1
@muru Ні, CursorHoldвиконується лише один раз, це чітко задокументовано так: "не запускає кожен" updatetime "мс, якщо ви залишаєте Vim робити каву. :)"
Martin Tournoij

1
Я видалив GVim тег знову, я сподіваюся , що все в порядку ;-) Як я розумію, це питання , це НЕ на насправді про GVim, оскільки зміна фокусу тільки одна подія , на якому Vim перевіряє , є чи файл змінено (є ціла купа, див детальну інформацію про мою відповідь). Більшість, якщо не всі способи покращити це, спрацюють чудово як у Vim, так і у gVim.
Мартін Турноїй

@Carpetsmoker ах, у мене було враження, що gVim регулярно перевіряє, коли він фокусується на клавіатурі (таким чином, це питання gVim), але, здається, я помилявся. Дякуємо, що очистили це.
falstro

Відповіді:


20

Оновлення 2015-06-25 :

  • Я заблокував метод "оболонки", оскільки він був надто нефункціональним. Він припинив режим вставки та залишив зомбі-процеси. Подивіться на історію редагування цієї публікації, чи справді ви хочете її все одно побачити.
  • Я зробив плагін із цього: 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 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, але, на жаль, потоки Ruby (використовуючи Thread) не працюють у фоновому режимі, як це робить Python, тому мені не вдалося змусити це працювати (можливо, є інший спосіб, хоча?)


2

Я зробив невеликий плагін vim-autoread, який використовує tail -fдля асинхронного оновлення буфера у фоновому режимі. Це, очевидно, потребує функції роботи Vim Версії 8.

Використовуйте :AutoReadдля ввімкнення та :AutoRead!вимкнення.


Сумісна з NeoVim версія буде чудовою!
Андрій

@AndrewMacFie Я не бачу, чому це не працює на Neovim.
Крістіан Брабандт

відсутність підтримки Vim 8 для роботи в NeoVim, я думав?
Андрій

@AndrewMacFie о, це, мабуть, правда. Оскільки я не використовую neovim, я не можу зробити NeoVim сумісним. Однак піар буде вітатися :)
Крістіан Брабандт

досить справедливо:)
Андрій

1

У Neovim ви можете використовувати таку команду, яка відкриє термінальний буфер, що виконує хвостову команду.

: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>)

1

з цієї відповіді (посилаючись на відповідь PhanHaiQuang та коментар flukus )

Можна запустити цей oneliner з ex (whithin vim) за потреби (або поставити кожну команду в vimrc, коли відкриваються файли журналу.)

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

Пояснення:
- autoread : читає файл при зміні ззовні (але він не працює сам по собі, немає внутрішнього таймера чи щось подібне. Він буде читати файл лише тоді, коли vim виконує дію, як команда в ex :!
- CursorHold * checktime : коли курсор не переміщується користувачем протягом часу, визначеного у 'updatetime' (який за замовчуванням становить 4000 мілісекунд), виконується контрольний час, який перевіряє зміни поза файлом
- виклики виклику ("lh") : курсор переміщується один раз, праворуч і назад ліворуч, і тоді нічого не відбувається (... це означає, що CursorHold спрацьовує, це означає, що у нас є цикл )

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