* lisp/vc/emerge.el: Use lexical-binding

Replace all `(lambda ...) with closures.  Use inhibit-read-only.
(emerge-mode): Use define-minor-mode.
(emerge-setup, emerge-setup-with-ancestor):
Don't use 'run-hooks' on local var.
(emerge-files, emerge-files-with-ancestor):
Don't use 'add-hook' on local var.
(emerge-convert-diffs-to-markers): Remove unused var 'B-point-min'.
Simplify 'offset'.
(emerge--current-beg, emerge--current-end): New macros.
(emerge-select-version): Pass 'diff-vector' to the function it calls.
Change all callers to use it instead of dyn-bound vars.
This commit is contained in:
Stefan Monnier 2018-04-03 23:17:30 -04:00
parent 9b0e8a4c6b
commit fbd025a667

View file

@ -1,6 +1,6 @@
;;; emerge.el --- merge diffs under Emacs control
;;; emerge.el --- merge diffs under Emacs control -*- lexical-binding:t -*-
;;; The author has placed this file in the public domain.
;; The author has placed this file in the public domain.
;; This file is part of GNU Emacs.
@ -24,42 +24,20 @@
;;; Code:
;; There aren't really global variables, just dynamic bindings
(defvar A-begin)
(defvar A-end)
(defvar B-begin)
(defvar B-end)
(defvar diff-vector)
(defvar merge-begin)
(defvar merge-end)
(defvar valid-diff)
;;; Macros
(defmacro emerge-defvar-local (var value doc)
"Defines SYMBOL as an advertised variable.
"Define SYMBOL as an advertised buffer-local variable.
Performs a defvar, then executes `make-variable-buffer-local' on
the variable. Also sets the `permanent-local' property, so that
`kill-all-local-variables' (called by major-mode setting commands)
won't destroy Emerge control variables."
`(progn
(defvar ,var ,value ,doc)
(make-variable-buffer-local ',var)
(put ',var 'permanent-local t)))
;; Add entries to minor-mode-alist so that emerge modes show correctly
(defvar emerge-minor-modes-list
'((emerge-mode " Emerge")
(emerge-fast-mode " F")
(emerge-edit-mode " E")
(emerge-auto-advance " A")
(emerge-skip-prefers " S")))
(if (not (assq 'emerge-mode minor-mode-alist))
(setq minor-mode-alist (append emerge-minor-modes-list
minor-mode-alist)))
(defvar-local ,var ,value ,doc)
(put ',var 'permanent-local t)))
;; We need to define this function so describe-mode can describe Emerge mode.
(defun emerge-mode ()
(define-minor-mode emerge-mode
"Emerge mode is used by the Emerge file-merging package.
It is entered only through one of the functions:
`emerge-files'
@ -74,7 +52,13 @@ It is entered only through one of the functions:
Commands:
\\{emerge-basic-keymap}
Commands must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in `edit' mode,
but can be invoked directly in `fast' mode.")
but can be invoked directly in `fast' mode."
:lighter (" Emerge"
(emerge-fast-mode " F")
(emerge-edit-mode " E")
(emerge-auto-advance " A")
(emerge-skip-prefers " S")))
(put 'emerge-mode 'permanent-local t)
;;; Emerge configuration variables
@ -453,8 +437,6 @@ Must be set before Emerge is loaded."
;; Variables which control each merge. They are local to the merge buffer.
;; Mode variables
(emerge-defvar-local emerge-mode nil
"Indicator for emerge-mode.")
(emerge-defvar-local emerge-fast-mode nil
"Indicator for emerge-mode fast submode.")
(emerge-defvar-local emerge-edit-mode nil
@ -556,7 +538,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(if temp
(setq file-A temp
startup-hooks
(cons `(lambda () (delete-file ,file-A))
(cons (lambda () (delete-file file-A))
startup-hooks))
;; Verify that the file matches the buffer
(emerge-verify-file-buffer))))
@ -567,7 +549,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(if temp
(setq file-B temp
startup-hooks
(cons `(lambda () (delete-file ,file-B))
(cons (lambda () (delete-file file-B))
startup-hooks))
;; Verify that the file matches the buffer
(emerge-verify-file-buffer))))
@ -584,48 +566,49 @@ This is *not* a user option, since Emerge uses it for its own processing.")
;; create the merge buffer from buffer A, so it inherits buffer A's
;; default directory, etc.
(merge-buffer (with-current-buffer
buffer-A
(get-buffer-create merge-buffer-name))))
buffer-A
(get-buffer-create merge-buffer-name))))
(with-current-buffer
merge-buffer
(emerge-copy-modes buffer-A)
(setq buffer-read-only nil)
(auto-save-mode 1)
(setq emerge-mode t)
(setq emerge-A-buffer buffer-A)
(setq emerge-B-buffer buffer-B)
(setq emerge-ancestor-buffer nil)
(setq emerge-merge-buffer merge-buffer)
(setq emerge-output-description
(if output-file
(concat "Output to file: " output-file)
(concat "Output to buffer: " (buffer-name merge-buffer))))
(save-excursion (insert-buffer-substring emerge-A-buffer))
(emerge-set-keys)
(setq emerge-difference-list (emerge-make-diff-list file-A file-B))
(setq emerge-number-of-differences (length emerge-difference-list))
(setq emerge-current-difference -1)
(setq emerge-quit-hook quit-hooks)
(emerge-remember-buffer-characteristics)
(emerge-handle-local-variables))
merge-buffer
(emerge-copy-modes buffer-A)
(setq buffer-read-only nil)
(auto-save-mode 1)
(setq emerge-mode t)
(setq emerge-A-buffer buffer-A)
(setq emerge-B-buffer buffer-B)
(setq emerge-ancestor-buffer nil)
(setq emerge-merge-buffer merge-buffer)
(setq emerge-output-description
(if output-file
(concat "Output to file: " output-file)
(concat "Output to buffer: " (buffer-name merge-buffer))))
(save-excursion (insert-buffer-substring emerge-A-buffer))
(emerge-set-keys)
(setq emerge-difference-list (emerge-make-diff-list file-A file-B))
(setq emerge-number-of-differences (length emerge-difference-list))
(setq emerge-current-difference -1)
(setq emerge-quit-hook quit-hooks)
(emerge-remember-buffer-characteristics)
(emerge-handle-local-variables))
(emerge-setup-windows buffer-A buffer-B merge-buffer t)
(with-current-buffer merge-buffer
(run-hooks 'startup-hooks 'emerge-startup-hook)
(setq buffer-read-only t))))
(mapc #'funcall startup-hooks)
(run-hooks 'emerge-startup-hook)
(setq buffer-read-only t))))
;; Generate the Emerge difference list between two files
(defun emerge-make-diff-list (file-A file-B)
(setq emerge-diff-buffer (get-buffer-create "*emerge-diff*"))
(with-current-buffer
emerge-diff-buffer
(erase-buffer)
(shell-command
(format "%s %s %s %s"
(shell-quote-argument emerge-diff-program)
emerge-diff-options
(shell-quote-argument file-A)
(shell-quote-argument file-B))
t))
emerge-diff-buffer
(erase-buffer)
(shell-command
(format "%s %s %s %s"
(shell-quote-argument emerge-diff-program)
emerge-diff-options
(shell-quote-argument file-A)
(shell-quote-argument file-B))
t))
(emerge-prepare-error-list emerge-diff-ok-lines-regexp)
(emerge-convert-diffs-to-markers
emerge-A-buffer emerge-B-buffer emerge-merge-buffer
@ -711,7 +694,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(if temp
(setq file-A temp
startup-hooks
(cons `(lambda () (delete-file ,file-A))
(cons (lambda () (delete-file file-A))
startup-hooks))
;; Verify that the file matches the buffer
(emerge-verify-file-buffer))))
@ -722,7 +705,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(if temp
(setq file-B temp
startup-hooks
(cons `(lambda () (delete-file ,file-B))
(cons (lambda () (delete-file file-B))
startup-hooks))
;; Verify that the file matches the buffer
(emerge-verify-file-buffer))))
@ -733,7 +716,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(if temp
(setq file-ancestor temp
startup-hooks
(cons `(lambda () (delete-file ,file-ancestor))
(cons (lambda () (delete-file file-ancestor))
startup-hooks))
;; Verify that the file matches the buffer
(emerge-verify-file-buffer))))
@ -746,6 +729,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
buffer-ancestor file-ancestor
&optional startup-hooks quit-hooks
output-file)
;; FIXME: Duplicated code!
(setq file-A (expand-file-name file-A))
(setq file-B (expand-file-name file-B))
(setq file-ancestor (expand-file-name file-ancestor))
@ -754,36 +738,37 @@ This is *not* a user option, since Emerge uses it for its own processing.")
;; create the merge buffer from buffer A, so it inherits buffer A's
;; default directory, etc.
(merge-buffer (with-current-buffer
buffer-A
(get-buffer-create merge-buffer-name))))
buffer-A
(get-buffer-create merge-buffer-name))))
(with-current-buffer
merge-buffer
(emerge-copy-modes buffer-A)
(setq buffer-read-only nil)
(auto-save-mode 1)
(setq emerge-mode t)
(setq emerge-A-buffer buffer-A)
(setq emerge-B-buffer buffer-B)
(setq emerge-ancestor-buffer buffer-ancestor)
(setq emerge-merge-buffer merge-buffer)
(setq emerge-output-description
(if output-file
(concat "Output to file: " output-file)
(concat "Output to buffer: " (buffer-name merge-buffer))))
(save-excursion (insert-buffer-substring emerge-A-buffer))
(emerge-set-keys)
(setq emerge-difference-list
(emerge-make-diff3-list file-A file-B file-ancestor))
(setq emerge-number-of-differences (length emerge-difference-list))
(setq emerge-current-difference -1)
(setq emerge-quit-hook quit-hooks)
(emerge-remember-buffer-characteristics)
(emerge-select-prefer-Bs)
(emerge-handle-local-variables))
merge-buffer
(emerge-copy-modes buffer-A)
(setq buffer-read-only nil)
(auto-save-mode 1)
(setq emerge-mode t)
(setq emerge-A-buffer buffer-A)
(setq emerge-B-buffer buffer-B)
(setq emerge-ancestor-buffer buffer-ancestor)
(setq emerge-merge-buffer merge-buffer)
(setq emerge-output-description
(if output-file
(concat "Output to file: " output-file)
(concat "Output to buffer: " (buffer-name merge-buffer))))
(save-excursion (insert-buffer-substring emerge-A-buffer))
(emerge-set-keys)
(setq emerge-difference-list
(emerge-make-diff3-list file-A file-B file-ancestor))
(setq emerge-number-of-differences (length emerge-difference-list))
(setq emerge-current-difference -1)
(setq emerge-quit-hook quit-hooks)
(emerge-remember-buffer-characteristics)
(emerge-select-prefer-Bs)
(emerge-handle-local-variables))
(emerge-setup-windows buffer-A buffer-B merge-buffer t)
(with-current-buffer merge-buffer
(run-hooks 'startup-hooks 'emerge-startup-hook)
(setq buffer-read-only t))))
(mapc #'funcall startup-hooks)
(run-hooks 'emerge-startup-hook)
(setq buffer-read-only t))))
;; Generate the Emerge difference list between two files with an ancestor
(defun emerge-make-diff3-list (file-A file-B file-ancestor)
@ -872,7 +857,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(emerge-read-file-name "Output file" emerge-last-dir-output
f f nil)))))
(if file-out
(add-hook 'quit-hooks `(lambda () (emerge-files-exit ,file-out))))
(push (lambda () (emerge-files-exit file-out)) quit-hooks))
(emerge-files-internal
file-A file-B startup-hooks
quit-hooks
@ -894,7 +879,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(emerge-read-file-name "Output file" emerge-last-dir-output
f f nil)))))
(if file-out
(add-hook 'quit-hooks `(lambda () (emerge-files-exit ,file-out))))
(push (lambda () (emerge-files-exit file-out)) quit-hooks))
(emerge-files-with-ancestor-internal
file-A file-B file-ancestor startup-hooks
quit-hooks
@ -922,9 +907,9 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(write-region (point-min) (point-max) emerge-file-B nil 'no-message))
(emerge-setup (get-buffer buffer-A) emerge-file-A
(get-buffer buffer-B) emerge-file-B
(cons `(lambda ()
(delete-file ,emerge-file-A)
(delete-file ,emerge-file-B))
(cons (lambda ()
(delete-file emerge-file-A)
(delete-file emerge-file-B))
startup-hooks)
quit-hooks
nil)))
@ -953,11 +938,10 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(get-buffer buffer-B) emerge-file-B
(get-buffer buffer-ancestor)
emerge-file-ancestor
(cons `(lambda ()
(delete-file ,emerge-file-A)
(delete-file ,emerge-file-B)
(delete-file
,emerge-file-ancestor))
(cons (lambda ()
(delete-file emerge-file-A)
(delete-file emerge-file-B)
(delete-file emerge-file-ancestor))
startup-hooks)
quit-hooks
nil)))
@ -972,7 +956,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(setq command-line-args-left (nthcdr 3 command-line-args-left))
(emerge-files-internal
file-a file-b nil
(list `(lambda () (emerge-command-exit ,file-out))))))
(list (lambda () (emerge-command-exit file-out))))))
;;;###autoload
(defun emerge-files-with-ancestor-command ()
@ -994,7 +978,7 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(setq command-line-args-left (nthcdr 4 command-line-args-left)))
(emerge-files-with-ancestor-internal
file-a file-b file-anc nil
(list `(lambda () (emerge-command-exit ,file-out))))))
(list (lambda () (emerge-command-exit file-out))))))
(defun emerge-command-exit (file-out)
(emerge-write-and-delete file-out)
@ -1007,7 +991,8 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(setq emerge-file-out file-out)
(emerge-files-internal
file-a file-b nil
(list `(lambda () (emerge-remote-exit ,file-out ',emerge-exit-func)))
(let ((f emerge-exit-func))
(list (lambda () (emerge-remote-exit file-out f))))
file-out)
(throw 'client-wait nil))
@ -1016,14 +1001,15 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(setq emerge-file-out file-out)
(emerge-files-with-ancestor-internal
file-a file-b file-anc nil
(list `(lambda () (emerge-remote-exit ,file-out ',emerge-exit-func)))
(let ((f emerge-exit-func))
(list (lambda () (emerge-remote-exit file-out f))))
file-out)
(throw 'client-wait nil))
(defun emerge-remote-exit (file-out emerge-exit-func)
(defun emerge-remote-exit (file-out exit-func)
(emerge-write-and-delete file-out)
(kill-buffer emerge-merge-buffer)
(funcall emerge-exit-func (if emerge-prefix-argument 1 0)))
(funcall exit-func (if emerge-prefix-argument 1 0)))
;;; Functions to start Emerge on RCS versions
@ -1041,10 +1027,9 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(emerge-revisions-internal
file revision-A revision-B startup-hooks
(if arg
(cons `(lambda ()
(shell-command
,(format "%s %s" emerge-rcs-ci-program file)))
quit-hooks)
(let ((cmd (format "%s %s" emerge-rcs-ci-program file)))
(cons (lambda () (shell-command cmd))
quit-hooks))
quit-hooks)))
;;;###autoload
@ -1065,12 +1050,10 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(emerge-revision-with-ancestor-internal
file revision-A revision-B ancestor startup-hooks
(if arg
(let ((cmd ))
(cons `(lambda ()
(shell-command
,(format "%s %s" emerge-rcs-ci-program file)))
(let ((cmd (format "%s %s" emerge-rcs-ci-program file)))
(cons (lambda () (shell-command cmd))
quit-hooks))
quit-hooks)))
quit-hooks)))
(defun emerge-revisions-internal (file revision-A revision-B &optional
startup-hooks quit-hooks _output-file)
@ -1098,11 +1081,11 @@ This is *not* a user option, since Emerge uses it for its own processing.")
;; Do the merge
(emerge-setup buffer-A emerge-file-A
buffer-B emerge-file-B
(cons `(lambda ()
(delete-file ,emerge-file-A)
(delete-file ,emerge-file-B))
(cons (lambda ()
(delete-file emerge-file-A)
(delete-file emerge-file-B))
startup-hooks)
(cons `(lambda () (emerge-files-exit ,file))
(cons (lambda () (emerge-files-exit file))
quit-hooks)
nil)))
@ -1146,12 +1129,12 @@ This is *not* a user option, since Emerge uses it for its own processing.")
(emerge-setup-with-ancestor
buffer-A emerge-file-A buffer-B emerge-file-B
buffer-ancestor emerge-ancestor
(cons `(lambda ()
(delete-file ,emerge-file-A)
(delete-file ,emerge-file-B)
(delete-file ,emerge-ancestor))
(cons (lambda ()
(delete-file emerge-file-A)
(delete-file emerge-file-B)
(delete-file emerge-ancestor))
startup-hooks)
(cons `(lambda () (emerge-files-exit ,file))
(cons (lambda () (emerge-files-exit file))
quit-hooks)
output-file)))
@ -1233,20 +1216,20 @@ Otherwise, the A or B file present is copied to the output file."
file-ancestor file-out
nil
;; When done, return to this buffer.
(list
`(lambda ()
(switch-to-buffer ,(current-buffer))
(message "Merge done.")))))
(let ((buf (current-buffer)))
(list (lambda ()
(switch-to-buffer buf)
(message "Merge done"))))))
;; Merge of two files without ancestor
((and file-A file-B)
(message "Merging %s and %s..." file-A file-B)
(emerge-files (not (not file-out)) file-A file-B file-out
nil
;; When done, return to this buffer.
(list
`(lambda ()
(switch-to-buffer ,(current-buffer))
(message "Merge done.")))))
(let ((buf (current-buffer)))
(list (lambda ()
(switch-to-buffer buf)
(message "Merge done"))))))
;; There is an output file (or there would have been an error above),
;; but only one input file.
;; The file appears to have been deleted in one version; do nothing.
@ -1456,9 +1439,8 @@ These characteristics are restored by `emerge-restore-buffer-characteristics'."
merge-buffer
lineno-list)
(let* (marker-list
(A-point-min (with-current-buffer A-buffer (point-min)))
(offset (1- A-point-min))
(B-point-min (with-current-buffer B-buffer (point-min)))
(offset (with-current-buffer A-buffer
(- (point-min) (save-restriction (widen) (point-min)))))
;; Record current line number in each buffer
;; so we don't have to count from the beginning.
(a-line 1)
@ -1480,17 +1462,17 @@ These characteristics are restored by `emerge-restore-buffer-characteristics'."
(state (aref list-element 4)))
;; place markers at the appropriate places in the buffers
(with-current-buffer
A-buffer
(setq a-line (emerge-goto-line a-begin a-line))
(setq a-begin-marker (point-marker))
(setq a-line (emerge-goto-line a-end a-line))
(setq a-end-marker (point-marker)))
A-buffer
(setq a-line (emerge-goto-line a-begin a-line))
(setq a-begin-marker (point-marker))
(setq a-line (emerge-goto-line a-end a-line))
(setq a-end-marker (point-marker)))
(with-current-buffer
B-buffer
(setq b-line (emerge-goto-line b-begin b-line))
(setq b-begin-marker (point-marker))
(setq b-line (emerge-goto-line b-end b-line))
(setq b-end-marker (point-marker)))
B-buffer
(setq b-line (emerge-goto-line b-begin b-line))
(setq b-begin-marker (point-marker))
(setq b-line (emerge-goto-line b-end b-line))
(setq b-end-marker (point-marker)))
(setq merge-begin-marker (set-marker
(make-marker)
(- (marker-position a-begin-marker)
@ -1502,15 +1484,15 @@ These characteristics are restored by `emerge-restore-buffer-characteristics'."
offset)
merge-buffer))
;; record all the markers for this difference
(setq marker-list (cons (vector a-begin-marker a-end-marker
b-begin-marker b-end-marker
merge-begin-marker merge-end-marker
state)
marker-list)))
(push (vector a-begin-marker a-end-marker
b-begin-marker b-end-marker
merge-begin-marker merge-end-marker
state)
marker-list))
(setq lineno-list (cdr lineno-list)))
;; convert the list of difference information into a vector for
;; fast access
(setq emerge-difference-list (apply 'vector (nreverse marker-list)))))
(setq emerge-difference-list (apply #'vector (nreverse marker-list)))))
;; If we have an ancestor, select all B variants that we prefer
(defun emerge-select-prefer-Bs ()
@ -1636,7 +1618,7 @@ the height of the merge window.
`C-u -' alone as argument scrolls half the height of the merge window."
(interactive "P")
(emerge-operate-on-windows
'scroll-up
#'scroll-up
;; calculate argument to scroll-up
;; if there is an explicit argument
(if (and arg (not (equal arg '-)))
@ -1663,7 +1645,7 @@ the height of the merge window.
`C-u -' alone as argument scrolls half the height of the merge window."
(interactive "P")
(emerge-operate-on-windows
'scroll-down
#'scroll-down
;; calculate argument to scroll-down
;; if there is an explicit argument
(if (and arg (not (equal arg '-)))
@ -1690,7 +1672,7 @@ the width of the A and B windows. `C-u -' alone as argument scrolls half the
width of the A and B windows."
(interactive "P")
(emerge-operate-on-windows
'scroll-left
#'scroll-left
;; calculate argument to scroll-left
;; if there is an explicit argument
(if (and arg (not (equal arg '-)))
@ -1718,7 +1700,7 @@ the width of the A and B windows. `C-u -' alone as argument scrolls half the
width of the A and B windows."
(interactive "P")
(emerge-operate-on-windows
'scroll-right
#'scroll-right
;; calculate argument to scroll-right
;; if there is an explicit argument
(if (and arg (not (equal arg '-)))
@ -1745,18 +1727,18 @@ This resets the horizontal scrolling of all three merge buffers
to the left margin, if they are in windows."
(interactive)
(emerge-operate-on-windows
(lambda (x) (set-window-hscroll (selected-window) 0))
(lambda (_) (set-window-hscroll (selected-window) 0))
nil))
;; Attempt to show the region nicely.
;; If there are min-lines lines above and below the region, then don't do
;; anything.
;; If not, recenter the region to make it so.
;; If that isn't possible, remove context lines evenly from top and bottom
;; so the entire region shows.
;; If that isn't possible, show the top of the region.
;; BEG must be at the beginning of a line.
(defun emerge-position-region (beg end pos)
"Attempt to show the region nicely.
If there are min-lines lines above and below the region, then don't do
anything.
If not, recenter the region to make it so.
If that isn't possible, remove context lines evenly from top and bottom
so the entire region shows.
If that isn't possible, show the top of the region.
BEG must be at the beginning of a line."
;; First test whether the entire region is visible with
;; emerge-min-visible-lines above and below it
(if (not (and (<= (progn
@ -1795,7 +1777,7 @@ to the left margin, if they are in windows."
(memq (aref (aref emerge-difference-list n) 6)
'(prefer-A prefer-B)))
(setq n (1+ n)))
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
(emerge-unselect-and-select-difference n)))
(error "At end")))
@ -1809,14 +1791,14 @@ to the left margin, if they are in windows."
(memq (aref (aref emerge-difference-list n) 6)
'(prefer-A prefer-B)))
(setq n (1- n)))
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
(emerge-unselect-and-select-difference n)))
(error "At beginning")))
(defun emerge-jump-to-difference (difference-number)
"Go to the N-th difference."
(interactive "p")
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
(setq difference-number (1- difference-number))
(if (and (>= difference-number -1)
(< difference-number (1+ emerge-number-of-differences)))
@ -1878,6 +1860,13 @@ buffer after this will cause serious problems."
(let ((emerge-prefix-argument arg))
(run-hooks 'emerge-quit-hook)))
(defmacro emerge--current-beg (diff-vector side)
;; +1 because emerge-place-flags-in-buffer1 moved the marker by 1.
`(1+ (aref ,diff-vector ,(pcase-exhaustive side ('A 0) ('B 2) ('merge 4)))))
(defmacro emerge--current-end (diff-vector side)
;; -1 because emerge-place-flags-in-buffer1 moved the marker by 1.
`(1- (aref ,diff-vector ,(pcase-exhaustive side ('A 1) ('B 3) ('merge 5)))))
(defun emerge-select-A (&optional force)
"Select the A variant of this difference.
Refuses to function if this difference has been edited, i.e., if it
@ -1885,26 +1874,25 @@ is neither the A nor the B variant.
A prefix argument forces the variant to be selected
even if the difference has been edited."
(interactive "P")
(let ((operate
(lambda ()
(emerge-select-A-edit merge-begin merge-end A-begin A-end)
(if emerge-auto-advance
(emerge-next-difference))))
(let ((operate #'emerge-select-A-edit)
(operate-no-change
(lambda () (if emerge-auto-advance
(emerge-next-difference)))))
(lambda (_diff-vector)
(if emerge-auto-advance (emerge-next-difference)))))
(emerge-select-version force operate-no-change operate operate)))
;; Actually select the A variant
(defun emerge-select-A-edit (merge-begin merge-end A-begin A-end)
(defun emerge-select-A-edit (diff-vector)
(with-current-buffer
emerge-merge-buffer
(delete-region merge-begin merge-end)
(goto-char merge-begin)
(insert-buffer-substring emerge-A-buffer A-begin A-end)
(goto-char merge-begin)
(aset diff-vector 6 'A)
(emerge-refresh-mode-line)))
emerge-merge-buffer
(goto-char (emerge--current-beg diff-vector merge))
(delete-region (point) (emerge--current-end diff-vector merge))
(save-excursion
(insert-buffer-substring emerge-A-buffer
(emerge--current-beg diff-vector A)
(emerge--current-end diff-vector A)))
(aset diff-vector 6 'A)
(emerge-refresh-mode-line)
(if emerge-auto-advance (emerge-next-difference))))
(defun emerge-select-B (&optional force)
"Select the B variant of this difference.
@ -1913,26 +1901,25 @@ is neither the A nor the B variant.
A prefix argument forces the variant to be selected
even if the difference has been edited."
(interactive "P")
(let ((operate
(lambda ()
(emerge-select-B-edit merge-begin merge-end B-begin B-end)
(if emerge-auto-advance
(emerge-next-difference))))
(let ((operate #'emerge-select-B-edit)
(operate-no-change
(lambda () (if emerge-auto-advance
(emerge-next-difference)))))
(lambda (_diff-vector)
(if emerge-auto-advance (emerge-next-difference)))))
(emerge-select-version force operate operate-no-change operate)))
;; Actually select the B variant
(defun emerge-select-B-edit (merge-begin merge-end B-begin B-end)
(defun emerge-select-B-edit (diff-vector)
(with-current-buffer
emerge-merge-buffer
(delete-region merge-begin merge-end)
(goto-char merge-begin)
(insert-buffer-substring emerge-B-buffer B-begin B-end)
(goto-char merge-begin)
(aset diff-vector 6 'B)
(emerge-refresh-mode-line)))
emerge-merge-buffer
(goto-char (emerge--current-beg diff-vector merge))
(delete-region (point) (emerge--current-end diff-vector merge))
(save-excursion
(insert-buffer-substring emerge-B-buffer
(emerge--current-beg diff-vector B)
(emerge--current-end diff-vector B)))
(aset diff-vector 6 'B)
(emerge-refresh-mode-line)
(if emerge-auto-advance (emerge-next-difference))))
(defun emerge-default-A ()
"Make the A variant the default from here down.
@ -1940,7 +1927,7 @@ This selects the A variant for all differences from here down in the buffer
which are still defaulted, i.e., which the user has not selected and for
which there is no preference."
(interactive)
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
(let ((selected-difference emerge-current-difference)
(n (max emerge-current-difference 0)))
(while (< n emerge-number-of-differences)
@ -1962,7 +1949,7 @@ This selects the B variant for all differences from here down in the buffer
which are still defaulted, i.e., which the user has not selected and for
which there is no preference."
(interactive)
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
(let ((selected-difference emerge-current-difference)
(n (max emerge-current-difference 0)))
(while (< n emerge-number-of-differences)
@ -2071,7 +2058,7 @@ With prefix argument, puts point before, mark after."
(A-begin (1+ (aref diff-vector 0)))
(A-end (1- (aref diff-vector 1)))
(opoint (point))
(buffer-read-only nil))
(inhibit-read-only t))
(insert-buffer-substring emerge-A-buffer A-begin A-end)
(if (not arg)
(set-mark opoint)
@ -2089,7 +2076,7 @@ With prefix argument, puts point before, mark after."
(B-begin (1+ (aref diff-vector 2)))
(B-end (1- (aref diff-vector 3)))
(opoint (point))
(buffer-read-only nil))
(inhibit-read-only t))
(insert-buffer-substring emerge-B-buffer B-begin B-end)
(if (not arg)
(set-mark opoint)
@ -2450,28 +2437,28 @@ the nearest previous difference."
(1- index)
(error "No difference contains or precedes point")))))))
(defvar emerge-line-diff)
(defun emerge-line-numbers ()
"Display the current line numbers.
This function displays the line numbers of the points in the A, B, and
merge buffers."
(interactive)
(let* ((valid-diff
(and (>= emerge-current-difference 0)
(< emerge-current-difference emerge-number-of-differences)))
(and (>= emerge-current-difference 0)
(< emerge-current-difference emerge-number-of-differences)))
(emerge-line-diff (and valid-diff
(aref emerge-difference-list
emerge-current-difference)))
(merge-line (emerge-line-number-in-buf 4 5))
(merge-line (emerge-line-number-in-buf valid-diff 4 5))
(A-line (with-current-buffer emerge-A-buffer
(emerge-line-number-in-buf 0 1)))
(emerge-line-number-in-buf valid-diff 0 1)))
(B-line (with-current-buffer emerge-B-buffer
(emerge-line-number-in-buf 2 3))))
(emerge-line-number-in-buf valid-diff 2 3))))
(message "At lines: merge = %d, A = %d, B = %d"
merge-line A-line B-line)))
(defvar emerge-line-diff)
(defun emerge-line-number-in-buf (begin-marker end-marker)
(defun emerge-line-number-in-buf (valid-diff begin-marker end-marker)
;; FIXME point-min rather than 1? widen?
(let ((temp (1+ (count-lines 1 (line-beginning-position)))))
(if valid-diff
@ -2537,46 +2524,41 @@ Interactively, reads the register using `register-read-with-preview'."
(error "Register does not contain text"))
(emerge-combine-versions-internal template force)))
(defun emerge-combine-versions-internal (emerge-combine-template force)
(let ((operate
(lambda ()
(emerge-combine-versions-edit merge-begin merge-end
A-begin A-end B-begin B-end)
(if emerge-auto-advance
(emerge-next-difference)))))
(defun emerge-combine-versions-internal (combine-template force)
(let ((operate (lambda (diff-vector)
(emerge-combine-versions-edit diff-vector
combine-template))))
(emerge-select-version force operate operate operate)))
(defvar emerge-combine-template)
(defun emerge-combine-versions-edit (merge-begin merge-end
A-begin A-end B-begin B-end)
(defun emerge-combine-versions-edit (diff-vector combine-template)
(with-current-buffer
emerge-merge-buffer
(delete-region merge-begin merge-end)
(goto-char merge-begin)
(let ((i 0))
(while (< i (length emerge-combine-template))
(let ((c (aref emerge-combine-template i)))
(if (= c ?%)
(progn
(setq i (1+ i))
(setq c
(condition-case nil
(aref emerge-combine-template i)
(error ?%)))
(cond ((= c ?a)
(insert-buffer-substring emerge-A-buffer A-begin A-end))
((= c ?b)
(insert-buffer-substring emerge-B-buffer B-begin B-end))
((= c ?%)
(insert ?%))
(t
(insert c))))
(insert c)))
(setq i (1+ i))))
(goto-char merge-begin)
(aset diff-vector 6 'combined)
(emerge-refresh-mode-line)))
emerge-merge-buffer
(goto-char (emerge--current-beg diff-vector merge))
(delete-region (point) (emerge--current-end diff-vector merge))
(save-excursion
(let ((i 0))
(while (< i (length combine-template))
(let ((c (aref combine-template i)))
(if (not (= c ?%))
(insert c)
(setq i (1+ i))
(pcase (condition-case nil
(aref combine-template i)
(error ?%))
(?a
(insert-buffer-substring emerge-A-buffer
(emerge--current-beg diff-vector A)
(emerge--current-end diff-vector A)))
(?b
(insert-buffer-substring emerge-B-buffer
(emerge--current-beg diff-vector B)
(emerge--current-end diff-vector B)))
(?% (insert ?%))
(c (insert c)))))
(setq i (1+ i)))))
(aset diff-vector 6 'combined)
(emerge-refresh-mode-line)
(if emerge-auto-advance (emerge-next-difference))))
(defun emerge-set-merge-mode (mode)
"Set the major mode in a merge buffer.
@ -2617,7 +2599,7 @@ keymap. Leaves merge in fast mode."
(emerge-place-flags-in-buffer1 difference before-index after-index)))
(defun emerge-place-flags-in-buffer1 (difference before-index after-index)
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
;; insert the flag before the difference
(let ((before (aref (aref emerge-globalized-difference-list difference)
before-index))
@ -2682,7 +2664,7 @@ keymap. Leaves merge in fast mode."
(defun emerge-remove-flags-in-buffer (buffer before after)
(with-current-buffer
buffer
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
;; remove the flags, if they're there
(goto-char (- before (1- emerge-before-flag-length)))
(if (looking-at emerge-before-flag-match)
@ -2717,18 +2699,18 @@ keymap. Leaves merge in fast mode."
(emerge-recenter)
(emerge-refresh-mode-line))))
;; Perform tests to see whether user should be allowed to select a version
;; of this difference:
;; a valid difference has been selected; and
;; the difference text in the merge buffer is:
;; the A version (execute a-version), or
;; the B version (execute b-version), or
;; empty (execute neither-version), or
;; argument FORCE is true (execute neither-version)
;; Otherwise, signal an error.
(defun emerge-select-version (force a-version b-version neither-version)
"Perform tests to see whether user should be allowed to select a version
of this difference:
a valid difference has been selected; and
the difference text in the merge buffer is:
the A version (execute a-version), or
the B version (execute b-version), or
empty (execute neither-version), or
argument FORCE is true (execute neither-version)
Otherwise, signal an error."
(emerge-validate-difference)
(let ((buffer-read-only nil))
(let ((inhibit-read-only t))
(let* ((diff-vector
(aref emerge-difference-list emerge-current-difference))
(A-begin (1+ (aref diff-vector 0)))
@ -2740,13 +2722,13 @@ keymap. Leaves merge in fast mode."
(if (emerge-compare-buffers emerge-A-buffer A-begin A-end
emerge-merge-buffer merge-begin
merge-end)
(funcall a-version)
(funcall a-version diff-vector)
(if (emerge-compare-buffers emerge-B-buffer B-begin B-end
emerge-merge-buffer merge-begin
merge-end)
(funcall b-version)
(funcall b-version diff-vector)
(if (or force (= merge-begin merge-end))
(funcall neither-version)
(funcall neither-version diff-vector)
(error "This difference region has been edited")))))))
;; Read a file name, handling all of the various defaulting rules.
@ -2972,78 +2954,6 @@ If some prefix of KEY has a non-prefix definition, it is redefined."
;; Now define the key
(define-key keymap key definition))
;;;;; Improvements to describe-mode, so that it describes minor modes as well
;;;;; as the major mode
;;(defun describe-mode (&optional minor)
;; "Display documentation of current major mode.
;;If optional arg MINOR is non-nil (or prefix argument is given if interactive),
;;display documentation of active minor modes as well.
;;For this to work correctly for a minor mode, the mode's indicator variable
;;\(listed in `minor-mode-alist') must also be a function whose documentation
;;describes the minor mode."
;; (interactive)
;; (with-output-to-temp-buffer "*Help*"
;; (princ mode-name)
;; (princ " Mode:\n")
;; (princ (documentation major-mode))
;; (let ((minor-modes minor-mode-alist)
;; (locals (buffer-local-variables)))
;; (while minor-modes
;; (let* ((minor-mode (car (car minor-modes)))
;; (indicator (car (cdr (car minor-modes))))
;; (local-binding (assq minor-mode locals)))
;; ;; Document a minor mode if it is listed in minor-mode-alist,
;; ;; bound locally in this buffer, non-nil, and has a function
;; ;; definition.
;; (if (and local-binding
;; (cdr local-binding)
;; (fboundp minor-mode))
;; (progn
;; (princ (format "\n\n\n%s minor mode (indicator%s):\n"
;; minor-mode indicator))
;; (princ (documentation minor-mode)))))
;; (setq minor-modes (cdr minor-modes))))
;; (with-current-buffer standard-output
;; (help-mode))
;; (help-print-return-message)))
;; This goes with the redefinition of describe-mode.
;;;; Adjust things so that keyboard macro definitions are documented correctly.
;;(fset 'defining-kbd-macro (symbol-function 'start-kbd-macro))
;; substitute-key-definition should work now.
;;;; Function to shadow a definition in a keymap with definitions in another.
;;(defun emerge-shadow-key-definition (olddef newdef keymap shadowmap)
;; "Shadow OLDDEF with NEWDEF for any keys in KEYMAP with entries in SHADOWMAP.
;;In other words, SHADOWMAP will now shadow all definitions of OLDDEF in KEYMAP
;;with NEWDEF. Does not affect keys that are already defined in SHADOWMAP,
;;including those whose definition is OLDDEF."
;; ;; loop through all keymaps accessible from keymap
;; (let ((maps (accessible-keymaps keymap)))
;; (while maps
;; (let ((prefix (car (car maps)))
;; (map (cdr (car maps))))
;; ;; examine a keymap
;; (if (arrayp map)
;; ;; array keymap
;; (let ((len (length map))
;; (i 0))
;; (while (< i len)
;; (if (eq (aref map i) olddef)
;; ;; set the shadowing definition
;; (let ((key (concat prefix (char-to-string i))))
;; (emerge-define-key-if-possible shadowmap key newdef)))
;; (setq i (1+ i))))
;; ;; sparse keymap
;; (while map
;; (if (eq (cdr-safe (car-safe map)) olddef)
;; ;; set the shadowing definition
;; (let ((key
;; (concat prefix (char-to-string (car (car map))))))
;; (emerge-define-key-if-possible shadowmap key newdef)))
;; (setq map (cdr map)))))
;; (setq maps (cdr maps)))))
;; Define a key if it (or a prefix) is not already defined in the map.
(defun emerge-define-key-if-possible (keymap key definition)
;; look up the present definition of the key
@ -3057,18 +2967,6 @@ If some prefix of KEY has a non-prefix definition, it is redefined."
(if (not present)
(define-key keymap key definition)))))
;; Ordinary substitute-key-definition should do this now.
;;(defun emerge-recursively-substitute-key-definition (olddef newdef keymap)
;; "Like `substitute-key-definition', but act recursively on subkeymaps.
;;Make sure that subordinate keymaps aren't shared with other keymaps!
;;\(`copy-keymap' will suffice.)"
;; ;; Loop through all keymaps accessible from keymap
;; (let ((maps (accessible-keymaps keymap)))
;; (while maps
;; ;; Substitute in this keymap
;; (substitute-key-definition olddef newdef (cdr (car maps)))
;; (setq maps (cdr maps)))))
;; Show the name of the file in the buffer.
(defun emerge-show-file-name ()
"Displays the name of the file loaded into the current buffer.