From fbd025a667b2361db30c3cb723b4f0ca15413d4a Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 3 Apr 2018 23:17:30 -0400 Subject: [PATCH] * 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. --- lisp/vc/emerge.el | 602 +++++++++++++++++++--------------------------- 1 file changed, 250 insertions(+), 352 deletions(-) diff --git a/lisp/vc/emerge.el b/lisp/vc/emerge.el index 0da14d07fd3..fc8c318e3af 100644 --- a/lisp/vc/emerge.el +++ b/lisp/vc/emerge.el @@ -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-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. -- 2.39.2