Как изменить буфер без отмены замечаний?

11

В: Как мне вставить / изменить текст в буфере, не undoзамечая этого?

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

Причина, по которой я хочу закорачивать undoздесь, связана со следующим краевым случаем, который возникает при редактировании / компиляции документов LaTeX (и, возможно, других, но это тот, который сводит меня с ума чаще всего):

  1. Сделайте небольшое изменение в файле, чтобы увидеть, как это повлияет на скомпилированный документ
  2. Сохраните файл (который обновляет отметку времени)
  3. Запустите latexфайл
  4. Решите, что изменение плохое
  5. undo перемены

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

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

Итак: как я могу не undoзаметить конкретную модификацию буфера?

Дэн
источник
1
Это не относится к вашему вопросу отмены, но может помочь с проблемой «отменить перемещение точки»: stackoverflow.com/a/20510025/1279369
няня
2
Разве не было бы лучше, если бы это изменение даты было добавлено к самому последнему элементу в истории отмен? Этот способ undoотменяет оба.
Малабарба
Я думаю, что вы действительно хотите atomic-change-group.
@john: Как это поможет? Два изменения в группе инициируются отдельными командами: «небольшое изменение» (например, вставка) и обновление отметки времени, выполняемое при сохранении.
Жиль "ТАК - перестань быть злым"
Обратите внимание, что по какой-то причине ни один из этих методов в существующих ответах не работал для меня, однако этот ответ определяет with-undo-collapseмакрос, который был очень полезен: emacs.stackexchange.com/a/7560/2418
ideasman42

Ответы:

6

Ответ @ stsquad вывел меня на правильный путь. В основном, шаги:

  1. спасти buffer-undo-list
  2. отключить undo
  3. занимайся своим делом
  4. повторно включить undoи восстановитьbuffer-undo-list

Итак, вот эскиз такой функции:

(defun disable-undo-one-off ()
  (let ((undo buffer-undo-list))        ; save the undo list
    (buffer-disable-undo)               ; disable undo
    (do-some-stuff)                     ; do your thing
    (buffer-enable-undo)                ; re-enable undo
    (setq buffer-undo-list undo)))      ; restore the undo list

Изменить: на самом деле, оказывается, что более простое решение по-прежнему просто let-bind, buffer-undo-listтак что изменения в теле в теле letget-clobreded при восстановлении исходного списка:

(defun disable-undo-one-off ()
  (let (buffer-undo-list)
    (do-some-stuff)))

Основным ограничением этого является то, что он работает для модификаций, которые не изменяют количество символов в буфере (например, изменяя «котята» на «щенки», но не «кошки»), потому что в остальном отмена отменяется. список теперь ссылается на неправильные точки. Следовательно, это только частичное решение .

Дэн
источник
Возможно, вы захотите обернуть это в защитную пленку на случай, если вы прервете свою деятельность на полпути через свою вещь. Я не осознавал, что вы делаете все это в функции, которая облегчает отслеживание вещей.
stsquad
Можете ли вы также добавить в решение обновление отметки времени, чтобы не обновлять историю отмен (и, если возможно, историю точек)?
Каушал Моди
@stsquad: хорошая идея, постараюсь сделать это позже. Еще раз спасибо за отзыв о функциях и список в вопросе.
Дан
@kaushalmodi: уточняющий вопрос: имеется в виду, что вы хотите увидеть актуальную функцию обновления отметки времени?
Дан
@Dan Хотелось бы узнать, как изменить функцию обновления отметки времени, чтобы не обновлять историю отмен или точек.
Каушал Моди
3

Операция отмены объединяет несколько элементов из списка отмен . nilЗапись в списке обозначает границу между двумя группами изменений. Удалив nilв начале списка, который автоматически вставляется циклом верхнего уровня¹, вы можете сгруппировать обновление метки времени с последним изменением буфера, которое технически не соответствует вашему запросу, но практически должно решить проблему в вашем сценарии.

(defun time-stamp-group-undo ()
  (if (eq nil (car buffer-undo-list))
      (setq buffer-undo-list (cdr buffer-undo-list)))
  (time-stamp))

(Предупреждение: непроверенный, список отмен может потребовать большего массажа.)

Вы также можете по-другому поиграть со списком отмен, изменив запись позиции (целое число) для обновления метки времени.

¹ делает аналогичное удаление для групповых вставок. self-insert-command

Жиль "ТАК - перестань быть злым"
источник
2

Проблема с тем, что вы предлагаете, состоит в том, что дерево отмены - это список дельт, которые вы получаете от того, где вы находитесь, где вы хотите быть. Хотя вполне возможно отключить отслеживание отмены в буфере, я не уверен, каким будет эффект неактивной записи изменений. В настоящее время у меня есть переключатель для включения / выключения отмены в определенном буфере, поскольку нет смысла иметь информацию об отмене в растущем журнале или обновлении страницы. Однако он отменяет изменения при переключении:

(defun my-toggle-buffer-undo ()
  "Toggle undo tracking in current buffer."
  (interactive)
  (with-current-buffer (current-buffer)
    (if (eq buffer-undo-list t)
        (setq buffer-undo-list nil)
      (buffer-disable-undo (current-buffer)))))

(define-key my-toggle-map "u" 'my-toggle-buffer-undo)

buffer-disable-undo на самом деле просто устанавливает buffer-undo-list на ноль . Может быть, если вы сохраните состояние буфера-отмены-списка при переключении, вы сможете восстановить его позже?

stsquad
источник