Привет, коллеги. Мы уже обсуждали отмену действий и возврат их. В vi отмена была одношаговой и сама считалась действием, то есть повторная отмена отменяла предыдущую, а третья отменяла отмену, возвращая правку обратно. В Вим тоже так можно, но вообще отмена многошаговая, можно отменить много правок с помощью команды u. Можно и вернуть их сочетанием <C-R>.
Получается линейная отмена: последовательность правок, которые можно отменять или возвращать обратно. Это удобно, но есть одна тонкость.
Прежде чем обсудить ее, давайте уточним понятие правки/действия. Это изменение, совершенное командной нормального режима или из командной строки, а также сеанс режима вставки целиком.
Если вы вошли в режим вставки и напечатали целую главу романа, то это одна правка!
Допустим, что вы сделали несколько правок, отменили одну или более, и сделали новое изменение. У вас появилась развилка, к которой вы можете вернуться... но вторая ветвь для обычной обратимой отмены потеряна!
Например. Вы вошли в режим вставки и набрали там "сорок два". Вышли. Скопировали строку в регистр (yy) и вставили: p. Вставили еще раз. Выполнили команду :%s/$/ (42)/
У вас такой текст:
сорок два (42)
сорок два (42)
сорок два (42)
Отменив действие (u), вы уберете скобки на все строках. Теперь вы решили сделать отступ: :%s/^/ /
Отступ-то вы получили, но возврата к скобочкам нет! Отмена приведет к "сорок два" от начала каждой строки. Возврат вернет отступ. Всё.
Это может быть досадно, так как, например. вы отменили что-то важное, временно, скажем, целую главу романа. Чтобы посмотреть, какое там имя было у героя изначально. И случайно нажали пробел. Всё! Это новая правка и новая ветвь в истории, а старая ветвь для линейной отмены недоступна.
Тема раскрыта в многочисленных фантастических произведениях. Герой отправился в прошлое изменить его, изменил, вернулся в другое уже будущее, в котором его подруга замужем за соседом - а всё, дружок, та ветка уже недоступна. Разве что полететь ещё раньше и помешать самому себе совершить изменение...
Но Вим поддерживает деревья правок. Давайте обсудим.
Гулять по дереву можно разными способами. Вим упорядочивает все правки по времени и дает к ним линейный доступ, по времени или по номеру или по порядку.
Команда нормального режима g- идет в прошлое, отменяя правки по порядку. g+ идет вперед, возвращая правки. Пример: создайте новый буфер (:tabnew) и выполните команды
iправка 1<esc>
<C-A>
r3
s4<esc>
u
r5
u
3<C-A>
r7
Это семь правок. Вы напечатали текст "правка 1", увеличили число на 1, получив 2, изменили 2 на 3, потом 3 на 4, вернулись к 3, заменили на 5. Отменили опять к 3, увеличили сразу на 3 до 6, и заменили на 7. Номера правок от 1 до 7, эти же номера стоят после слова "правка" (но это мы специально так устроили).
Команда g- последовательно вернет текст "правка 6", "правка 5" и так далее до "правка 1". А g+ последовательно вернет обратно. Сравните с поведением u: она пропустит "4" и "5", эти ветви для нее утеряны: от "6" перейдем к "3", потом к "2" и "1". Команда <C-R> вернет обратно "2", потом "3", потом "6" и "7".
Если вы знаете номер правки, к которой хотели бы вернуться, можете прыгнуть сразу на нее, командой :undo N, где N - номер правки.
Команды g- и g+ могут принимать повторители.
Есть возможность посмотреть дерево правок. Точнее, не дерево, а линейную последовательность правок во времени. Это команда :undolist.
Она выдает табличку с информацией о листьях дерева правок. Лист дерева - это последняя правка: отменить ее можно, а вот возвращать после нее нечего. Это либо текущее состояние текста, либо из этого состояния была совершена отмена, возврат, и пошла новая ветвь.
Каждый листик имеет номер, это первый столбец. Во втором столбце - число правок от начала дерева до листика, то есть длина линейной цепи правок, если бы других ветвей не было. Указано в третьем столбце время правки, в удобном формате: "6 секунд назад", время, время и дата, возможно, с годом. Есть еще столбец, в котором написано, было ли сохранено это состояние в файл.
Вы можете вернуться не только к листу дерева, но и к промежуточным состояниями командой :undo N. В нашем примере текст имеет вид "правка N" и это и есть правка номер N.
Вы можете перемещаться не по номерам правок, а прямо по времени. Для этого есть команды :earlier и :later. Например, :earlier 10s
Просто число показывает номер правки, а суффикс s (секунды), m(минуты), h(часы), d(сутки) позволяет откатываться к состоянию на данный момент в прошлом.
Конечно, это не всегда удобно. Когда вы много чиркали, отменяя и переделывая, то помнить, когда там точно была такая правка, может быть сложно. Но порой бывает удобно. Особенно, если вы запомнили время или знаете, что вас устраивал этот файл неделю назад и с тех пор он не менялся, а сегодня вы что-то запортили (с многочисленными отменами!) и вас это не устраивает.
Можно еще путешествовать по состояниям на момент записи. :earlier Nf откатывает на N записей в файл назад.
По опыту могу сказать, что всё это очень удобно, если вы не злоупотребляете отменами. Но если вы что-то сделали, отменили и сделали иначе, то вернуться к первому варианту может быть нужно и это сделать легко и приятно, и разными способами.
Есть и плагины, которые сильно упрощают работу с деревом правок, о них в другой раз.
Напоследок замечу, что разобраться в мешанине собственных версий поможет сохранение их в разных файлах командой :w и сравнение через :vimdiff. О нем был материал.
Удачи, коллеги!