aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorStefan Monnier2000-08-16 19:56:10 +0000
committerStefan Monnier2000-08-16 19:56:10 +0000
commit027ac3f8db2a1837cb53d84130d07d0a7ea4574b (patch)
treefa3b24ccb73b89cdde4d84f6b22840b83e8463a3 /lisp
parent239e21e2242a8883778032d5ad9cfbab0a72cecf (diff)
downloademacs-027ac3f8db2a1837cb53d84130d07d0a7ea4574b.tar.gz
emacs-027ac3f8db2a1837cb53d84130d07d0a7ea4574b.zip
(diff-mode-map): Bind diff-apply-hunk.
(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.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/diff-mode.el219
1 files changed, 130 insertions, 89 deletions
diff --git a/lisp/diff-mode.el b/lisp/diff-mode.el
index 8db4887beb8..1775a0165b3 100644
--- a/lisp/diff-mode.el
+++ b/lisp/diff-mode.el
@@ -4,7 +4,7 @@
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.7 2000/05/10 22:12:46 monnier Exp $ 7;; Revision: $Id: diff-mode.el,v 1.8 2000/06/05 07:30:09 monnier Exp $
8 8
9;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
10 10
@@ -40,21 +40,25 @@
40 40
41;; Bugs: 41;; Bugs:
42 42
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;; - diff-apply-hunk only works on unified diffs.
45 46
46;; Todo: 47;; Todo:
47 48
48;; - spice up the minor-mode with font-lock support 49;; - Add change-log support.
49;; - improve narrowed-view support 50;; - Spice up the minor-mode with font-lock support.
50;; - improve the `compile' support (?) 51;; - Improve narrowed-view support.
51;; - recognize pcl-cvs' special string for `cvs-execute-single' 52;; - Improve the `compile' support (?).
52;; - support for # comments in context->unified 53;; - Recognize pcl-cvs' special string for `cvs-execute-single'.
53;; - diff-apply-hunk 54;; - Support for # comments in context->unified.
54;; - do a fuzzy search in diff-goto-source 55;; - Do a fuzzy search in diff-goto-source.
55;; - allow diff.el to use diff-mode 56;; - Allow diff.el to use diff-mode.
56;; - imenu support 57;; This mostly means ability to jump from half-hunk to half-hunk
57;; - handle `diff -b' output in context->unified 58;; in context (and normal) diffs and to jump to the corresponding
59;; (i.e. new or old) file.
60;; - imenu support.
61;; - Handle `diff -b' output in context->unified.
58 62
59;;; Code: 63;;; Code:
60 64
@@ -93,18 +97,18 @@ when editing big diffs)."
93;;;; 97;;;;
94 98
95(easy-mmode-defmap diff-mode-shared-map 99(easy-mmode-defmap diff-mode-shared-map
96 '(;; from Pavel Machek's patch-mode 100 '(;; From Pavel Machek's patch-mode.
97 ("n" . diff-hunk-next) 101 ("n" . diff-hunk-next)
98 ("N" . diff-file-next) 102 ("N" . diff-file-next)
99 ("p" . diff-hunk-prev) 103 ("p" . diff-hunk-prev)
100 ("P" . diff-file-prev) 104 ("P" . diff-file-prev)
101 ("k" . diff-hunk-kill) 105 ("k" . diff-hunk-kill)
102 ("K" . diff-file-kill) 106 ("K" . diff-file-kill)
103 ;; from compilation-minor-mode 107 ;; From compilation-minor-mode.
104 ("}" . diff-file-next) 108 ("}" . diff-file-next)
105 ("{" . diff-file-prev) 109 ("{" . diff-file-prev)
106 ("\C-m" . diff-goto-source) 110 ("\C-m" . diff-goto-source)
107 ;; from XEmacs' diff-mode 111 ;; From XEmacs' diff-mode.
108 ("W" . widen) 112 ("W" . widen)
109 ;;("." . diff-goto-source) ;display-buffer 113 ;;("." . diff-goto-source) ;display-buffer
110 ;;("f" . diff-goto-source) ;find-file 114 ;;("f" . diff-goto-source) ;find-file
@@ -116,7 +120,7 @@ when editing big diffs)."
116 ;;("q" . diff-quit) 120 ;;("q" . diff-quit)
117 (" " . scroll-up) 121 (" " . scroll-up)
118 ("\177" . scroll-down) 122 ("\177" . scroll-down)
119 ;; our very own bindings 123 ;; Our very own bindings.
120 ("A" . diff-ediff-patch) 124 ("A" . diff-ediff-patch)
121 ("r" . diff-restrict-view) 125 ("r" . diff-restrict-view)
122 ("R" . diff-reverse-direction) 126 ("R" . diff-reverse-direction)
@@ -126,8 +130,10 @@ when editing big diffs)."
126 130
127(easy-mmode-defmap diff-mode-map 131(easy-mmode-defmap diff-mode-map
128 `(("\e" . ,diff-mode-shared-map) 132 `(("\e" . ,diff-mode-shared-map)
129 ;; from compilation-minor-mode 133 ;; From compilation-minor-mode.
130 ("\C-c\C-c" . diff-goto-source)) 134 ("\C-c\C-c" . diff-goto-source)
135 ;; Misc operations.
136 ("\C-cda" . diff-apply-hunk))
131 "Keymap for `diff-mode'. See also `diff-mode-shared-map'.") 137 "Keymap for `diff-mode'. See also `diff-mode-shared-map'.")
132 138
133(easy-menu-define diff-mode-menu diff-mode-map 139(easy-menu-define diff-mode-menu diff-mode-map
@@ -420,42 +426,51 @@ Non-nil OLD means that we want the old file."
420 (cons (cons fs file) diff-remembered-files-alist)) 426 (cons (cons fs file) diff-remembered-files-alist))
421 file))))) 427 file)))))
422 428
429(defun diff-find-source-location (&optional other-file)
430 "Find out (FILE LINE SPAN)."
431 (save-excursion
432 (diff-beginning-of-hunk)
433 (let* ((old (if (not other-file) diff-jump-to-old-file-flag
434 (not diff-jump-to-old-file-flag)))
435 ;; Find the location specification.
436 (loc (if (not (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?"))
437 (error "Can't find the hunk header")
438 (if old (match-string 1)
439 (if (match-end 3) (match-string 3)
440 (unless (re-search-forward "^--- \\([0-9,]+\\)" nil t)
441 (error "Can't find the hunk separator"))
442 (match-string 1)))))
443 ;; Extract the actual line number.
444 (lines (if (string-match "^\\([0-9]*\\),\\([0-9]*\\)" loc)
445 (cons (string-to-number (match-string 1 loc))
446 (string-to-number (match-string 2 loc)))
447 (cons (string-to-number loc) nil)))
448 (file (diff-find-file-name old))
449 (line (car lines))
450 (span (if (or (null (cdr lines)) (< (cdr lines) 0)) 0
451 ;; Bad hack.
452 (if (< (cdr lines) line) (cdr lines)
453 (- (cdr lines) line)))))
454 ;; Update the user preference if he so wished.
455 (when (> (prefix-numeric-value other-file) 8)
456 (setq diff-jump-to-old-file-flag old))
457 (if (null file) (error "Can't find the file")
458 (list file line span)))))
459
423(defun diff-goto-source (&optional other-file) 460(defun diff-goto-source (&optional other-file)
424 "Jump to the corresponding source line. 461 "Jump to the corresponding source line.
425`diff-jump-to-old-file-flag' (or its opposite if the OTHER-FILE prefix arg 462`diff-jump-to-old-file-flag' (or its opposite if the OTHER-FILE prefix arg
426is give) determines whether to jump to the old or the new file. 463is give) determines whether to jump to the old or the new file.
427If the prefix arg is bigger than 8 (for example with \\[universal-argument] \\[universal-argument]) 464If the prefix arg is bigger than 8 (for example with \\[universal-argument] \\[universal-argument])
428 then `diff-jump-to-old-file-flag' is also set, for the next invokations." 465 then `diff-jump-to-old-file-flag' is also set, for the next invocations."
429 (interactive "P") 466 (interactive "P")
430 (save-excursion 467 (save-excursion
431 (let ((old (if (not other-file) diff-jump-to-old-file-flag 468 (let ((loc (diff-find-source-location other-file)))
432 (not diff-jump-to-old-file-flag)))) 469 (pop-to-buffer (find-file-noselect (car loc)))
433 (when (> (prefix-numeric-value other-file) 8) 470 (ignore-errors
434 (setq diff-jump-to-old-file-flag old)) 471 (goto-line (+ (cadr loc) (caddr loc)))
435 (diff-beginning-of-hunk) 472 (push-mark (point) t t)
436 (let* ((loc (if (not (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?")) 473 (goto-line (cadr loc))))))
437 (error "Can't find the hunk header")
438 (if old (match-string 1)
439 (if (match-end 3) (match-string 3)
440 (unless (re-search-forward "^--- \\([0-9,]+\\)" nil t)
441 (error "Can't find the hunk separator"))
442 (match-string 1)))))
443 (lines (if (string-match "^\\([0-9]*\\),\\([0-9]*\\)" loc)
444 (cons (string-to-number (match-string 1 loc))
445 (string-to-number (match-string 2 loc)))
446 (cons (string-to-number loc) nil)))
447 (file (diff-find-file-name old)))
448 (unless file (error "Can't find the file"))
449 (pop-to-buffer (find-file-noselect file))
450 (let* ((line (car lines))
451 (span (if (or (null (cdr lines)) (< (cdr lines) 0)) 0
452 (if (< (cdr lines) line) (cdr lines)
453 (- (cdr lines) line)))))
454 (ignore-errors
455 (goto-line line)
456 (forward-line span)
457 (push-mark (point) t t)
458 (goto-line line)))))))
459 474
460 475
461(defun diff-ediff-patch () 476(defun diff-ediff-patch ()
@@ -836,50 +851,76 @@ This mode runs `diff-mode-hook'.
836 'diff-post-command-hook nil t))) 851 'diff-post-command-hook nil t)))
837 852
838 853
854;;;
855;;; Misc operations that have proved useful at some point.
856;;;
857
858(defun diff-next-complex-hunk ()
859 "Jump to the next \"complex\" hunk.
860\"Complex\" is approximated by \"the hunk changes the number of lines\".
861Only works for unified diffs."
862 (interactive)
863 (while
864 (and (re-search-forward "^@@ [-0-9]+,\\([0-9]+\\) [+0-9]+,\\([0-9]+\\) @@"
865 nil t)
866 (equal (match-string 1) (match-string 2)))))
867
868
869(defun diff-filter-lines (char)
870 (goto-char (point-min))
871 (while (not (eobp))
872 (if (eq (char-after) char)
873 (delete-region (point) (progn (forward-line 1) (point)))
874 (delete-char 1)
875 (forward-line 1))))
876
877(defun diff-apply-hunk (&optional reverse)
878 "Apply the current hunk.
879With a prefix argument, REVERSE the hunk.
880FIXME: Only works for unified diffs."
881 (interactive "P")
882 (save-excursion
883 (let ((loc (diff-find-source-location nil)))
884 (diff-beginning-of-hunk)
885 (unless (looking-at diff-hunk-header-re) (error "Help! Mom!"))
886 (goto-char (1+ (match-end 0)))
887 ;; Extract the SRC and DEST strings.
888 (let ((text (buffer-substring (point) (progn (diff-end-of-hunk) (point))))
889 src dest)
890 (with-temp-buffer
891 (insert text)
892 (diff-filter-lines ?+)
893 (setq src (buffer-string))
894 (erase-buffer)
895 (insert text)
896 (diff-filter-lines ?-)
897 (setq dest (buffer-string)))
898 ;; Exchange the two strings if we're reversing the patch.
899 (if reverse (let ((tmp src)) (setq src dest) (setq dest tmp)))
900 ;; Look for SRC in the file.
901 (pop-to-buffer (find-file-noselect (car loc)))
902 (goto-line (cadr loc))
903 (let* ((pos (point))
904 (forw (and (search-forward src nil t)
905 (match-beginning 0)))
906 (back (and (goto-char (+ pos (length src)))
907 (search-backward src nil t)
908 (match-beginning 0))))
909 ;; Choose the closest match.
910 (setq pos (if (and forw back)
911 (if (> (- forw pos) (- pos back)) back forw)
912 (or back forw)))
913 (unless pos (error "Can't find the text to patch"))
914 ;; Do it!
915 (goto-char pos)
916 (delete-char (length src))
917 (insert dest))))))
918
919
839;; provide the package 920;; provide the package
840(provide 'diff-mode) 921(provide 'diff-mode)
841 922
842;;; Change Log: 923;;; Old Change Log from when diff-mode wasn't part of Emacs:
843;; $Log: diff-mode.el,v $
844;; Revision 1.7 2000/05/10 22:12:46 monnier
845;; (diff-font-lock-keywords): Recognize comments.
846;; (diff-font-lock-defaults): Explicitly turn off multiline.
847;; (diff-end-of-hunk): Handle comments and fix end-of-buffer bug.
848;; (diff-ediff-patch): Fix call to ediff-patch-file.
849;; (diff-end-of-file, diff-reverse-direction, diff-fixup-modifs):
850;; Handle comments.
851;;
852;; Revision 1.6 2000/03/21 16:59:17 monnier
853;; (diff-mode-*-map): use `easy-mmode-defmap'.
854;; (diff-end-of-hunk): Return the end position for use in
855;; `easy-mmode-define-navigation'.
856;; (diff-recenter): Remove.
857;; (diff-(next|prev)-*): Rename `diff-*-(prev|next)' and defined in terms
858;; of `easy-mmode-define-navigation'.
859;; (diff-kill-*): Rename `diff-*-kill' (for consistency with the
860;; previous renaming) and fix to use new names.
861;; (diff-merge-strings): Use \n as separator: simpler, faster.
862;; (diff-mode): Use `define-derived-mode'.
863;;
864;; Revision 1.5 2000/02/07 02:01:07 monnier
865;; (diff-kill-junk): New interactive function.
866;; (diff-reverse-direction): Use delete-and-extract-region.
867;; (diff-post-command-hook): Restrict the area so that the hook also works
868;; outside of any diff hunk. This is necessary for the minor-mode.
869;; (diff-mode): Use toggle-read-only and minor-mode-overriding-map-alist.
870;; (diff-minor-mode): Setup the hooks for header-hunk rewriting.
871;;
872;; Revision 1.4 1999/12/07 07:04:03 monnier
873;; * diff-mode.el (diff-mode-shared-map): fset'd and doc change.
874;; (diff-minor-mode, diff-minor-mode-prefix, diff-minor-mode-map):
875;; New code to support the minor mode version.
876;; (diff-recenter): New function.
877;; (diff-next-hunk, diff-next-file): Use it.
878;; (diff-remembered-files-alist): New var.
879;; (diff-merge-strings): New function.
880;; (diff-find-file-name): Make it smarter and use the user's input more.
881;; (diff-mode): Cosmetic changes.
882;;
883;; Revision 1.11 1999/10/09 23:38:29 monnier 924;; Revision 1.11 1999/10/09 23:38:29 monnier
884;; (diff-mode-load-hook): dropped. 925;; (diff-mode-load-hook): dropped.
885;; (auto-mode-alist): also catch *.diffs. 926;; (auto-mode-alist): also catch *.diffs.