> > This patch binds functions in Ediff that copy all changes from one > > buffer to another, without having to manually go through each > > difference. Any feedback welcome. > > Can you describe situation(s) where these commands will be useful?
I use Ediff to merge documents outside of git, like when working with someone over email or using a computer program to refactor code. Sometimes all changes go one way, say from B to A. The standard workflow then involves pressing "n" to review and "b" to apply each change. When the changes turn out to be mundane, this leads to repetitive "n b" keystrokes. The proposed patch allows a more efficient process: rapidly review with "n", then apply all at once using "C-c C-b". > > I think all we need to install this is a suitable NEWS entry. > > Thanks. I've updated the patch with a NEWS entry (formatted to the best of my ability), together with updates to the Ediff manual and the internal help system. Happy to revise further if I missed anything. Thanks, best, Paul
From 70cb106941e10fee1e0946928b4ade7f599dfd41 Mon Sep 17 00:00:00 2001 From: Paul Nelson <ultrono@gmail.com> Date: Thu, 29 Aug 2024 07:50:27 +0200 Subject: [PATCH] Add ediff-copy-all-X-to-Y functions * lisp/vc/ediff-util.el (ediff--copy-all): (ediff-copy-all-A-to-B): (ediff-copy-all-B-to-A): (ediff-copy-all-A-to-C): (ediff-copy-all-B-to-C): (ediff-copy-all-C-to-A): (ediff-copy-all-C-to-B): New functions. (ediff-setup-keymap): Bind them. * doc/misc/ediff.texi (Quick Help Commands): Document them. * lisp/vc/ediff-help.el (ediff-long-help-message-compare3): (ediff-long-help-message-compare2): (ediff-long-help-message-narrow2): (ediff-long-help-message-word-mode): (ediff-long-help-message-merge): Mention them. * etc/NEWS (Lisp Changes in Emacs 31.1): Mention them. --- doc/misc/ediff.texi | 21 ++++++++++++++ etc/NEWS | 17 +++++++++++ lisp/vc/ediff-help.el | 66 +++++++++++++++++++++---------------------- lisp/vc/ediff-util.el | 64 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 33 deletions(-) diff --git a/doc/misc/ediff.texi b/doc/misc/ediff.texi index 749025c870b..5cdd4e8388f 100644 --- a/doc/misc/ediff.texi +++ b/doc/misc/ediff.texi @@ -539,6 +539,27 @@ Quick Help Commands Copies the difference region from buffer C to buffer B@. The command @kbd{rb} undoes this. +@item C-c C-a +@itemx C-c C-b +@itemx C-c C-a C-b +@itemx C-c C-a C-c +@itemx C-c C-b C-a +@itemx C-c C-b C-c +@itemx C-c C-c C-a +@itemx C-c C-c C-b +@kindex C-c C-a +@kindex C-c C-b +@kindex C-c C-a C-b +@kindex C-c C-a C-c +@kindex C-c C-b C-a +@kindex C-c C-b C-c +@kindex C-c C-c C-a +@kindex C-c C-c C-b +Behaves like the above commands, but copies @emph{all} difference +regions from one buffer to another. For instance, @kbd{C-c C-a} copies +all changes from buffer A to buffer B (in a 2-way diff) or to buffer C +(in a merge). + @item p @itemx @key{DEL} @kindex p diff --git a/etc/NEWS b/etc/NEWS index f10f9ae4d65..dbee66ea978 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -121,6 +121,23 @@ A new ':authorizable t' parameter has been added to 'dbus-call-method' and 'dbus-call-method-asynchronously' to allow the user to interactively authorize the invoked D-Bus method (e.g., via polkit). ++++ +** Ediff now supports copying all changes between buffers at once. +New commands have been added to Ediff to copy all changes from one buffer +to another in a single operation: + +- 'C-c C-a' copies all changes from buffer A to buffer B (in 2-way diff) + or to buffer C (in 3-way diff or merge). +- 'C-c C-b' copies all changes from buffer B to buffer A (in 2-way diff) + or to buffer C (in 3-way diff or merge). +- 'C-c C-a C-b' copies all changes from buffer A to buffer B. +- 'C-c C-b C-a' copies all changes from buffer B to buffer A. +- 'C-c C-a C-c' copies all changes from buffer A to buffer C. +- 'C-c C-b C-c' copies all changes from buffer B to buffer C. +- 'C-c C-c C-a' copies all changes from buffer C to buffer A. +- 'C-c C-c C-b' copies all changes from buffer C to buffer B. + + * Changes in Emacs 31.1 on Non-Free Operating Systems diff --git a/lisp/vc/ediff-help.el b/lisp/vc/ediff-help.el index 56e1ec80c5c..1078322a816 100644 --- a/lisp/vc/ediff-help.el +++ b/lisp/vc/ediff-help.el @@ -46,13 +46,13 @@ ediff-long-help-message-tail (defconst ediff-long-help-message-compare3 " p,DEL -previous diff | | -vert/horiz split | xy -copy buf X's region to Y -n,SPC -next diff | h -highlighting | rx -restore buf X's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| ## -ignore whitespace | ! -update diff regions - C-l -recenter | #c -ignore case | - v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X - </> -scroll lt/rt | X -read-only in buf X | wd -save diff output - ~ -rotate buffers| m -wide display | +n,SPC -next diff | h -highlighting | C-c C-x C-y: copy all X->Y + j -jump to diff | @ -auto-refinement | rx -restore buf X's old diff + gx -goto X's point| ## -ignore whitespace | * -refine current region + C-l -recenter | #c -ignore case | ! -update diff regions + v/V -scroll up/dn | #f/#h -focus/hide regions | + </> -scroll lt/rt | X -read-only in buf X | wx -save buf X + ~ -rotate buffers| m -wide display | wd -save diff output " "Help message usually used for 3-way comparison. Normally, not a user option. See `ediff-help-message' for details.") @@ -60,13 +60,13 @@ ediff-long-help-message-compare3 (defconst ediff-long-help-message-compare2 " p,DEL -previous diff | | -vert/horiz split |a/b -copy A/B's region to B/A -n,SPC -next diff | h -highlighting | rx -restore buf X's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| ## -ignore whitespace | ! -update diff regions - C-l -recenter | #c -ignore case | - v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X - </> -scroll lt/rt | X -read-only in buf X | wd -save diff output - ~ -swap variants | m -wide display | +n,SPC -next diff | h -highlighting |C-c C-a/b: copy all A/B->B/A + j -jump to diff | @ -auto-refinement | rx -restore buf X's old diff + gx -goto X's point| ## -ignore whitespace | * -refine current region + C-l -recenter | #c -ignore case | ! -update diff regions + v/V -scroll up/dn | #f/#h -focus/hide regions | + </> -scroll lt/rt | X -read-only in buf X | wx -save buf X + ~ -swap variants | m -wide display | wd -save diff output " "Help message usually used for 2-way comparison. Normally, not a user option. See `ediff-help-message' for details.") @@ -74,13 +74,13 @@ ediff-long-help-message-compare2 (defconst ediff-long-help-message-narrow2 " p,DEL -previous diff | | -vert/horiz split |a/b -copy A/B's region to B/A -n,SPC -next diff | h -highlighting | rx -restore buf X's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| ## -ignore whitespace | ! -update diff regions - C-l -recenter | #c -ignore case | % -narrow/widen buffs - v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X - </> -scroll lt/rt | X -read-only in buf X | wd -save diff output - ~ -swap variants | m -wide display | +n,SPC -next diff | h -highlighting | C-c C-a/b: copy all A/B->B/A + j -jump to diff | @ -auto-refinement | rx -restore buf X's old diff + gx -goto X's point| ## -ignore whitespace | * -refine current region + C-l -recenter | #c -ignore case | ! -update diff regions + v/V -scroll up/dn | #f/#h -focus/hide regions | % -narrow/widen buffs + </> -scroll lt/rt | X -read-only in buf X | wx -save buf X + ~ -swap variants | m -wide display | wd -save diff output " "Help message when comparing windows or regions line-by-line. Normally, not a user option. See `ediff-help-message' for details.") @@ -88,13 +88,13 @@ ediff-long-help-message-narrow2 (defconst ediff-long-help-message-word-mode " p,DEL -previous diff | | -vert/horiz split | xy -copy buf X's region to Y -n,SPC -next diff | h -highlighting | rx -restore buf X's old diff - j -jump to diff | | +n,SPC -next diff | h -highlighting | C-c C-x C-y: copy all X->Y + j -jump to diff | | rx -restore buf X's old diff gx -goto X's point| % -narrow/widen buffs | ! -recompute diffs C-l -recenter | #c -ignore case | v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X </> -scroll lt/rt | X -read-only in buf X | wd -save diff output - ~ -swap variants | m -wide display | + ~ -swap variants | m -wide display | C-c C-x C-y: copy all X->Y " "Help message when comparing windows or regions word-by-word. Normally, not a user option. See `ediff-help-message' for details.") @@ -102,15 +102,15 @@ ediff-long-help-message-word-mode (defconst ediff-long-help-message-merge " p,DEL -previous diff | | -vert/horiz split | x -copy buf X's region to C -n,SPC -next diff | h -highlighting | r -restore buf C's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| ## -ignore whitespace | ! -update diff regions - C-l -recenter | #f/#h -focus/hide regions | + -combine diff regions - v/V -scroll up/dn | X -read-only in buf X | wx -save buf X - </> -scroll lt/rt | m -wide display | wd -save diff output - ~ -swap variants | s -shrink window C | / -show/hide ancestor buff - | $$ -show clashes only | & -merge w/new default - | $* -skip changed regions | +n,SPC -next diff | h -highlighting | C-c C-x: copy all X->C + j -jump to diff | @ -auto-refinement | r -restore buf C's old diff + gx -goto X's point| ## -ignore whitespace | * -refine current region + C-l -recenter | #f/#h -focus/hide regions | ! -update diff regions + v/V -scroll up/dn | X -read-only in buf X | + -combine diff regions + </> -scroll lt/rt | m -wide display | wx -save buf X + ~ -swap variants | s -shrink window C | wd -save diff output + | $$ -show clashes only | / -show/hide ancestor buff + | $* -skip changed regions | & -merge w/new default " "Help message for merge sessions. Normally, not a user option. See `ediff-help-message' for details.") diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el index 597d8a5e643..b575eaeca75 100644 --- a/lisp/vc/ediff-util.el +++ b/lisp/vc/ediff-util.el @@ -159,6 +159,8 @@ ediff-setup-keymap ;; In merging, we allow only A->C and B->C copying. (define-key ediff-mode-map "a" #'ediff-copy-A-to-C) (define-key ediff-mode-map "b" #'ediff-copy-B-to-C) + (define-key ediff-mode-map "C-c C-a" #'ediff-copy-all-A-to-C) + (define-key ediff-mode-map "C-c C-b" #'ediff-copy-all-B-to-C) (define-key ediff-mode-map "r" #'ediff-restore-diff-in-merge-buffer) (define-key ediff-mode-map "s" #'ediff-shrink-window-C) (define-key ediff-mode-map "+" #'ediff-combine-diffs) @@ -174,6 +176,12 @@ ediff-setup-keymap (define-key ediff-mode-map "c" nil) (define-key ediff-mode-map "ca" #'ediff-copy-C-to-A) (define-key ediff-mode-map "cb" #'ediff-copy-C-to-B) + (define-key ediff-mode-map "C-c C-a C-b" #'ediff-copy-all-A-to-B) + (define-key ediff-mode-map "C-c C-b C-a" #'ediff-copy-all-B-to-A) + (define-key ediff-mode-map "C-c C-a C-c" #'ediff-copy-all-A-to-C) + (define-key ediff-mode-map "C-c C-b C-c" #'ediff-copy-all-B-to-C) + (define-key ediff-mode-map "C-c C-c C-a" #'ediff-copy-all-C-to-A) + (define-key ediff-mode-map "C-c C-c C-b" #'ediff-copy-all-C-to-B) (define-key ediff-mode-map "ra" #'ediff-restore-diff) (define-key ediff-mode-map "rb" #'ediff-restore-diff) (define-key ediff-mode-map "rc" #'ediff-restore-diff) @@ -181,6 +189,8 @@ ediff-setup-keymap (t ; 2-way comparison (define-key ediff-mode-map "a" #'ediff-copy-A-to-B) (define-key ediff-mode-map "b" #'ediff-copy-B-to-A) + (define-key ediff-mode-map "C-c C-a" #'ediff-copy-all-A-to-B) + (define-key ediff-mode-map "C-c C-b" #'ediff-copy-all-B-to-A) (define-key ediff-mode-map "ra" #'ediff-restore-diff) (define-key ediff-mode-map "rb" #'ediff-restore-diff)) ) ; cond @@ -1952,6 +1962,60 @@ ediff-copy-C-to-A (interactive "P") (ediff-diff-to-diff arg "ca")) +(defun ediff--copy-all (source dest) + "Copy all changes from SOURCE to DEST in Ediff. +SOURCE and DEST should each be one of the symbols `A', `B', or `C'." + (ediff-barf-if-not-control-buffer) + (let ((valid-buffers '(A B C))) + (unless (and (memq source valid-buffers) + (memq dest valid-buffers)) + (error "Buffer arguments should be `A', `B', or `C'"))) + (unless (eq source dest) + (let* ((copy-func-name (format "ediff-copy-%s-to-%s" + (symbol-name source) + (symbol-name dest))) + (copy-func (intern copy-func-name))) + (condition-case err + (let ((n 0)) + (while (ediff-valid-difference-p n) + (ediff-jump-to-difference (1+ n)) + (funcall copy-func nil) + (setq n (1+ n))) + (message "All changes copied from buffer %s to %s" + (symbol-name source) + (symbol-name dest))) + (error + (message "Error occurred while copying: %s" (error-message-string err))))))) + +(defun ediff-copy-all-A-to-B () + "Copy all changes from buffer A to buffer B in Ediff." + (interactive) + (ediff--copy-all 'A 'B)) + +(defun ediff-copy-all-B-to-A () + "Copy all changes from buffer B to buffer A in Ediff." + (interactive) + (ediff--copy-all 'B 'A)) + +(defun ediff-copy-all-A-to-C () + "Copy all changes from buffer A to buffer C in Ediff." + (interactive) + (ediff--copy-all 'A 'C)) + +(defun ediff-copy-all-B-to-C () + "Copy all changes from buffer B to buffer C in Ediff." + (interactive) + (ediff--copy-all 'B 'C)) + +(defun ediff-copy-all-C-to-A () + "Copy all changes from buffer C to buffer A in Ediff." + (interactive) + (ediff--copy-all 'C 'A)) + +(defun ediff-copy-all-C-to-B () + "Copy all changes from buffer C to buffer B in Ediff." + (interactive) + (ediff--copy-all 'C 'B)) ;; Copy diff N from FROM-BUF-TYPE (given as A, B or C) to TO-BUF-TYPE. -- 2.39.3 (Apple Git-145)