Mercurial > emacs
comparison lisp/diff-mode.el @ 31795:868648c4a36b
* diff-mode.el (diff-add-log-file-name, diff-current-defun): New funs.
(diff-mode): Add support for add-log.el.
(diff-hunk-text): Use char offsets rather than line offsets.
(diff-find-source-location): Replace LINE with line-offset (nil
if not found) and always set POS to a meaningful position.
Adapt to the new char-offsets.
(diff-apply-hunk): Drop support for the unused `select' POPUP.
Adapt to the new diff-find-source-location.
(diff-goto-source): Adapt to the new diff-find-source-location.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Wed, 20 Sep 2000 22:36:23 +0000 |
parents | 181947e98152 |
children | e23774b771e1 |
comparison
equal
deleted
inserted
replaced
31794:7e8ab579609b | 31795:868648c4a36b |
---|---|
2 | 2 |
3 ;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: Stefan Monnier <monnier@cs.yale.edu> | 5 ;; Author: Stefan Monnier <monnier@cs.yale.edu> |
6 ;; Keywords: patch diff | 6 ;; Keywords: patch diff |
7 ;; Revision: $Id: diff-mode.el,v 1.18 2000/09/20 06:40:30 miles Exp $ | 7 ;; Revision: $Id: diff-mode.el,v 1.19 2000/09/20 16:56:13 monnier Exp $ |
8 | 8 |
9 ;; This file is part of GNU Emacs. | 9 ;; This file is part of GNU Emacs. |
10 | 10 |
11 ;; GNU Emacs is free software; you can redistribute it and/or modify | 11 ;; GNU Emacs is free software; you can redistribute it and/or modify |
12 ;; it under the terms of the GNU General Public License as published by | 12 ;; it under the terms of the GNU General Public License as published by |
43 ;; - Reverse doesn't work with normal diffs. | 43 ;; - Reverse doesn't work with normal diffs. |
44 ;; - (nitpick) The mark is not always quite right in diff-goto-source. | 44 ;; - (nitpick) The mark is not always quite right in diff-goto-source. |
45 | 45 |
46 ;; Todo: | 46 ;; Todo: |
47 | 47 |
48 ;; - Add change-log support. | |
49 ;; - Spice up the minor-mode with font-lock support. | 48 ;; - Spice up the minor-mode with font-lock support. |
50 ;; - Improve narrowed-view support. | 49 ;; - Improve narrowed-view support. |
51 ;; - Improve the `compile' support (?). | 50 ;; - Improve the `compile' support (?). |
52 ;; - Recognize pcl-cvs' special string for `cvs-execute-single'. | 51 ;; - Recognize pcl-cvs' special string for `cvs-execute-single'. |
53 ;; - Support for # comments in context->unified. | 52 ;; - Support for # comments in context->unified. |
451 "Run `diff-goto-source' for the diff at a mouse click." | 450 "Run `diff-goto-source' for the diff at a mouse click." |
452 (interactive "e") | 451 (interactive "e") |
453 (save-excursion | 452 (save-excursion |
454 (mouse-set-point event) | 453 (mouse-set-point event) |
455 (diff-goto-source))) | 454 (diff-goto-source))) |
455 | |
456 (defun diff-add-log-file-name (log-file) | |
457 "File name to use in add-log for the hunk at point. | |
458 For use in `add-log-file-name-function'. | |
459 LOG-FILE should be the path to the ChangeLog file." | |
460 (add-log-file-name (expand-file-name (diff-find-file-name)) log-file)) | |
461 | |
456 | 462 |
457 (defun diff-ediff-patch () | 463 (defun diff-ediff-patch () |
458 "Call `ediff-patch-file' on the current buffer." | 464 "Call `ediff-patch-file' on the current buffer." |
459 (interactive) | 465 (interactive) |
460 (condition-case err | 466 (condition-case err |
823 'diff-after-change-function nil t) | 829 'diff-after-change-function nil t) |
824 (add-hook (make-local-hook 'post-command-hook) | 830 (add-hook (make-local-hook 'post-command-hook) |
825 'diff-post-command-hook nil t)) | 831 'diff-post-command-hook nil t)) |
826 ;; Neat trick from Dave Love to add more bindings in read-only mode: | 832 ;; Neat trick from Dave Love to add more bindings in read-only mode: |
827 (add-to-list (make-local-variable 'minor-mode-overriding-map-alist) | 833 (add-to-list (make-local-variable 'minor-mode-overriding-map-alist) |
828 (cons 'buffer-read-only diff-mode-shared-map))) | 834 (cons 'buffer-read-only diff-mode-shared-map)) |
835 ;; add-log support | |
836 (set (make-local-variable 'add-log-current-defun-function) | |
837 'diff-current-defun) | |
838 (set (make-local-variable 'add-log-file-name-function) | |
839 'diff-add-log-file-name)) | |
829 | 840 |
830 ;;;###autoload | 841 ;;;###autoload |
831 (define-minor-mode diff-minor-mode | 842 (define-minor-mode diff-minor-mode |
832 "Minor mode for viewing/editing context diffs. | 843 "Minor mode for viewing/editing context diffs. |
833 \\{diff-minor-mode-map}" | 844 \\{diff-minor-mode-map}" |
855 (while | 866 (while |
856 (and (re-search-forward "^@@ [-0-9]+,\\([0-9]+\\) [+0-9]+,\\([0-9]+\\) @@" | 867 (and (re-search-forward "^@@ [-0-9]+,\\([0-9]+\\) [+0-9]+,\\([0-9]+\\) @@" |
857 nil t) | 868 nil t) |
858 (equal (match-string 1) (match-string 2))))) | 869 (equal (match-string 1) (match-string 2))))) |
859 | 870 |
860 (defun diff-hunk-text (hunk destp &optional line-offset) | 871 (defun diff-hunk-text (hunk destp &optional char-offset) |
861 "Returns the literal source text from HUNK. | 872 "Returns the literal source text from HUNK. |
862 if DESTP is nil return the source, otherwise the destination text. | 873 if DESTP is nil return the source, otherwise the destination text. |
863 If LINE-OFFSET is non-nil, it should be a line-offset in | 874 If CHAR-OFFSET is non-nil, it should be a char-offset in |
864 HUNK, and instead of a string, a cons cell is returned whose car is the | 875 HUNK, and instead of a string, a cons cell is returned whose car is the |
865 appropriate text, and whose cdr is the corresponding line-offset in that text." | 876 appropriate text, and whose cdr is the corresponding char-offset in that text." |
866 (with-temp-buffer | 877 (with-temp-buffer |
867 (insert hunk) | 878 (insert hunk) |
868 (goto-char (point-min)) | 879 (goto-char (point-min)) |
869 (let ((src-pos nil) | 880 (let ((src-pos nil) |
870 (dst-pos nil) | 881 (dst-pos nil) |
908 (setq dst-pos (point))) | 919 (setq dst-pos (point))) |
909 (t | 920 (t |
910 (error "Unknown diff hunk type"))) | 921 (error "Unknown diff hunk type"))) |
911 (if (if destp (null dst-pos) (null src-pos)) | 922 (if (if destp (null dst-pos) (null src-pos)) |
912 ;; Implied empty text | 923 ;; Implied empty text |
913 (if line-offset '("" . 0) "") | 924 (if char-offset '("" . 0) "") |
914 | 925 |
915 (when line-offset | 926 (when char-offset (goto-char char-offset)) |
916 (goto-char (point-min)) | |
917 (forward-line line-offset)) | |
918 | 927 |
919 ;; Get rid of anything except the desired text. | 928 ;; Get rid of anything except the desired text. |
920 (save-excursion | 929 (save-excursion |
921 ;; Delete unused text region | 930 ;; Delete unused text region |
922 (let ((keep (if destp dst-pos src-pos)) | 931 (let ((keep (if destp dst-pos src-pos)) |
932 (delete-region (point) (progn (forward-line 1) (point))) | 941 (delete-region (point) (progn (forward-line 1) (point))) |
933 (delete-char num-pfx-chars) | 942 (delete-char num-pfx-chars) |
934 (forward-line 1))))) | 943 (forward-line 1))))) |
935 | 944 |
936 (let ((text (buffer-substring-no-properties (point-min) (point-max)))) | 945 (let ((text (buffer-substring-no-properties (point-min) (point-max)))) |
937 (if line-offset | 946 (if char-offset (cons text (point)) text)))))) |
938 (cons text (count-lines (point-min) (point))) | |
939 text)))))) | |
940 | 947 |
941 (defun diff-find-text (text) | 948 (defun diff-find-text (text) |
942 "Return the buffer position of the nearest occurance of TEXT. | 949 "Return the buffer position of the nearest occurrence of TEXT. |
943 If TEXT isn't found, nil is returned." | 950 If TEXT isn't found, nil is returned." |
944 (let* ((orig (point)) | 951 (let* ((orig (point)) |
945 (forw (and (search-forward text nil t) | 952 (forw (and (search-forward text nil t) |
946 (match-beginning 0))) | 953 (match-beginning 0))) |
947 (back (and (goto-char (+ orig (length text))) | 954 (back (and (goto-char (+ orig (length text))) |
951 (if (and forw back) | 958 (if (and forw back) |
952 (if (> (- forw orig) (- orig back)) back forw) | 959 (if (> (- forw orig) (- orig back)) back forw) |
953 (or back forw)))) | 960 (or back forw)))) |
954 | 961 |
955 (defun diff-find-source-location (&optional other-file reverse) | 962 (defun diff-find-source-location (&optional other-file reverse) |
956 "Find out (BUF LINE POS SRC DST SWITCHED)." | 963 "Find out (BUF LINE-OFFSET POS SRC DST SWITCHED)." |
957 (save-excursion | 964 (save-excursion |
958 (let* ((old (if (not other-file) diff-jump-to-old-file-flag | 965 (let* ((old (if (not other-file) diff-jump-to-old-file-flag |
959 (not diff-jump-to-old-file-flag))) | 966 (not diff-jump-to-old-file-flag))) |
960 (orig-point (point)) | 967 (hunk-char-offset |
961 (hunk-line-offset | 968 (- (point) (progn (diff-beginning-of-hunk) (point)))) |
962 (progn (diff-beginning-of-hunk) (count-lines (point) orig-point))) | |
963 ;; Find the location specification. | 969 ;; Find the location specification. |
964 (line (if (not (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?")) | 970 (line (if (not (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?")) |
965 (error "Can't find the hunk header") | 971 (error "Can't find the hunk header") |
966 (if old (match-string 1) | 972 (if old (match-string 1) |
967 (if (match-end 3) (match-string 3) | 973 (if (match-end 3) (match-string 3) |
970 (match-string 1))))) | 976 (match-string 1))))) |
971 (file (or (diff-find-file-name old) (error "Can't find the file"))) | 977 (file (or (diff-find-file-name old) (error "Can't find the file"))) |
972 (buf (find-file-noselect file)) | 978 (buf (find-file-noselect file)) |
973 (hunk | 979 (hunk |
974 (buffer-substring (point) (progn (diff-end-of-hunk) (point)))) | 980 (buffer-substring (point) (progn (diff-end-of-hunk) (point)))) |
975 (old (diff-hunk-text hunk reverse hunk-line-offset)) | 981 (old (diff-hunk-text hunk reverse hunk-char-offset)) |
976 (new (diff-hunk-text hunk (not reverse) hunk-line-offset))) | 982 (new (diff-hunk-text hunk (not reverse) hunk-char-offset))) |
977 ;; Update the user preference if he so wished. | 983 ;; Update the user preference if he so wished. |
978 (when (> (prefix-numeric-value other-file) 8) | 984 (when (> (prefix-numeric-value other-file) 8) |
979 (setq diff-jump-to-old-file-flag old)) | 985 (setq diff-jump-to-old-file-flag old)) |
980 (with-current-buffer buf | 986 (with-current-buffer buf |
981 (goto-line (string-to-number line)) | 987 (goto-line (string-to-number line)) |
982 (let* ((orig-pos (point)) | 988 (let* ((orig-pos (point)) |
983 (pos (diff-find-text (car old))) | 989 (pos (diff-find-text (car old))) |
984 (switched nil)) | 990 (switched nil)) |
985 (when (null pos) | 991 (when (null pos) |
986 (setq pos (diff-find-text (car new)) switched t)) | 992 (setq pos (diff-find-text (car new)) switched t)) |
987 (list* buf (string-to-number line) pos | 993 (cons buf |
988 (if switched (list new old t) (list old new)))))))) | 994 (nconc |
995 (if pos (list (count-lines orig-pos pos) pos) (list nil orig-pos)) | |
996 (if switched (list new old t) (list old new))))))))) | |
989 | 997 |
990 (defun diff-apply-hunk (&optional reverse other-file dry-run popup noerror) | 998 (defun diff-apply-hunk (&optional reverse other-file dry-run popup noerror) |
991 "Apply the current hunk to the source file. | 999 "Apply the current hunk to the source file. |
992 By default, the new source file is patched, but if the variable | 1000 By default, the new source file is patched, but if the variable |
993 `diff-jump-to-old-file-flag' is non-nil, then the old source file is | 1001 `diff-jump-to-old-file-flag' is non-nil, then the old source file is |
997 With a prefix argument, REVERSE the hunk. | 1005 With a prefix argument, REVERSE the hunk. |
998 If OTHER-FILE is non-nil, patch the old file by default, and reverse the | 1006 If OTHER-FILE is non-nil, patch the old file by default, and reverse the |
999 sense of `diff-jump-to-old-file-flag'. | 1007 sense of `diff-jump-to-old-file-flag'. |
1000 If DRY-RUN is non-nil, don't actually modify anything, just see whether | 1008 If DRY-RUN is non-nil, don't actually modify anything, just see whether |
1001 it's possible to do so. | 1009 it's possible to do so. |
1002 If POPUP is non-nil, pop up the patched file in another window; if POPUP | 1010 If POPUP is non-nil, pop up the patched file in another window. |
1003 is `select' then select the new window too. | |
1004 If NOERROR is non-nil, then no error is signaled in the case where the hunk | 1011 If NOERROR is non-nil, then no error is signaled in the case where the hunk |
1005 cannot be found in the source file (other errors may still be signaled). | 1012 cannot be found in the source file (other errors may still be signaled). |
1006 | 1013 |
1007 Return values are t if the hunk was sucessfully applied (or could be | 1014 Return values are t if the hunk was sucessfully applied (or could be |
1008 applied, in the case where DRY-RUN was non-nil), `reversed' if the hunk | 1015 applied, in the case where DRY-RUN was non-nil), `reversed' if the hunk |
1016 (when diff-jump-to-old-file-flag | 1023 (when diff-jump-to-old-file-flag |
1017 ;; The global variable `diff-jump-to-old-file-flag' inverts the | 1024 ;; The global variable `diff-jump-to-old-file-flag' inverts the |
1018 ;; sense of OTHER-FILE (in `diff-find-source-location') | 1025 ;; sense of OTHER-FILE (in `diff-find-source-location') |
1019 (setq reverse (not reverse))) | 1026 (setq reverse (not reverse))) |
1020 | 1027 |
1021 (destructuring-bind (buf patch-line pos old new &optional switched) | 1028 (destructuring-bind (buf line-offset pos old new &optional switched) |
1022 (diff-find-source-location other-file reverse) | 1029 (diff-find-source-location other-file reverse) |
1023 | 1030 |
1024 (when (and pos switched popup) | 1031 (when (and line-offset switched popup) |
1025 ;; A reversed patch was detected, perhaps apply it in reverse | 1032 ;; A reversed patch was detected, perhaps apply it in reverse |
1026 ;; (this is only done in `interactive' mode, when POPUP is non-nil). | 1033 ;; (this is only done in `interactive' mode, when POPUP is non-nil). |
1027 (if (or dry-run | 1034 (if (or dry-run |
1028 (save-window-excursion | 1035 (save-window-excursion |
1029 (pop-to-buffer buf) | 1036 (pop-to-buffer buf) |
1030 (goto-char pos) | 1037 (goto-char (+ pos (cdr old))) |
1031 (forward-line (cdr old)) | |
1032 (if reverse | 1038 (if reverse |
1033 (y-or-n-p | 1039 (y-or-n-p |
1034 "Hunk hasn't been applied yet, so can't reverse it; apply it now? ") | 1040 "Hunk hasn't been applied yet, so can't reverse it; apply it now? ") |
1035 (y-or-n-p "Hunk has already been applied; undo it? ")))) | 1041 (y-or-n-p "Hunk has already been applied; undo it? ")))) |
1036 | 1042 |
1037 nil | 1043 nil |
1038 ;; The user has chosen not to apply the reversed hunk, but we | 1044 ;; The user has chosen not to apply the reversed hunk, but we |
1039 ;; don't want to given an error message, so set things up so | 1045 ;; don't want to given an error message, so set things up so |
1040 ;; nothing else gets done down below | 1046 ;; nothing else gets done down below |
1041 (setq pos nil) | 1047 (setq line-offset nil) |
1042 (message "(Nothing done)") | 1048 (message "(Nothing done)") |
1043 (setq noerror t))) | 1049 (setq noerror t))) |
1044 | 1050 |
1045 (if (null pos) | 1051 (if (null line-offset) |
1046 ;; POS is nil, so we couldn't find the source text. | 1052 ;; LINE-OFFSET is nil, so we couldn't find the source text. |
1047 (unless noerror | 1053 (funcall (if noerror 'message 'error) "Can't find the text to patch") |
1048 (error "Can't find the text to patch")) | |
1049 | 1054 |
1050 (let ((reversed (if switched (not reverse) reverse))) | 1055 (let ((reversed (if switched (not reverse) reverse))) |
1051 (unless dry-run | 1056 (unless dry-run |
1052 ;; Apply the hunk | 1057 ;; Apply the hunk |
1053 (with-current-buffer buf | 1058 (with-current-buffer buf |
1056 (insert (car new)))) | 1061 (insert (car new)))) |
1057 | 1062 |
1058 (when popup | 1063 (when popup |
1059 (with-current-buffer buf | 1064 (with-current-buffer buf |
1060 ;; Show a message describing what was done | 1065 ;; Show a message describing what was done |
1061 (let ((real-line (1+ (count-lines (point-min) pos))) | 1066 (let ((msg |
1062 (msg | |
1063 (if dry-run | 1067 (if dry-run |
1064 (if reversed "already applied" "not yet applied") | 1068 (if reversed "already applied" "not yet applied") |
1065 (if reversed "undone" "applied")))) | 1069 (if reversed "undone" "applied")))) |
1066 (cond ((= real-line patch-line) | 1070 (message (cond ((= line-offset 0) "Hunk %s") |
1067 (message "Hunk %s" msg)) | 1071 ((= line-offset 1) "Hunk %s at offset %d line") |
1068 ((= real-line (1+ patch-line)) | 1072 (t "Hunk %s at offset %d lines")) |
1069 (message "Hunk %s at offset 1 line" msg)) | 1073 msg line-offset)) |
1070 (t | 1074 |
1071 (message "Hunk %s at offset %d lines" | 1075 ;; fixup POS to reflect the hunk char offset |
1072 msg | 1076 (goto-char (+ pos (cdr (if dry-run old new)))) |
1073 (- real-line patch-line))))) | |
1074 | |
1075 ;; fixup POS to reflect the hunk line offset | |
1076 (goto-char pos) | |
1077 (forward-line (cdr (if dry-run old new))) | |
1078 (setq pos (point))) | 1077 (setq pos (point))) |
1079 | 1078 |
1080 ;; Display BUF in a window, and maybe select it | 1079 ;; Display BUF in a window, and maybe select it |
1081 (let ((win (display-buffer buf))) | 1080 (let ((win (display-buffer buf))) |
1082 (set-window-point win pos) | 1081 (set-window-point win pos))) |
1083 (when (eq popup 'select) | |
1084 (select-window win)))) | |
1085 | 1082 |
1086 ;; Return an appropriate indicator of success | 1083 ;; Return an appropriate indicator of success |
1087 (if reversed 'reversed t))))) | 1084 (if reversed 'reversed t))))) |
1088 | 1085 |
1089 | 1086 |
1094 (diff-apply-hunk reverse nil t t)) | 1091 (diff-apply-hunk reverse nil t t)) |
1095 | 1092 |
1096 (defun diff-goto-source (&optional other-file) | 1093 (defun diff-goto-source (&optional other-file) |
1097 "Jump to the corresponding source line. | 1094 "Jump to the corresponding source line. |
1098 `diff-jump-to-old-file-flag' (or its opposite if the OTHER-FILE prefix arg | 1095 `diff-jump-to-old-file-flag' (or its opposite if the OTHER-FILE prefix arg |
1099 is give) determines whether to jump to the old or the new file. | 1096 is given) determines whether to jump to the old or the new file. |
1100 If the prefix arg is bigger than 8 (for example with \\[universal-argument] \\[universal-argument]) | 1097 If the prefix arg is bigger than 8 (for example with \\[universal-argument] \\[universal-argument]) |
1101 then `diff-jump-to-old-file-flag' is also set, for the next invocations." | 1098 then `diff-jump-to-old-file-flag' is also set, for the next invocations." |
1102 (interactive "P") | 1099 (interactive "P") |
1103 (destructuring-bind (buf patch-line pos src &rest ignore) | 1100 (destructuring-bind (buf line-offset pos src dst &optional switched) |
1104 (diff-find-source-location other-file) | 1101 (diff-find-source-location other-file) |
1105 (pop-to-buffer buf) | 1102 (pop-to-buffer buf) |
1106 (if (null pos) | 1103 (goto-char (+ pos (cdr src))) |
1107 (progn | 1104 (if (null line-offset) (message "Hunk text not found")))) |
1108 (goto-line patch-line) | 1105 |
1109 (message "Hunk text not found")) | 1106 (defun diff-current-defun () |
1110 (goto-char pos) | 1107 (destructuring-bind (buf line-offset pos src dst &optional switched) |
1111 (forward-line (cdr src))))) | 1108 (diff-find-source-location) |
1112 | 1109 (save-excursion |
1113 | 1110 (beginning-of-line) |
1111 (or (when (memq (char-after) '(?< ?-)) | |
1112 (let ((old (if switched dst src))) | |
1113 (with-temp-buffer | |
1114 (insert (car old)) | |
1115 (goto-char (cdr old)) | |
1116 (funcall (with-current-buffer buf major-mode)) | |
1117 (add-log-current-defun)))) | |
1118 (with-current-buffer buf | |
1119 (goto-char (+ pos (cdr src))) | |
1120 (add-log-current-defun)))))) | |
1114 | 1121 |
1115 ;; provide the package | 1122 ;; provide the package |
1116 (provide 'diff-mode) | 1123 (provide 'diff-mode) |
1117 | 1124 |
1118 ;;; Old Change Log from when diff-mode wasn't part of Emacs: | 1125 ;;; Old Change Log from when diff-mode wasn't part of Emacs: |