Як змінити буфер, не відміняючи його?


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
ideaman42

Відповіді:


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-пов'язати, buffer-undo-listщоб зміни в списку в тілі letget clobbered при відновленні початкового списку:

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

"буфер-відключення-скасування" насправді просто встановлює буфер-скасування списку на нуль . Можливо, якщо ви зберегли стан перемикання буфера під час переключення, ви могли б відновити його згодом?

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