aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Gutov2024-10-08 02:25:14 +0300
committerDmitry Gutov2024-10-08 02:25:21 +0300
commit2d139141a6c249691a50ade9c8d08dc35fcdf456 (patch)
treea047186eb212e3d768855ca860332161b1a243c1
parent9904376c797665de47ff760bcf8c2fe33d7ae625 (diff)
downloademacs-2d139141a6c249691a50ade9c8d08dc35fcdf456.tar.gz
emacs-2d139141a6c249691a50ade9c8d08dc35fcdf456.zip
Support file creation and deletion in diff-apply-hunk
* lisp/vc/diff-mode.el (diff-find-file-name): Allow entering non-existing file name when the corresponding hunk is of type "create file" (bug#62731). Default to file name with deleted prefix if diff-buffer-type is Git or Hg. Make sure not to add such input to diff-remembered-files-alist, it would be hard to change otherwise in case of typo. (diff-setup-buffer-type): Match against the diff header common to 'hg diff' output. (diff-find-source-location): Look at the other source when the buffer is applied in reverse. (diff-apply-hunk): Delect file deletion and pass a different argument to 'diff-find-source-location' in such case. Bind diff-vc-backend to nil to avoid older revision buffer being returned. In the end, offer to delete the file if the hunk was of corresponding type and matched the existing contents. * etc/NEWS: Mention the new capability.
-rw-r--r--etc/NEWS2
-rw-r--r--lisp/vc/diff-mode.el37
2 files changed, 31 insertions, 8 deletions
diff --git a/etc/NEWS b/etc/NEWS
index b5104145878..d5f48ae4391 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -424,6 +424,8 @@ useful to prepare a *vc-diff* buffer for committing a single hunk.
424When the region is active, it deletes all hunks that the region does not 424When the region is active, it deletes all hunks that the region does not
425overlap. 425overlap.
426 426
427*** 'diff-apply-hunk' now supports creating and deleting files.
428
427** php-ts-mode 429** php-ts-mode
428 430
429--- 431---
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index d085c721bc8..cfa90d380ad 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -1091,13 +1091,24 @@ PREFIX is only used internally: don't use it."
1091 (diff-find-file-name old noprompt (match-string 1))) 1091 (diff-find-file-name old noprompt (match-string 1)))
1092 ;; if all else fails, ask the user 1092 ;; if all else fails, ask the user
1093 (unless noprompt 1093 (unless noprompt
1094 (let ((file (expand-file-name (or (car fs) "")))) 1094 (let ((file (or (car fs) ""))
1095 (creation (equal null-device
1096 (car (diff-hunk-file-names (not old))))))
1097 (when (and (memq diff-buffer-type '(git hg))
1098 (string-match "/" file))
1099 ;; Strip the dst prefix (like b/) if diff is from Git/Hg.
1100 (setq file (substring file (match-end 0))))
1101 (setq file (expand-file-name file))
1095 (setq file 1102 (setq file
1096 (read-file-name (format "Use file %s: " file) 1103 (read-file-name (format "Use file %s: " file)
1097 (file-name-directory file) file t 1104 (file-name-directory file) file
1105 ;; Allow non-matching for creation.
1106 (not creation)
1098 (file-name-nondirectory file))) 1107 (file-name-nondirectory file)))
1099 (setq-local diff-remembered-files-alist 1108 (when (or (not creation) (file-exists-p file))
1100 (cons (cons fs file) diff-remembered-files-alist)) 1109 ;; Only remember files that exist. User might have mistyped.
1110 (setq-local diff-remembered-files-alist
1111 (cons (cons fs file) diff-remembered-files-alist)))
1101 file))))))) 1112 file)))))))
1102 1113
1103 1114
@@ -1647,7 +1658,9 @@ modified lines of the diff."
1647 (setq-local diff-buffer-type 1658 (setq-local diff-buffer-type
1648 (if (re-search-forward "^diff --git" nil t) 1659 (if (re-search-forward "^diff --git" nil t)
1649 'git 1660 'git
1650 nil))) 1661 (if (re-search-forward "^diff -r.*-r" nil t)
1662 'hg
1663 nil))))
1651 (when (eq diff-buffer-type 'git) 1664 (when (eq diff-buffer-type 'git)
1652 (setq diff-outline-regexp 1665 (setq diff-outline-regexp
1653 (concat "\\(^diff --git.*\\|" diff-hunk-header-re "\\)"))) 1666 (concat "\\(^diff --git.*\\|" diff-hunk-header-re "\\)")))
@@ -1957,7 +1970,7 @@ SWITCHED is non-nil if the patch is already applied."
1957 diff-context-mid-hunk-header-re nil t) 1970 diff-context-mid-hunk-header-re nil t)
1958 (error "Can't find the hunk separator")) 1971 (error "Can't find the hunk separator"))
1959 (match-string 1))))) 1972 (match-string 1)))))
1960 (file (or (diff-find-file-name other noprompt) 1973 (file (or (diff-find-file-name (xor other reverse) noprompt)
1961 (error "Can't find the file"))) 1974 (error "Can't find the file")))
1962 (revision (and other diff-vc-backend 1975 (revision (and other diff-vc-backend
1963 (if reverse (nth 1 diff-vc-revisions) 1976 (if reverse (nth 1 diff-vc-revisions)
@@ -2020,7 +2033,11 @@ the value of this variable when given an appropriate prefix argument).
2020With a prefix argument, REVERSE the hunk." 2033With a prefix argument, REVERSE the hunk."
2021 (interactive "P") 2034 (interactive "P")
2022 (diff-beginning-of-hunk t) 2035 (diff-beginning-of-hunk t)
2023 (pcase-let ((`(,buf ,line-offset ,pos ,old ,new ,switched) 2036 (pcase-let* (;; Do not accept BUFFER.REV buffers as source location.
2037 (diff-vc-backend nil)
2038 ;; When we detect deletion, we will use the old file name.
2039 (deletion (equal null-device (car (diff-hunk-file-names reverse))))
2040 (`(,buf ,line-offset ,pos ,old ,new ,switched)
2024 ;; Sometimes we'd like to have the following behavior: if 2041 ;; Sometimes we'd like to have the following behavior: if
2025 ;; REVERSE go to the new file, otherwise go to the old. 2042 ;; REVERSE go to the new file, otherwise go to the old.
2026 ;; But that means that by default we use the old file, which is 2043 ;; But that means that by default we use the old file, which is
@@ -2030,7 +2047,7 @@ With a prefix argument, REVERSE the hunk."
2030 ;; TODO: make it possible to ask explicitly for this behavior. 2047 ;; TODO: make it possible to ask explicitly for this behavior.
2031 ;; 2048 ;;
2032 ;; This is duplicated in diff-test-hunk. 2049 ;; This is duplicated in diff-test-hunk.
2033 (diff-find-source-location nil reverse))) 2050 (diff-find-source-location deletion reverse)))
2034 (cond 2051 (cond
2035 ((null line-offset) 2052 ((null line-offset)
2036 (user-error "Can't find the text to patch")) 2053 (user-error "Can't find the text to patch"))
@@ -2056,6 +2073,10 @@ With a prefix argument, REVERSE the hunk."
2056 "Hunk hasn't been applied yet; apply it now? " 2073 "Hunk hasn't been applied yet; apply it now? "
2057 "Hunk has already been applied; undo it? "))))) 2074 "Hunk has already been applied; undo it? ")))))
2058 (message "(Nothing done)")) 2075 (message "(Nothing done)"))
2076 ((and deletion (not switched))
2077 (when (y-or-n-p (format-message "Delete file `%s'?" (buffer-file-name buf)))
2078 (delete-file (buffer-file-name buf) delete-by-moving-to-trash)
2079 (kill-buffer buf)))
2059 (t 2080 (t
2060 ;; Apply the hunk 2081 ;; Apply the hunk
2061 (with-current-buffer buf 2082 (with-current-buffer buf