]> code.delx.au - gnu-emacs/blobdiff - lisp/diff-mode.el
New file, a portion of emacs-xtra.texi.
[gnu-emacs] / lisp / diff-mode.el
index b9c9e338388012b939f30726718cbde02b6c12ae..cc89aad6ca31f5144fbb28a2d97322886e0e1b17 100644 (file)
@@ -1,9 +1,9 @@
 ;;; diff-mode.el --- a mode for viewing/editing context diffs
 
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
-;; Author: Stefan Monnier <monnier@cs.yale.edu>
+;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: convenience patch diff
 
 ;; This file is part of GNU Emacs.
@@ -20,8 +20,8 @@
 
 ;; 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, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -55,6 +55,8 @@
 
 (eval-when-compile (require 'cl))
 
+(defvar add-log-buffer-file-name-function)
+
 
 (defgroup diff-mode ()
   "Major mode for viewing/editing diffs."
@@ -116,7 +118,8 @@ when editing big diffs)."
     ("\C-m" . diff-goto-source)
     ([mouse-2] . diff-goto-source)
     ;; From XEmacs' diff-mode.
-    ("W" . widen)
+;; Standard M-w is useful, so don't change M-W.
+;;    ("W" . widen)
     ;;("." . diff-goto-source)         ;display-buffer
     ;;("f" . diff-goto-source)         ;find-file
     ("o" . diff-goto-source)           ;other-window
@@ -125,14 +128,14 @@ when editing big diffs)."
     ;;("h" . diff-show-header)
     ;;("j" . diff-show-difference)     ;jump to Nth diff
     ;;("q" . diff-quit)
-    (" " . scroll-up)
-    ("\177" . scroll-down)
-    ;; Our very own bindings.
-    ("A" . diff-ediff-patch)
-    ("r" . diff-restrict-view)
-    ("R" . diff-reverse-direction)
-    ("U" . diff-context->unified)
-    ("C" . diff-unified->context)
+;; Not useful if you have to metafy them.
+;;    (" " . scroll-up)
+;;    ("\177" . scroll-down)
+;; Standard M-a is useful, so don't change M-A.
+;;    ("A" . diff-ediff-patch)
+;; Standard M-r is useful, so don't change M-r or M-R.
+;;    ("r" . diff-restrict-view)
+;;    ("R" . diff-reverse-direction)
     ("q" . quit-window))
   "Basic keymap for `diff-mode', bound to various prefix keys.")
 
@@ -141,10 +144,14 @@ when editing big diffs)."
     ;; From compilation-minor-mode.
     ("\C-c\C-c" . diff-goto-source)
     ;; Misc operations.
-    ("\C-c\C-r" . diff-refine-hunk)
-    ("\C-c\C-s" . diff-split-hunk)
     ("\C-c\C-a" . diff-apply-hunk)
+    ("\C-c\C-e" . diff-ediff-patch)
+    ("\C-c\C-n" . diff-restrict-view)
+    ("\C-c\C-r" . diff-reverse-direction)
+    ("\C-c\C-s" . diff-split-hunk)
     ("\C-c\C-t" . diff-test-hunk)
+    ("\C-c\C-u" . diff-context->unified)
+    ("\C-c\C-w" . diff-refine-hunk)
     ("\C-c\C-f" . next-error-follow-minor-mode))
   "Keymap for `diff-mode'.  See also `diff-mode-shared-map'.")
 
@@ -197,7 +204,7 @@ when editing big diffs)."
     (((class color) (min-colors 88) (background dark))
      :background "grey60" :weight bold)
     (((class color) (background light))
-     :foreground "yellow" :weight bold)
+     :foreground "green" :weight bold)
     (((class color) (background dark))
      :foreground "cyan" :weight bold)
     (t :weight bold))                  ; :height 1.3
@@ -250,8 +257,29 @@ when editing big diffs)."
 (put 'diff-changed-face 'face-alias 'diff-changed)
 (defvar diff-changed-face 'diff-changed)
 
+(defface diff-indicator-removed
+  '((t :inherit diff-removed))
+  "`diff-mode' face used to highlight indicator of removed lines (-, <)."
+  :group 'diff-mode
+  :version "22.1")
+(defvar diff-indicator-removed-face 'diff-indicator-removed)
+
+(defface diff-indicator-added
+  '((t :inherit diff-added))
+  "`diff-mode' face used to highlight indicator of added lines (+, >)."
+  :group 'diff-mode
+  :version "22.1")
+(defvar diff-indicator-added-face 'diff-indicator-added)
+
+(defface diff-indicator-changed
+  '((t :inherit diff-changed))
+  "`diff-mode' face used to highlight indicator of changed lines."
+  :group 'diff-mode
+  :version "22.1")
+(defvar diff-indicator-changed-face 'diff-indicator-changed)
+
 (defface diff-function
-  '((t :inherit diff-context))
+  '((t :inherit diff-header))
   "`diff-mode' face used to highlight function names produced by \"diff -p\"."
   :group 'diff-mode)
 ;; backward-compatibility alias
@@ -259,7 +287,7 @@ when editing big diffs)."
 (defvar diff-function-face 'diff-function)
 
 (defface diff-context
-  '((t :inherit shadow))
+  '((((class color grayscale) (min-colors 88)) :inherit shadow))
   "`diff-mode' face used to highlight context and other side-information."
   :group 'diff-mode)
 ;; backward-compatibility alias
@@ -298,24 +326,29 @@ when editing big diffs)."
 
 
 (defvar diff-font-lock-keywords
-  `(("^\\(@@ -[0-9,]+ \\+[0-9,]+ @@\\)\\(.*\\)$" ;unified
-     (1 diff-hunk-header-face)
-     (2 diff-function-face))
-    ("^--- .+ ----$" . diff-hunk-header-face) ;context
-    ("^\\(\\*\\{15\\}\\)\\(.*\\)$"     ;context
-     (1 diff-hunk-header-face)
-     (2 diff-function-face))
+  `(("^\\(@@ -[0-9,]+ \\+[0-9,]+ @@\\)\\(.*\\)$"          ;unified
+     (1 diff-hunk-header-face) (2 diff-function-face))
+    ("^\\(\\*\\{15\\}\\)\\(.*\\)$"                        ;context
+     (1 diff-hunk-header-face) (2 diff-function-face))
     ("^\\*\\*\\* .+ \\*\\*\\*\\*". diff-hunk-header-face) ;context
+    ("^--- .+ ----$"             . diff-hunk-header-face) ;context
+    ("^[0-9,]+[acd][0-9,]+$"     . diff-hunk-header-face) ;normal
+    ("^---$"                     . diff-hunk-header-face) ;normal
     ("^\\(---\\|\\+\\+\\+\\|\\*\\*\\*\\) \\(\\S-+\\)\\(.*[^*-]\\)?\n"
      (0 diff-header-face) (2 diff-file-header-face prepend))
-    ("^[0-9,]+[acd][0-9,]+$" . diff-hunk-header-face)
-    ("^!.*\n" (0 diff-changed-face))
-    ("^[+>].*\n" (0 diff-added-face))
-    ("^[-<].*\n" (0 diff-removed-face))
-    ("^Index: \\(.+\\).*\n" (0 diff-header-face) (1 diff-index-face prepend))
+    ("^\\([-<]\\)\\(.*\n\\)"
+     (1 diff-indicator-removed-face) (2 diff-removed-face))
+    ("^\\([+>]\\)\\(.*\n\\)"
+     (1 diff-indicator-added-face) (2 diff-added-face))
+    ("^\\(!\\)\\(.*\n\\)"
+     (1 diff-indicator-changed-face) (2 diff-changed-face))
+    ("^Index: \\(.+\\).*\n"
+     (0 diff-header-face) (1 diff-index-face prepend))
     ("^Only in .*\n" . diff-nonexistent-face)
-    ("^#.*" . font-lock-string-face)
-    ("^[^-=+*!<>].*\n" (0 diff-context-face))))
+    ("^\\(#\\)\\(.*\\)"
+     (1 font-lock-comment-delimiter-face)
+     (2 font-lock-comment-face))
+    ("^[^-=+*!<>#].*\n" (0 diff-context-face))))
 
 (defconst diff-font-lock-defaults
   '(diff-font-lock-keywords t nil nil nil (font-lock-multiline . nil)))
@@ -683,77 +716,80 @@ else cover the whole bufer."
                            (delete-region last-pt (point))
                            (setq delete nil)))))))))))))))
 
-(defun diff-context->unified (start end)
+(defun diff-context->unified (start end &optional to-context)
   "Convert context diffs to unified diffs.
-START and END are either taken from the region (if a prefix arg is given) or
-else cover the whole bufer."
-  (interactive (if current-prefix-arg
-                  (list (mark) (point))
-                (list (point-min) (point-max))))
-  (unless (markerp end) (setq end (copy-marker end)))
-  (let (;;(diff-inhibit-after-change t)
-       (inhibit-read-only t))
-    (save-excursion
-      (goto-char start)
-      (while (and (re-search-forward "^\\(\\(\\*\\*\\*\\) .+\n\\(---\\) .+\\|\\*\\{15\\}.*\n\\*\\*\\* \\([0-9]+\\),\\(-?[0-9]+\\) \\*\\*\\*\\*\\)$" nil t)
-                 (< (point) end))
-       (combine-after-change-calls
-         (if (match-beginning 2)
-             ;; we matched a file header
-             (progn
-               ;; use reverse order to make sure the indices are kept valid
-               (replace-match "+++" t t nil 3)
-               (replace-match "---" t t nil 2))
-           ;; we matched a hunk header
-           (let ((line1s (match-string 4))
-                 (line1e (match-string 5))
-                 (pt1 (match-beginning 0)))
-             (replace-match "")
-             (unless (re-search-forward
-                      "^--- \\([0-9]+\\),\\(-?[0-9]+\\) ----$" nil t)
-               (error "Can't find matching `--- n1,n2 ----' line"))
-             (let ((line2s (match-string 1))
-                   (line2e (match-string 2))
-                   (pt2 (progn
-                          (delete-region (progn (beginning-of-line) (point))
-                                         (progn (forward-line 1) (point)))
-                          (point-marker))))
-               (goto-char pt1)
-               (forward-line 1)
-               (while (< (point) pt2)
-                 (case (char-after)
-                   ((?! ?-) (delete-char 2) (insert "-") (forward-line 1))
-                   (?\s                ;merge with the other half of the chunk
-                    (let* ((endline2
-                            (save-excursion
-                              (goto-char pt2) (forward-line 1) (point)))
-                           (c (char-after pt2)))
-                      (case c
-                        ((?! ?+)
-                         (insert "+"
-                                 (prog1 (buffer-substring (+ pt2 2) endline2)
-                                   (delete-region pt2 endline2))))
-                        (?\s           ;FIXME: check consistency
-                         (delete-region pt2 endline2)
-                         (delete-char 1)
-                         (forward-line 1))
-                        (?\\ (forward-line 1))
-                        (t (delete-char 1) (forward-line 1)))))
-                   (t (forward-line 1))))
-               (while (looking-at "[+! ] ")
-                 (if (/= (char-after) ?!) (forward-char 1)
-                   (delete-char 1) (insert "+"))
-                 (delete-char 1) (forward-line 1))
-               (save-excursion
+START and END are either taken from the region
+\(when it is highlighted) or else cover the whole buffer.
+With a prefix argument, convert unified format to context format."
+  (interactive (if (and transient-mark-mode mark-active)
+                  (list (mark) (point) current-prefix-arg)
+                (list (point-min) (point-max) current-prefix-arg)))
+  (if to-context
+      (diff-unified->context start end)
+    (unless (markerp end) (setq end (copy-marker end)))
+    (let ( ;;(diff-inhibit-after-change t)
+         (inhibit-read-only t))
+      (save-excursion
+       (goto-char start)
+       (while (and (re-search-forward "^\\(\\(\\*\\*\\*\\) .+\n\\(---\\) .+\\|\\*\\{15\\}.*\n\\*\\*\\* \\([0-9]+\\),\\(-?[0-9]+\\) \\*\\*\\*\\*\\)$" nil t)
+                   (< (point) end))
+         (combine-after-change-calls
+           (if (match-beginning 2)
+               ;; we matched a file header
+               (progn
+                 ;; use reverse order to make sure the indices are kept valid
+                 (replace-match "+++" t t nil 3)
+                 (replace-match "---" t t nil 2))
+             ;; we matched a hunk header
+             (let ((line1s (match-string 4))
+                   (line1e (match-string 5))
+                   (pt1 (match-beginning 0)))
+               (replace-match "")
+               (unless (re-search-forward
+                        "^--- \\([0-9]+\\),\\(-?[0-9]+\\) ----$" nil t)
+                 (error "Can't find matching `--- n1,n2 ----' line"))
+               (let ((line2s (match-string 1))
+                     (line2e (match-string 2))
+                     (pt2 (progn
+                            (delete-region (progn (beginning-of-line) (point))
+                                           (progn (forward-line 1) (point)))
+                            (point-marker))))
                  (goto-char pt1)
-                 (insert "@@ -" line1s ","
-                         (number-to-string (- (string-to-number line1e)
-                                              (string-to-number line1s)
-                                              -1))
-                         " +" line2s ","
-                         (number-to-string (- (string-to-number line2e)
-                                              (string-to-number line2s)
-                                              -1)) " @@"))))))))))
+                 (forward-line 1)
+                 (while (< (point) pt2)
+                   (case (char-after)
+                     ((?! ?-) (delete-char 2) (insert "-") (forward-line 1))
+                     (?\s     ;merge with the other half of the chunk
+                      (let* ((endline2
+                              (save-excursion
+                                (goto-char pt2) (forward-line 1) (point)))
+                             (c (char-after pt2)))
+                        (case c
+                          ((?! ?+)
+                           (insert "+"
+                                   (prog1 (buffer-substring (+ pt2 2) endline2)
+                                     (delete-region pt2 endline2))))
+                          (?\s         ;FIXME: check consistency
+                           (delete-region pt2 endline2)
+                           (delete-char 1)
+                           (forward-line 1))
+                          (?\\ (forward-line 1))
+                          (t (delete-char 1) (forward-line 1)))))
+                     (t (forward-line 1))))
+                 (while (looking-at "[+! ] ")
+                   (if (/= (char-after) ?!) (forward-char 1)
+                     (delete-char 1) (insert "+"))
+                   (delete-char 1) (forward-line 1))
+                 (save-excursion
+                   (goto-char pt1)
+                   (insert "@@ -" line1s ","
+                           (number-to-string (- (string-to-number line1e)
+                                                (string-to-number line1s)
+                                                -1))
+                           " +" line2s ","
+                           (number-to-string (- (string-to-number line2e)
+                                                (string-to-number line2s)
+                                                -1)) " @@")))))))))))
 
 (defun diff-reverse-direction (start end)
   "Reverse the direction of the diffs.
@@ -939,7 +975,7 @@ If you edit the buffer manually, diff-mode will try to update the hunk
 headers for you on-the-fly.
 
 You can also switch between context diff and unified diff with \\[diff-context->unified],
-or vice versa with \\[diff-unified->context] and you can also revert the direction of
+or vice versa with \\[diff-unified->context] and you can also reverse the direction of
 a diff with \\[diff-reverse-direction]."
   (set (make-local-variable 'font-lock-defaults) diff-font-lock-defaults)
   (set (make-local-variable 'outline-regexp) diff-outline-regexp)