Come modificare un buffer senza annullare la notifica?


11

D: Come posso inserire / modificare il testo in un buffer senza undonotarlo?

Ecco il caso d'uso. Ho un blocco di commenti all'inizio di ogni file che, tra le altre cose, aggiorna un timestamp per l'ultima modifica a un file. Mi piacerebbe essere in grado di modificare quel timestamp senza che le undostrutture lo notino.

Il motivo per cui voglio cortocircuitare undoqui è dovuto al seguente caso limite, che emerge durante la modifica / compilazione di documenti LaTeX (e probabilmente altri, ma questo è quello che mi fa impazzire più frequentemente):

  1. Apporta una piccola modifica al file per vedere come influirà sul documento compilato
  2. Salva il file (che aggiorna il timestamp)
  3. Esegui latexsul file
  4. Decidi che il cambiamento è negativo
  5. undo i cambiamenti

Il problema al passaggio (5) ( undo) è che non annulla la modifica apportata al passaggio (1), ma piuttosto annulla l'aggiornamento del timestamp nel passaggio (2). Ciò non mi disturberà (potrei solo di undonuovo), tranne per il fatto che si sposta anche fino al timestamp nella parte superiore del file, che è quasi sempre a molte, molte righe di distanza dall'effettivo cambiamento sostanziale. È molto sconcertante e rompe completamente la mia concentrazione.

Sto ponendo la domanda rispetto a un file che sto visitando, ma è più in generale sulla modifica dei buffer.

Quindi: come posso evitare undodi notare una specifica modifica a un buffer?


1
Questo non è correlato alla domanda di annullamento, ma potrebbe essere utile con il problema "annulla sposta il punto": stackoverflow.com/a/20510025/1279369
tata

2
Non sarebbe meglio se questa modifica del timbro data fosse aggiunta all'elemento più recente nella cronologia degli annullamenti? In questo modo undosi annullerebbero entrambi.
Malabarba,

Penso che quello che vuoi davvero sia atomic-change-group.

@john: come sarebbe d'aiuto? Le due modifiche al gruppo sono attivate da comandi separati: una "piccola modifica" (ad esempio un inserimento) e l'aggiornamento del timestamp fatto durante il salvataggio.
Gilles 'SO- smetti di essere malvagio' il

Nota che per qualche motivo nessuno di questi metodi nelle risposte esistenti ha funzionato per me, tuttavia questa risposta definisce una with-undo-collapsemacro che è stata molto utile: emacs.stackexchange.com/a/7560/2418
ideasman42

Risposte:


6

La risposta di @ stsquad mi ha portato sulla strada giusta. Fondamentalmente, i passaggi sono:

  1. Salva buffer-undo-list
  2. disattivare undo
  3. fare ciò che sai fare
  4. riattivare undoe ripristinare il filebuffer-undo-list

Quindi, ecco uno schizzo di tale funzione:

(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

Modifica: in realtà, si scopre che una soluzione più semplice è ancora semplicemente let-bind in buffer-undo-listmodo che le modifiche all'elenco nel corpo del letvengano bloccate quando viene ripristinato l'elenco originale:

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

La principale limitazione è che sembra funzionare per le modifiche che non cambiano il numero di caratteri nel buffer (ad esempio, cambiando "gattini" in "cuccioli", ma non "gatti"), perché altrimenti il ​​resto dell'annullamento l'elenco ora si riferisce ai punti sbagliati. Quindi, questa è solo una soluzione parziale .


Potresti voler concludere che, nel caso in cui ti interrompi, a metà strada attraverso la tua cosa, ti rilassi in una distesa. Non avevo capito che stavi facendo tutto questo in una funzione che rende più facile tenere traccia delle cose.
stsquad,

Puoi anche aggiungere la soluzione per l'aggiornamento del timestamp per non aggiornare la cronologia degli annullamenti (e la cronologia dei punti, se possibile)?
Kaushal Modi,

@stsquad: buona idea, proverò a farlo più tardi. Grazie ancora per il suggerimento sulle funzioni e sull'elenco in questione.
Dan

@kaushalmodi: chiarire la domanda: significa che vuoi vedere la funzione di aggiornamento del timestamp attuale?
Dan

@Dan Vorrei vedere come modificare la funzione di aggiornamento del timestamp per non aggiornare la cronologia dei punti o degli annullamenti.
Kaushal Modi,

3

Un'operazione di annullamento combina diversi elementi dall'elenco di annullamenti . Una nilvoce nell'elenco segna il confine tra due gruppi di modifiche. Rimuovendo nilall'inizio dell'elenco che viene automaticamente inserito dal ciclo di livello superiore¹, è possibile raggruppare l'aggiornamento del timestamp con l'ultima modifica del buffer, che tecnicamente non corrisponde alla richiesta ma praticamente dovrebbe risolvere il problema nel proprio scenario.

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

(Attenzione: non testato, l'elenco di annullamento potrebbe richiedere un maggiore massaggio.)

Puoi anche giocare con la lista degli annullamenti in un modo diverso, modificando la voce position (un numero intero) per l'aggiornamento del timestamp.

¹ esegue una rimozione simile alle inserzioni di gruppo. self-insert-command


2

Il problema con ciò che suggerisci è che l'annullamento dell'albero è un elenco di delta da ottenere da dove ti trovi a dove vuoi essere. Sebbene sia perfettamente possibile disabilitare il rilevamento degli annullamenti su un buffer, non sono sicuro di quale sarebbe l'effetto di non registrare attivamente le modifiche. Al momento ho un interruttore per attivare / disattivare l'annullamento su un determinato buffer in quanto non ha senso avere informazioni di annullamento in un registro crescente o in una pagina di aggiornamento. Tuttavia, annulla le modifiche sull'interruttore:

(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 in realtà imposta solo buffer-undo-list su zero . Forse se hai salvato lo stato di buffer-undo-list sul tuo toggle potresti ripristinarlo in seguito?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.