aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apheleia.el65
1 files changed, 35 insertions, 30 deletions
diff --git a/apheleia.el b/apheleia.el
index e46898b..9b5885e 100644
--- a/apheleia.el
+++ b/apheleia.el
@@ -44,9 +44,6 @@
(buffer-hash)
(md5 (current-buffer))))
-(defvar apheleia--buffer-hash nil
- "Return value of `buffer-hash' when formatter started running.")
-
(defun apheleia--disallowed-p ()
"Return an error message if Apheleia cannot be run, else nil."
(when (and buffer-file-name
@@ -96,33 +93,41 @@ changes), CALLBACK, if provided, is invoked with no arguments."
;; error on `post-command-hook'. We already took care of throwing
;; `user-error' on interactive usage above.
(unless (apheleia--disallowed-p)
- (setq-local apheleia--buffer-hash (apheleia--buffer-hash))
- (let ((cur-buffer (current-buffer))
- (remote (file-remote-p (or buffer-file-name
- default-directory))))
- (apheleia--run-formatters
- formatters
- cur-buffer
- remote
- (lambda (formatted-buffer)
- (when (buffer-live-p cur-buffer)
- (with-current-buffer cur-buffer
- ;; Short-circuit.
- (when
- (equal
- apheleia--buffer-hash (apheleia--buffer-hash))
- (apheleia--create-rcs-patch
- cur-buffer formatted-buffer remote
- (lambda (patch-buffer)
- (when (buffer-live-p cur-buffer)
- (with-current-buffer cur-buffer
- (when
- (equal
- apheleia--buffer-hash (apheleia--buffer-hash))
- (apheleia--apply-rcs-patch
- (current-buffer) patch-buffer)
- (when callback
- (funcall callback))))))))))))))))
+ ;; It's important to store the saved buffer hash in a lexical
+ ;; variable rather than a dynamic (global) one, else multiple
+ ;; concurrent invocations of `apheleia-format-buffer' can
+ ;; overwrite each other, and get the wrong results about whether
+ ;; the buffer was actually modified since the formatting
+ ;; operation started, leading to data loss.
+ ;;
+ ;; https://github.com/radian-software/apheleia/issues/226
+ (let ((saved-buffer-hash (apheleia--buffer-hash)))
+ (let ((cur-buffer (current-buffer))
+ (remote (file-remote-p (or buffer-file-name
+ default-directory))))
+ (apheleia--run-formatters
+ formatters
+ cur-buffer
+ remote
+ (lambda (formatted-buffer)
+ (when (buffer-live-p cur-buffer)
+ (with-current-buffer cur-buffer
+ ;; Short-circuit.
+ (when
+ (equal
+ saved-buffer-hash (apheleia--buffer-hash))
+ (apheleia--create-rcs-patch
+ cur-buffer formatted-buffer remote
+ (lambda (patch-buffer)
+ (when (buffer-live-p cur-buffer)
+ (with-current-buffer cur-buffer
+ (when
+ (equal
+ saved-buffer-hash (apheleia--buffer-hash))
+ (apheleia--apply-rcs-patch
+ (current-buffer) patch-buffer)
+ (when callback
+ (funcall callback)))))))))))))))))
(defcustom apheleia-post-format-hook nil
"Normal hook run after Apheleia formats a buffer successfully."