From 9df72ecb6339110a0380c6faf75e7e93025bb26a Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Fri, 30 Aug 2019 12:20:30 +0200 Subject: [PATCH] Preserve more markers when reverting .gpg files * lisp/epa-file.el (epa-file--replace-text): Gingerly replace the text in the buffer to preserve as many markers as possible (bug#34720). This emulates the behaviour of Finsert_file_contents more accurately. (epa-file-decode-and-insert): Remove compat code. (epa-file-insert-file-contents): Use the new function. * lisp/emacs-lisp/cl-lib.el (cl-incf): Add autoload cookie. --- lisp/emacs-lisp/cl-lib.el | 1 + lisp/epa-file.el | 64 ++++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index c09fcf51eba..ff096918173 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el @@ -110,6 +110,7 @@ a future Emacs interpreter will be able to use it.") ;; These macros are defined here so that they ;; can safely be used in init files. +;;;###autoload (defmacro cl-incf (place &optional x) "Increment PLACE by X (1 by default). PLACE may be a symbol, or any generalized variable allowed by `setf'. diff --git a/lisp/epa-file.el b/lisp/epa-file.el index d9886d3d67f..c43641aacf3 100644 --- a/lisp/epa-file.el +++ b/lisp/epa-file.el @@ -102,16 +102,15 @@ encryption is used." (apply operation args))) (defun epa-file-decode-and-insert (string file visit beg end replace) - (if (fboundp 'decode-coding-inserted-region) - (save-restriction - (narrow-to-region (point) (point)) - (insert string) - (decode-coding-inserted-region - (point-min) (point-max) - (substring file 0 (string-match epa-file-name-regexp file)) - visit beg end replace)) - (insert (epa-file--decode-coding-string string (or coding-system-for-read - 'undecided))))) + (save-restriction + (narrow-to-region (point) (point)) + (insert string) + (decode-coding-inserted-region + (point-min) (point-max) + (substring file 0 (string-match epa-file-name-regexp file)) + visit beg end replace) + (goto-char (point-max)) + (- (point-max) (point-min)))) (defvar epa-file-error nil) (defun epa-file--find-file-not-found-function () @@ -147,8 +146,6 @@ encryption is used." (format "Decrypting %s" file))) (unwind-protect (progn - (if replace - (goto-char (point-min))) (condition-case error (setq string (epg-decrypt-file context local-file nil)) (error @@ -187,12 +184,11 @@ encryption is used." ;; really edit the buffer. (let ((buffer-file-name (if visit nil buffer-file-name))) - (save-restriction - (narrow-to-region (point) (point)) - (epa-file-decode-and-insert string file visit beg end replace) - (setq length (- (point-max) (point-min)))) - (if replace - (delete-region (point) (point-max)))) + (setq length + (if replace + (epa-file--replace-text string file visit beg end) + (epa-file-decode-and-insert + string file visit beg end replace)))) (if visit (set-visited-file-modtime)))) (if (and local-copy @@ -201,6 +197,38 @@ encryption is used." (list file length))) (put 'insert-file-contents 'epa-file 'epa-file-insert-file-contents) +(defun epa-file--replace-text (string file visit beg end) + ;; The idea here is that we want to replace the text in the buffer + ;; (for instance, for a `revert-buffer'), but we want to touch as + ;; little of the text as possible. So we compare the new and the + ;; old text and only starts replacing when the text changes. + (let ((orig-point (point)) + new-start length) + (goto-char (point-max)) + (setq new-start (point)) + (setq length + (epa-file-decode-and-insert + string file visit beg end t)) + (if (equal (buffer-substring (point-min) new-start) + (buffer-substring new-start (point-max))) + ;; The new text is equal to the old, so just keep the old. + (delete-region new-start (point-max)) + ;; Compute the region the hard way. + (let ((p1 (point-min)) + (p2 new-start)) + (while (and (< p1 new-start) + (< p2 (point-max)) + (eql (char-after p1) (char-after p2))) + (cl-incf p1) + (cl-incf p2)) + (delete-region new-start p2) + (delete-region p1 new-start))) + ;; Restore point, if possible. + (if (< orig-point (point-max)) + (goto-char orig-point) + (goto-char (point-max))) + length)) + (defun epa-file-write-region (start end file &optional append visit lockname mustbenew) (if append -- 2.39.5