Comment modifier un buffer sans annuler la remarque?

11

Q: Comment insérer / modifier du texte dans un tampon sans m'en rendre undocompte?

Voici le cas d'utilisation. J'ai un bloc de commentaires au début de chaque fichier qui, entre autres, met à jour un horodatage pour la modification la plus récente d'un fichier. J'aimerais pouvoir modifier cet horodatage sans que les undoinstallations le remarquent.

La raison pour laquelle je veux court-circuiter undoici est due au cas de bord suivant, qui apparaît lors de l'édition / compilation des documents LaTeX (et probablement d'autres, mais c'est celui qui me rend le plus souvent fou):

  1. Apportez une petite modification au fichier pour voir comment cela affectera le document compilé
  2. Enregistrez le fichier (qui met à jour l'horodatage)
  3. Exécuter latexsur le fichier
  4. Décidez que le changement est mauvais
  5. undo les changements

Le problème à l'étape (5) ( undo) est qu'il n'annule pas la modification effectuée à l'étape (1), mais annule plutôt la mise à jour de l'horodatage à l'étape (2). Cela ne me dérangerait pas (je pourrais le faire à undonouveau), sauf qu'il déplace également le point jusqu'à l'horodatage en haut du fichier, ce qui est presque toujours à de nombreuses lignes du changement de fond réel. C'est très choquant et brise complètement ma concentration.

Je pose la question par rapport à un fichier que je visite, mais il s'agit plus généralement de modifier les tampons.

Alors: comment puis-je éviter undode remarquer une modification spécifique d'un tampon?

Dan
la source
1
Ce n'est pas lié à votre question d'annulation, mais cela pourrait aider avec le problème "annuler le point": stackoverflow.com/a/20510025/1279369
nounou
2
Ne serait-il pas préférable que cette modification d'horodatage soit ajoutée à l'élément le plus récent de l'historique d'annulation? De cette façon , undoanéantirait les deux.
Malabarba du
Je pense que ce que vous voulez vraiment atomic-change-group.
@john: Comment cela aiderait-il? Les deux changements de groupe sont déclenchés par des commandes distinctes: un «petit changement» (par exemple une insertion) et la mise à jour de l'horodatage effectuée lors de la sauvegarde.
Gilles 'SO- arrête d'être méchant'
Notez que pour une raison quelconque, aucune de ces méthodes dans les réponses existantes n'a fonctionné pour moi, mais cette réponse définit une with-undo-collapsemacro qui était très utile: emacs.stackexchange.com/a/7560/2418
ideasman42

Réponses:

6

La réponse de @ stsquad m'a mis sur la bonne voie. Fondamentalement, les étapes sont les suivantes:

  1. enregistrer buffer-undo-list
  2. désactiver undo
  3. faire votre truc
  4. réactiver undoet restaurer lebuffer-undo-list

Voici donc un schéma d'une telle fonction:

(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

Edit: en fait, il s'avère qu'une solution plus simple consiste simplement à let-bind buffer-undo-listafin que les modifications apportées à la liste dans le corps du letget soient écrasées lorsque la liste d'origine est restaurée:

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

La principale limitation est que cela semble fonctionner pour les modifications qui ne changent pas le nombre de caractères dans le tampon (par exemple, changer "chatons" en "chiots", mais pas "chats"), car sinon le reste de l'annulation la liste fait maintenant référence aux mauvais points. Il ne s'agit donc que d'une solution partielle .

Dan
la source
Vous voudrez peut-être envelopper dans une protection de détente au cas où vous sortiriez de l'activité à mi-chemin de votre truc. Je ne savais pas que vous faisiez tout cela dans une fonction qui facilite le suivi des choses.
stsquad
Pouvez-vous également ajouter la solution pour la mise à jour de l'horodatage afin de ne pas mettre à jour l'historique d'annulation (et l'historique des points, si possible)?
Kaushal Modi
@stsquad: bonne idée, j'essaierai de le faire plus tard. Merci encore pour l'avertissement sur les fonctions et la liste en question.
Dan
@kaushalmodi: question de clarification: ce qui signifie que vous voulez voir la fonction de mise à jour de l'horodatage réelle?
Dan
@Dan aimerait voir comment modifier la fonction de mise à jour de l'horodatage pour ne pas mettre à jour l'historique d'annulation ou de point.
Kaushal Modi
3

Une opération d'annulation combine plusieurs éléments de la liste d'annulation . Une nilentrée dans la liste marque la frontière entre deux groupes de modifications. En supprimant le nilau début de la liste qui est automatiquement inséré par la boucle de niveau supérieur¹, vous pouvez grouper la mise à jour de l'horodatage avec le dernier changement de tampon, ce qui ne correspond pas techniquement à votre demande mais devrait pratiquement résoudre le problème dans votre scénario.

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

(Attention: non testé, la liste d'annulation peut nécessiter plus de massage.)

Vous pouvez également jouer avec la liste d'annulation d'une manière différente, en modifiant l' entrée de position (un entier) pour la mise à jour de l'horodatage.

¹ effectue un retrait similaire aux insertions de groupe. self-insert-command

Gilles 'SO- arrête d'être méchant'
la source
2

Le problème avec ce que vous suggérez est que l'arborescence d'annulation est une liste de deltas pour aller de l'endroit où vous êtes à l'endroit où vous voulez être. Bien qu'il soit parfaitement possible de désactiver le suivi d'annulation sur un tampon, je ne suis pas sûr de l'effet de l'enregistrement non actif des modifications. J'ai actuellement une bascule pour activer / désactiver l'annulation sur un tampon particulier car cela n'a pas de sens d'avoir des informations d'annulation sur un journal en pleine croissance ou une page rafraîchissante. Cependant, il supprime les changements de bascule:

(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 définit en fait juste buffer-undo-list à nil . Peut-être que si vous sauvegardiez l'état de la liste des tampons-annulations sur votre bascule, vous pourriez le restaurer ensuite?

stsquad
la source