[comp.emacs] A GREP-like interface to DIFF ???

Ram-Ashwin@cs.yale.edu (Ashwin Ram) (01/22/88)

Is there a GNU Emacs interface to 'diff' that works sort of like 'grep'?
For example, one might type:

        M-x diff foo bar

and it would start up a diff process in the background, such that each time
you hit next-difference (the equivalent of next-error), you would be shown
the two files foo and bar in two windows, each positioned at the next
difference found.  (This is a generalization of the compile command, where
you're running some command (diff) with two arguments instead of one.  I
suppose you could generalize this further to n arguments.)

Alternatively, a next-difference command for compare-w.el would be useful
too, although I think the diff interface would be nice in its own right.

If you have something like this (or are now inspired to write it), please
send me a copy.

Thanks in advance.

-- Ashwin Ram --

ARPA:    Ram-Ashwin@cs.yale.edu
UUCP:    {decvax,ucbvax,harvard,cmcl2,...}!yale!Ram-Ashwin
BITNET:  Ram@yalecs

wolfgang@mgm.mit.edu (Wolfgang Rupprecht) (01/23/88)

Here is a little hack, show-diff that I have used in the past, to find
and examine diffs. Showdiff will find the files corresponding to the
diff, and display them in two separate windows. It will also put the
point and mark around the diffs in each file for you. This makes it
trivial to copy/kill the sectio from one buffer to the next. Just the
thing for selectively applying patches.

Showdiff is meant for examining whole, direcory tree diffs, but will
work for single files too. You just have to make sure that the diff
*looks* like a recursive (non-comtext) diff, with 'diff -r fromfile
tofile' preceeding the actual diffs for that file.

enjoy,
-wolfgang

Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
Freelance Consultant	UUCP:  mit-eddie!mgm.mit.edu!wolfgang
Boston, Ma.		VOICE: Hey_Wolfgang!_(617)_267-4365


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;									     ;;
;;	File:     showdiff.el						     ;;
;;	Author:   Wolfgang Rupprecht					     ;;
;;	Created:  Tue Apr 14 20:48:35 EDT 1987				     ;;
;;	Contents: parse a diff listing and finds the files		     ;;
;;									     ;;
;;	Copyright (c) 1987 Wolfgang Rupprecht.				     ;;
;;									     ;;
;;	$Log$								     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; GNU Emacs and this file showdiff.el, are distributed in the hope
;; that they will be useful, but WITHOUT ANY WARRANTY.  No author or
;; distributor accepts responsibility to anyone for the consequences of
;; using them or for whether they serve any particular purpose or work at
;; all, unless he says so in writing.  Refer to the GNU Emacs General
;; Public License for full details.

;; Everyone is granted permission to copy, modify and redistribute GNU
;; Emacs and showdiff.el, but only under the conditions described in the
;; GNU Emacs General Public License.  A copy of this license is supposed
;; to have been given to you along with GNU Emacs so you can know your
;; rights and responsibilities.  It should be in a file named COPYING.
;; Among other things, the copyright notice and this notice must be
;; preserved on all copies.

;; If you like this diff hack, and would like other custom
;; non-proprietary GnuEmacs extensions, let me know. I may be
;; interested in doing them for you on a contract basis. -wsr

(defvar diff-line-regexp
    "^diff[ \t]+\\([^ \t\n]+[ \t]+\\)*\\([^ \t\n]+\\)[ \t]+\\([^ \t\n]+\\)[ \t]*$"
  "rexexp for finding file names in a 'diff -r' listing")
(defvar changed-line-regexp
    "^\\(^[0-9]+\\)\\(,\\([0-9]+\\)\\)?[acd]\\([0-9]+\\)\\(,\\([0-9]+\\)\\)?$"
    "regexp for finding the line that descibes the changed line
numbers in a diff listing")

(defun show-diff ()
  "Find the two files corresponding to the section of the diff listing
in buffer and display the apropriate sections in two windows.  The
point and mark in both files will be around the diffs. The diff must
be a non-context diff. It must also be a diff -r so that the \"diff
file1 file2\" will appear in the output (you may also edit this in by
hand).  The file with the lower number in the name extension is
usually the 'to' file.  The 'from' file will be write-protected to
avoid inadvertant editing of the wrong file.

In short, use as follows:
\\[compile]
diff -r /absolute/path/foodir-old /absolute/path/foodir
\\[switch-to-buffer]
*compilation*
(or redirect the diff output to a file, and \\[find-file] filename)
move to diff that you want to examine.
\\[show-diff]"
  (interactive)
  (let (from-file to-file to-point from-point to-mark
		  from-mark (diff-directory default-directory))
    (save-excursion
      (end-of-line 1)
      (if (re-search-backward diff-line-regexp nil t)
	  (setq from-file (buffer-substring
			   (match-beginning 2) (match-end 2))
		to-file (buffer-substring
			 (match-beginning 3) (match-end 3)))
	  (error "Not inside a diff (couldn't find a 'diff * file1 file2')")))
    (save-excursion
      (end-of-line 1)
      (if (re-search-backward changed-line-regexp nil t)     
	  (setq 
	   from-point (match-as-int 1)
	   from-mark (if (nth 6 (match-data))
			 (1+ (match-as-int 3)) ; 1+ I think
			 (1+ from-point))
	   to-point (match-as-int 4)
	   to-mark (if (nth 12 (match-data))
		       (1+ (match-as-int 6)) ; ditto 
		       (1+ to-point)))
	  (error "Couldn't find the change descriptor line (eg. 15,17c24,33)")))
    (find-file-other-window to-file)
    (goto-line to-mark)
    (set-mark (point))
    (goto-line to-point)
    (find-file-other-window
     (if (file-name-absolute-p from-file)	; we might have changed directories
	 from-file
	 (concat diff-directory from-file)))
    (goto-line from-mark)
    (set-mark (point))
    (goto-line from-point)
    (setq buffer-read-only t)		; don't go editing the wrong one !!!
    (other-window 1)			;put the cursor in 'to' file
    (message "%s:(%d,%d) -> %s:(%d,%d)" from-file from-point from-mark
	     to-file to-point to-mark)))

(defun match-as-int (n)
  "Extract an integer for match NUMBER-N"
  (string-to-int (buffer-substring (match-beginning n) (match-end n))))

Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
Freelance Consultant	UUCP:  mit-eddie!mgm.mit.edu!wolfgang
Boston, Ma.		VOICE: Hey_Wolfgang!_(617)_267-4365

wolfgang@mgm.mit.edu (Wolfgang Rupprecht) (01/23/88)

Here is another useful file, unix.el which includes another diff tool.
It takes the diff of a buffer's file and the oldest backup that it can
locate.

Also in this collection is a set of functions for linting a buffer,
C-indenting a buffer (via the Unix Cuisinart indent(1)), grepping for
a symbol and a few other useful interface functions.

enjoy,
-wolfgang

PS. the 'gid' program referred to is available from comp.sources
in the 'ids' package (on archived on uunet.uu.net).

Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
Freelance Consultant	UUCP:  mit-eddie!mgm.mit.edu!wolfgang
Boston, Ma.		VOICE: Hey_Wolfgang!_(617)_267-4365

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;									     ;;
;;	File:     unix.el						     ;;
;;	Author:   Wolfgang Rupprecht					     ;;
;;	Created:  Wed Jan 20 12:24:16 EST 1988				     ;;
;;	Contents: some useful unix interface routines for gnueamcs           ;;
;;									     ;;
;;	Copyright (c) 1988 Wolfgang Rupprecht.				     ;;
;;									     ;;
;;	$Log$								     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; GNU Emacs and this file unix.el, are distributed in the hope
;; that they will be useful, but WITHOUT ANY WARRANTY.  No author or
;; distributor accepts responsibility to anyone for the consequences of
;; using them or for whether they serve any particular purpose or work at
;; all, unless he says so in writing.  Refer to the GNU Emacs General
;; Public License for full details.

;; Everyone is granted permission to copy, modify and redistribute GNU
;; Emacs and unix.el, but only under the conditions described in the
;; GNU Emacs General Public License.  A copy of this license is supposed
;; to have been given to you along with GNU Emacs so you can know your
;; rights and responsibilities.  It should be in a file named COPYING.
;; Among other things, the copyright notice and this notice must be
;; preserved on all copies.

(autoload 'compile1 "compile")

(defun lint (buffer)
  "Run lint(1) on specified buffer and collect output in a buffer.
While lint runs asynchronously, you can use the \\[next-error] command
to find the text that lint gripes refer to."
  (interactive "bbuffer to lint ")
  (save-excursion
    (switch-to-buffer buffer t)
    (save-buffer buffer)
    (compile1 (concat "lint -abchx " buffer-file-name)
	      "No more lint gripes" "lint")))

(defun cindent (buffer)
  "Reformat the specified BUFFER using the Unix indent(1) program.
Selects the specified buffer, and saves it to disk, displays new version.
M-x revert-buffer and M-x undo work as expected. User may opt not to save
the newly indented buffer."
  (interactive "bbuffer to indent ")
  (switch-to-buffer buffer)
  (let ((auto-save-file-name (make-auto-save-file-name))
	(opoint (point)) )
    (save-buffer)
    (shell-command  (concat "indent -l80 -bl -bc -v " buffer-file-name
			    " " auto-save-file-name) nil)
    (if (file-exists-p auto-save-file-name)
	(progn
	  (erase-buffer)
	  (insert-file auto-save-file-name)
	  (goto-char (min opoint (point-max))))
      (error "indent failed to produce the output file"))))

(defun diff (buf &optional nocontext) 
"Take the diff(1) of a BUFFER and its oldest backup file. With prefix
arg, (or optional flag if noninteractive) does an normal non-context
diff. This option is required for \\[show-diff]."
  (interactive "bBuffer: ")
  (switch-to-buffer buf)
  (let*
      ((file-base-name (file-name-nondirectory buffer-file-name))
       (back-list
	 (file-name-all-completions file-base-name default-directory))
       (back-name (oldest-file back-list)))
    (if interactive-p
	(setq nocontext current-prefix-arg))
    (if (string-match back-name file-base-name)
	(message "No older backup of %s found." file-base-name)
      (compile1 (format "diff %s %s %s"
			(if nocontext "-r" "-c")
			back-name file-base-name)
		"Use show-diff to move to diffs"
		"diff"))))

(defun oldest-file (list)
  "Return the oldest file, from the LIST of files."
  (let ((oldest (car list)))
    (if list (setq list (cdr list)))
    (while list
      (if (file-newer-than-file-p oldest (car list))
	  (setq oldest (car list)))
      (setq list (cdr list)))
    oldest))

(defun grep (command)
  "Run grep, with user-specified args, and collect output in a buffer.
While grep runs asynchronously, you can use the \\[next-error] command
to find the text that grep hits refer to."
  (interactive (list (read-input "Run grep (with args): "
				 (concat (symbol-around-point) " "
					 (other-possibly-interesting-files)))))
  (compile1 (concat "grep -n " command " /dev/null")
	    "No more grep hits" "grep"))

(defun gid (command)
  "Run gid, with user-specified args, and collect output in a buffer.
While gid runs asynchronously, you can use the \\[next-error] command
to find the text that gid hits refer to.  Gid is Greg Mcgary's
pre-digested-grep program, like ctags, but for grep."
  (interactive (list (read-input "Run gid (with args): "
				 (symbol-around-point))))
  (compile1 (concat "gid " command)
	    "No more gid hits" "gid"))

(defun other-possibly-interesting-files ()
  "Return a sh-regexp for other files that may be of intrest for
the purpose of grep-ing"
  (if (equal major-mode 'c-mode)
      "*.h *.c"				;for .h and .c files
      (concat "*" (and buffer-file-name
		       (string-match "\.[^.]+$" buffer-file-name)
		       (substring buffer-file-name
				  (match-beginning 0) (match-end 0))))))

(defun word-around-point ()
  "Return the word around the point as a string."
  (save-excursion
    (let (beg)
      (if (not (looking-at "\\<"))
	  (forward-word -1))
      (setq beg (point))
      (forward-word 1)
      (buffer-substring beg (point)))))

(defun symbol-around-point ()
  "Return the symbol around the point as a string."
  (save-excursion
    (if (not (looking-at "\\s_\\|\\sw")) ; if not in a symbol
	(re-search-backward "\\s_\\|\\sw" nil t)) ; go into prev. one
    (buffer-substring
      (progn (forward-sexp 1) (point))
      (progn (backward-sexp 1) (point)))))


Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
Freelance Consultant	UUCP:  mit-eddie!mgm.mit.edu!wolfgang
Boston, Ma.		VOICE: Hey_Wolfgang!_(617)_267-4365

wolfgang@mgm.mit.edu (Wolfgang Rupprecht) (01/23/88)

Here is another useful file, unix.el which includes another diff tool.
It takes the diff of a buffer's file and the oldest backup that it can
locate.

Also in this collection is a set of functions for linting a buffer,
C-indenting a buffer (via the Unix Cuisinart indent(1)), grepping for
a symbol and a few other useful interface functions.

enjoy,
-wolfgang

PS. the 'gid' program referred to is available from comp.sources
in the 'ids' package (on archived on uunet.uu.net).

Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
Freelance Consultant	UUCP:  mit-eddie!mgm.mit.edu!wolfgang
Boston, Ma.		VOICE: Hey_Wolfgang!_(617)_267-4365

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;									     ;;
;;	File:     unix.el						     ;;
;;	Author:   Wolfgang Rupprecht					     ;;
;;	Created:  Wed Jan 20 12:24:16 EST 1988				     ;;
;;	Contents: some useful unix interface routines for gnueamcs           ;;
;;									     ;;
;;	Copyright (c) 1988 Wolfgang Rupprecht.				     ;;
;;									     ;;
;;	$Log$								     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; GNU Emacs and this file unix.el, are distributed in the hope
;; that they will be useful, but WITHOUT ANY WARRANTY.  No author or
;; distributor accepts responsibility to anyone for the consequences of
;; using them or for whether they serve any particular purpose or work at
;; all, unless he says so in writing.  Refer to the GNU Emacs General
;; Public License for full details.

;; Everyone is granted permission to copy, modify and redistribute GNU
;; Emacs and unix.el, but only under the conditions described in the
;; GNU Emacs General Public License.  A copy of this license is supposed
;; to have been given to you along with GNU Emacs so you can know your
;; rights and responsibilities.  It should be in a file named COPYING.
;; Among other things, the copyright notice and this notice must be
;; preserved on all copies.

(autoload 'compile1 "compile")

(defun lint (buffer)
  "Run lint(1) on specified buffer and collect output in a buffer.
While lint runs asynchronously, you can use the \\[next-error] command
to find the text that lint gripes refer to."
  (interactive "bbuffer to lint ")
  (save-excursion
    (switch-to-buffer buffer t)
    (save-buffer buffer)
    (compile1 (concat "lint -abchx " buffer-file-name)
	      "No more lint gripes" "lint")))

(defun cindent (buffer)
  "Reformat the specified BUFFER using the Unix indent(1) program.
Selects the specified buffer, and saves it to disk, displays new version.
M-x revert-buffer and M-x undo work as expected. User may opt not to save
the newly indented buffer."
  (interactive "bbuffer to indent ")
  (switch-to-buffer buffer)
  (let ((auto-save-file-name (make-auto-save-file-name))
	(opoint (point)) )
    (save-buffer)
    (shell-command  (concat "indent -l80 -bl -bc -v " buffer-file-name
			    " " auto-save-file-name) nil)
    (if (file-exists-p auto-save-file-name)
	(progn
	  (erase-buffer)
	  (insert-file auto-save-file-name)
	  (goto-char (min opoint (point-max))))
      (error "indent failed to produce the output file"))))

(defun diff (buf &optional nocontext) 
"Take the diff(1) of a BUFFER and its oldest backup file. With prefix
arg, (or optional flag if noninteractive) does an normal non-context
diff. This option is required for \\[show-diff]."
  (interactive "bBuffer: ")
  (switch-to-buffer buf)
  (let*
      ((file-base-name (file-name-nondirectory buffer-file-name))
       (back-list
	 (file-name-all-completions file-base-name default-directory))
       (back-name (oldest-file back-list)))
    (if (interactive-p)
	(setq nocontext current-prefix-arg))
    (if (string-match back-name file-base-name)
	(message "No older backup of %s found." file-base-name)
      (compile1 (format "diff %s %s %s"
			(if nocontext "-r" "-c")
			back-name file-base-name)
		"Use show-diff to move to diffs"
		"diff"))))

(defun oldest-file (list)
  "Return the oldest file, from the LIST of files."
  (let ((oldest (car list)))
    (if list (setq list (cdr list)))
    (while list
      (if (file-newer-than-file-p oldest (car list))
	  (setq oldest (car list)))
      (setq list (cdr list)))
    oldest))

(defun grep (command)
  "Run grep, with user-specified args, and collect output in a buffer.
While grep runs asynchronously, you can use the \\[next-error] command
to find the text that grep hits refer to."
  (interactive (list (read-input "Run grep (with args): "
				 (concat (symbol-around-point) " "
					 (other-possibly-interesting-files)))))
  (compile1 (concat "grep -n " command " /dev/null")
	    "No more grep hits" "grep"))

(defun gid (command)
  "Run gid, with user-specified args, and collect output in a buffer.
While gid runs asynchronously, you can use the \\[next-error] command
to find the text that gid hits refer to.  Gid is Greg Mcgary's
pre-digested-grep program, like ctags, but for grep."
  (interactive (list (read-input "Run gid (with args): "
				 (symbol-around-point))))
  (compile1 (concat "gid " command)
	    "No more gid hits" "gid"))

(defun other-possibly-interesting-files ()
  "Return a sh-regexp for other files that may be of intrest for
the purpose of grep-ing"
  (if (equal major-mode 'c-mode)
      "*.h *.c"				;for .h and .c files
      (concat "*" (and buffer-file-name
		       (string-match "\.[^.]+$" buffer-file-name)
		       (substring buffer-file-name
				  (match-beginning 0) (match-end 0))))))

(defun word-around-point ()
  "Return the word around the point as a string."
  (save-excursion
    (let (beg)
      (if (not (looking-at "\\<"))
	  (forward-word -1))
      (setq beg (point))
      (forward-word 1)
      (buffer-substring beg (point)))))

(defun symbol-around-point ()
  "Return the symbol around the point as a string."
  (save-excursion
    (if (not (looking-at "\\s_\\|\\sw")) ; if not in a symbol
	(re-search-backward "\\s_\\|\\sw" nil t)) ; go into prev. one
    (buffer-substring
      (progn (forward-sexp 1) (point))
      (progn (backward-sexp 1) (point)))))


Wolfgang Rupprecht	ARPA:  wolfgang@mgm.mit.edu (IP 18.82.0.114)
Freelance Consultant	UUCP:  mit-eddie!mgm.mit.edu!wolfgang
Boston, Ma.		VOICE: Hey_Wolfgang!_(617)_267-4365

liberte@uiucdcsb.cs.uiuc.edu (01/25/88)

/* Written 11:00 pm  Jan 21, 1988 by Ram-Ashwin@cs.yale.edu in uiucdcsb:comp.emacs */
Alternatively, a next-difference command for compare-w.el would be useful
too, although I think the diff interface would be nice in its own right.
/* End of text from uiucdcsb:comp.emacs */

I extended compare-w.el with this next-difference command and added
a two-window-command.  These are the same as I posted last summer.



Dan LaLiberte
liberte@a.cs.uiuc.edu
uiucdcs!liberte

;; Two window commands: compare-windows, two-window-command.
;; This is a modified version of compare-w.el
;; Copyright (C) 1986 Free Software Foundation, Inc.

;; This file is part of GNU Emacs.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY.  No author or distributor
;; accepts responsibility to anyone for the consequences of using it
;; or for whether it serves any particular purpose or works at all,
;; unless he says so in writing.  Refer to the GNU Emacs General Public
;; License for full details.

;; Everyone is granted permission to copy, modify and redistribute
;; GNU Emacs, but only under the conditions described in the
;; GNU Emacs General Public License.   A copy of this license is
;; supposed to have been given to you along with GNU Emacs so you
;; can know your rights and responsibilities.  It should be in a
;; file named COPYING.  Among other things, the copyright notice
;; and this notice must be preserved on all copies.

(defvar cw-ignore-whitespace nil
  "*Set to non-nil if you wish compare-windws to ignore all whitespace.")

(defvar cw-find-match-string-size 20
  "*The length of string to match in compare-window-find-match")
(defvar cw-find-match-distance 5
  "*The number of lines forward in which to search for a find-matchy point.")

(defvar cw-bounce-cursor t
  "*Set to nil to avoid point bouncing with compare-window")

(defvar bounce-cursor-time 1
  "*Number of seconds to sit at bounce point")


(defun compare-windows ()
  "Compare text in current window with text in next window.
Compares the text starting at point in each window,
moving over text in each one as far as they match."
  (interactive)
  (cw-find-match) ; first recover from initial difference

  (let ((opoint (point))
	p1 p2 maxp1 maxp2 b1 b2 w2
	success size done s1 s2)

    (setq p1 (point)
	  b1 (current-buffer))
    (setq w2 (next-window (selected-window)))
    (if (eq w2 (selected-window))
	(error "No other window."))
    (setq p2 (window-point w2)
	  b2 (window-buffer w2))
    (setq maxp1 (point-max))
    (save-excursion
     (set-buffer b2)
     (setq maxp2 (point-max)))

    (setq done nil)
    (while (not done)
    ;; Try advancing the pointers comparing 1024 chars at a time.
    ;; When that fails, divide by 2 and so on.
    (setq size 1024)
    (while (> size 0)
      (setq success t)
      (while success
	(setq size (min size (- maxp1 p1) (- maxp2 p2)))
	(setq s1 (buffer-substring p1 (+ size p1)))
	(save-excursion
	 (set-buffer b2)
	 (goto-char p2)
	 (setq success (search-forward s1 (+ p2 size) t)))
	(setq success (and (> size 0) success))
	(if success
	      (setq p1 (+ p1 size)
		    p2 (+ p2 size)))
	)
      ; no success - 
      (setq size (lsh size -1))  ; divide by two
      )
    ; found a difference (or eob) but is it significant?
;    (message "found a difference")

    (if (and cw-ignore-whitespace (not (eobp)))
	(let ((c2 (save-excursion
		    (set-buffer b2)
		    (goto-char p2)
		    (skip-chars-forward " \t\n\f\r")
		    (setq p2 (point))
		    (following-char)))
	      (c1 (progn
		    (goto-char p1)
		    (skip-chars-forward " \t\n\f\r")
		    (setq p1 (point))
		    (following-char))))
	  (setq done (not (char-equal c1 c2)))
;	  (message "c1=%c c2=%c" c1 c2)
	  )
      ; \n and \r are the same
      (while (and selective-display
		  (let ((c1 (progn
			      (goto-char p1)
			      (following-char)))
			(c2 (save-excursion
			      (set-buffer b2)
			      (goto-char p2)
			      (following-char))))
		    (and (or (char-equal c1 ?\n) (char-equal c2 ?\r))
			 (or (char-equal c2 ?\n) (char-equal c1 ?\r)))))
	(setq p1 (1+ p1))
	(setq p2 (1+ p2))
	)

      (setq done t))

    ) ; while
	      
    ; finish up
    (goto-char p1)
    (set-window-point w2 p2)
    (save-window-excursion
      (select-window w2)
;      (goto-char p2)
      (if cw-bounce-cursor (sit-for bounce-cursor-time)))
      
    (if (= (point) opoint)
	(ding)) ; nothing new found
    ))


(defun cw-find-match ()

  "Find the next common substring between two windows starting at
point in each window.  The substring to be found is the smaller of the
remainder of the line (or up to first whitespace if
cw-ignore-whitespace) and cw-find-match-string-size characters past point.
The maximum distance to search is cw-find-match-distance."

  (interactive)
  (let ((opoint (point))
	p1 p2
	maxp1 maxp2 b1 b2 w2 s1 s2 size success)
    (setq w2 (next-window (selected-window)))
    (if cw-ignore-whitespace
 	(skip-chars-forward " \t\n\f\r"))
    (setq p1 (point)
	  b1 (current-buffer))
    (if (eq w2 (selected-window))
 	(error "No other window."))
    (setq p2 (window-point w2)
	  b2 (window-buffer w2))
    (setq maxp1 (point-max))
    (save-excursion
      (set-buffer b2)
      (if cw-ignore-whitespace
	  (skip-chars-forward " \t\n\f\r"))
      (setq p2 (point))
      (setq maxp2 (point-max)))

    ; search for buffer 1 substring in buffer 2
    (save-excursion
      (set-buffer b1)
      (setq size (min cw-find-match-string-size (- maxp1 p1) (- maxp2 p2)
		      (- (save-excursion
			   (if cw-ignore-whitespace
			       (if (re-search-forward "[ \t\n\f\r]" maxp1 t)
				   (backward-char 1)
				 (end-of-line))
			     (end-of-line))
			   (point))
			 p1)))

      (setq s1 (buffer-substring p1 (+ size p1)))
;      (message "search 1 for \"%s\"" s1) (sit-for 1)
      (set-buffer b2)
      (goto-char p2)
      (setq success
	    (search-forward
	     s1
	     (save-excursion  ; limit search distance
	       (next-line cw-find-match-distance)
	       (point))
	     t))
      (if success
	  (setq p2 (- (point) size))) ; find beginnning of match
      )

    (if success
	(set-window-point w2 p2)

      ; else search for buffer 2 string in buffer 1
;      (message "search failed") (sit-for 1)
      (save-excursion
	(set-buffer b2)
	(setq size (min cw-find-match-string-size (- maxp1 p1) (- maxp2 p2)
			(- (save-excursion
			     (goto-char p2)
			     (if cw-ignore-whitespace
				 (if (re-search-forward "[ \t\n\f\r]" maxp2 t)
				     (backward-char 1)
				   (end-of-line))
			       (end-of-line))
			     (point))
			   p2)))
	(setq s2 (buffer-substring p2 (+ size p2)))
;	(message "search 2 for \"%s\"" s2) (sit-for 1)
	(set-buffer b1)
	(goto-char p1)
	(setq success
	      (search-forward
	       s2
	       (save-excursion
		 (next-line cw-find-match-distance)
		 (point))
	       t))
	(if success
	    (setq p1 (- (point) size)))
	))

    (if success
	(progn
	    (goto-char p1)
	    (save-window-excursion
	      (select-window w2)
	      (goto-char p2)
	      (if cw-bounce-cursor (sit-for bounce-cursor-time))
	      ))
	(error "Can't find common text"))
    ))


(defun two-window-command (keys)
  "Execute the next command in two windows.  Any arguments will be reused."
  (interactive "kEnter command for two windows: ")
  (let ((command (key-binding keys))
	w1 w2)
    (setq w1 (selected-window))
    (if command
	(unwind-protect
	    (command-execute command t)   ; put it in the command history
	  (setq w2 (next-window (selected-window)))
	  (if (eq w2 (selected-window))
	      (error "No other window."))
	  (select-window w2)
	  (unwind-protect
	      (eval (car command-history)) ; any arguments given will apply
	    (sit-for bounce-cursor-time)
	    (select-window w1)
	    ))))
  )
	 

deg@druhi.ATT.COM (GillespieD) (01/26/88)

In article <21729@yale-celray.yale.UUCP>, Ram-Ashwin@cs.yale.edu (Ashwin Ram) writes:
> 
> Is there a GNU Emacs interface to 'diff' that works sort of like 'grep'?


Gosling's EMACS contained a macro package called 'srccom' which
did this.  I'm not sure if it is available with GNU.

		Don Gillespie
		druhi!deg