Skip to content

Commit d7121b5

Browse files
committed
Add Ediff support
Add the command 'diff-hl-ediff-current-hunk', bound to 'C-x v e' in 'diff-hl-mode-map' and 'e' in the show-hunk UI, that uses Ediff to compare against the reference revision, jumping to the hunk nearest point. * diff-hl.el (diff-hl--use-git-index-base-p): New helper function. (diff-hl-diff-against-reference, diff-hl-diff-buffer-with-reference): Use it. (diff-hl--ediff-reference-buffer): New helper function. (diff-hl-ediff-current-hunk): New command. (diff-hl-command-map): Bind 'e' to 'diff-hl-ediff-current-hunk'. (diff-hl-repeat-exceptions): Add 'diff-hl-ediff-current-hunk'. * diff-hl-show-hunk.el (diff-hl-show-hunk-ediff): New command. (diff-hl-show-hunk-map): Bind it to 'e'. * diff-hl-show-hunk-inline.el (diff-hl-show-hunk-inline): Update footer text to include Ediff keybinding. * diff-hl-show-hunk-posframe.el (diff-hl-show-hunk-posframe--header-line): Add Ediff button to the posframe header line.
1 parent bb9af85 commit d7121b5

4 files changed

Lines changed: 78 additions & 8 deletions

File tree

diff-hl-show-hunk-inline.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ BUFFER is a buffer with the hunk."
361361
(when smart-lines
362362
(when (not (eq 0 original-lines-number))
363363
original-lines-number)))
364-
(footer "(q)Quit (p)Previous (n)Next (r)Revert (c)Copy original"))
364+
(footer "(q)Quit (p)Previous (n)Next (e)Ediff (r)Revert (c)Copy original"))
365365
(unless diff-hl-show-staged-changes
366366
(setq footer (concat footer " (S)Stage")))
367367
(diff-hl-show-hunk-inline-show

diff-hl-show-hunk-posframe.el

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ The button calls an ACTION."
145145
"Copy original (\\[diff-hl-show-hunk-copy-original-text])"
146146
#'diff-hl-show-hunk-copy-original-text)
147147

148+
(diff-hl-show-hunk--posframe-button
149+
"⇄ Ediff"
150+
"Ediff (\\[diff-hl-show-hunk-ediff])"
151+
#'diff-hl-show-hunk-ediff)
152+
148153
(diff-hl-show-hunk--posframe-button
149154
"♻ Revert hunk"
150155
"Revert hunk (\\[diff-hl-show-hunk-revert-hunk])"

diff-hl-show-hunk.el

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ Returns a list with the buffer and the line number of the clicked line."
219219
(define-key map (kbd "p") #'diff-hl-show-hunk-previous)
220220
(define-key map (kbd "n") #'diff-hl-show-hunk-next)
221221
(define-key map (kbd "c") #'diff-hl-show-hunk-copy-original-text)
222+
(define-key map (kbd "e") #'diff-hl-show-hunk-ediff)
222223
(define-key map (kbd "r") #'diff-hl-show-hunk-revert-hunk)
223224
(define-key map (kbd "[") #'diff-hl-show-hunk-previous)
224225
(define-key map (kbd "]") #'diff-hl-show-hunk-next)
@@ -246,6 +247,12 @@ Returns a list with the buffer and the line number of the clicked line."
246247
(diff-hl-show-hunk-hide)
247248
(diff-hl-stage-current-hunk))
248249

250+
(defun diff-hl-show-hunk-ediff ()
251+
"Dismiss the popup and run Ediff for the current hunk."
252+
(interactive)
253+
(diff-hl-show-hunk-hide)
254+
(diff-hl-ediff-current-hunk))
255+
249256
;;;###autoload
250257
(defun diff-hl-show-hunk-previous ()
251258
"Go to previous hunk/change and show it."

diff-hl.el

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
;; `diff-hl-previous-hunk' C-x v [
3737
;; `diff-hl-next-hunk' C-x v ]
3838
;; `diff-hl-show-hunk' C-x v *
39+
;; `diff-hl-ediff-current-hunk' C-x v e
3940
;; `diff-hl-stage-current-hunk' C-x v S
4041
;; `diff-hl-set-reference-rev'
4142
;; `diff-hl-reset-reference-rev'
@@ -435,6 +436,17 @@ It can be a relative expression as well, such as \"HEAD^\" with Git, or
435436
(declare-function vc-git--rev-parse "vc-git")
436437
(declare-function vc-hg-command "vc-hg")
437438
(declare-function vc-bzr-command "vc-bzr")
439+
(declare-function vc-find-revision-no-save "vc")
440+
(declare-function ediff-buffers "ediff")
441+
(declare-function ediff-diff-at-point "ediff-util")
442+
(declare-function ediff-jump-to-difference "ediff-util")
443+
(defvar ediff-number-of-differences)
444+
445+
(defun diff-hl--use-git-index-base-p (backend)
446+
"Whether diff-hl should use the Git index as the reference base."
447+
(and (eq backend 'Git)
448+
(not diff-hl-reference-revision)
449+
(not diff-hl-show-staged-changes)))
438450

439451
(defun diff-hl-changes-buffer (file backend &optional new-rev bufname)
440452
(diff-hl-with-diff-switches
@@ -443,9 +455,7 @@ It can be a relative expression as well, such as \"HEAD^\" with Git, or
443455
(defun diff-hl-diff-against-reference (file backend buffer &optional new-rev)
444456
(cond
445457
((and (not new-rev)
446-
(not diff-hl-reference-revision)
447-
(not diff-hl-show-staged-changes)
448-
(eq backend 'Git))
458+
(diff-hl--use-git-index-base-p backend))
449459
(apply #'vc-git-command buffer
450460
(if (diff-hl--use-async-p) 'async 1)
451461
(list file)
@@ -903,6 +913,54 @@ buffer will show the position corresponding to its current line."
903913
(diff-hl-diff-skip-to line relname)
904914
(setq vc-sentinel-movepoint (point))))))))
905915

916+
(defun diff-hl--ediff-reference-buffer (file)
917+
"Return the reference buffer for FILE used in Ediff."
918+
(unless file
919+
(user-error "No current file"))
920+
(let ((backend (vc-backend file)))
921+
(unless backend
922+
(user-error "The buffer is not under version control"))
923+
(let* ((reference diff-hl-reference-revision)
924+
;; Use the index snapshot only when diff-hl hides staged changes.
925+
(use-index (and (diff-hl--use-git-index-base-p backend)
926+
(not diff-hl-highlight-reference-function)))
927+
(buf
928+
(if use-index
929+
(let ((obj (diff-hl-git-index-object-name file)))
930+
(unless obj
931+
(user-error "No index entry for %s" file))
932+
(let ((filename (diff-hl-git-index-revision file obj)))
933+
(find-file-noselect filename)))
934+
(let ((rev (or reference
935+
(assoc-default backend diff-hl-head-revision-alist)
936+
(diff-hl-working-revision file backend))))
937+
(unless rev
938+
(user-error "No reference revision specified"))
939+
(setq rev (diff-hl-resolved-revision backend rev))
940+
(vc-find-revision-no-save file rev backend)))))
941+
(with-current-buffer buf
942+
(set-buffer-modified-p nil)
943+
(read-only-mode 1))
944+
buf)))
945+
946+
;;;###autoload
947+
(defun diff-hl-ediff-current-hunk ()
948+
"Run Ediff against current comparison base. Jump to hunk at point."
949+
(interactive)
950+
(require 'ediff)
951+
(let* ((pos (point))
952+
(file (or buffer-file-name
953+
(and-let* ((base (buffer-base-buffer)))
954+
(buffer-file-name base))))
955+
(refbuf (diff-hl--ediff-reference-buffer file))
956+
(startup
957+
(list
958+
(lambda ()
959+
(unless (zerop ediff-number-of-differences)
960+
(ediff-jump-to-difference
961+
(max 1 (ediff-diff-at-point 'B pos))))))))
962+
(ediff-buffers refbuf (current-buffer) startup 'diff-hl-ediff)))
963+
906964
(defun diff-hl-diff-read-revisions (rev1-default)
907965
(let* ((file buffer-file-name)
908966
(files (list file))
@@ -1304,6 +1362,7 @@ Pops up a diff buffer that can be edited to choose the changes to stage."
13041362
(define-key map "[" 'diff-hl-previous-hunk)
13051363
(define-key map "]" 'diff-hl-next-hunk)
13061364
(define-key map "*" 'diff-hl-show-hunk)
1365+
(define-key map "e" 'diff-hl-ediff-current-hunk)
13071366
(define-key map "{" 'diff-hl-show-hunk-previous)
13081367
(define-key map "}" 'diff-hl-show-hunk-next)
13091368
(define-key map "S" 'diff-hl-stage-dwim)
@@ -1376,7 +1435,8 @@ The value of this variable is a mode line template as in
13761435

13771436
(defvar diff-hl-repeat-exceptions '(diff-hl-show-hunk
13781437
diff-hl-show-hunk-previous
1379-
diff-hl-show-hunk-next))
1438+
diff-hl-show-hunk-next
1439+
diff-hl-ediff-current-hunk))
13801440

13811441
(when (require 'smartrep nil t)
13821442
(declare-function smartrep-define-key 'smartrep)
@@ -1516,9 +1576,7 @@ CONTEXT-LINES is the size of the unified diff context, defaults to 0."
15161576
(backend (or backend (vc-backend file)))
15171577
(temporary-file-directory diff-hl-temporary-directory)
15181578
(rev
1519-
(if (and (eq backend 'Git)
1520-
(not diff-hl-reference-revision)
1521-
(not diff-hl-show-staged-changes))
1579+
(if (diff-hl--use-git-index-base-p backend)
15221580
(diff-hl-git-index-revision
15231581
file
15241582
(diff-hl-git-index-object-name file))

0 commit comments

Comments
 (0)