]> git.eshelyaron.com Git - emacs.git/commitdiff
New command diff-delete-other-hunks
authorSean Whitton <spwhitton@spwhitton.name>
Mon, 30 Sep 2024 13:08:38 +0000 (21:08 +0800)
committerEshel Yaron <me@eshelyaron.com>
Thu, 3 Oct 2024 06:39:29 +0000 (08:39 +0200)
* lisp/vc/diff-mode.el (diff-delete-other-hunks): New
command (bug#73387).
(diff-mode-map): Bind the new command to C-c RET n.
(diff-mode-menu): New entry for the new command.
(vc-next-action): Stop, and warn, if the user attempts to commit
a patch from a narrowed buffer (bug#73387).
* doc/emacs/files.texi (Diff Mode):
* etc/NEWS: Document the new command.

(cherry picked from commit b64f69f6dcc08e5aeea0464f6d8b560ed7002d36)

doc/emacs/files.texi
etc/NEWS
lisp/vc/diff-mode.el
lisp/vc/vc.el

index 59baa304eda8e26086e2a1f0cb16df2a6df39d43..32f7fc5c5973222e8b4b39163c60d84bf3105e84 100644 (file)
@@ -1701,6 +1701,11 @@ confirm you really want to revert and kill the hunk.  You can customize
 Apply all the hunks in the buffer (@code{diff-apply-buffer}).  If the
 diffs were applied successfully, save the changed buffers.
 
+@findex diff-delete-other-hunks
+@item C-c @key{RET} n
+Delete all hunks other than the current hunk.  If the region is active,
+then delete all hunks that the region does not overlap.
+
 @findex diff-refine-hunk
 @item C-c C-b
 Highlight the changes of the hunk at point with a finer granularity
index 4e0f638cb8a947864c2bc20010c84f741beaa60c..59861a59f588946eaf34d2a690d61172569ae4cf 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -341,6 +341,13 @@ Previously, 'diff-file-prev' and 'diff-hunk-prev' would move when point
 is after the corresponding file or hunk header, but not when inside it.
 Now they will always move to the start of the current header.
 
++++
+*** New command 'diff-delete-other-hunks' bound to C-c RET n.
+This command deletes all hunks other than the current hunk.  It is
+useful to prepare a *vc-diff* buffer for committing a single hunk.
+When the region is active, it deletes all hunks that the region does not
+overlap.
+
 ** php-ts-mode
 
 ---
index 318389be2dc2c7550eb6b85bbfd96d33703a9c93..48d34c86779379bbe4d5eb4a383eb8a2792cb02c 100644 (file)
@@ -219,6 +219,7 @@ The default \"-b\" means to ignore whitespace-only changes,
   "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-m n" #'diff-delete-other-hunks
   "C-c C-e" #'diff-ediff-patch
   "C-c C-n" #'diff-restrict-view
   "C-c C-s" #'diff-split-hunk
@@ -277,6 +278,8 @@ The default \"-b\" means to ignore whitespace-only changes,
      :help "Kill current hunk"]
     ["Kill current file's hunks" diff-file-kill
      :help "Kill all current file's hunks"]
+    ["Delete other hunks"       diff-delete-other-hunks
+     :help "Delete hunks other than the current hunk"]
     "-----"
     ["Previous Hunk"           diff-hunk-prev
      :help "Go to the previous count'th hunk"]
@@ -813,6 +816,37 @@ If the prefix ARG is given, restrict the view to the current file instead."
       (goto-char (car bounds))
       (ignore-errors (diff-beginning-of-hunk t)))))
 
+;; This is not `diff-kill-other-hunks' because we might need to make
+;; copies of file headers in order to ensure the new kill ring entry
+;; would be a patch with the same meaning.  That is not implemented
+;; because it does not seem like it would be useful.
+(defun diff-delete-other-hunks (&optional beg end)
+  "Delete all hunks other than the current hunk.
+Interactively, if the region is active, then delete all hunks that the
+region does not overlap.  When called from Lisp, the optional arguments
+BEG and END specify the region of hunks not to delete."
+  (interactive (list (use-region-beginning) (use-region-end)))
+  (when (buffer-narrowed-p)
+    (user-error "Command is not safe in a narrowed buffer"))
+  (let ((inhibit-read-only t))
+    (save-excursion
+      (cond ((xor beg end)
+             (error "Require exactly zero or two arguments"))
+            (beg
+             (goto-char beg)
+             (setq beg (car (diff-bounds-of-hunk)))
+             (goto-char end)
+             (setq end (cadr (diff-bounds-of-hunk))))
+            (t
+             (pcase-setq `(,beg ,end) (diff-bounds-of-hunk))))
+      (delete-region end (point-max))
+      (goto-char beg)
+      (diff-beginning-of-file)
+      (diff-hunk-next)
+      (delete-region (point) beg)
+      (diff-beginning-of-file-and-junk)
+      (delete-region (point-min) (point)))))
+
 (defun diff-beginning-of-file-and-junk ()
   "Go to the beginning of file-related diff-info.
 This is like `diff-beginning-of-file' except it tries to skip back over leading
index 15636048307c674f99776c653b0223e48ce80369..d79bb12e9173e01130bb59915f430586e1821c1f 100644 (file)
@@ -1302,6 +1302,17 @@ from which to check out the file(s)."
      ;; Fileset comes from a diff-mode buffer, see
      ;; 'diff-vc-deduce-fileset', and the buffer is the patch to apply.
      ((eq model 'patch)
+      (when (buffer-narrowed-p)
+        ;; If user used `diff-restrict-view' then we may not have the
+        ;; file header, and the commit will not succeed (bug#73387).
+        (user-error "Cannot commit patch when narrowed; consider %s"
+                    (mapconcat (lambda (c)
+                                 (key-description
+                                  (where-is-internal c nil t)))
+                               '(widen
+                                 diff-delete-other-hunks
+                                 vc-next-action)
+                               " ")))
       (vc-checkin files backend nil nil nil (buffer-string)))
      ((or (null state) (eq state 'unregistered))
       (cond (verbose