;;; compare-w.el --- compare text between windows for Emacs.
-;; Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc.
+;; Copyright (C) 1986, 1989, 1993, 1997 Free Software Foundation, Inc.
;; Maintainer: FSF
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
;;; Commentary:
;;; Code:
-(defvar compare-windows-whitespace "[ \t\n]+"
+(defgroup compare-w nil
+ "Compare text between windows."
+ :prefix "compare-"
+ :group 'tools)
+
+(defcustom compare-windows-whitespace "[ \t\n]+"
"*Regexp that defines whitespace sequences for \\[compare-windows].
Changes in whitespace are optionally ignored.
The function is passed one argument, the point where `compare-windows'
was originally called; it should not consider any text before that point.
If the function returns the same value for both buffers, then the
-whitespace is considered to match, and is skipped.")
+whitespace is considered to match, and is skipped."
+ :type '(choice regexp function)
+ :group 'compare-w)
-(defvar compare-ignore-case nil
- "*Non-nil means \\[compare-windows] ignores case differences.")
+(defcustom compare-ignore-case nil
+ "*Non-nil means \\[compare-windows] ignores case differences."
+ :type 'boolean
+ :group 'compare-w)
;;;###autoload
(defun compare-windows (ignore-whitespace)
Compares the text starting at point in each window,
moving over text in each one as far as they match.
+This command pushes the mark in each window
+at the prior location of point in that window.
+If both windows display the same buffer,
+the mark is pushed twice in that buffer:
+first in the other window, then in the selected window.
+
A prefix arg means ignore changes in whitespace.
The variable `compare-windows-whitespace' controls how whitespace is skipped.
If `compare-ignore-case' is non-nil, changes in case are also ignored."
(interactive "P")
(let* (p1 p2 maxp1 maxp2 b1 b2 w2
- success size
+ (progress 1)
(opoint1 (point))
opoint2
- (skip-whitespace (if ignore-whitespace
- compare-windows-whitespace)))
+ (skip-func (if ignore-whitespace
+ (if (stringp compare-windows-whitespace)
+ 'compare-windows-skip-whitespace
+ compare-windows-whitespace))))
(setq p1 (point) b1 (current-buffer))
(setq w2 (next-window (selected-window)))
+ (if (eq w2 (selected-window))
+ (setq w2 (next-window (selected-window) nil 'visible)))
(if (eq w2 (selected-window))
(error "No other window"))
(setq p2 (window-point w2)
(setq maxp1 (point-max))
(save-excursion
(set-buffer b2)
+ (push-mark p2 t)
(setq maxp2 (point-max)))
+ (push-mark)
- (setq success t)
- (while success
- (setq success nil)
- ;; if interrupted, show how far we've gotten
- (goto-char p1)
- (set-window-point w2 p2)
-
+ (while (> progress 0)
;; If both buffers have whitespace next to point,
;; optionally skip over it.
- (and skip-whitespace
+ (and skip-func
(save-excursion
(let (p1a p2a w1 w2 result1 result2)
- (setq result1
- (if (stringp skip-whitespace)
- (compare-windows-skip-whitespace opoint1)
- (funcall skip-whitespace opoint1)))
+ (setq result1 (funcall skip-func opoint1))
(setq p1a (point))
(set-buffer b2)
(goto-char p2)
- (setq result2
- (if (stringp skip-whitespace)
- (compare-windows-skip-whitespace opoint2)
- (funcall skip-whitespace opoint2)))
+ (setq result2 (funcall skip-func opoint2))
(setq p2a (point))
- (and result1 result2 (eq result1 result2)
- (setq p1 p1a
- p2 p2a)))))
-
- ;; Try advancing comparing 1000 chars at a time.
- ;; When that fails, go 500 chars at a time, and so on.
- (let ((size 1000)
- success-1
+ (if (or (stringp compare-windows-whitespace)
+ (and result1 result2 (eq result1 result2)))
+ (setq p1 p1a
+ p2 p2a)))))
+
+ (let ((size (min (- maxp1 p1) (- maxp2 p2)))
(case-fold-search compare-ignore-case))
- (while (> size 0)
- (setq success-1 t)
- ;; Try comparing SIZE chars at a time, repeatedly, till that fails.
- (while success-1
- (setq size (min size (- maxp1 p1) (- maxp2 p2)))
- (setq success-1
- (and (> size 0)
- (= 0 (compare-buffer-substrings b2 p2 (+ size p2)
- b1 p1 (+ size p1)))))
- (if success-1
- (setq p1 (+ p1 size) p2 (+ p2 size)
- success t)))
- ;; If SIZE chars don't match, try fewer.
- (setq size (/ size 2)))))
-
- (goto-char p1)
- (set-window-point w2 p2)
+ (setq progress (compare-buffer-substrings b2 p2 (+ size p2)
+ b1 p1 (+ size p1)))
+ (setq progress (if (zerop progress) size (1- (abs progress))))
+ (setq p1 (+ p1 progress) p2 (+ p2 progress)))
+ ;; Advance point now rather than later, in case we're interrupted.
+ (goto-char p1)
+ (set-window-point w2 p2))
+
(if (= (point) opoint1)
(ding))))