diff options
| author | Dmitry Gutov | 2024-10-08 02:25:14 +0300 |
|---|---|---|
| committer | Dmitry Gutov | 2024-10-08 02:25:21 +0300 |
| commit | 2d139141a6c249691a50ade9c8d08dc35fcdf456 (patch) | |
| tree | a047186eb212e3d768855ca860332161b1a243c1 | |
| parent | 9904376c797665de47ff760bcf8c2fe33d7ae625 (diff) | |
| download | emacs-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/NEWS | 2 | ||||
| -rw-r--r-- | lisp/vc/diff-mode.el | 37 |
2 files changed, 31 insertions, 8 deletions
| @@ -424,6 +424,8 @@ useful to prepare a *vc-diff* buffer for committing a single hunk. | |||
| 424 | When the region is active, it deletes all hunks that the region does not | 424 | When the region is active, it deletes all hunks that the region does not |
| 425 | overlap. | 425 | overlap. |
| 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). | |||
| 2020 | With a prefix argument, REVERSE the hunk." | 2033 | With 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 |