emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master b64f69f6dcc: New command diff-delete-other-hunks


From: Sean Whitton
Subject: master b64f69f6dcc: New command diff-delete-other-hunks
Date: Mon, 30 Sep 2024 20:57:37 -0400 (EDT)

branch: master
commit b64f69f6dcc08e5aeea0464f6d8b560ed7002d36
Author: Sean Whitton <spwhitton@spwhitton.name>
Commit: Sean Whitton <spwhitton@spwhitton.name>

    New command diff-delete-other-hunks
    
    * 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.
---
 doc/emacs/files.texi |  5 +++++
 etc/NEWS             |  7 +++++++
 lisp/vc/diff-mode.el | 34 ++++++++++++++++++++++++++++++++++
 lisp/vc/vc.el        | 11 +++++++++++
 4 files changed, 57 insertions(+)

diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index a3a8c854aa6..67a1a3be3ff 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -1703,6 +1703,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
diff --git a/etc/NEWS b/etc/NEWS
index 37568ffdbea..bc1d0cf52c8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -382,6 +382,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
 
 ---
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index 25c6238765d..948d89c579e 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -220,6 +220,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
@@ -278,6 +279,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"]
@@ -814,6 +817,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
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 597a1622f5a..fce98d091bf 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]