¿Cómo modificar un búfer sin deshacer el aviso?

11

P: ¿Cómo inserto / modifico texto en un búfer sin undodarme cuenta?

Aquí está el caso de uso. Tengo un bloque de comentarios al comienzo de cada archivo que, entre otras cosas, actualiza una marca de tiempo para el cambio más reciente en un archivo. Me gustaría poder modificar esa marca de tiempo sin que las undoinstalaciones lo noten.

La razón por la que quiero hacer un cortocircuito undoaquí se debe al siguiente caso límite, que surge al editar / compilar documentos LaTeX (y probablemente otros, pero este es el que me vuelve loco con más frecuencia):

  1. Realice un pequeño cambio en el archivo para ver cómo afectará al documento compilado
  2. Guarde el archivo (que actualiza la marca de tiempo)
  3. Ejecutar latexen el archivo
  4. Decide que el cambio es malo
  5. undo los cambios

El problema en el paso (5) ( undo) es que no deshace el cambio realizado en el paso (1), sino que deshace la actualización de la marca de tiempo en el paso (2). Eso no me molestaría (podría undovolver a hacerlo), excepto que también mueve el punto hasta la marca de tiempo en la parte superior del archivo, que casi siempre está a muchas, muchas líneas del cambio sustantivo real. Es muy discordante y rompe completamente mi concentración.

Estoy haciendo la pregunta con respecto a un archivo que estoy visitando, pero en general se trata de modificar buffers.

Entonces: ¿cómo puedo evitar undonotar una modificación específica en un búfer?

Dan
fuente
1
Esto no está relacionado con su pregunta de deshacer, pero podría ayudar con el problema de "deshacer mueve el punto": stackoverflow.com/a/20510025/1279369
niñera
2
¿No sería mejor si este cambio de sello de fecha se añadiera al elemento más reciente en el historial de deshacer? De esa forma undodeshacería ambas.
Malabarba
Creo que lo que realmente quieres es atomic-change-group.
@john: ¿Cómo ayudaría eso? Los dos cambios al grupo se activan mediante comandos separados: un "pequeño cambio" (por ejemplo, una inserción) y la actualización de la marca de tiempo realizada mientras se guarda.
Gilles 'SO- deja de ser malvado'
Tenga en cuenta que, por alguna razón, ninguno de estos métodos en las respuestas existentes funcionó para mí, sin embargo, esta respuesta define una with-undo-collapsemacro que fue muy útil: emacs.stackexchange.com/a/7560/2418
ideasman42

Respuestas:

6

La respuesta de @ stsquad me llevó por el camino correcto. Básicamente, los pasos son:

  1. salvar buffer-undo-list
  2. inhabilitar undo
  3. Haz tus cosas
  4. volver a habilitar undoy restaurar elbuffer-undo-list

Así que aquí hay un boceto de dicha función:

(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

Editar: en realidad, resulta que una solución más simple sigue siendo simplemente letvincular buffer-undo-listpara que los cambios en la lista en el cuerpo del letclobbered cuando se restaure la lista original:

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

La principal limitación con esto es que parece funcionar para modificaciones que no cambian el número de caracteres en el búfer (p. Ej., Cambiar "gatitos" a "cachorros", pero no "gatos"), porque de lo contrario el resto se deshace La lista ahora se refiere a los puntos equivocados. Por lo tanto, esta es solo una solución parcial .

Dan
fuente
Es posible que desee envolverlo en una protección de relajación en caso de que salga de la actividad a la mitad de su actividad. No me di cuenta de que estabas haciendo todo esto en una función que facilita el seguimiento de las cosas.
stsquad
¿Puede agregar también la solución para la actualización de marca de tiempo para no actualizar el historial de deshacer (y el historial de puntos, si es posible)?
Kaushal Modi
@stsquad: buena idea, intentaré hacerlo más tarde. Gracias de nuevo por el aviso sobre las funciones y la lista en cuestión.
Dan
@kaushalmodi: pregunta aclaratoria: ¿quiere decir que desea ver la función de actualización de marca de tiempo real?
Dan
@Dan Me gustaría ver cómo modificar la función de actualización de la marca de tiempo para no actualizar el historial de deshacer o de puntos.
Kaushal Modi
3

Una operación de deshacer combina varios elementos de la lista de deshacer . Una nilentrada en la lista marca el límite entre dos grupos de cambio. Al eliminar nilal principio de la lista que se inserta automáticamente por el bucle de nivel superior¹, puede agrupar la actualización de la marca de tiempo con el último cambio de búfer, que técnicamente no coincide con su solicitud, pero prácticamente debería resolver el problema en su escenario.

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

(Advertencia: sin probar, la lista de deshacer puede requerir más masajes).

También puede jugar con la lista de deshacer de una manera diferente, modificando la entrada de posición (un entero) para la actualización de la marca de tiempo.

¹ realiza una eliminación similar a las inserciones de grupo. self-insert-command

Gilles 'SO- deja de ser malvado'
fuente
2

El problema con lo que sugiere es que el árbol de deshacer es una lista de deltas para llegar desde donde está hasta donde quiere estar. Si bien es perfectamente posible deshabilitar el seguimiento de deshacer en un búfer, no estoy seguro de cuál sería el efecto de no registrar activamente los cambios. Actualmente tengo un interruptor para activar / desactivar deshacer en un búfer en particular, ya que no tiene sentido tener información de deshacer en un registro creciente o una página de actualización. Sin embargo, rechaza los cambios en alternar:

(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 en realidad solo establece buffer-undo-list en nil . ¿Tal vez si guardaste el estado de buffer-undo-list en tu alternador podrías restaurarlo después?

stsquad
fuente