emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/diff-hl 2c07ababaa: Allow updating indicators asynchron


From: ELPA Syncer
Subject: [elpa] externals/diff-hl 2c07ababaa: Allow updating indicators asynchronously (without blocking Emacs) (#207)
Date: Sun, 21 Jan 2024 18:57:51 -0500 (EST)

branch: externals/diff-hl
commit 2c07ababaa621c593fbd2746551311e14ce5af55
Author: Wai Hon Law <whhone@gmail.com>
Commit: GitHub <noreply@github.com>

    Allow updating indicators asynchronously (without blocking Emacs) (#207)
    
    Problem: On a slow VC backend, `diff-hl-mode` freezes Emacs because
    `(diff-hl-changes)` takes a long time.
    
    Changes:
    - Add a custom variable `diff-hl-update-async`.
    - When it's non-nil, update inside a separate thread.
    - Log a message if diff-hl--update throws an error.
    - Add a TODO to debounce if a thread is already running.
---
 diff-hl.el           | 26 ++++++++++++++++++++++++++
 test/diff-hl-test.el | 25 +++++++++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/diff-hl.el b/diff-hl.el
index 2a8bce556b..c654e73e01 100644
--- a/diff-hl.el
+++ b/diff-hl.el
@@ -194,6 +194,14 @@ the NEW revision is not specified (meaning, the diff is 
against
 the current version of the file)."
   :type 'boolean)
 
+(defcustom diff-hl-update-async nil
+  "When non-nil, `diff-hl-update' will run asynchronously.
+
+This can help prevent Emacs from freezing, especially by a slow version
+control (VC) backend. Remote files will not be affected since this feature
+does not work reliably with them."
+  :type 'boolean)
+
 (defvar diff-hl-reference-revision nil
   "Revision to diff against.  nil means the most recent one.")
 
@@ -384,6 +392,24 @@ the current version of the file)."
       (nreverse res))))
 
 (defun diff-hl-update ()
+  "Updates the diff-hl overlay in a thread."
+  (if (and diff-hl-update-async
+           ;; Disable threading on the remote file as it is unreliable.
+           (not (file-remote-p default-directory)))
+      ;; TODO: debounce if a thread is already running.
+      (make-thread 'diff-hl--update-safe "diff-hl--update-safe")
+    (diff-hl--update)))
+
+(defun diff-hl--update-safe ()
+  "Updates the diff-hl overlay. It handles and logs when an error is signaled."
+  (condition-case err
+      (diff-hl--update)
+    (error
+     (message "An error occurred in diff-hl--update: %S" err)
+     nil)))
+
+(defun diff-hl--update ()
+  "Updates the diff-hl overlay."
   (let ((changes (diff-hl-changes))
         (current-line 1))
     (diff-hl-remove-overlays)
diff --git a/test/diff-hl-test.el b/test/diff-hl-test.el
index d255f0a147..412532f01a 100644
--- a/test/diff-hl-test.el
+++ b/test/diff-hl-test.el
@@ -126,6 +126,31 @@
     (should (looking-at "added"))
     (should-error (diff-hl-next-hunk) :type 'user-error)))
 
+(diff-hl-deftest diff-hl-indirect-buffer-move-async ()
+  (diff-hl-test-in-source
+   (let ((diff-hl-update-async t))
+     (narrow-to-region (point-min) (point-max))
+     (goto-char (point-min))
+     (kill-whole-line 3)
+     (goto-char (point-max))
+     (insert "added\n")
+     (save-buffer)
+     (diff-hl-mode 1)
+
+     ;; wait for all thread to complete.
+     (dolist (thread (all-threads))
+       (unless (eq thread main-thread)
+         (thread-join thread)))
+
+     (diff-hl-previous-hunk)
+     (should (looking-at "added"))
+     (diff-hl-previous-hunk)
+     (should (looking-at "function2"))
+     (should-error (diff-hl-previous-hunk) :type 'user-error)
+     (diff-hl-next-hunk)
+     (should (looking-at "added"))
+     (should-error (diff-hl-next-hunk) :type 'user-error))))
+
 (diff-hl-deftest diff-hl-can-ignore-staged-changes ()
   (diff-hl-test-in-source
     (goto-char (point-min))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]