]> code.delx.au - gnu-emacs/blobdiff - lisp/diff.el
Add a provide statement.
[gnu-emacs] / lisp / diff.el
index dab3c7ebff33c5d3f68376eacfa33129081577c3..c985b66036e605b9ea7e57a07520909543e27d97 100644 (file)
 
 ;;; Code:
 
-(require 'compile)
-
 (defgroup diff nil
   "Comparing files with `diff'."
   :group 'tools)
 
 ;;;###autoload
 (defcustom diff-switches "-c"
-  "*A string or list of strings specifying switches to be be passed to diff."
+  "*A string or list of strings specifying switches to be passed to diff."
   :type '(choice string (repeat string))
   :group 'diff)
 
   :type 'string
   :group 'diff)
 
-(defvar diff-regexp-alist
-  '(
-    ;; -u format: @@ -OLDSTART,OLDEND +NEWSTART,NEWEND @@
-    ("^@@ -\\([0-9]+\\),[0-9]+ \\+\\([0-9]+\\),[0-9]+ @@$" 1 2)
-
-    ;; -c format: *** OLDSTART,OLDEND ****
-    ("^\\*\\*\\* \\([0-9]+\\),[0-9]+ \\*\\*\\*\\*$" 1 nil)
-    ;;            --- NEWSTART,NEWEND ----
-    ("^--- \\([0-9]+\\),[0-9]+ ----$" nil 1)
-
-    ;; plain diff format: OLDSTART[,OLDEND]{a,d,c}NEWSTART[,NEWEND]
-    ("^\\([0-9]+\\)\\(,[0-9]+\\)?[adc]\\([0-9]+\\)\\(,[0-9]+\\)?$" 1 3)
-
-    ;; -e (ed) format: OLDSTART[,OLDEND]{a,d,c}
-    ("^\\([0-9]+\\)\\(,[0-9]+\\)?[adc]$" 1)
-
-    ;; -f format: {a,d,c}OLDSTART[ OLDEND]
-    ;; -n format: {a,d,c}OLDSTART LINES-CHANGED
-    ("^[adc]\\([0-9]+\\)\\( [0-9]+\\)?$" 1)
-    )
-  "Alist of regular expressions to match difference sections in \\[diff] output.
-Each element has the form (REGEXP OLD-IDX NEW-IDX).
-Any text that REGEXP matches identifies one difference hunk
-or the header of a hunk.
-
-The OLD-IDX'th subexpression of REGEXP gives the line number
-in the old file, and NEW-IDX'th subexpression gives the line number
-in the new file.  If OLD-IDX or NEW-IDX
-is nil, REGEXP matches only half a hunk.")
-
-(defvar diff-old-file nil
-  "This is the old file name in the comparison in this buffer.")
-(defvar diff-new-file nil
-  "This is the new file name in the comparison in this buffer.")
 (defvar diff-old-temp-file nil
   "This is the name of a temp file to be deleted after diff finishes.")
 (defvar diff-new-temp-file nil
   "This is the name of a temp file to be deleted after diff finishes.")
 
-;; See compilation-parse-errors-function (compile.el).
-(defun diff-parse-differences (limit-search find-at-least)
-  (setq compilation-error-list nil)
-  (message "Parsing differences...")
-
-  ;; Don't reparse diffs already seen at last parse.
-  (if compilation-parsing-end (goto-char compilation-parsing-end))
-
-  ;; Construct in REGEXP a regexp composed of all those in dired-regexp-alist.
-  (let ((regexp (mapconcat (lambda (elt)
-                            (concat "\\(" (car elt) "\\)"))
-                          diff-regexp-alist
-                          "\\|"))
-       ;; (GROUP-IDX OLD-IDX NEW-IDX)
-       (groups (let ((subexpr 1))
-                 (mapcar (lambda (elt)
-                           (prog1
-                               (cons subexpr
-                                     (mapcar (lambda (n)
-                                               (and n
-                                                    (+ subexpr n)))
-                                             (cdr elt)))
-                             (setq subexpr (+ subexpr 1
-                                              (count-regexp-groupings
-                                               (car elt))))))
-                         diff-regexp-alist)))
-
-       (new-error
-        (function (lambda (file subexpr)
-                    (setq compilation-error-list
-                          (cons
-                           (list (save-excursion
-                                   ;; Report location of message
-                                   ;; at beginning of line.
-                                   (goto-char
-                                    (match-beginning subexpr))
-                                   (beginning-of-line)
-                                   (point-marker))
-                                 ;; Report location of corresponding text.
-                                 (list file nil)
-                                 (string-to-int
-                                  (buffer-substring
-                                   (match-beginning subexpr)
-                                   (match-end subexpr)))
-                                 nil)
-                           compilation-error-list)))))
-
-       (found-desired nil)
-       (num-loci-found 0)
-       g)
-
-    (while (and (not found-desired)
-               ;; We don't just pass LIMIT-SEARCH to re-search-forward
-               ;; because we want to find matches containing LIMIT-SEARCH
-               ;; but which extend past it.
-               (re-search-forward regexp nil t))
-
-      ;; Find which individual regexp matched.
-      (setq g groups)
-      (while (and g (null (match-beginning (car (car g)))))
-       (setq g (cdr g)))
-      (setq g (car g))
-
-      (if (nth 1 g)                    ;OLD-IDX
-         (funcall new-error diff-old-file (nth 1 g)))
-      (if (nth 2 g)                    ;NEW-IDX
-         (funcall new-error diff-new-file (nth 2 g)))
-
-      (setq num-loci-found (1+ num-loci-found))
-      (if (or (and find-at-least
-                  (>= num-loci-found find-at-least))
-             (and limit-search (>= (point) limit-search)))
-             ;; We have found as many new loci as the user wants,
-             ;; or the user wanted a specific diff, and we're past it.
-         (setq found-desired t)))
-    (set-marker compilation-parsing-end
-               (if found-desired (point)
-                 ;; Set to point-max, not point, so we don't perpetually
-                 ;; parse the last bit of text when it isn't a diff header.
-                 (point-max)))
-    (message "Parsing differences...done"))
-  (setq compilation-error-list (nreverse compilation-error-list)))
-
-(defun diff-process-setup ()
-  "Set up \`compilation-exit-message-function' for \`diff'."
-  ;; Avoid frightening people with "abnormally terminated"
-  ;; if diff finds differences.
-  (set (make-local-variable 'compilation-exit-message-function)
-       (lambda (status code msg)
-        (cond ((not (eq status 'exit))
-               (cons msg code))
-              ((zerop code)
-               '("finished (no differences)\n" . "no differences"))
-              ((= code 1)
-               '("finished\n" . "differences found"))
-              (t
-               (cons msg code))))))
-
 ;; prompt if prefix arg present
 (defun diff-switches ()
   (if current-prefix-arg
@@ -193,6 +59,17 @@ is nil, REGEXP matches only half a hunk.")
                       diff-switches
                     (mapconcat 'identity diff-switches " ")))))
 
+(defun diff-sentinel (code)
+  "Code run when the diff process exits.
+CODE is the exit code of the process.  It should be 0 iff no diffs were found."
+  (if diff-old-temp-file (delete-file diff-old-temp-file))
+  (if diff-new-temp-file (delete-file diff-new-temp-file))
+  (save-excursion
+    (goto-char (point-max))
+    (insert (format "\nDiff finished%s.  %s\n"
+                   (if (equal 0 code) " (no differences)" "")
+                   (current-time-string)))))
+
 ;;;###autoload
 (defun diff (old new &optional switches no-async)
   "Find and display the differences between OLD and NEW files.
@@ -220,51 +97,50 @@ With prefix arg, prompt for diff switches."
      (list oldf newf (diff-switches))))
   (setq new (expand-file-name new)
        old (expand-file-name old))
-  (let ((old-alt (file-local-copy old))
+  (or switches (setq switches diff-switches)) ; If not specified, use default.
+  (let* ((old-alt (file-local-copy old))
        (new-alt (file-local-copy new))
-       buf)
+        (command
+         (mapconcat 'identity
+                    `(,diff-command
+                      ;; Use explicitly specified switches
+                      ,@(if (listp switches) switches (list switches))
+                      ,@(if (or old-alt new-alt)
+                            (list "-L" old "-L" new))
+                      ,(shell-quote-argument (or old-alt old))
+                      ,(shell-quote-argument (or new-alt new)))
+                    " "))
+        (buf (get-buffer-create "*Diff*"))
+        (thisdir default-directory)
+        proc)
     (save-excursion
-       (let ((compilation-process-setup-function 'diff-process-setup)
-             (command
-              (mapconcat 'identity
-                         `(,diff-command
-                           ;; Use explicitly specified switches
-                           ,@(if switches
-                                 (if (listp switches)
-                                     switches (list switches))
-                               ;; If not specified, use default.
-                               (if (listp diff-switches)
-                                   diff-switches
-                                 (list diff-switches)))
-                           ,@(if (or old-alt new-alt)
-                                 (list "-L" old "-L" new))
-                           ,(shell-quote-argument (or old-alt old))
-                           ,(shell-quote-argument (or new-alt new)))
-                         " ")))
-         (setq buf
-               (compile-internal command
-                                 "No more differences" "Diff"
-                                 'diff-parse-differences
-                                 nil nil nil nil nil nil no-async))
-         (set-buffer buf)
-         (set (make-local-variable 'revert-buffer-function)
-              `(lambda (ignore-auto noconfirm)
-                 (diff ',old ',new ',switches ',no-async)))
-         (set (make-local-variable 'diff-old-file) old)
-         (set (make-local-variable 'diff-new-file) new)
-         (set (make-local-variable 'diff-old-temp-file) old-alt)
-         (set (make-local-variable 'diff-new-temp-file) new-alt)
-         (set (make-local-variable 'compilation-finish-function)
-              (function (lambda (buff msg)
-                          (if diff-old-temp-file
-                              (delete-file diff-old-temp-file))
-                          (if diff-new-temp-file
-                              (delete-file diff-new-temp-file)))))
-         ;; When async processes aren't available, the compilation finish
-         ;; function doesn't get chance to run.  Invoke it by hand.
-         (or (fboundp 'start-process)
-             (funcall compilation-finish-function nil nil))
-         buf))))
+      (display-buffer buf)
+      (set-buffer buf)
+      (setq buffer-read-only nil)
+      (buffer-disable-undo (current-buffer))
+      (erase-buffer)
+      (buffer-enable-undo (current-buffer))
+      (diff-mode)
+      (set (make-local-variable 'revert-buffer-function)
+          `(lambda (ignore-auto noconfirm)
+             (diff ',old ',new ',switches ',no-async)))
+      (set (make-local-variable 'diff-old-temp-file) old-alt)
+      (set (make-local-variable 'diff-new-temp-file) new-alt)
+      (setq default-directory thisdir)
+      (insert command "\n")
+      (if (and (not no-async) (fboundp 'start-process))
+         (progn
+           (setq proc (start-process "Diff" buf shell-file-name
+                                     shell-command-switch command))
+           (set-process-sentinel
+            proc (lambda (proc msg)
+                   (with-current-buffer (process-buffer proc)
+                     (diff-sentinel (process-exit-status proc))))))
+       ;; Async processes aren't available.
+       (diff-sentinel
+        (call-process shell-file-name nil buf nil
+                      shell-command-switch command))))
+    buf))
 
 ;;;###autoload
 (defun diff-backup (file &optional switches)