Найти в Дзене
Блокнот математика

Рубрика "Секреты Вим". Если файл изменился.

Привет, коллеги. Существует известная проблема независимого изменения файла, если доступ к нему не закрыт. Например, файл открыт в двух разных терминалах с Вим. Или в Вим и в другом редакторе. Или разными пользователями по сети. Или файл изменила какая-то программа. Да мало ли! Вариант сохранять файл при каждом изменении вполне рабочий, так действуют облачные сервисы. В Вим так можно, но это не лучший способ. Обсудим, как Вим вообще борется с этой проблемой. Сравнение атрибутов Вим запоминает время изменения файла, его размер и некоторую дополнительную информацию, когда открывает его. Если вызывается программы извне (через !, команду K, другими способами), эти характеристики сверяются с сохраненными, для всех файлов в окне. Если обнаружено расхождение, Вим либо выполнит автокоманду для события FileChangedShell (позволяя Вам среагировать), либо предупредит о том, что файл изменился: W12: Предупреждение: файл "falsiamici" и буфер Vim были изменены независимо друг от друга
См. ":help W12"

Привет, коллеги. Существует известная проблема независимого изменения файла, если доступ к нему не закрыт. Например, файл открыт в двух разных терминалах с Вим. Или в Вим и в другом редакторе. Или разными пользователями по сети. Или файл изменила какая-то программа. Да мало ли!

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

Обсудим, как Вим вообще борется с этой проблемой.

Здесь объект один и каждое изменение сразу сохраняется. А вот если унести дверку, а потом кто-то еще повесит новую дверку, могут возникнуть конфликты.
Здесь объект один и каждое изменение сразу сохраняется. А вот если унести дверку, а потом кто-то еще повесит новую дверку, могут возникнуть конфликты.

Сравнение атрибутов

Вим запоминает время изменения файла, его размер и некоторую дополнительную информацию, когда открывает его. Если вызывается программы извне (через !, команду K, другими способами), эти характеристики сверяются с сохраненными, для всех файлов в окне. Если обнаружено расхождение, Вим либо выполнит автокоманду для события FileChangedShell (позволяя Вам среагировать), либо предупредит о том, что файл изменился:

W12: Предупреждение: файл "falsiamici" и буфер Vim были изменены независимо друг от друга
См. ":help W12" для дополнительной информации.
[O]K, (L) Загрузить файл:

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

Обработка событий

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

au FileChangedShell * !cp <afile> <afile>.copy

Вам доступны переменные v:fsc_reason и v:fsc_choice. Первая описывает, что именно произошло: deleted, если файл более не существует; conflict, если характеристики файла изменились, и при этом в буфере есть несохраненные изменения; changed, если изменилось содержимое файла; mode, если изменились атрибуты файла; time, если изменилось время изменения файла. Вторую переменную можете задать вы в ходе обработки события, и по ней Вим ориентируется, что делать дальше. Если ее не задавать, оставив пустой, то автокоманда должна сама обо всем позаботиться. Например, перезагрузить файл. Если задать reload, то Вим сделает это сам. Если же задать ask, то Вим задаст вопрос пользователю, как и в отсутствие автокоманды.

Еще есть событие FileChangedShellPost, которое наступает после обработки FileChangedShell. В нем можно обновить строку информации, например.

Автоперезагрузка файла

Иногда имеет смысл просто обновлять файл в буфере, не задавая вопросов. Часто. Например, если вы запустили что-то с целью поменять файл вне Вим, то ясно же, что вы хотите увидеть результат. Или если у вас открыт файл с результатами расчетов и вы запустили новый. Вы хотите обновить буфер и посмотреть, что получилось. Для этого необязательно создавать автокоманду: есть опция autoread, которую можно выставить.

Важно: если в буфере есть несохраненные изменения, то есть конфликт, опция не срабатывает. Конфликты вы должны решать сами, это может быть важно. Если файл был удален, он тоже не "перезагружается", то есть не теряется.

Форсирование проверки

Можно вручную инициировать проверку: командой :checktime. Без параметров она проверяет все открытые файлы. Можно проверить адресно заданный файл, указав его имя после команды, или буфер по номеру (указав его до или после).

Проверка при записи

Сказанное выше относится к ситуациям, когда Вим может заподозрить, что файл изменился или мог измениться. Однако файл мог измениться незаметно для Вим, а для проверки нет оснований. Вы можете инициировать ее вручную, но вы тоже можете не знать или забыть. Поэтому при записи файла есть риск запортить сделанные извне изменения. Особенно это опасно, если файл лежит в облаке вроде DropBox или на удаленном ресурсе по ssh, и вы работаете с ним то с работы, то из дома.

Но Вим проверяет всё, когда дана команда на запись файла. Любым способом: просто перед записью файла он проверяется по указанным выше атрибутам. Если зафиксировано различие, то выдается предупреждение:

ПРЕДУПРЕЖДЕНИЕ: Файл изменён с момента чтения!!!
Серьёзно хотите записать в этот файл (y/n)?

Если вы не знаете точно, что произошло, то откажитесь (n), сохраните файл под другим именем и используйте vimdiff для отслеживания различий. Если же вы обновили файл и забыли об этом, а внесенные правки невелики, то откажитесь (n) и перезагрузите файл: :e!

Наконец, если файл был изменен не по делу и вы настаиваете на своей версии, то сохраняйте (y)!

Удачи, коллеги!

Научно-популярные каналы на Дзене: путеводитель
Новости популярной науки12 марта 2022