branch: externals/diff-hl
commit 7a89c85b89dd742be271629d6473ea3e1e26d233
Author: Dmitry Gutov <dmi...@gutov.dev>
Commit: Dmitry Gutov <dmi...@gutov.dev>

    diff-hl-update-async: Improve parallelism
    
    When called synchronously, the diff process holds the Lisp interpreter lock,
    even when it's performed in a separate Lisp thread. Calling it 
asynchronously
    improves contention.
    
    This requires the latest Emacs 31, commit 
https://cgit.git.savannah.gnu.org/cgit/emacs.git/commit/?id=bec823b107ef7d3b51b8e430ccab82c81bd63d24
---
 diff-hl-show-hunk.el |  1 +
 diff-hl.el           | 39 +++++++++++++++++++++++++--------------
 2 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/diff-hl-show-hunk.el b/diff-hl-show-hunk.el
index 6ab097ca6f..45f201c90e 100644
--- a/diff-hl-show-hunk.el
+++ b/diff-hl-show-hunk.el
@@ -132,6 +132,7 @@ point in that buffer to the corresponding line of the 
original
 buffer."
   (defvar vc-sentinel-movepoint)
   (let* ((buffer (or (buffer-base-buffer) (current-buffer)))
+         (diff-hl-update-async nil)
          (line (line-number-at-pos))
          (dest-buffer diff-hl-show-hunk-diff-buffer-name))
     (with-current-buffer buffer
diff --git a/diff-hl.el b/diff-hl.el
index 01210f6f57..d8b9c2f486 100644
--- a/diff-hl.el
+++ b/diff-hl.el
@@ -364,21 +364,24 @@ It can be a relative expression as well, such as 
\"HEAD^\" with Git, or
   (if (and (eq backend 'Git)
            (not diff-hl-reference-revision)
            (not diff-hl-show-staged-changes))
-      (apply #'vc-git-command buffer 1
+      (apply #'vc-git-command buffer
+             (if (diff-hl--use-async-p) 'async 1)
              (list file)
              "diff-files"
              (cons "-p" (vc-switches 'git 'diff)))
     (condition-case err
         (vc-call-backend backend 'diff (list file)
                          diff-hl-reference-revision nil
-                         buffer)
+                         buffer
+                         (diff-hl--use-async-p))
       (error
        ;; https://github.com/dgutov/diff-hl/issues/117
        (when (string-match-p "\\`Failed (status 128)" (error-message-string 
err))
          (vc-call-backend backend 'diff (list file)
                           "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
                           nil
-                          buffer)))))
+                          buffer
+                          (diff-hl--use-async-p))))))
   buffer)
 
 (defun diff-hl-changes ()
@@ -395,14 +398,19 @@ It can be a relative expression as well, such as 
\"HEAD^\" with Git, or
          ((eq state 'removed)
           `((1 ,(line-number-at-pos (point-max)) delete))))))))
 
+(defun diff-hl-process-wait (buf)
+  (let ((proc (get-buffer-process buf)))
+    (while (process-live-p proc)
+      (accept-process-output proc 0.01))))
+
 (defun diff-hl-changes-from-buffer (buf)
+  (diff-hl-process-wait buf)
   (with-current-buffer buf
     (let (res)
       (goto-char (point-min))
       (unless (eobp)
         ;; TODO: When 27.1 is the minimum requirement, we can drop
         ;; these bindings: that version, in addition to switching over
-        ;; to the diff-refine var, also added the
         ;; called-interactively-p check, so refinement can't be
         ;; triggered by code calling the navigation functions, only by
         ;; direct interactive invocations.
@@ -429,12 +437,15 @@ It can be a relative expression as well, such as 
\"HEAD^\" with Git, or
               (push (list line len type) res)))))
       (nreverse res))))
 
+(defun diff-hl--use-async-p ()
+  (and diff-hl-update-async
+       (not
+        (run-hook-with-args-until-success 'diff-hl-async-inhibit-functions
+                                          default-directory))))
+
 (defun diff-hl-update ()
   "Updates the diff-hl overlay."
-  (if (and diff-hl-update-async
-           (not
-            (run-hook-with-args-until-success 'diff-hl-async-inhibit-functions
-                                              default-directory)))
+  (if (diff-hl--use-async-p)
       ;; TODO: debounce if a thread is already running.
       (let ((buf (current-buffer))
             (temp-buffer
@@ -667,6 +678,7 @@ in the source file, or the last line of the hunk above it."
     (let* ((diff-buffer (get-buffer-create
                          (generate-new-buffer-name "*diff-hl*")))
            (buffer (current-buffer))
+           (diff-hl-update-async nil)
            (line (save-excursion
                    (diff-hl-find-current-hunk)
                    (line-number-at-pos)))
@@ -838,7 +850,8 @@ Only supported with Git."
     (with-current-buffer dest-buffer
       (let ((inhibit-read-only t))
         (erase-buffer)))
-    (let (diff-hl-reference-revision)
+    (let (diff-hl-reference-revision
+          diff-hl-update-async)
       (diff-hl-diff-buffer-with-reference file dest-buffer nil 3))
     (with-current-buffer dest-buffer
       (with-no-warnings
@@ -1178,12 +1191,10 @@ CONTEXT-LINES is the size of the unified diff context, 
defaults to 0."
                (or (diff-hl-resolved-reference-revision backend)
                    (diff-hl-working-revision file backend)))))
            (switches (format "-U %d --strip-trailing-cr" (or context-lines 
0))))
-      (diff-no-select rev (current-buffer) switches 'noasync
+      (diff-no-select rev (current-buffer) switches (not 
(diff-hl--use-async-p))
                       (get-buffer-create dest-buffer))
-      (with-current-buffer dest-buffer
-        (let ((inhibit-read-only t))
-          ;; Function `diff-sentinel' adds a final line, so remove it
-          (delete-matching-lines "^Diff finished.*")))
+      ;; Function `diff-sentinel' adds a summary line, but that seems fine.
+      ;; In all commands which use exact text we call it synchronously.
       (get-buffer-create dest-buffer))))
 
 (defun diff-hl-resolved-reference-revision (backend)

Reply via email to