Teach diff-apply-hunk to handle hunks with empty context

* lisp/vc/diff-mode.el (diff-find-source-location):
Consider the case when there is no diff context above or below
edited lines.  (bug#72556)

* test/lisp/vc/diff-mode-tests.el: Add tests for undoing hunks
from diffs with addtions only in the beginning or end of the
source file.
This commit is contained in:
Tomas Nordin 2025-03-15 04:08:47 +02:00 committed by Dmitry Gutov
parent af5a75a0bd
commit 4980287e08
2 changed files with 101 additions and 3 deletions

View file

@ -2048,9 +2048,11 @@ SWITCHED is non-nil if the patch is already applied."
(goto-char (point-min)) (forward-line (1- (string-to-number line)))
(let* ((orig-pos (point))
(switched nil)
;; FIXME: Check for case where both OLD and NEW are found.
(pos (or (diff-find-text (car old))
(progn (setq switched t) (diff-find-text (car new)))
(maybe-old (diff-find-text (car old)))
(maybe-new (diff-find-text (car new)))
(pos (or (and maybe-new maybe-old (null reverse) (setq switched t) maybe-new)
maybe-old
(progn (setq switched t) maybe-new)
(progn (setq switched nil)
(condition-case nil
(diff-find-approx-text (car old))

View file

@ -597,5 +597,101 @@ baz"))))
(should (eq (get-text-property (match-beginning 0) 'face)
'diff-context)))))
(ert-deftest diff-mode-test-topmost-addition-undo ()
(let ((patch "diff --git a/fruits b/fruits
index 0dcecd3..d0eb2e7 100644
--- a/fruits
+++ b/fruits
@@ -1,2 +1,3 @@
+fruits
apple
orange
")
(text-before "apple
orange
")
(text-after "fruits
apple
orange
"))
(ert-with-temp-directory temp-dir
(let ((buf-after
(find-file-noselect (format "%s/%s" temp-dir "fruits"))))
(cd temp-dir)
(with-current-buffer buf-after (insert text-after) (save-buffer))
(with-temp-buffer
(insert patch)
(goto-char (point-min))
(diff-hunk-next)
;; Undo hunk by non-nil REVERSE argument (C-u C-c C-a)
(diff-apply-hunk t))
(with-current-buffer buf-after
(should (string-equal (buffer-string) text-before)))
(with-current-buffer buf-after
(erase-buffer) (insert text-after) (save-buffer))
(with-temp-buffer
(insert patch)
(goto-char (point-min))
(diff-hunk-next)
;; Undo hunk by dwim behaviour
(cl-letf (((symbol-function 'y-or-n-p) #'always))
(diff-apply-hunk)))
(with-current-buffer buf-after
(should (string-equal (buffer-string) text-before)))
(with-current-buffer buf-after
(set-buffer-modified-p nil)
(kill-buffer buf-after))))))
(ert-deftest diff-mode-test-bottommost-addition-undo ()
(let ((patch "diff --git a/fruits b/fruits
index 0dcecd3..6f210ff 100644
--- a/fruits
+++ b/fruits
@@ -1,2 +1,3 @@
apple
orange
+plum
")
(text-before "apple
orange
")
(text-after "apple
orange
plum
"))
(ert-with-temp-directory temp-dir
(let ((buf-after
(find-file-noselect (format "%s/%s" temp-dir "fruits"))))
(cd temp-dir)
(with-current-buffer buf-after (insert text-after) (save-buffer))
(with-temp-buffer
(insert patch)
(goto-char (point-min))
(diff-hunk-next)
;; Undo hunk by non-nil REVERSE argument (C-u C-c C-a)
(diff-apply-hunk t))
(with-current-buffer buf-after
(should (string-equal (buffer-string) text-before)))
(with-current-buffer buf-after
(erase-buffer) (insert text-after) (save-buffer))
(with-temp-buffer
(insert patch)
(goto-char (point-min))
(diff-hunk-next)
;; Undo hunk by dwim behaviour
(cl-letf (((symbol-function 'y-or-n-p) #'always))
(diff-apply-hunk)))
(with-current-buffer buf-after
(should (string-equal (buffer-string) text-before)))
(with-current-buffer buf-after
(set-buffer-modified-p nil)
(kill-buffer buf-after))))))
(provide 'diff-mode-tests)
;;; diff-mode-tests.el ends here