]> git.eshelyaron.com Git - emacs.git/commitdiff
* diff-mode.el (diff-mode-shared-map): fset'd and doc change.
authorStefan Monnier <monnier@iro.umontreal.ca>
Tue, 7 Dec 1999 07:04:03 +0000 (07:04 +0000)
committerStefan Monnier <monnier@iro.umontreal.ca>
Tue, 7 Dec 1999 07:04:03 +0000 (07:04 +0000)
(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.

lisp/ChangeLog
lisp/diff-mode.el

index a054c3b8b7c50795809d1bb295dc31535a836dd3..a897f0bed96fb95f680a410303e6160a21c8a69f 100644 (file)
@@ -1,5 +1,15 @@
 1999-12-07  Stefan Monnier  <monnier@cs.yale.edu>
 
+       * 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.
+
        * files.el (save-some-buffers): Turn EXITING into the more general
        PRED argument to allow specifying a subset of buffers.
 
index 852737742dd811f2cb1bc6f9611a24dd7908fa23..2c0553efcc2074d11bea480b6c1a5c5dad5bc4de 100644 (file)
@@ -4,8 +4,7 @@
 
 ;; Author: Stefan Monnier <monnier@cs.yale.edu>
 ;; Keywords: patch diff
-;; Version: v1_8
-;; Revision: diff-mode.el,v 1.11 1999/10/09 23:38:29 monnier Exp
+;; Revision: $Id$
 
 ;; This file is part of GNU Emacs.
 
@@ -30,8 +29,6 @@
 ;; commands, editing and various conversions as well as jumping
 ;; to the corresponding source file.
 
-;; History:
-
 ;; inspired by Pavel Machek's patch-mode.el (<pavel@atrey.karlin.mff.cuni.cz>)
 ;; some efforts were spent to have it somewhat compatible with XEmacs'
 ;; diff-mode as well as with compilation-minor-mode
 
 ;; Todo:
 
+;; - spice up the minor-mode with editing and font-lock support.
 ;; - improve narrowed-view support.
-;; - improve diff-find-file-name.
-;; - improve the `compile' support.
+;; - improve the `compile' support (?).
+;; - recognize pcl-cvs' special string for `cvs-execute-single'.
 
 ;;; Code:
 
@@ -110,6 +108,7 @@ when editing big diffs)."
     ("\C-m" . diff-goto-source)
     ;; from XEmacs' diff-mode
     ("W" . widen)
+    ;;("\C-l" . diff-recenter)
     ;;("." . diff-goto-source)         ;display-buffer
     ;;("f" . diff-goto-source)         ;find-file
     ("o" . diff-goto-source)           ;other-window
@@ -126,7 +125,8 @@ when editing big diffs)."
     ("R" . diff-reverse-direction)
     ("U" . diff-context->unified)
     ("C" . diff-unified->context))
-  "Keymap for read-only `diff-mode'. Only active in read-only mode.")
+  "Basic keymap for `diff-mode', bound to various prefix keys.")
+(fset 'diff-mode-shared-map diff-mode-shared-map)
 
 (diff-defmap diff-mode-map
   `(("\e" . ,diff-mode-shared-map)
@@ -146,6 +146,15 @@ when editing big diffs)."
     ;;["Fixup Headers"         diff-fixup-modifs       (not buffer-read-only)]
     ))
 
+(defcustom diff-minor-mode-prefix "\C-cd"
+  "Prefix key for `diff-minor-mode' commands."
+  :group 'diff-mode
+  :type '(choice (string "\e") (string "C-cd") string))
+
+(diff-defmap diff-minor-mode-map
+  `((,diff-minor-mode-prefix . diff-mode-shared-map))
+  "Keymap for `diff-minor-mode'.  See also `diff-mode-shared-map'.")
+
 
 ;;;; 
 ;;;; font-lock support
@@ -259,6 +268,17 @@ when editing big diffs)."
   (re-search-forward "^[^-+!<>0-9@* \\]" nil 'move)
   (beginning-of-line))
 
+(defun diff-recenter ()
+  "Scroll if necessary to display the current hunk."
+  (interactive)
+  (when (eq (current-buffer) (window-buffer (selected-window)))
+    (let ((endpt (save-excursion (diff-end-of-hunk) (point))))
+      (unless (<= endpt (window-end))
+       (recenter)
+       ;;(unless (<= endpt (window-end nil t))
+       ;;  (set-window-start (selected-window) (point)))
+       ))))
+
 (defun diff-next-hunk (&optional count)
   "Move to next (COUNT'th) hunk."
   (interactive "p")
@@ -268,7 +288,8 @@ when editing big diffs)."
     (condition-case ()
        (re-search-forward diff-hunk-header-re nil nil count)
       (error (error "Can't find next hunk")))
-    (goto-char (match-beginning 0))))
+    (goto-char (match-beginning 0))
+    (diff-recenter)))
 
 (defun diff-prev-hunk (&optional count)
   "Move to previous (COUNT'th) hunk."
@@ -288,7 +309,8 @@ when editing big diffs)."
     (condition-case ()
        (re-search-forward diff-file-header-re nil nil count)
       (error (error "Can't find next file")))
-    (goto-char (match-beginning 0))))
+    (goto-char (match-beginning 0))
+    (diff-recenter)))
 
 (defun diff-prev-file (&optional count)
   "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."
 ;;;; jump to other buffers
 ;;;;
 
+(defvar diff-remembered-files-alist nil)
+
 (defun diff-filename-drop-dir (file)
   (when (string-match "/" file) (substring file (match-end 0))))
 
+(defun diff-merge-strings (ancestor from to)
+  "Merge the diff between ANCESTOR and FROM into TO.
+Returns the merged string if successful or nil otherwise.
+If ANCESTOR = FROM, returns TO.
+If ANCESTOR = TO, returns FROM.
+The heuristic is simplistic and only really works for cases
+like \(diff-merge-strings \"b/foo\" \"b/bar\" \"/a/c/foo\")."
+  ;; Ideally, we want:
+  ;;   AMB ANB CMD -> CND
+  ;; but that's ambiguous if `foo' or `bar' is empty:
+  ;; a/foo a/foo1 b/foo.c -> b/foo1.c but not 1b/foo.c or b/foo.c1
+  (let ((str (concat ancestor " /|/ " from " /|/ " to)))
+    (when (and (string-match (concat
+                             "\\`\\(.*?\\)\\(.*\\)\\(.*\\) /|/ "
+                             "\\1\\(.*\\)\\3 /|/ "
+                             "\\(.*\\(\\2\\).*\\)\\'") str)
+              (equal to (match-string 5 str)))
+      (concat (substring str (match-beginning 5) (match-beginning 6))
+             (match-string 4 str)
+             (substring str (match-end 6) (match-end 5))))))
+
+
+
 (defun diff-find-file-name (&optional old)
   "Return the file corresponding to the current patch.
 Non-nil OLD means that we want the old file."
@@ -378,26 +425,33 @@ Non-nil OLD means that we want the old file."
                (when (re-search-backward "^diff \\(-\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?" nil t)
                  (list (if old (match-string 2) (match-string 4))
                        (if old (match-string 4) (match-string 2))))))
-          (fs (delq nil fs))
-          (file
-           ;; look for each file in turn.  If none found, try again but
-           ;; ignoring the first level of directory, ...
-           (do* ((files fs (delq nil (mapcar 'diff-filename-drop-dir files)))
-                 (file nil nil))
-               ((or (null files)
-                    (setq file (do* ((files files (cdr files))
-                                     (file (car files) (car files)))
-                                   ((or (null file) (file-exists-p file))
-                                    file))))
-                file))))
+          (fs (delq nil fs)))
       (or
-       file
+       ;; use any previously used preference
+       (cdr (assoc fs diff-remembered-files-alist))
+       ;; try to be clever and use previous choices as an inspiration
+       (dolist (rf diff-remembered-files-alist)
+        (let ((newfile (diff-merge-strings (caar rf) (car fs) (cdr rf))))
+          (if (and newfile (file-exists-p newfile)) (return newfile))))
+       ;; look for each file in turn.  If none found, try again but
+       ;; ignoring the first level of directory, ...
+       (do* ((files fs (delq nil (mapcar 'diff-filename-drop-dir files)))
+            (file nil nil))
+          ((or (null files)
+               (setq file (do* ((files files (cdr files))
+                                (file (car files) (car files)))
+                              ((or (null file) (file-exists-p file))
+                               file))))
+           file))
+       ;; <foo>.rej patches implicitly apply to <foo>
        (and (string-match "\\.rej\\'" (or buffer-file-name ""))
            (let ((file (substring buffer-file-name 0 (match-beginning 0))))
              (when (file-exists-p file) file)))
-       ;; FIXME: use a more informative prompt
-       (let ((file (read-file-name "File: " nil (first fs) nil (first fs))))
-        ;; FIXME: remember for the next invocation
+       ;; if all else fails, ask the user
+       (let ((file (read-file-name (format "Use file %s: " (or (first fs) ""))
+                                  nil (first fs) t (first fs))))
+        (set (make-local-variable 'diff-remembered-files-alist)
+             (cons (cons fs file) diff-remembered-files-alist))
         file)))))
 
 (defun diff-goto-source (&optional other-file)
@@ -760,10 +814,9 @@ See `after-change-functions' for the meaning of BEG, END and LEN."
 ;;;; The main function
 ;;;; 
 
-;;(autoload 'diff-mode "diff-mode" "Major mode for viewing context diffs." t)
 ;;;###autoload
 (defun diff-mode ()
-  "Major mode for viewing context diffs.
+  "Major mode for viewing/editing context diffs.
 Supports unified and context diffs as well as (to a lesser extent) normal diffs.
 When the buffer is read-only, the ESC prefix is not necessary.
 This mode runs `diff-mode-hook'.
@@ -789,10 +842,10 @@ This mode runs `diff-mode-hook'.
   (if (not diff-update-on-the-fly-flag)
       (add-hook 'write-contents-hooks 'diff-write-contents-hooks)
     (make-local-variable 'diff-unhandled-changes)
-    (make-local-hook 'after-change-functions)
-    (add-hook 'after-change-functions 'diff-after-change-function nil t)
-    (make-local-hook 'post-command-hook)
-    (add-hook 'post-command-hook 'diff-post-command-hook nil t))
+    (add-hook (make-local-hook 'after-change-functions)
+             'diff-after-change-function nil t)
+    (add-hook (make-local-hook 'post-command-hook)
+             'diff-post-command-hook nil t))
   ;; Neat trick from Dave Love to add more bindings in read-only mode:
   (add-to-list (make-local-variable 'minor-mode-map-alist)
               (cons 'buffer-read-only diff-mode-shared-map))
@@ -800,13 +853,20 @@ This mode runs `diff-mode-hook'.
   (run-hooks 'diff-mode-hook))
 
 ;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode))
+(define-minor-mode diff-minor-mode
+  "Minor mode for viewing/editing context diffs.
+\\{diff-minor-mode-map}"
+  nil " Diff" nil
+  ;; FIXME: setup font-lock
+  ;; FIXME: setup change hooks
+  )
+
 
 ;; provide the package
 (provide 'diff-mode)
 
 ;;; Change Log:
-;; diff-mode.el,v
+;; $Log: diff-mode.el,v $
 ;; Revision 1.11  1999/10/09 23:38:29  monnier
 ;; (diff-mode-load-hook): dropped.
 ;; (auto-mode-alist): also catch *.diffs.