aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/diff-mode.el
diff options
context:
space:
mode:
authorStefan Monnier1999-12-07 07:04:03 +0000
committerStefan Monnier1999-12-07 07:04:03 +0000
commit0b82e382e320f9e0d3be725b3a5e9b6cd2bf03d2 (patch)
tree63c2d9da72da848a22dc1b7faeb11d6135d80c5e /lisp/diff-mode.el
parent01e924b8c772e17333b2d6a3ab241d19a8748cff (diff)
downloademacs-0b82e382e320f9e0d3be725b3a5e9b6cd2bf03d2.tar.gz
emacs-0b82e382e320f9e0d3be725b3a5e9b6cd2bf03d2.zip
* 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.
Diffstat (limited to 'lisp/diff-mode.el')
-rw-r--r--lisp/diff-mode.el126
1 files changed, 93 insertions, 33 deletions
diff --git a/lisp/diff-mode.el b/lisp/diff-mode.el
index 852737742dd..2c0553efcc2 100644
--- a/lisp/diff-mode.el
+++ b/lisp/diff-mode.el
@@ -4,8 +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;; Version: v1_8 7;; Revision: $Id$
8;; Revision: diff-mode.el,v 1.11 1999/10/09 23:38:29 monnier Exp
9 8
10;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
11 10
@@ -30,8 +29,6 @@
30;; commands, editing and various conversions as well as jumping 29;; commands, editing and various conversions as well as jumping
31;; to the corresponding source file. 30;; to the corresponding source file.
32 31
33;; History:
34
35;; inspired by Pavel Machek's patch-mode.el (<pavel@atrey.karlin.mff.cuni.cz>) 32;; inspired by Pavel Machek's patch-mode.el (<pavel@atrey.karlin.mff.cuni.cz>)
36;; some efforts were spent to have it somewhat compatible with XEmacs' 33;; some efforts were spent to have it somewhat compatible with XEmacs'
37;; diff-mode as well as with compilation-minor-mode 34;; diff-mode as well as with compilation-minor-mode
@@ -48,9 +45,10 @@
48 45
49;; Todo: 46;; Todo:
50 47
48;; - spice up the minor-mode with editing and font-lock support.
51;; - improve narrowed-view support. 49;; - improve narrowed-view support.
52;; - improve diff-find-file-name. 50;; - improve the `compile' support (?).
53;; - improve the `compile' support. 51;; - recognize pcl-cvs' special string for `cvs-execute-single'.
54 52
55;;; Code: 53;;; Code:
56 54
@@ -110,6 +108,7 @@ when editing big diffs)."
110 ("\C-m" . diff-goto-source) 108 ("\C-m" . diff-goto-source)
111 ;; from XEmacs' diff-mode 109 ;; from XEmacs' diff-mode
112 ("W" . widen) 110 ("W" . widen)
111 ;;("\C-l" . diff-recenter)
113 ;;("." . diff-goto-source) ;display-buffer 112 ;;("." . diff-goto-source) ;display-buffer
114 ;;("f" . diff-goto-source) ;find-file 113 ;;("f" . diff-goto-source) ;find-file
115 ("o" . diff-goto-source) ;other-window 114 ("o" . diff-goto-source) ;other-window
@@ -126,7 +125,8 @@ when editing big diffs)."
126 ("R" . diff-reverse-direction) 125 ("R" . diff-reverse-direction)
127 ("U" . diff-context->unified) 126 ("U" . diff-context->unified)
128 ("C" . diff-unified->context)) 127 ("C" . diff-unified->context))
129 "Keymap for read-only `diff-mode'. Only active in read-only mode.") 128 "Basic keymap for `diff-mode', bound to various prefix keys.")
129(fset 'diff-mode-shared-map diff-mode-shared-map)
130 130
131(diff-defmap diff-mode-map 131(diff-defmap diff-mode-map
132 `(("\e" . ,diff-mode-shared-map) 132 `(("\e" . ,diff-mode-shared-map)
@@ -146,6 +146,15 @@ when editing big diffs)."
146 ;;["Fixup Headers" diff-fixup-modifs (not buffer-read-only)] 146 ;;["Fixup Headers" diff-fixup-modifs (not buffer-read-only)]
147 )) 147 ))
148 148
149(defcustom diff-minor-mode-prefix "\C-cd"
150 "Prefix key for `diff-minor-mode' commands."
151 :group 'diff-mode
152 :type '(choice (string "\e") (string "C-cd") string))
153
154(diff-defmap diff-minor-mode-map
155 `((,diff-minor-mode-prefix . diff-mode-shared-map))
156 "Keymap for `diff-minor-mode'. See also `diff-mode-shared-map'.")
157
149 158
150;;;; 159;;;;
151;;;; font-lock support 160;;;; font-lock support
@@ -259,6 +268,17 @@ when editing big diffs)."
259 (re-search-forward "^[^-+!<>0-9@* \\]" nil 'move) 268 (re-search-forward "^[^-+!<>0-9@* \\]" nil 'move)
260 (beginning-of-line)) 269 (beginning-of-line))
261 270
271(defun diff-recenter ()
272 "Scroll if necessary to display the current hunk."
273 (interactive)
274 (when (eq (current-buffer) (window-buffer (selected-window)))
275 (let ((endpt (save-excursion (diff-end-of-hunk) (point))))
276 (unless (<= endpt (window-end))
277 (recenter)
278 ;;(unless (<= endpt (window-end nil t))
279 ;; (set-window-start (selected-window) (point)))
280 ))))
281
262(defun diff-next-hunk (&optional count) 282(defun diff-next-hunk (&optional count)
263 "Move to next (COUNT'th) hunk." 283 "Move to next (COUNT'th) hunk."
264 (interactive "p") 284 (interactive "p")
@@ -268,7 +288,8 @@ when editing big diffs)."
268 (condition-case () 288 (condition-case ()
269 (re-search-forward diff-hunk-header-re nil nil count) 289 (re-search-forward diff-hunk-header-re nil nil count)
270 (error (error "Can't find next hunk"))) 290 (error (error "Can't find next hunk")))
271 (goto-char (match-beginning 0)))) 291 (goto-char (match-beginning 0))
292 (diff-recenter)))
272 293
273(defun diff-prev-hunk (&optional count) 294(defun diff-prev-hunk (&optional count)
274 "Move to previous (COUNT'th) hunk." 295 "Move to previous (COUNT'th) hunk."
@@ -288,7 +309,8 @@ when editing big diffs)."
288 (condition-case () 309 (condition-case ()
289 (re-search-forward diff-file-header-re nil nil count) 310 (re-search-forward diff-file-header-re nil nil count)
290 (error (error "Can't find next file"))) 311 (error (error "Can't find next file")))
291 (goto-char (match-beginning 0)))) 312 (goto-char (match-beginning 0))
313 (diff-recenter)))
292 314
293(defun diff-prev-file (&optional count) 315(defun diff-prev-file (&optional count)
294 "Move to (COUNT'th) previous file header." 316 "Move to (COUNT'th) previous file header."
@@ -351,9 +373,34 @@ If the prefix ARG is given, restrict the view to the current file instead."
351;;;; jump to other buffers 373;;;; jump to other buffers
352;;;; 374;;;;
353 375
376(defvar diff-remembered-files-alist nil)
377
354(defun diff-filename-drop-dir (file) 378(defun diff-filename-drop-dir (file)
355 (when (string-match "/" file) (substring file (match-end 0)))) 379 (when (string-match "/" file) (substring file (match-end 0))))
356 380
381(defun diff-merge-strings (ancestor from to)
382 "Merge the diff between ANCESTOR and FROM into TO.
383Returns the merged string if successful or nil otherwise.
384If ANCESTOR = FROM, returns TO.
385If ANCESTOR = TO, returns FROM.
386The heuristic is simplistic and only really works for cases
387like \(diff-merge-strings \"b/foo\" \"b/bar\" \"/a/c/foo\")."
388 ;; Ideally, we want:
389 ;; AMB ANB CMD -> CND
390 ;; but that's ambiguous if `foo' or `bar' is empty:
391 ;; a/foo a/foo1 b/foo.c -> b/foo1.c but not 1b/foo.c or b/foo.c1
392 (let ((str (concat ancestor " /|/ " from " /|/ " to)))
393 (when (and (string-match (concat
394 "\\`\\(.*?\\)\\(.*\\)\\(.*\\) /|/ "
395 "\\1\\(.*\\)\\3 /|/ "
396 "\\(.*\\(\\2\\).*\\)\\'") str)
397 (equal to (match-string 5 str)))
398 (concat (substring str (match-beginning 5) (match-beginning 6))
399 (match-string 4 str)
400 (substring str (match-end 6) (match-end 5))))))
401
402
403
357(defun diff-find-file-name (&optional old) 404(defun diff-find-file-name (&optional old)
358 "Return the file corresponding to the current patch. 405 "Return the file corresponding to the current patch.
359Non-nil OLD means that we want the old file." 406Non-nil OLD means that we want the old file."
@@ -378,26 +425,33 @@ Non-nil OLD means that we want the old file."
378 (when (re-search-backward "^diff \\(-\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?" nil t) 425 (when (re-search-backward "^diff \\(-\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?" nil t)
379 (list (if old (match-string 2) (match-string 4)) 426 (list (if old (match-string 2) (match-string 4))
380 (if old (match-string 4) (match-string 2)))))) 427 (if old (match-string 4) (match-string 2))))))
381 (fs (delq nil fs)) 428 (fs (delq nil fs)))
382 (file
383 ;; look for each file in turn. If none found, try again but
384 ;; ignoring the first level of directory, ...
385 (do* ((files fs (delq nil (mapcar 'diff-filename-drop-dir files)))
386 (file nil nil))
387 ((or (null files)
388 (setq file (do* ((files files (cdr files))
389 (file (car files) (car files)))
390 ((or (null file) (file-exists-p file))
391 file))))
392 file))))
393 (or 429 (or
394 file 430 ;; use any previously used preference
431 (cdr (assoc fs diff-remembered-files-alist))
432 ;; try to be clever and use previous choices as an inspiration
433 (dolist (rf diff-remembered-files-alist)
434 (let ((newfile (diff-merge-strings (caar rf) (car fs) (cdr rf))))
435 (if (and newfile (file-exists-p newfile)) (return newfile))))
436 ;; look for each file in turn. If none found, try again but
437 ;; ignoring the first level of directory, ...
438 (do* ((files fs (delq nil (mapcar 'diff-filename-drop-dir files)))
439 (file nil nil))
440 ((or (null files)
441 (setq file (do* ((files files (cdr files))
442 (file (car files) (car files)))
443 ((or (null file) (file-exists-p file))
444 file))))
445 file))
446 ;; <foo>.rej patches implicitly apply to <foo>
395 (and (string-match "\\.rej\\'" (or buffer-file-name "")) 447 (and (string-match "\\.rej\\'" (or buffer-file-name ""))
396 (let ((file (substring buffer-file-name 0 (match-beginning 0)))) 448 (let ((file (substring buffer-file-name 0 (match-beginning 0))))
397 (when (file-exists-p file) file))) 449 (when (file-exists-p file) file)))
398 ;; FIXME: use a more informative prompt 450 ;; if all else fails, ask the user
399 (let ((file (read-file-name "File: " nil (first fs) nil (first fs)))) 451 (let ((file (read-file-name (format "Use file %s: " (or (first fs) ""))
400 ;; FIXME: remember for the next invocation 452 nil (first fs) t (first fs))))
453 (set (make-local-variable 'diff-remembered-files-alist)
454 (cons (cons fs file) diff-remembered-files-alist))
401 file))))) 455 file)))))
402 456
403(defun diff-goto-source (&optional other-file) 457(defun diff-goto-source (&optional other-file)
@@ -760,10 +814,9 @@ See `after-change-functions' for the meaning of BEG, END and LEN."
760;;;; The main function 814;;;; The main function
761;;;; 815;;;;
762 816
763;;(autoload 'diff-mode "diff-mode" "Major mode for viewing context diffs." t)
764;;;###autoload 817;;;###autoload
765(defun diff-mode () 818(defun diff-mode ()
766 "Major mode for viewing context diffs. 819 "Major mode for viewing/editing context diffs.
767Supports unified and context diffs as well as (to a lesser extent) normal diffs. 820Supports unified and context diffs as well as (to a lesser extent) normal diffs.
768When the buffer is read-only, the ESC prefix is not necessary. 821When the buffer is read-only, the ESC prefix is not necessary.
769This mode runs `diff-mode-hook'. 822This mode runs `diff-mode-hook'.
@@ -789,10 +842,10 @@ This mode runs `diff-mode-hook'.
789 (if (not diff-update-on-the-fly-flag) 842 (if (not diff-update-on-the-fly-flag)
790 (add-hook 'write-contents-hooks 'diff-write-contents-hooks) 843 (add-hook 'write-contents-hooks 'diff-write-contents-hooks)
791 (make-local-variable 'diff-unhandled-changes) 844 (make-local-variable 'diff-unhandled-changes)
792 (make-local-hook 'after-change-functions) 845 (add-hook (make-local-hook 'after-change-functions)
793 (add-hook 'after-change-functions 'diff-after-change-function nil t) 846 'diff-after-change-function nil t)
794 (make-local-hook 'post-command-hook) 847 (add-hook (make-local-hook 'post-command-hook)
795 (add-hook 'post-command-hook 'diff-post-command-hook nil t)) 848 'diff-post-command-hook nil t))
796 ;; Neat trick from Dave Love to add more bindings in read-only mode: 849 ;; Neat trick from Dave Love to add more bindings in read-only mode:
797 (add-to-list (make-local-variable 'minor-mode-map-alist) 850 (add-to-list (make-local-variable 'minor-mode-map-alist)
798 (cons 'buffer-read-only diff-mode-shared-map)) 851 (cons 'buffer-read-only diff-mode-shared-map))
@@ -800,13 +853,20 @@ This mode runs `diff-mode-hook'.
800 (run-hooks 'diff-mode-hook)) 853 (run-hooks 'diff-mode-hook))
801 854
802;;;###autoload 855;;;###autoload
803(add-to-list 'auto-mode-alist '("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)) 856(define-minor-mode diff-minor-mode
857 "Minor mode for viewing/editing context diffs.
858\\{diff-minor-mode-map}"
859 nil " Diff" nil
860 ;; FIXME: setup font-lock
861 ;; FIXME: setup change hooks
862 )
863
804 864
805;; provide the package 865;; provide the package
806(provide 'diff-mode) 866(provide 'diff-mode)
807 867
808;;; Change Log: 868;;; Change Log:
809;; diff-mode.el,v 869;; $Log: diff-mode.el,v $
810;; Revision 1.11 1999/10/09 23:38:29 monnier 870;; Revision 1.11 1999/10/09 23:38:29 monnier
811;; (diff-mode-load-hook): dropped. 871;; (diff-mode-load-hook): dropped.
812;; (auto-mode-alist): also catch *.diffs. 872;; (auto-mode-alist): also catch *.diffs.