Как стать автором
Обновить

Undo/Redo своими руками

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров896

Больше двадцати лет назад мне довелось поработать в одном берлинском стартапе, где мы пилили визуальную трансформацию UML в код и обратно. Пользовательский интерфейс на свинге, изоморфная (в теории) обработка кода и диаграмм — на хаскеле. Было весело, потом полопались доткомы, кончилось финансирование и мы еще почти год пытались как-то дотянуть до продукта без денег. Капитализм победил, и продукт погиб (насколько я знаю) — так и не родившись.

Из интересного (помимо того, что я сам нарисовал почти полсотни иконок для нашего приложения, что до сих пор считаю самым выдающимся собственным достижением в IT) — там был придуманный и воплощенный мной механизм Undo/Redo, о котором я и собираюсь сегодня рассказать.

Как нерадивый Вася Пупкин воплощает в реальность маловнятную просьбу заказчика добавить «чтобы оно удалялось, а потом обратно появлялось, как в ворде»? — Строит линейную очередь изменений и ходит туда-сюда указателем по этому тоннелю без света в конце. После добавления ручной правки — все элементы в очереди дальше текущего — просто стираются, от греха подальше. Так ведь?

Как ту же самую задачу решает несдержанный на язык швед финского происхождения? — Правильно, пишет git.

Гита тогда еще не было, поэтому я черпал вдохновение из svn. Всё-таки у нас был свой внутренний формат, в котором возможности копи-пасты, прямо скажем, были немного ограничены, поэтому на Undo/Redo возлагались чуть бо́льшие, чем обычно, надежды. Нам казалось, что хотя бы механизм «чёрт, я же вот это только что рисовал, а потом удалил, как вернуть?» — необходимо по возможности предоставить. Поэтому Undo/Redo у нас изначально предполагался такой урезанной системой версий с ветками и возможностью слияния.

Любой, кто хоть раз выполнял кодревью файла, подвергшегося разрушительному воздействию автоматического форматтера, знает, что сравнивать диффом имеет смысл только нормализованные сущности. Поэтому нам требовался какой-то внутренний формат, допускающий нормализацию и диффеоморфный одновременно исходному коду и его UML-представлению. Я внезапно не стал изобретать велосипед и взял то, что просилось и так: AST. Иными словами, мы хранили содержимое пользовательских файлов в некоем LISP’е, из которого воспроизводили и код на джаве, и его UML-представление.

Мы довольно быстро научились гонять форматы туда-сюда без потерь, и тут встал вопрос: что является атомарной неделимой конструкцией, позволяющей над собой операцию Undo/Redo?

Чтобы оттянуть решение этого вопроса, мы для начала разрешили «коммиты» (не помню, как они у нас назывались, кажется, «точками фиксации»). Если код в текущем его состоянии компилировался, то действие «зафиксировать» становилось активным и пользователь мог «нажать кнопку „коммит“». Мы создавали дифф относительно предыдущего состояния в этой ветке и добавляли его в «дерево истории». Были доступны функции cleanup (аналог merge из гита) и squeeze . Это всё довольно несложно реализуется и я не могу придумать ни единой веской причины не добавлять подобное во все редакторы.

При этом, что считать атомарной единицей изменений — было по-прежнему неясно. Набранный символ — это несерьёзно, пользоваться такой штукой будет невозможно. В результате был выбран «компилируемый юнит». Как только дифф компилировался, мы добавляли его в историю; поскольку основным редактором был редактор UML — оказалось достаточно просто генерировать заглушки на добавляемые сущности и история оказывалась более-менее читаемой из коробки.

Такой подход позволил нам, по сути, бесплатно получить функциональность черри-пиков и простые слияния. По сути, мы получили возможность не только сколько угодно ветвить нашу историю, но и корректно разрешать конфликты в ситуации, когда они разрешимы (изменения не пересекаются)

A → A & B → ‹UNDO› → A → A & C → ‹REDO› → A & B & C

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

Удачного андуредуинга!

Теги:
Хабы:
+4
Комментарии5

Публикации

Ближайшие события