Add command to copy contents in a diff-mode buffer

* lisp/vc/diff-mode.el (diff-mode-shared-map): Bind 'diff-kill-ring-save'.
(diff-mode-map): Ensure the "w" binding does not get prefixed.
(diff-kill-ring-save): Add the command.
* etc/NEWS: Mention 'diff-kill-ring-save'.  (Bug#65380)
This commit is contained in:
Philip Kaludercic 2023-08-19 11:47:54 +02:00
parent 44e3eceeb0
commit f8d42e29a5
No known key found for this signature in database
2 changed files with 60 additions and 1 deletions

View file

@ -244,6 +244,15 @@ The host name for Kubernetes connections can be of kind
used. This overrides the setiing in 'tramp-kubernetes-namespace', if
any.
** Diff
---
*** New command 'diff-kill-ring-save'
This command copies to the 'kill-ring' a region of text modified
according to diffs in the current buffer, but without applying the diffs
to the original text. If the selected range extends a hunk, the
commands attempts to look up and copy the text in-between the hunks.
* New Modes and Packages in Emacs 31.1

View file

@ -196,6 +196,7 @@ The default \"-b\" means to ignore whitespace-only changes,
"RET" #'diff-goto-source
"<mouse-2>" #'diff-goto-source
"W" #'widen
"w" #'diff-kill-ring-save
"o" #'diff-goto-source ; other-window
"A" #'diff-ediff-patch
"r" #'diff-restrict-view
@ -208,7 +209,7 @@ The default \"-b\" means to ignore whitespace-only changes,
;; We want to inherit most bindings from
;; `diff-mode-shared-map', but not all since they may hide
;; useful `M-<foo>' global bindings when editing.
(dolist (key '("A" "r" "R" "g" "q" "W" "z"))
(dolist (key '("A" "r" "R" "g" "q" "W" "w" "z"))
(keymap-set map key nil))
map)
;; From compilation-minor-mode.
@ -2108,6 +2109,55 @@ revision of the file otherwise."
(goto-char (+ (car pos) (cdr src)))
(when buffer (next-error-found buffer (current-buffer))))))
(defun diff-kill-ring-save (beg end &optional reverse)
"Save to `kill-ring' the result of applying diffs in region between BEG and END.
By default the command will copy the text that applying the diff would
produce, along with the text between hunks. If REVERSE is non-nil, or
the command was invoked with a prefix argument, copy the lines that the
diff would remove (beginning with \"+\" or \"<\")."
(interactive
(append (if (use-region-p)
(list (region-beginning) (region-end))
(save-excursion
(list (diff-beginning-of-hunk)
(diff-end-of-hunk))))
(list current-prefix-arg)))
(unless (derived-mode-p 'diff-mode)
(user-error "Command can only be invoked in a diff-buffer"))
(let ((parts '()))
(save-excursion
(goto-char beg)
(catch 'break
(while t
(let ((hunk (diff-hunk-text
(buffer-substring
(save-excursion (diff-beginning-of-hunk))
(save-excursion (min (diff-end-of-hunk) end)))
(not reverse)
(save-excursion
(- (point) (diff-beginning-of-hunk))))))
(push (substring (car hunk) (cdr hunk))
parts))
;; check if we have copied everything
(diff-end-of-hunk)
(when (<= end (point)) (throw 'break t))
;; copy the text between hunks
(let ((inhibit-message t) start)
(save-window-excursion
(save-excursion
(forward-line -1)
;; FIXME: Detect if the line we jump to doesn't match
;; the line in the diff.
(diff-goto-source t)
(forward-line +1)
(setq start (point))))
(save-window-excursion
(diff-goto-source t)
(push (buffer-substring start (point))
parts))))))
(kill-new (string-join (nreverse parts)))
(setq deactivate-mark t)
(message (if reverse "Copied original text" "Copied modified text"))))
(defun diff-current-defun ()
"Find the name of function at point.