New command diff-revert-and-kill-hunk

* lisp/vc/diff-mode.el (diff-revert-and-kill-hunk): New
command (bug#73407).
(diff-ask-before-revert-and-kill-hunk): New user option.
(diff-apply-buffer): New optional BEG, END and REVERSE
arguments.  Return nil if buffers were saved, or the number of
failed applications.
(diff-mode-map): Bind the new command to C-c M-r.
(diff-mode-menu): New entry for the new command.
* doc/emacs/files.texi (Diff Mode):
* etc/NEWS: Document the change.
This commit is contained in:
Sean Whitton 2024-09-24 09:38:43 +01:00
parent 8ffb680d09
commit f2e3e563d4
3 changed files with 59 additions and 6 deletions

View file

@ -1682,6 +1682,21 @@ reverse of the hunk, which changes the ``new'' version into the ``old''
version. If @code{diff-jump-to-old-file} is non-@code{nil}, apply the
hunk to the ``old'' version of the file instead.
@findex diff-revert-and-kill-hunk
@item C-c M-r
Reverse-apply this hunk to the target file, and then kill it
(@code{diff-revert-and-kill-hunk}). Save the buffer visiting the target
file.
This command is useful in buffers generated by @w{@kbd{C-x v =}} and
@w{@kbd{C-x v D}} (@pxref{Old Revisions}). These buffers present you
with a view of the changes you've made, and then you can use this
command to drop changes you didn't intend, or no longer want.
This is a destructive operation, so by default, this command asks you to
confirm you really want to reverse-apply and kill the hunk. You can
customize @code{diff-ask-before-revert-and-kill-hunk} to change that.
@findex diff-apply-buffer
@item C-c @key{RET} a
Apply all the hunks in the buffer (@code{diff-apply-buffer}). If the

View file

@ -363,6 +363,11 @@ according to diffs in the current buffer, but without applying the diffs
to the original text. If the selected range extends a hunk, the
command attempts to look up and copy the text in-between the hunks.
+++
*** New command 'diff-revert-and-kill-hunk' bound to C-c M-r.
This command reverse-applies the hunk at point, and then kills it.
This is useful in buffers generated by C-x v = and C-x v D.
** php-ts-mode
---

View file

@ -218,6 +218,7 @@ The default \"-b\" means to ignore whitespace-only changes,
"C-x 4 A" #'diff-add-change-log-entries-other-window
;; Misc operations.
"C-c C-a" #'diff-apply-hunk
"C-c M-r" #'diff-revert-and-kill-hunk
"C-c C-m a" #'diff-apply-buffer
"C-c C-e" #'diff-ediff-patch
"C-c C-n" #'diff-restrict-view
@ -242,6 +243,8 @@ The default \"-b\" means to ignore whitespace-only changes,
:help "Apply the current hunk to the source file and go to the next"]
["Test applying hunk" diff-test-hunk
:help "See whether it's possible to apply the current hunk"]
["Revert and kill hunk" diff-revert-and-kill-hunk
:help "Reverse-apply and then kill the current hunk."]
["Apply all hunks" diff-apply-buffer
:help "Apply all hunks in the current diff buffer"]
["Apply diff with Ediff" diff-ediff-patch
@ -2050,24 +2053,52 @@ With a prefix argument, try to REVERSE the hunk."
(diff-hunk-kill)
(diff-hunk-next)))))
(defun diff-apply-buffer ()
(defcustom diff-ask-before-revert-and-kill-hunk t
"If non-nil, `diff-revert-and-kill-hunk' will ask for confirmation."
:type 'boolean)
(defun diff-revert-and-kill-hunk ()
"Reverse-apply and then kill the hunk at point. Save changed buffer.
This command is useful in buffers generated by \\[vc-diff] and \\[vc-root-diff],
especially when preparing to commit the patch with \\[vc-next-action].
You can use \\<diff-mode-map>\\[diff-hunk-kill] to temporarily remove changes that you intend to
include in a separate commit or commits, and you can use this command
to permanently drop changes you didn't intend, or no longer want.
This is a destructive operation, so by default, this command asks you to
confirm you really want to reverse-apply and kill the hunk. You can
customize `diff-ask-before-revert-and-kill-hunk' to change that."
(interactive)
(when (or (not diff-ask-before-revert-and-kill-hunk)
(yes-or-no-p "Really reverse-apply and kill this hunk?"))
(cl-destructuring-bind (beg end) (diff-bounds-of-hunk)
(when (null (diff-apply-buffer beg end t))
(diff-hunk-kill)))))
(defun diff-apply-buffer (&optional beg end reverse)
"Apply the diff in the entire diff buffer.
When applying all hunks was successful, then save the changed buffers."
When applying all hunks was successful, then save the changed buffers.
When called from Lisp with optional arguments, restrict the application
to hunks lying between BEG and END, and reverse-apply when REVERSE is
non-nil. Returns nil if buffers were saved, or the number of failed
applications."
(interactive)
(let ((buffer-edits nil)
(failures 0)
(diff-refine nil))
(save-excursion
(goto-char (point-min))
(goto-char (or beg (point-min)))
(diff-beginning-of-hunk t)
(while (pcase-let ((`(,buf ,line-offset ,pos ,_src ,dst ,switched)
(diff-find-source-location nil nil)))
(diff-find-source-location nil reverse)))
(cond ((and line-offset (not switched))
(push (cons pos dst)
(alist-get buf buffer-edits)))
(t (setq failures (1+ failures))))
(and (not (eq (prog1 (point) (ignore-errors (diff-hunk-next)))
(point)))
(or (not end) (< (point) end))
(looking-at-p diff-hunk-header-re)))))
(cond ((zerop failures)
(dolist (buf-edits (reverse buffer-edits))
@ -2080,11 +2111,13 @@ When applying all hunks was successful, then save the changed buffers."
(delete-region (car pos) (cdr pos))
(insert (car dst))))
(save-buffer)))
(message "Saved %d buffers" (length buffer-edits)))
(message "Saved %d buffers" (length buffer-edits))
nil)
(t
(message (ngettext "%d hunk failed; no buffers changed"
"%d hunks failed; no buffers changed"
failures))))))
failures))
failures))))
(defalias 'diff-mouse-goto-source #'diff-goto-source)