changeset 31684:e05ee0693dda

(diff-hunk-text): Add new optional arg LINE-OFFSET, and return a cons if it's non-nil. (diff-apply-hunk): Try to jump to the exact line in the source text corresponding to the position of point in the in the hunk.
author Miles Bader <miles@gnu.org>
date Mon, 18 Sep 2000 08:15:38 +0000
parents 67dd2c5ce0ed
children b1285f4f9a39
files lisp/diff-mode.el
diffstat 1 files changed, 112 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/diff-mode.el	Mon Sep 18 05:55:03 2000 +0000
+++ b/lisp/diff-mode.el	Mon Sep 18 08:15:38 2000 +0000
@@ -4,7 +4,7 @@
 
 ;; Author: Stefan Monnier <monnier@cs.yale.edu>
 ;; Keywords: patch diff
-;; Revision: $Id: diff-mode.el,v 1.12 2000/09/11 13:49:38 miles Exp $
+;; Revision: $Id: diff-mode.el,v 1.13 2000/09/12 11:24:28 miles Exp $
 
 ;; This file is part of GNU Emacs.
 
@@ -881,75 +881,86 @@
 			      nil t)
 	   (equal (match-string 1) (match-string 2)))))
 
-(defun diff-hunk-text (hunk dest)
-  "Returns the literal source text from HUNK, if DEST is nil, otherwise
-the destination text."
+(defun diff-hunk-text (hunk destp &optional line-offset)
+  "Returns the literal source text from HUNK, if DESTP is nil, otherwise the
+destination text.  If LINE-OFFSET is non-nil, it should be a line-offset in
+HUNK, and instead of a string, a cons cell is returned who's car is the
+appropriate text, and who's cdr is the corresponding line-offset."
   (with-temp-buffer
-    (erase-buffer)
-    (insert hunk)
-    (goto-char (point-min))
-    (let ((src nil)
-	  (dst nil)
-	  (divider nil)
-	  (num-pfx-chars 2))
-      (cond ((looking-at "^@@")
-	     ;; unified diff
-	     (setq num-pfx-chars 1)
-	     (forward-line 1)
-	     (setq src (point) dst (point)))
-	    ((looking-at "^\\*\\*")
-	     ;; context diff
-	     (forward-line 2)
-	     (setq src (point))
-	     (re-search-forward "^--- " nil t)
-	     (forward-line 0)
-	     (setq divider (point))
-	     (forward-line 1)
-	     (setq dst (point)))
-	    ((looking-at "^[0-9]+a[0-9,]+$")
-	     ;; normal diff, insert
-	     (forward-line 1)
-	     (setq dst (point)))
-	    ((looking-at "^[0-9,]+d[0-9]+$")
-	     ;; normal diff, delete
-	     (forward-line 1)
-	     (setq src (point)))
-	    ((looking-at "^[0-9,]+c[0-9,]+$")
-	     ;; normal diff, change
-	     (forward-line 1)
-	     (setq src (point))
-	     (re-search-forward "^---$" nil t)
-	     (forward-line 0)
-	     (setq divider (point))
-	     (forward-line 1)
-	     (setq dst (point)))
-	    (t
-	     (error "Unknown diff hunk type")))
+     (erase-buffer)
+     (insert hunk)
+     (goto-char (point-min))
+     (let ((src-pos nil)
+	   (dst-pos nil)
+	   (divider-pos nil)
+	   (num-pfx-chars 2))
+       ;; Set the following variables:
+       ;;  SRC-POS     buffer pos of the source part of the hunk or nil if none
+       ;;  DST-POS     buffer pos of the destination part of the hunk or nil
+       ;;  DIVIDER-POS buffer pos of any divider line separating the src & dst
+       ;;  NUM-PFX-CHARS  number of line-prefix characters used by this format"
+       (cond ((looking-at "^@@")
+	      ;; unified diff
+	      (setq num-pfx-chars 1)
+	      (forward-line 1)
+	      (setq src-pos (point) dst-pos (point)))
+	     ((looking-at "^\\*\\*")
+	      ;; context diff
+	      (forward-line 2)
+	      (setq src-pos (point))
+	      (re-search-forward "^--- " nil t)
+	      (forward-line 0)
+	      (setq divider-pos (point))
+	      (forward-line 1)
+	      (setq dst-pos (point)))
+	     ((looking-at "^[0-9]+a[0-9,]+$")
+	      ;; normal diff, insert
+	      (forward-line 1)
+	      (setq dst-pos (point)))
+	     ((looking-at "^[0-9,]+d[0-9]+$")
+	      ;; normal diff, delete
+	      (forward-line 1)
+	      (setq src-pos (point)))
+	     ((looking-at "^[0-9,]+c[0-9,]+$")
+	      ;; normal diff, change
+	      (forward-line 1)
+	      (setq src-pos (point))
+	      (re-search-forward "^---$" nil t)
+	      (forward-line 0)
+	      (setq divider-pos (point))
+	      (forward-line 1)
+	      (setq dst-pos (point)))
+	     (t
+	      (error "Unknown diff hunk type")))
+    (if (if destp (null dst-pos) (null src-pos))
+	;; Implied empty text
+	(if line-offset '("" . 0) "")
 
-      (if (if dest (null dst) (null src))
-	  ;; Implied empty text
-	  ""
+      (when line-offset
+	(goto-char (point-min))
+	(forward-line line-offset))
 
-	;; Explicit text
-
+      ;; Get rid of anything except the desired text.
+      (save-excursion
 	;; Delete unused text region
-	(let ((keep (if dest dst src))
-	      (kill (or divider (if dest src dst))))
+	(let ((keep (if destp dst-pos src-pos))
+	      (kill (or divider-pos (if destp src-pos dst-pos))))
 	  (when (and kill (> kill keep))
 	    (delete-region kill (point-max)))
 	  (delete-region (point-min) keep))
+	;; Remove line-prefix characters, and unneeded lines (unified diffs).
+	(let ((kill-char (if destp ?- ?+)))
+	  (goto-char (point-min))
+	  (while (not (eobp))
+	    (if (eq (char-after) kill-char)
+		(delete-region (point) (progn (forward-line 1) (point)))
+	      (delete-char num-pfx-chars)
+	      (forward-line 1)))))
 
-	;; Remove line-prefix characters, and unneeded lines (for
-	;; unified diffs).
-	(let ((kill-char (if dest ?- ?+)))
-  (goto-char (point-min))
-  (while (not (eobp))
-	    (if (eq (char-after) kill-char)
-	(delete-region (point) (progn (forward-line 1) (point)))
-	      (delete-char num-pfx-chars)
-      (forward-line 1))))
-
-	(buffer-substring-no-properties (point-min) (point-max))))))
+      (let ((text (buffer-substring-no-properties (point-min) (point-max))))
+	(if line-offset
+	    (cons text (count-lines (point-min) (point)))
+	  text))))))
 
 (defun diff-find-text (text line)
   "Return the buffer position of the nearest occurance of TEXT to line LINE.
@@ -1000,19 +1011,23 @@
   (let* ((loc (diff-find-source-location other-file))
 	 (buf (find-file-noselect (car loc)))
 	 (patch-line (cadr loc))
+	 hunk-line-offset
 	 (hunk
-	  (save-excursion
-	    (diff-beginning-of-hunk)
-	    (unless (looking-at diff-hunk-header-re)
-	      (error "Malformed hunk"))
-	    (buffer-substring (point) (progn (diff-end-of-hunk) (point)))))
-	 (src (diff-hunk-text hunk reverse))
-	 (dst (diff-hunk-text hunk (not reverse)))
+	  (let ((orig-point (point)))
+	    (save-excursion
+	      (diff-beginning-of-hunk)
+	      (setq hunk-line-offset (count-lines (point) orig-point))
+	      (unless (looking-at diff-hunk-header-re)
+		(error "Malformed hunk"))
+	      (buffer-substring (point) (progn (diff-end-of-hunk) (point))))))
+	 (old (diff-hunk-text hunk reverse hunk-line-offset))
+	 (new (diff-hunk-text hunk (not reverse) hunk-line-offset))
 	 (pos
-	  (with-current-buffer buf (diff-find-text src patch-line)))
+	  (with-current-buffer buf (diff-find-text (car old) patch-line)))
 	 (reversed-pos
 	  (and (null pos)
-	       (with-current-buffer buf (diff-find-text dst patch-line)))))
+	       (with-current-buffer buf
+		 (diff-find-text (car new) patch-line)))))
 
     (when (and reversed-pos popup)
       ;; A reversed patch was detected, perhaps apply it in reverse
@@ -1021,16 +1036,17 @@
 	      (save-window-excursion
 		(pop-to-buffer buf)
 		(goto-char reversed-pos)
+		(forward-line (cdr new))
 		(if reverse
 		    (y-or-n-p
 		     "Hunk hasn't been applied yet, so can't reverse it; apply it now? ")
 		  (y-or-n-p "Hunk has already been applied; undo it? "))))
 
 	  ;; Set up things to reverse the diff
-	  (let ((swap dst))
+	  (let ((swap new))
 	    (setq pos reversed-pos)
-	    (setq src dst)
-	    (setq dst swap))
+	    (setq old new)
+	    (setq new swap))
 
 	;; The user has chosen not to apply the reversed hunk, but we
 	;; don't want to given an error message, so set things up so
@@ -1048,25 +1064,30 @@
 	  ;; Apply the hunk
 	  (with-current-buffer buf
 	    (goto-char pos)
-	    (delete-char (length src))
-	    (insert dst)))
+	    (delete-char (length (car old)))
+	    (insert (car new))))
 
 	(when popup
-	  ;; Show a message describing what was done
-	  (let ((real-line
-		 (1+ (with-current-buffer buf (count-lines (point-min) pos))))
-		(msg 
-		 (if dry-run
-		     (if reversed "already applied" "not yet applied")
-		   (if reversed "undone" "applied"))))
-	    (cond ((= real-line patch-line)
-		   (message "Hunk %s" msg))
-		  ((= real-line (1+ patch-line))
-		   (message "Hunk %s at offset 1 line" msg))
-		  (t
-		   (message "Hunk %s at offset %d lines"
-			    msg
-			    (- real-line patch-line)))))
+	  (with-current-buffer buf
+	    ;; Show a message describing what was done
+	    (let ((real-line (1+ (count-lines (point-min) pos)))
+		  (msg
+		   (if dry-run
+		       (if reversed "already applied" "not yet applied")
+		     (if reversed "undone" "applied"))))
+	      (cond ((= real-line patch-line)
+		     (message "Hunk %s" msg))
+		    ((= real-line (1+ patch-line))
+		     (message "Hunk %s at offset 1 line" msg))
+		    (t
+		     (message "Hunk %s at offset %d lines"
+			      msg
+			      (- real-line patch-line)))))
+
+	    ;; fixup POS to reflect the hunk line offset
+	    (goto-char pos)
+	    (forward-line (cdr new))
+	    (setq pos (point)))
 
 	  ;; Display BUF in a window, and maybe select it
 	  (let ((win (display-buffer buf)))