Skip to content

Commit 246621d

Browse files
authored
Merge pull request #276 from jamescherti/fix-indirect-buffers
Add support for indirect buffers
2 parents 902d082 + 55806aa commit 246621d

5 files changed

Lines changed: 98 additions & 77 deletions

File tree

diff-hl-amend.el

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Currently only supports Git, Mercurial and Bazaar."
4444
(diff-hl-update)))
4545

4646
(defun diff-hl-amend-setup ()
47-
(let ((backend (vc-backend buffer-file-name)))
47+
(let ((backend (vc-backend (diff-hl--buffer-file-name))))
4848
(when backend
4949
(setq-local diff-hl-reference-revision
5050
(cl-case backend
@@ -62,7 +62,7 @@ Currently only supports Git, Mercurial and Bazaar."
6262

6363
(defun turn-on-diff-hl-amend-mode ()
6464
"Turn on `diff-hl-amend-mode' in a buffer if appropriate."
65-
(and buffer-file-name (diff-hl-amend-mode 1)))
65+
(and (diff-hl--buffer-file-name) (diff-hl-amend-mode 1)))
6666

6767
(provide 'diff-hl-amend)
6868

diff-hl-flydiff.el

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@
5252
(unless (or
5353
(not diff-hl-mode)
5454
(eq diff-hl-flydiff-modified-tick (buffer-chars-modified-tick))
55-
(not buffer-file-name)
56-
(file-remote-p default-directory)
57-
(not (file-exists-p buffer-file-name)))
55+
(let ((file (diff-hl--buffer-file-name)))
56+
(or (not file)
57+
(file-remote-p default-directory)
58+
(not (file-exists-p file)))))
5859
(diff-hl-update)))
5960

6061
(defun diff-hl-flydiff/modified-p (state)

diff-hl-show-hunk.el

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,16 @@ Then put the differences inside a special buffer and set the
129129
point in that buffer to the corresponding line of the original
130130
buffer."
131131
(defvar vc-sentinel-movepoint)
132-
(let* ((buffer (or (buffer-base-buffer) (current-buffer)))
132+
(let* ((buffer (current-buffer))
133133
(diff-hl-update-async nil)
134134
(line (line-number-at-pos))
135135
(dest-buffer diff-hl-show-hunk-diff-buffer-name))
136136
(with-current-buffer buffer
137-
(if (buffer-modified-p)
138-
(diff-hl-diff-buffer-with-reference buffer-file-name dest-buffer)
139-
(diff-hl-changes-buffer buffer-file-name (vc-backend buffer-file-name)
140-
nil dest-buffer))
137+
(let ((file (diff-hl--buffer-file-name)))
138+
(if (buffer-modified-p)
139+
(diff-hl-diff-buffer-with-reference file dest-buffer)
140+
(diff-hl-changes-buffer file (vc-backend file)
141+
nil dest-buffer)))
141142
(switch-to-buffer dest-buffer)
142143
(diff-hl-diff-skip-to line)
143144
(setq vc-sentinel-movepoint (point)))
@@ -303,7 +304,7 @@ end of the OVERLAY, so posframe/inline is placed below the hunk."
303304
The backend is determined by `diff-hl-show-hunk-function'."
304305
(interactive)
305306

306-
(unless (vc-backend buffer-file-name)
307+
(unless (vc-backend (diff-hl--buffer-file-name))
307308
(user-error "The buffer is not under version control"))
308309

309310
(diff-hl-find-current-hunk)

diff-hl.el

Lines changed: 77 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,15 @@ It can be a relative expression as well, such as \"HEAD^\" with Git, or
314314
(lambda (value)
315315
(or (null value) (stringp value))))
316316

317+
(defun diff-hl--target-buffer (buf)
318+
"Return the correct buffer for the situation, preferring the base buffer."
319+
(or (buffer-base-buffer buf) buf))
320+
321+
(defun diff-hl--buffer-file-name (&optional buffer)
322+
"Return the file name of the BUFFER or its base buffer.
323+
BUFFER defaults to the current buffer."
324+
(buffer-file-name (diff-hl--target-buffer (or buffer (current-buffer)))))
325+
317326
(defun diff-hl-define-bitmaps ()
318327
(let* ((scale (if (and (boundp 'text-scale-mode-amount)
319328
(numberp text-scale-mode-amount))
@@ -485,7 +494,7 @@ It can be a relative expression as well, such as \"HEAD^\" with Git, or
485494
buffer)
486495

487496
(defun diff-hl-changes ()
488-
(let* ((file buffer-file-name)
497+
(let* ((file (diff-hl--buffer-file-name))
489498
(backend (vc-backend file))
490499
(hide-staged (and (eq backend 'Git) (not diff-hl-show-staged-changes))))
491500
(when backend
@@ -530,7 +539,7 @@ It can be a relative expression as well, such as \"HEAD^\" with Git, or
530539
(or (assoc-default backend diff-hl-head-revision-alist)
531540
;; It's usually cached already (e.g. for mode-line).
532541
;; So this is basically an optimization for rare cases.
533-
(vc-working-revision buffer-file-name backend)))
542+
(vc-working-revision (diff-hl--buffer-file-name) backend)))
534543

535544
(defun diff-hl-adjust-changes (old new)
536545
"Adjust changesets in OLD using changes in NEW.
@@ -732,17 +741,22 @@ Return a list of line overlays used."
732741
(lambda (ref-changes)
733742
(when (buffer-live-p orig)
734743
(let ((ref-changes (diff-hl-adjust-changes ref-changes changes))
735-
reuse)
736-
(with-current-buffer orig
737-
(diff-hl-remove-overlays)
738-
(let ((diff-hl-highlight-function
739-
diff-hl-highlight-reference-function)
740-
(diff-hl-fringe-face-function
741-
diff-hl-fringe-reference-face-function))
742-
(setq reuse (diff-hl--update-overlays ref-changes nil)))
743-
(diff-hl--update-overlays changes reuse)
744-
(when (not (or changes ref-changes))
745-
(diff-hl--autohide-margin)))))))))))
744+
(base (diff-hl--target-buffer orig)))
745+
(dolist (buf (buffer-list))
746+
(when (and (buffer-live-p buf)
747+
(eq (diff-hl--target-buffer buf) base)
748+
(buffer-local-value 'diff-hl-mode buf))
749+
(with-current-buffer buf
750+
(let (reuse)
751+
(diff-hl-remove-overlays)
752+
(let ((diff-hl-highlight-function
753+
diff-hl-highlight-reference-function)
754+
(diff-hl-fringe-face-function
755+
diff-hl-fringe-reference-face-function))
756+
(setq reuse (diff-hl--update-overlays ref-changes nil)))
757+
(diff-hl--update-overlays changes reuse)
758+
(when (not (or changes ref-changes))
759+
(diff-hl--autohide-margin))))))))))))))
746760

747761
(defun diff-hl--resolve (value-or-buffer cb)
748762
(if (listp value-or-buffer)
@@ -869,15 +883,15 @@ Return a list of line overlays used."
869883
With double prefix argument (C-u C-u), the diff is made against the
870884
reference revision."
871885
(interactive (list current-prefix-arg))
872-
(with-current-buffer (or (buffer-base-buffer) (current-buffer))
886+
(with-current-buffer (current-buffer)
873887
(if (equal historic '(16))
874888
(diff-hl-diff-reference-goto-hunk)
875889
(diff-hl-diff-goto-hunk-1 historic nil))))
876890

877891
(defun diff-hl-diff-reference-goto-hunk ()
878892
"Run VC diff command against the reference and go to the corresponding line."
879893
(interactive)
880-
(with-current-buffer (or (buffer-base-buffer) (current-buffer))
894+
(with-current-buffer (current-buffer)
881895
(diff-hl-diff-goto-hunk-1 nil diff-hl-reference-revision)))
882896

883897
(defun diff-hl-root-diff-reference-goto-hunk ()
@@ -886,7 +900,7 @@ And if the current buffer is visiting a file, and it has changes, the diff
886900
buffer will show the position corresponding to its current line."
887901
(interactive)
888902
(defvar vc-sentinel-movepoint)
889-
(with-current-buffer (or (buffer-base-buffer) (current-buffer))
903+
(with-current-buffer (current-buffer)
890904
(let ((backend (vc-deduce-backend))
891905
(default-directory default-directory)
892906
rootdir fileset
@@ -895,8 +909,9 @@ buffer will show the position corresponding to its current line."
895909
(setq rootdir (vc-call-backend backend 'root default-directory)
896910
default-directory rootdir
897911
fileset `(,backend (,rootdir))
898-
relname (if buffer-file-name (file-relative-name buffer-file-name
899-
rootdir)))
912+
relname (let ((file (diff-hl--buffer-file-name)))
913+
(when file
914+
(file-relative-name file rootdir))))
900915
(error "Directory is not version controlled"))
901916
(setq fileset (or fileset (vc-deduce-fileset)))
902917
(vc-buffer-sync-fileset fileset t)
@@ -911,7 +926,7 @@ buffer will show the position corresponding to its current line."
911926
(setq vc-sentinel-movepoint (point))))))))
912927

913928
(defun diff-hl-diff-read-revisions (rev1-default)
914-
(let* ((file buffer-file-name)
929+
(let* ((file (diff-hl--buffer-file-name))
915930
(files (list file))
916931
(backend (vc-backend file))
917932
(rev2-default nil))
@@ -1011,7 +1026,7 @@ that file, if it's present."
10111026
(line (save-excursion
10121027
(diff-hl-find-current-hunk)
10131028
(line-number-at-pos)))
1014-
(file buffer-file-name)
1029+
(file (diff-hl--buffer-file-name))
10151030
(backend (vc-backend file)))
10161031
(unwind-protect
10171032
(progn
@@ -1091,7 +1106,7 @@ its end position."
10911106
(defun diff-hl-revert-hunk ()
10921107
"Revert the diff hunk with changes at or above the point."
10931108
(interactive)
1094-
(with-current-buffer (or (buffer-base-buffer) (current-buffer))
1109+
(with-current-buffer (current-buffer)
10951110
(diff-hl-revert-hunk-1)))
10961111

10971112
(defun diff-hl-hunk-overlay-at (pos)
@@ -1147,7 +1162,7 @@ its end position."
11471162
(push-mark (overlay-end hunk) nil t)))
11481163

11491164
(defun diff-hl--ensure-staging-supported ()
1150-
(let ((backend (vc-backend buffer-file-name)))
1165+
(let ((backend (vc-backend (diff-hl--buffer-file-name))))
11511166
(unless (eq backend 'Git)
11521167
(user-error "Only Git supports staging; this file is controlled by %s" backend))))
11531168

@@ -1174,7 +1189,7 @@ Only supported with Git."
11741189
(diff-hl--ensure-staging-supported)
11751190
(diff-hl-find-current-hunk)
11761191
(let* ((line (line-number-at-pos))
1177-
(file buffer-file-name)
1192+
(file (diff-hl--buffer-file-name))
11781193
(dest-buffer (get-buffer-create " *diff-hl-stage*"))
11791194
(orig-buffer (current-buffer))
11801195
;; FIXME: If the file name has double quotes, these need to be quoted.
@@ -1215,13 +1230,14 @@ Only supported with Git."
12151230
12161231
Only supported with Git."
12171232
(interactive)
1218-
(unless buffer-file-name
1219-
(user-error "No current file"))
1220-
(diff-hl--ensure-staging-supported)
1221-
(vc-git-command nil 0 buffer-file-name "reset")
1222-
(message "Unstaged all")
1223-
(unless diff-hl-show-staged-changes
1224-
(diff-hl-update)))
1233+
(let ((file (diff-hl--buffer-file-name)))
1234+
(unless file
1235+
(user-error "No current file"))
1236+
(diff-hl--ensure-staging-supported)
1237+
(vc-git-command nil 0 file "reset")
1238+
(message "Unstaged all")
1239+
(unless diff-hl-show-staged-changes
1240+
(diff-hl-update))))
12251241

12261242
(defun diff-hl-stage-dwim (&optional with-edit)
12271243
"Stage the current hunk or choose the hunks to stage.
@@ -1248,7 +1264,7 @@ Pops up a diff buffer that can be edited to choose the changes to stage."
12481264
(diff-hl--ensure-staging-supported)
12491265
(let* ((line-beg (and beg (line-number-at-pos beg t)))
12501266
(line-end (and end (line-number-at-pos end t)))
1251-
(file buffer-file-name)
1267+
(file (diff-hl--buffer-file-name))
12521268
(dest-buffer (get-buffer-create "*diff-hl-stage-some*"))
12531269
(orig-buffer (current-buffer))
12541270
(diff-hl-update-async nil)
@@ -1392,14 +1408,14 @@ The value of this variable is a mode line template as in
13921408
(declare-function smartrep-define-key 'smartrep)
13931409
(let (smart-keys)
13941410
(cl-labels ((scan (map)
1395-
(map-keymap
1396-
(lambda (event binding)
1397-
(if (consp binding)
1398-
(scan binding)
1399-
(when (and (characterp event)
1400-
(not (memq binding diff-hl-repeat-exceptions)))
1401-
(push (cons (string event) binding) smart-keys))))
1402-
map)))
1411+
(map-keymap
1412+
(lambda (event binding)
1413+
(if (consp binding)
1414+
(scan binding)
1415+
(when (and (characterp event)
1416+
(not (memq binding diff-hl-repeat-exceptions)))
1417+
(push (cons (string event) binding) smart-keys))))
1418+
map)))
14031419
(scan diff-hl-command-map)
14041420
(smartrep-define-key diff-hl-mode-map diff-hl-command-prefix smart-keys))))
14051421

@@ -1424,19 +1440,21 @@ The value of this variable is a mode line template as in
14241440
(let* ((topdir (magit-toplevel))
14251441
(modified-files
14261442
(magit-git-items "diff-tree" "-z" "--name-only" "-r" "HEAD~" "HEAD"))
1427-
(unmodified-states '(up-to-date ignored unregistered)))
1443+
(unmodified-states '(up-to-date ignored unregistered))
1444+
file)
14281445
(dolist (buf (buffer-list))
1429-
(when (and (buffer-local-value 'diff-hl-mode buf)
1430-
(not (buffer-modified-p buf))
1431-
;; Solve the "cloned indirect buffer" problem
1432-
;; (diff-hl-mode could be non-nil there, even if
1433-
;; buffer-file-name is nil):
1434-
(buffer-file-name buf)
1435-
(file-in-directory-p (buffer-file-name buf) topdir)
1436-
(file-exists-p (buffer-file-name buf)))
1446+
(setq file (diff-hl--buffer-file-name buf))
1447+
(when (and
1448+
(buffer-local-value 'diff-hl-mode buf)
1449+
(not (buffer-modified-p buf))
1450+
;; Solve the "cloned indirect buffer" problem
1451+
;; (diff-hl-mode could be non-nil there, even if
1452+
;; buffer-file-name is nil):
1453+
file
1454+
(file-in-directory-p file topdir)
1455+
(file-exists-p file))
14371456
(with-current-buffer buf
1438-
(let* ((file buffer-file-name)
1439-
(backend (vc-backend file)))
1457+
(let* ((backend (vc-backend file)))
14401458
(when backend
14411459
(cond
14421460
((member file modified-files)
@@ -1538,7 +1556,7 @@ CONTEXT-LINES is the size of the unified diff context, defaults to 0."
15381556
backend
15391557
(or diff-hl-reference-revision
15401558
(assoc-default backend diff-hl-head-revision-alist)))
1541-
(diff-hl-working-revision buffer-file-name backend)))))
1559+
(diff-hl-working-revision (diff-hl--buffer-file-name) backend)))))
15421560
(switches (format "-U %d --strip-trailing-cr" (or context-lines 0))))
15431561
(diff-no-select rev (current-buffer) switches (not (diff-hl--use-async-p))
15441562
(get-buffer-create dest-buffer))
@@ -1606,13 +1624,14 @@ CONTEXT-LINES is the size of the unified diff context, defaults to 0."
16061624
;;;###autoload
16071625
(defun turn-on-diff-hl-mode ()
16081626
"Turn on `diff-hl-mode' or `diff-hl-dir-mode' in a buffer if appropriate."
1609-
(cond
1610-
(buffer-file-name
1611-
(unless (and diff-hl-disable-on-remote
1612-
(file-remote-p buffer-file-name))
1613-
(diff-hl-mode 1)))
1614-
((eq major-mode 'vc-dir-mode)
1615-
(diff-hl-dir-mode 1))))
1627+
(let ((file (diff-hl--buffer-file-name)))
1628+
(cond
1629+
(file
1630+
(unless (and diff-hl-disable-on-remote
1631+
(file-remote-p file))
1632+
(diff-hl-mode 1)))
1633+
((eq major-mode 'vc-dir-mode)
1634+
(diff-hl-dir-mode 1)))))
16161635

16171636
;;;###autoload
16181637
(defun diff-hl--global-turn-on ()

test/diff-hl-test.el

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@
5050
(erase-buffer)
5151
(insert diff-hl-test-initial-content)
5252
(save-buffer)
53-
(pcase (vc-backend buffer-file-name)
53+
(pcase (vc-backend (diff-hl--buffer-file-name))
5454
(`Git
55-
(vc-git-command nil 0 buffer-file-name "reset"))
55+
(vc-git-command nil 0 (diff-hl--buffer-file-name) "reset"))
5656
(`Hg
57-
(vc-hg-command nil 0 buffer-file-name "revert")))))
57+
(vc-hg-command nil 0 (diff-hl--buffer-file-name) "revert")))))
5858

5959
(defun diff-hl-test-compute-diff-lines ()
6060
(diff-hl-test-in-source
@@ -160,7 +160,7 @@
160160
(goto-char (point-min))
161161
(insert "new line 1\n")
162162
(save-buffer)
163-
(vc-git-command nil 0 buffer-file-name "add")
163+
(vc-git-command nil 0 (diff-hl--buffer-file-name) "add")
164164
(goto-char (point-max))
165165
(insert "new line 2\n")
166166
(save-buffer)
@@ -180,19 +180,19 @@
180180
(goto-char (point-min))
181181
(insert "new line 1\n")
182182
(save-buffer)
183-
(vc-git-command nil 0 buffer-file-name "add")
183+
(vc-git-command nil 0 (diff-hl--buffer-file-name) "add")
184184
(goto-char (point-max))
185185
(insert "new line 2\n")
186186
(let ((diff-hl-show-staged-changes t))
187187
(should
188188
(equal (diff-hl-changes-from-buffer
189-
(diff-hl-diff-buffer-with-reference buffer-file-name))
189+
(diff-hl-diff-buffer-with-reference (diff-hl--buffer-file-name)))
190190
'((1 1 0 insert)
191191
(12 1 0 insert)))))
192192
(let ((diff-hl-show-staged-changes nil))
193193
(should
194194
(equal (diff-hl-changes-from-buffer
195-
(diff-hl-diff-buffer-with-reference buffer-file-name))
195+
(diff-hl-diff-buffer-with-reference (diff-hl--buffer-file-name)))
196196
'((12 1 0 insert)))))))
197197

198198
(diff-hl-deftest diff-hl-can-split-away-no-trailing-newline ()
@@ -202,7 +202,7 @@
202202
(search-backward "}")
203203
(insert " ")
204204
(save-buffer)
205-
(let ((file buffer-file-name)
205+
(let ((file (diff-hl--buffer-file-name))
206206
(dest-buffer (get-buffer-create " *diff-hl-test*")))
207207
(diff-hl-diff-buffer-with-reference file dest-buffer nil 3)
208208
(with-current-buffer dest-buffer

0 commit comments

Comments
 (0)