aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/diff-mode.el
diff options
context:
space:
mode:
authorStefan Monnier2001-11-26 00:20:41 +0000
committerStefan Monnier2001-11-26 00:20:41 +0000
commit1eabc5e6c74e1ff5ebfce50e34f9c00784149c4e (patch)
treef81965f8723cf4912be8fdb5c91c1f214eda110b /lisp/diff-mode.el
parent98040cf1861fe3c118085b4bcb04855b1c327ddd (diff)
downloademacs-1eabc5e6c74e1ff5ebfce50e34f9c00784149c4e.tar.gz
emacs-1eabc5e6c74e1ff5ebfce50e34f9c00784149c4e.zip
(diff-end-of-hunk): Watch out for ambiguities.
(diff-hunk-kill): Simplify. (diff-post-command-hook): Only apply to a single hunk. (diff-hunk-text): Make `char-offset' non-optional. (diff-find-text): Return a cons cell. (diff-find-approx-text): New fun. (diff-find-source-location): Use it. (diff-apply-hunk, diff-test-hunk, diff-goto-source): Adapt to new retval of diff-find-source-location.
Diffstat (limited to 'lisp/diff-mode.el')
-rw-r--r--lisp/diff-mode.el162
1 files changed, 92 insertions, 70 deletions
diff --git a/lisp/diff-mode.el b/lisp/diff-mode.el
index 2c86b1fbeb3..c46d152d97e 100644
--- a/lisp/diff-mode.el
+++ b/lisp/diff-mode.el
@@ -47,7 +47,6 @@
47;; - re-enable (conditionally) the `compile' support after improving it to use 47;; - re-enable (conditionally) the `compile' support after improving it to use
48;; the same code as diff-goto-source. 48;; the same code as diff-goto-source.
49;; - Support for # comments in context->unified. 49;; - Support for # comments in context->unified.
50;; - Do a fuzzy search in diff-goto-source.
51;; - Allow diff.el to use diff-mode. 50;; - Allow diff.el to use diff-mode.
52;; This mostly means ability to jump from half-hunk to half-hunk 51;; This mostly means ability to jump from half-hunk to half-hunk
53;; in context (and normal) diffs and to jump to the corresponding 52;; in context (and normal) diffs and to jump to the corresponding
@@ -77,7 +76,6 @@
77(defcustom diff-jump-to-old-file nil 76(defcustom diff-jump-to-old-file nil
78 "*Non-nil means `diff-goto-source' jumps to the old file. 77 "*Non-nil means `diff-goto-source' jumps to the old file.
79Else, it jumps to the new file." 78Else, it jumps to the new file."
80 :group 'diff-mode
81 :type '(boolean)) 79 :type '(boolean))
82 80
83(defcustom diff-update-on-the-fly t 81(defcustom diff-update-on-the-fly t
@@ -87,12 +85,10 @@ need to be kept consistent with the actual diff. This can
87either be done on the fly (but this sometimes interacts poorly with the 85either be done on the fly (but this sometimes interacts poorly with the
88undo mechanism) or whenever the file is written (can be slow 86undo mechanism) or whenever the file is written (can be slow
89when editing big diffs)." 87when editing big diffs)."
90 :group 'diff-mode
91 :type '(boolean)) 88 :type '(boolean))
92 89
93(defcustom diff-advance-after-apply-hunk t 90(defcustom diff-advance-after-apply-hunk t
94 "*Non-nil means `diff-apply-hunk' will move to the next hunk after applying." 91 "*Non-nil means `diff-apply-hunk' will move to the next hunk after applying."
95 :group 'diff-mode
96 :type 'boolean) 92 :type 'boolean)
97 93
98 94
@@ -164,7 +160,6 @@ when editing big diffs)."
164 160
165(defcustom diff-minor-mode-prefix "\C-c=" 161(defcustom diff-minor-mode-prefix "\C-c="
166 "Prefix key for `diff-minor-mode' commands." 162 "Prefix key for `diff-minor-mode' commands."
167 :group 'diff-mode
168 :type '(choice (string "\e") (string "C-c=") string)) 163 :type '(choice (string "\e") (string "C-c=") string))
169 164
170(easy-mmode-defmap diff-minor-mode-map 165(easy-mmode-defmap diff-minor-mode-map
@@ -186,8 +181,7 @@ when editing big diffs)."
186 (((class color) (background dark)) 181 (((class color) (background dark))
187 (:background "grey45")) 182 (:background "grey45"))
188 (t (:bold t))) 183 (t (:bold t)))
189 "`diff-mode' face inherited by hunk and index header faces." 184 "`diff-mode' face inherited by hunk and index header faces.")
190 :group 'diff-mode)
191(defvar diff-header-face 'diff-header-face) 185(defvar diff-header-face 'diff-header-face)
192 186
193(defface diff-file-header-face 187(defface diff-file-header-face
@@ -200,32 +194,27 @@ when editing big diffs)."
200 (((class color) (background dark)) 194 (((class color) (background dark))
201 (:background "grey60" :bold t)) 195 (:background "grey60" :bold t))
202 (t (:bold t))) ; :height 1.3 196 (t (:bold t))) ; :height 1.3
203 "`diff-mode' face used to highlight file header lines." 197 "`diff-mode' face used to highlight file header lines.")
204 :group 'diff-mode)
205(defvar diff-file-header-face 'diff-file-header-face) 198(defvar diff-file-header-face 'diff-file-header-face)
206 199
207(defface diff-index-face 200(defface diff-index-face
208 '((t (:inherit diff-file-header-face))) 201 '((t (:inherit diff-file-header-face)))
209 "`diff-mode' face used to highlight index header lines." 202 "`diff-mode' face used to highlight index header lines.")
210 :group 'diff-mode)
211(defvar diff-index-face 'diff-index-face) 203(defvar diff-index-face 'diff-index-face)
212 204
213(defface diff-hunk-header-face 205(defface diff-hunk-header-face
214 '((t (:inherit diff-header-face))) 206 '((t (:inherit diff-header-face)))
215 "`diff-mode' face used to highlight hunk header lines." 207 "`diff-mode' face used to highlight hunk header lines.")
216 :group 'diff-mode)
217(defvar diff-hunk-header-face 'diff-hunk-header-face) 208(defvar diff-hunk-header-face 'diff-hunk-header-face)
218 209
219(defface diff-removed-face 210(defface diff-removed-face
220 '((t (:inherit diff-changed-face))) 211 '((t (:inherit diff-changed-face)))
221 "`diff-mode' face used to highlight removed lines." 212 "`diff-mode' face used to highlight removed lines.")
222 :group 'diff-mode)
223(defvar diff-removed-face 'diff-removed-face) 213(defvar diff-removed-face 'diff-removed-face)
224 214
225(defface diff-added-face 215(defface diff-added-face
226 '((t (:inherit diff-changed-face))) 216 '((t (:inherit diff-changed-face)))
227 "`diff-mode' face used to highlight added lines." 217 "`diff-mode' face used to highlight added lines.")
228 :group 'diff-mode)
229(defvar diff-added-face 'diff-added-face) 218(defvar diff-added-face 'diff-added-face)
230 219
231(defface diff-changed-face 220(defface diff-changed-face
@@ -234,14 +223,12 @@ when editing big diffs)."
234 (((type tty pc) (class color) (background dark)) 223 (((type tty pc) (class color) (background dark))
235 (:foreground "yellow" :bold t :italic t)) 224 (:foreground "yellow" :bold t :italic t))
236 (t ())) 225 (t ()))
237 "`diff-mode' face used to highlight changed lines." 226 "`diff-mode' face used to highlight changed lines.")
238 :group 'diff-mode)
239(defvar diff-changed-face 'diff-changed-face) 227(defvar diff-changed-face 'diff-changed-face)
240 228
241(defface diff-function-face 229(defface diff-function-face
242 '((t (:inherit diff-context-face))) 230 '((t (:inherit diff-context-face)))
243 "`diff-mode' face used to highlight function names produced by \"diff -p\"." 231 "`diff-mode' face used to highlight function names produced by \"diff -p\".")
244 :group 'diff-mode)
245(defvar diff-function-face 'diff-function-face) 232(defvar diff-function-face 'diff-function-face)
246 233
247(defface diff-context-face 234(defface diff-context-face
@@ -250,14 +237,12 @@ when editing big diffs)."
250 (((class color) (background dark)) 237 (((class color) (background dark))
251 (:foreground "grey70")) 238 (:foreground "grey70"))
252 (t )) 239 (t ))
253 "`diff-mode' face used to highlight context and other side-information." 240 "`diff-mode' face used to highlight context and other side-information.")
254 :group 'diff-mode)
255(defvar diff-context-face 'diff-context-face) 241(defvar diff-context-face 'diff-context-face)
256 242
257(defface diff-nonexistent-face 243(defface diff-nonexistent-face
258 '((t (:inherit diff-file-header-face))) 244 '((t (:inherit diff-file-header-face)))
259 "`diff-mode' face used to highlight nonexistent files in recursive diffs." 245 "`diff-mode' face used to highlight nonexistent files in recursive diffs.")
260 :group 'diff-mode)
261(defvar diff-nonexistent-face 'diff-nonexistent-face) 246(defvar diff-nonexistent-face 'diff-nonexistent-face)
262 247
263(defvar diff-font-lock-keywords 248(defvar diff-font-lock-keywords
@@ -313,7 +298,9 @@ when editing big diffs)."
313(defun diff-end-of-hunk (&optional style) 298(defun diff-end-of-hunk (&optional style)
314 (if (looking-at diff-hunk-header-re) (goto-char (match-end 0))) 299 (if (looking-at diff-hunk-header-re) (goto-char (match-end 0)))
315 (let ((end (and (re-search-forward (case style 300 (let ((end (and (re-search-forward (case style
316 (unified "^[^-+# \\]") 301 ;; A `unified' header is ambiguous.
302 (unified (concat "^[^-+# \\]\\|"
303 diff-file-header-re))
317 (context "^[^-+#! \\]") 304 (context "^[^-+#! \\]")
318 (normal "^[^<>#\\]") 305 (normal "^[^<>#\\]")
319 (t "^[^-+#!<> \\]")) 306 (t "^[^-+#!<> \\]"))
@@ -365,20 +352,17 @@ If the prefix ARG is given, restrict the view to the current file instead."
365 "Kill current hunk." 352 "Kill current hunk."
366 (interactive) 353 (interactive)
367 (diff-beginning-of-hunk) 354 (diff-beginning-of-hunk)
368 (let ((start (point)) 355 (let* ((start (point))
369 (firsthunk (save-excursion 356 (nexthunk (ignore-errors (diff-hunk-next) (point)))
370 (ignore-errors 357 (firsthunk (ignore-errors
371 (diff-beginning-of-file) (diff-hunk-next) (point)))) 358 (goto-char start)
372 (nexthunk (save-excursion 359 (diff-beginning-of-file) (diff-hunk-next) (point)))
373 (ignore-errors 360 (nextfile (ignore-errors (diff-file-next) (point))))
374 (diff-hunk-next) (point)))) 361 (goto-char start)
375 (nextfile (save-excursion
376 (ignore-errors
377 (diff-file-next) (point)))))
378 (if (and firsthunk (= firsthunk start) 362 (if (and firsthunk (= firsthunk start)
379 (or (null nexthunk) 363 (or (null nexthunk)
380 (and nextfile (> nexthunk nextfile)))) 364 (and nextfile (> nexthunk nextfile))))
381 ;; we're the only hunk for this file, so kill the file 365 ;; It's the only hunk for this file, so kill the file.
382 (diff-file-kill) 366 (diff-file-kill)
383 (diff-end-of-hunk) 367 (diff-end-of-hunk)
384 (kill-region start (point))))) 368 (kill-region start (point)))))
@@ -849,15 +833,24 @@ See `after-change-functions' for the meaning of BEG, END and LEN."
849 (ignore-errors 833 (ignore-errors
850 (save-excursion 834 (save-excursion
851 (goto-char (car diff-unhandled-changes)) 835 (goto-char (car diff-unhandled-changes))
852 (unless (ignore-errors 836 ;; We used to fixup modifs on all the changes, but it turns out
853 (diff-beginning-of-hunk) 837 ;; that it's safer not to do it on big changes, for example
854 (save-excursion 838 ;; when yanking a big diff, since we might then screw up perfectly
855 (diff-end-of-hunk) 839 ;; correct values. -stef
856 (> (point) (car diff-unhandled-changes)))) 840 ;; (unless (ignore-errors
857 (goto-char (car diff-unhandled-changes)) 841 ;; (diff-beginning-of-hunk)
858 (re-search-forward diff-hunk-header-re (cdr diff-unhandled-changes)) 842 ;; (save-excursion
859 (diff-beginning-of-hunk)) 843 ;; (diff-end-of-hunk)
860 (diff-fixup-modifs (point) (cdr diff-unhandled-changes)))) 844 ;; (> (point) (car diff-unhandled-changes))))
845 ;; (goto-char (car diff-unhandled-changes))
846 ;; (re-search-forward diff-hunk-header-re (cdr diff-unhandled-changes))
847 ;; (diff-beginning-of-hunk))
848 ;; (diff-fixup-modifs (point) (cdr diff-unhandled-changes))
849 (diff-beginning-of-hunk)
850 (when (save-excursion
851 (diff-end-of-hunk)
852 (> (point) (cdr diff-unhandled-changes)))
853 (diff-fixup-modifs (point) (cdr diff-unhandled-changes)))))
861 (setq diff-unhandled-changes nil))) 854 (setq diff-unhandled-changes nil)))
862 855
863;;;; 856;;;;
@@ -941,12 +934,11 @@ Only works for unified diffs."
941 nil t) 934 nil t)
942 (equal (match-string 1) (match-string 2))))) 935 (equal (match-string 1) (match-string 2)))))
943 936
944(defun diff-hunk-text (hunk destp &optional char-offset) 937(defun diff-hunk-text (hunk destp char-offset)
945 "Return the literal source text from HUNK. 938 "Return the literal source text from HUNK as (TEXT . OFFSET).
946if DESTP is nil return the source, otherwise the destination text. 939if DESTP is nil TEXT is the source, otherwise the destination text.
947If CHAR-OFFSET is non-nil, it should be a char-offset in 940CHAR-OFFSET is a char-offset in HUNK, and OFFSET is the corresponding
948HUNK, and instead of a string, a cons cell is returned whose car is the 941char-offset in TEXT."
949appropriate text, and whose cdr is the corresponding char-offset in that text."
950 (with-temp-buffer 942 (with-temp-buffer
951 (insert hunk) 943 (insert hunk)
952 (goto-char (point-min)) 944 (goto-char (point-min))
@@ -1025,23 +1017,47 @@ appropriate text, and whose cdr is the corresponding char-offset in that text."
1025 1017
1026 1018
1027(defun diff-find-text (text) 1019(defun diff-find-text (text)
1028 "Return the buffer position of the nearest occurrence of TEXT. 1020 "Return the buffer position (BEG . END) of the nearest occurrence of TEXT.
1029If TEXT isn't found, nil is returned." 1021If TEXT isn't found, nil is returned."
1030 (let* ((orig (point)) 1022 (let* ((orig (point))
1031 (forw (and (search-forward text nil t) 1023 (forw (and (search-forward text nil t)
1032 (match-beginning 0))) 1024 (cons (match-beginning 0) (match-end 0))))
1033 (back (and (goto-char (+ orig (length text))) 1025 (back (and (goto-char (+ orig (length text)))
1034 (search-backward text nil t) 1026 (search-backward text nil t)
1035 (match-beginning 0)))) 1027 (cons (match-beginning 0) (match-end 0)))))
1036 ;; Choose the closest match. 1028 ;; Choose the closest match.
1029 (if (and forw back)
1030 (if (> (- (car forw) orig) (- orig (car back))) back forw)
1031 (or back forw))))
1032
1033(defun diff-find-approx-text (text)
1034 "Return the buffer position (BEG . END) of the nearest occurrence of TEXT.
1035Whitespace differences are ignored."
1036 (let* ((orig (point))
1037 (re (concat "^[ \t\n ]*"
1038 (mapconcat 'regexp-quote (split-string text) "[ \t\n ]+")
1039 "[ \t\n ]*\n"))
1040 (forw (and (re-search-forward re nil t)
1041 (cons (match-beginning 0) (match-end 0))))
1042 (back (and (goto-char (+ orig (length text)))
1043 (re-search-backward re nil t)
1044 (cons (match-beginning 0) (match-end 0)))))
1045 ;; Choose the closest match.
1037 (if (and forw back) 1046 (if (and forw back)
1038 (if (> (- forw orig) (- orig back)) back forw) 1047 (if (> (- (car forw) orig) (- orig (car back))) back forw)
1039 (or back forw)))) 1048 (or back forw))))
1040 1049
1041(defsubst diff-xor (a b) (if a (not b) b)) 1050(defsubst diff-xor (a b) (if a (not b) b))
1042 1051
1043(defun diff-find-source-location (&optional other-file reverse) 1052(defun diff-find-source-location (&optional other-file reverse)
1044 "Find out (BUF LINE-OFFSET POS SRC DST SWITCHED)." 1053 "Find out (BUF LINE-OFFSET POS SRC DST SWITCHED).
1054BUF is the buffer corresponding to the source file.
1055LINE-OFFSET is the offset between the expected and actual positions
1056 of the text of the hunk or nil if the text was not found.
1057POS is a pair (BEG . END) indicating the position of the text in the buffer.
1058SRC and DST are the two variants of text as returned by `diff-hunk-text'.
1059 SRC is the variant that was found in the buffer.
1060SWITCHED is non-nil if the patch is already applied."
1045 (save-excursion 1061 (save-excursion
1046 (let* ((other (diff-xor other-file diff-jump-to-old-file)) 1062 (let* ((other (diff-xor other-file diff-jump-to-old-file))
1047 (char-offset (- (point) (progn (diff-beginning-of-hunk) (point)))) 1063 (char-offset (- (point) (progn (diff-beginning-of-hunk) (point))))
@@ -1065,13 +1081,19 @@ If TEXT isn't found, nil is returned."
1065 (with-current-buffer buf 1081 (with-current-buffer buf
1066 (goto-line (string-to-number line)) 1082 (goto-line (string-to-number line))
1067 (let* ((orig-pos (point)) 1083 (let* ((orig-pos (point))
1068 (pos (diff-find-text (car old))) 1084 (switched nil)
1069 (switched nil)) 1085 (pos (or (diff-find-text (car old))
1070 (when (null pos) 1086 (progn (setq switched t) (diff-find-text (car new)))
1071 (setq pos (diff-find-text (car new)) switched t)) 1087 (progn (setq switched nil)
1088 (diff-find-approx-text (car old)))
1089 (progn (setq switched t)
1090 (diff-find-approx-text (car new)))
1091 (progn (setq switched nil) nil))))
1072 (nconc 1092 (nconc
1073 (list buf) 1093 (list buf)
1074 (if pos (list (count-lines orig-pos pos) pos) (list nil orig-pos)) 1094 (if pos
1095 (list (count-lines orig-pos (car pos)) pos)
1096 (list nil (cons orig-pos (+ orig-pos (length (car old))))))
1075 (if switched (list new old t) (list old new)))))))) 1097 (if switched (list new old t) (list old new))))))))
1076 1098
1077 1099
@@ -1104,7 +1126,7 @@ With a prefix argument, REVERSE the hunk."
1104 ;; A reversed patch was detected, perhaps apply it in reverse. 1126 ;; A reversed patch was detected, perhaps apply it in reverse.
1105 (not (save-window-excursion 1127 (not (save-window-excursion
1106 (pop-to-buffer buf) 1128 (pop-to-buffer buf)
1107 (goto-char (+ pos (cdr old))) 1129 (goto-char (+ (car pos) (cdr old)))
1108 (y-or-n-p 1130 (y-or-n-p
1109 (if reverse 1131 (if reverse
1110 "Hunk hasn't been applied yet; apply it now? " 1132 "Hunk hasn't been applied yet; apply it now? "
@@ -1113,11 +1135,11 @@ With a prefix argument, REVERSE the hunk."
1113 (t 1135 (t
1114 ;; Apply the hunk 1136 ;; Apply the hunk
1115 (with-current-buffer buf 1137 (with-current-buffer buf
1116 (goto-char pos) 1138 (goto-char (car pos))
1117 (delete-char (length (car old))) 1139 (delete-region (car pos) (cdr pos))
1118 (insert (car new))) 1140 (insert (car new)))
1119 ;; Display BUF in a window 1141 ;; Display BUF in a window
1120 (set-window-point (display-buffer buf) (+ pos (cdr new))) 1142 (set-window-point (display-buffer buf) (+ (car pos) (cdr new)))
1121 (diff-hunk-status-msg line-offset (diff-xor switched reverse) nil) 1143 (diff-hunk-status-msg line-offset (diff-xor switched reverse) nil)
1122 (when diff-advance-after-apply-hunk 1144 (when diff-advance-after-apply-hunk
1123 (diff-hunk-next)))))) 1145 (diff-hunk-next))))))
@@ -1129,7 +1151,7 @@ With a prefix argument, try to REVERSE the hunk."
1129 (interactive "P") 1151 (interactive "P")
1130 (destructuring-bind (buf line-offset pos src dst &optional switched) 1152 (destructuring-bind (buf line-offset pos src dst &optional switched)
1131 (diff-find-source-location nil reverse) 1153 (diff-find-source-location nil reverse)
1132 (set-window-point (display-buffer buf) (+ pos (cdr src))) 1154 (set-window-point (display-buffer buf) (+ (car pos) (cdr src)))
1133 (diff-hunk-status-msg line-offset (diff-xor reverse switched) t))) 1155 (diff-hunk-status-msg line-offset (diff-xor reverse switched) t)))
1134 1156
1135 1157
@@ -1147,7 +1169,7 @@ If the prefix arg is bigger than 8 (for example with \\[universal-argument] \\[u
1147 (destructuring-bind (buf line-offset pos src dst &optional switched) 1169 (destructuring-bind (buf line-offset pos src dst &optional switched)
1148 (diff-find-source-location other-file rev) 1170 (diff-find-source-location other-file rev)
1149 (pop-to-buffer buf) 1171 (pop-to-buffer buf)
1150 (goto-char (+ pos (cdr src))) 1172 (goto-char (+ (car pos) (cdr src)))
1151 (diff-hunk-status-msg line-offset (diff-xor rev switched) t)))) 1173 (diff-hunk-status-msg line-offset (diff-xor rev switched) t))))
1152 1174
1153 1175
@@ -1170,7 +1192,7 @@ For use in `add-log-current-defun-function'."
1170 (funcall (with-current-buffer buf major-mode)) 1192 (funcall (with-current-buffer buf major-mode))
1171 (add-log-current-defun)))) 1193 (add-log-current-defun))))
1172 (with-current-buffer buf 1194 (with-current-buffer buf
1173 (goto-char (+ pos (cdr src))) 1195 (goto-char (+ (car pos) (cdr src)))
1174 (add-log-current-defun)))))) 1196 (add-log-current-defun))))))
1175 1197
1176;; provide the package 1198;; provide the package