]> git.eshelyaron.com Git - emacs.git/commitdiff
(diff-mode-map): Bind diff-apply-hunk.
authorStefan Monnier <monnier@iro.umontreal.ca>
Wed, 16 Aug 2000 19:56:10 +0000 (19:56 +0000)
committerStefan Monnier <monnier@iro.umontreal.ca>
Wed, 16 Aug 2000 19:56:10 +0000 (19:56 +0000)
(diff-find-source-location): New fun, extracted from diff-goto-source.
(diff-goto-source): Use it.
(diff-next-complex-hunk, diff-filter-lines): New function.
(diff-apply-hunk): New command.

lisp/diff-mode.el

index 8db4887beb83b5982045f7d9a0913ae52f89e821..1775a0165b355c25e6b4bb844f3c6e42d99ae397 100644 (file)
@@ -4,7 +4,7 @@
 
 ;; Author: Stefan Monnier <monnier@cs.yale.edu>
 ;; Keywords: patch diff
-;; Revision: $Id: diff-mode.el,v 1.7 2000/05/10 22:12:46 monnier Exp $
+;; Revision: $Id: diff-mode.el,v 1.8 2000/06/05 07:30:09 monnier Exp $
 
 ;; This file is part of GNU Emacs.
 
 
 ;; Bugs:
 
-;; - reverse doesn't work with normal diffs.
-;; - (nitpick) the mark is not always quite right in diff-goto-source.
+;; - Reverse doesn't work with normal diffs.
+;; - (nitpick) The mark is not always quite right in diff-goto-source.
+;; - diff-apply-hunk only works on unified diffs.
 
 ;; Todo:
 
-;; - spice up the minor-mode with font-lock support
-;; - improve narrowed-view support
-;; - improve the `compile' support (?)
-;; - recognize pcl-cvs' special string for `cvs-execute-single'
-;; - support for # comments in context->unified
-;; - diff-apply-hunk
-;; - do a fuzzy search in diff-goto-source
-;; - allow diff.el to use diff-mode
-;; - imenu support
-;; - handle `diff -b' output in context->unified
+;; - Add change-log support.
+;; - Spice up the minor-mode with font-lock support.
+;; - Improve narrowed-view support.
+;; - Improve the `compile' support (?).
+;; - Recognize pcl-cvs' special string for `cvs-execute-single'.
+;; - Support for # comments in context->unified.
+;; - Do a fuzzy search in diff-goto-source.
+;; - Allow diff.el to use diff-mode.
+;;   This mostly means ability to jump from half-hunk to half-hunk
+;;   in context (and normal) diffs and to jump to the corresponding
+;;   (i.e. new or old) file.
+;; - imenu support.
+;; - Handle `diff -b' output in context->unified.
 
 ;;; Code:
 
@@ -93,18 +97,18 @@ when editing big diffs)."
 ;;;; 
 
 (easy-mmode-defmap diff-mode-shared-map
-  '(;; from Pavel Machek's patch-mode
+  '(;; From Pavel Machek's patch-mode.
     ("n" . diff-hunk-next)
     ("N" . diff-file-next)
     ("p" . diff-hunk-prev)
     ("P" . diff-file-prev)
     ("k" . diff-hunk-kill)
     ("K" . diff-file-kill)
-    ;; from compilation-minor-mode
+    ;; From compilation-minor-mode.
     ("}" . diff-file-next)
     ("{" . diff-file-prev)
     ("\C-m" . diff-goto-source)
-    ;; from XEmacs' diff-mode
+    ;; From XEmacs' diff-mode.
     ("W" . widen)
     ;;("." . diff-goto-source)         ;display-buffer
     ;;("f" . diff-goto-source)         ;find-file
@@ -116,7 +120,7 @@ when editing big diffs)."
     ;;("q" . diff-quit)
     (" " . scroll-up)
     ("\177" . scroll-down)
-    ;; our very own bindings
+    ;; Our very own bindings.
     ("A" . diff-ediff-patch)
     ("r" . diff-restrict-view)
     ("R" . diff-reverse-direction)
@@ -126,8 +130,10 @@ when editing big diffs)."
 
 (easy-mmode-defmap diff-mode-map
   `(("\e" . ,diff-mode-shared-map)
-    ;; from compilation-minor-mode
-    ("\C-c\C-c" . diff-goto-source))
+    ;; From compilation-minor-mode.
+    ("\C-c\C-c" . diff-goto-source)
+    ;; Misc operations.
+    ("\C-cda" . diff-apply-hunk))
   "Keymap for `diff-mode'.  See also `diff-mode-shared-map'.")
 
 (easy-menu-define diff-mode-menu diff-mode-map
@@ -420,42 +426,51 @@ Non-nil OLD means that we want the old file."
              (cons (cons fs file) diff-remembered-files-alist))
         file)))))
 
+(defun diff-find-source-location (&optional other-file)
+  "Find out (FILE LINE SPAN)."
+  (save-excursion
+    (diff-beginning-of-hunk)
+    (let* ((old (if (not other-file) diff-jump-to-old-file-flag
+                 (not diff-jump-to-old-file-flag)))
+          ;; Find the location specification.
+          (loc (if (not (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?"))
+                   (error "Can't find the hunk header")
+                 (if old (match-string 1)
+                   (if (match-end 3) (match-string 3)
+                     (unless (re-search-forward "^--- \\([0-9,]+\\)" nil t)
+                       (error "Can't find the hunk separator"))
+                     (match-string 1)))))
+          ;; Extract the actual line number.
+          (lines (if (string-match "^\\([0-9]*\\),\\([0-9]*\\)" loc)
+                     (cons (string-to-number (match-string 1 loc))
+                           (string-to-number (match-string 2 loc)))
+                   (cons (string-to-number loc) nil)))
+          (file (diff-find-file-name old))
+          (line (car lines))
+          (span (if (or (null (cdr lines)) (< (cdr lines) 0)) 0
+                  ;; Bad hack.
+                  (if (< (cdr lines) line) (cdr lines)
+                    (- (cdr lines) line)))))
+      ;; Update the user preference if he so wished.
+      (when (> (prefix-numeric-value other-file) 8)
+       (setq diff-jump-to-old-file-flag old))
+      (if (null file) (error "Can't find the file")
+       (list file line span)))))
+
 (defun diff-goto-source (&optional other-file)
   "Jump to the corresponding source line.
 `diff-jump-to-old-file-flag' (or its opposite if the OTHER-FILE prefix arg
 is give) determines whether to jump to the old or the new file.
 If the prefix arg is bigger than 8 (for example with \\[universal-argument] \\[universal-argument])
-  then `diff-jump-to-old-file-flag' is also set, for the next invokations."
+  then `diff-jump-to-old-file-flag' is also set, for the next invocations."
   (interactive "P")
   (save-excursion
-    (let ((old (if (not other-file) diff-jump-to-old-file-flag
-                (not diff-jump-to-old-file-flag))))
-      (when (> (prefix-numeric-value other-file) 8)
-       (setq diff-jump-to-old-file-flag old))
-      (diff-beginning-of-hunk)
-      (let* ((loc (if (not (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?"))
-                     (error "Can't find the hunk header")
-                   (if old (match-string 1)
-                     (if (match-end 3) (match-string 3)
-                       (unless (re-search-forward "^--- \\([0-9,]+\\)" nil t)
-                         (error "Can't find the hunk separator"))
-                       (match-string 1)))))
-            (lines (if (string-match "^\\([0-9]*\\),\\([0-9]*\\)" loc)
-                       (cons (string-to-number (match-string 1 loc))
-                             (string-to-number (match-string 2 loc)))
-                     (cons (string-to-number loc) nil)))
-            (file (diff-find-file-name old)))
-       (unless file (error "Can't find the file"))
-       (pop-to-buffer (find-file-noselect file))
-       (let* ((line (car lines))
-              (span (if (or (null (cdr lines)) (< (cdr lines) 0)) 0
-                      (if (< (cdr lines) line) (cdr lines)
-                        (- (cdr lines) line)))))
-         (ignore-errors
-           (goto-line line)
-           (forward-line span)
-           (push-mark (point) t t)
-           (goto-line line)))))))
+    (let ((loc (diff-find-source-location other-file)))
+      (pop-to-buffer (find-file-noselect (car loc)))
+      (ignore-errors
+       (goto-line (+ (cadr loc) (caddr loc)))
+       (push-mark (point) t t)
+       (goto-line (cadr loc))))))
 
 
 (defun diff-ediff-patch ()
@@ -836,50 +851,76 @@ This mode runs `diff-mode-hook'.
              'diff-post-command-hook nil t)))
 
 
+;;;
+;;; Misc operations that have proved useful at some point.
+;;;
+
+(defun diff-next-complex-hunk ()
+  "Jump to the next \"complex\" hunk.
+\"Complex\" is approximated by \"the hunk changes the number of lines\".
+Only works for unified diffs."
+  (interactive)
+  (while
+      (and (re-search-forward "^@@ [-0-9]+,\\([0-9]+\\) [+0-9]+,\\([0-9]+\\) @@"
+                             nil t)
+          (equal (match-string 1) (match-string 2)))))
+
+
+(defun diff-filter-lines (char)
+  (goto-char (point-min))
+  (while (not (eobp))
+    (if (eq (char-after) char)
+       (delete-region (point) (progn (forward-line 1) (point)))
+      (delete-char 1)
+      (forward-line 1))))
+
+(defun diff-apply-hunk (&optional reverse)
+  "Apply the current hunk.
+With a prefix argument, REVERSE the hunk.
+FIXME: Only works for unified diffs."
+  (interactive "P")
+  (save-excursion
+    (let ((loc (diff-find-source-location nil)))
+      (diff-beginning-of-hunk)
+      (unless (looking-at diff-hunk-header-re) (error "Help! Mom!"))
+      (goto-char (1+ (match-end 0)))
+      ;; Extract the SRC and DEST strings.
+      (let ((text (buffer-substring (point) (progn (diff-end-of-hunk) (point))))
+           src dest)
+       (with-temp-buffer
+         (insert text)
+         (diff-filter-lines ?+)
+         (setq src (buffer-string))
+         (erase-buffer)
+         (insert text)
+         (diff-filter-lines ?-)
+         (setq dest (buffer-string)))
+       ;; Exchange the two strings if we're reversing the patch.
+       (if reverse (let ((tmp src)) (setq src dest) (setq dest tmp)))
+       ;; Look for SRC in the file.
+       (pop-to-buffer (find-file-noselect (car loc)))
+       (goto-line (cadr loc))
+       (let* ((pos (point))
+              (forw (and (search-forward src nil t)
+                         (match-beginning 0)))
+              (back (and (goto-char (+ pos (length src)))
+                         (search-backward src nil t)
+                         (match-beginning 0))))
+         ;; Choose the closest match.
+         (setq pos (if (and forw back)
+                       (if (> (- forw pos) (- pos back)) back forw)
+                     (or back forw)))
+         (unless pos (error "Can't find the text to patch"))
+         ;; Do it!
+         (goto-char pos)
+         (delete-char (length src))
+         (insert dest))))))
+      
+
 ;; provide the package
 (provide 'diff-mode)
 
-;;; Change Log:
-;; $Log: diff-mode.el,v $
-;; Revision 1.7  2000/05/10 22:12:46  monnier
-;; (diff-font-lock-keywords): Recognize comments.
-;; (diff-font-lock-defaults): Explicitly turn off multiline.
-;; (diff-end-of-hunk): Handle comments and fix end-of-buffer bug.
-;; (diff-ediff-patch): Fix call to ediff-patch-file.
-;; (diff-end-of-file, diff-reverse-direction, diff-fixup-modifs):
-;; Handle comments.
-;;
-;; Revision 1.6  2000/03/21 16:59:17  monnier
-;; (diff-mode-*-map): use `easy-mmode-defmap'.
-;; (diff-end-of-hunk): Return the end position for use in
-;; `easy-mmode-define-navigation'.
-;; (diff-recenter): Remove.
-;; (diff-(next|prev)-*): Rename `diff-*-(prev|next)' and defined in terms
-;; of `easy-mmode-define-navigation'.
-;; (diff-kill-*): Rename `diff-*-kill' (for consistency with the
-;; previous renaming) and fix to use new names.
-;; (diff-merge-strings): Use \n as separator: simpler, faster.
-;; (diff-mode): Use `define-derived-mode'.
-;;
-;; Revision 1.5  2000/02/07 02:01:07  monnier
-;; (diff-kill-junk): New interactive function.
-;; (diff-reverse-direction): Use delete-and-extract-region.
-;; (diff-post-command-hook): Restrict the area so that the hook also works
-;; outside of any diff hunk.  This is necessary for the minor-mode.
-;; (diff-mode): Use toggle-read-only and minor-mode-overriding-map-alist.
-;; (diff-minor-mode): Setup the hooks for header-hunk rewriting.
-;;
-;; Revision 1.4  1999/12/07 07:04:03  monnier
-;; * diff-mode.el (diff-mode-shared-map): fset'd and doc change.
-;; (diff-minor-mode, diff-minor-mode-prefix, diff-minor-mode-map):
-;; New code to support the minor mode version.
-;; (diff-recenter): New function.
-;; (diff-next-hunk, diff-next-file): Use it.
-;; (diff-remembered-files-alist): New var.
-;; (diff-merge-strings): New function.
-;; (diff-find-file-name): Make it smarter and use the user's input more.
-;; (diff-mode): Cosmetic changes.
-;;
+;;; Old Change Log from when diff-mode wasn't part of Emacs:
 ;; Revision 1.11  1999/10/09 23:38:29  monnier
 ;; (diff-mode-load-hook): dropped.
 ;; (auto-mode-alist): also catch *.diffs.