Bug fix for vc-dispatcher split.
[bpt/emacs.git] / lisp / log-view.el
index 0f2b8d7..a92d826 100644 (file)
@@ -1,7 +1,7 @@
 ;;; log-view.el --- Major mode for browsing RCS/CVS/SCCS log output
 
 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-;;   2006, 2007 Free Software Foundation, Inc.
+;;   2006, 2007, 2008 Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: rcs sccs cvs log version-control
@@ -10,7 +10,7 @@
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 
 ;;;; Subversion:
 
+;; ------------------------------------------------------------------------
+;; r4622 | ckuethe | 2007-12-23 18:18:01 -0500 (Sun, 23 Dec 2007) | 2 lines
+;; 
+;; uBlox AEK-4T in binary mode. Added to unstable because it breaks gpsfake
+;; 
+;; ------------------------------------------------------------------------
+;; r4621 | ckuethe | 2007-12-23 16:48:11 -0500 (Sun, 23 Dec 2007) | 3 lines
+;; 
+;; Add a note about requiring usbfs to use the garmin gps18 (usb)
+;; Mention firmware testing the AC12 with firmware BQ00 and BQ04
+;; 
+;; ------------------------------------------------------------------------
+;; r4620 | ckuethe | 2007-12-23 15:52:34 -0500 (Sun, 23 Dec 2007) | 1 line
+;; 
+;; add link to latest hardware reference
+;; ------------------------------------------------------------------------
+;; r4619 | ckuethe | 2007-12-23 14:37:31 -0500 (Sun, 23 Dec 2007) | 1 line
+;; 
+;; there is now a regression test for AC12 without raw data output
+
 ;;;; Darcs:
 
 ;; Changes to darcsum.el:
 ;;   Add trailing-whitespace option to mode hook and fix
 ;;   darcsum-display-changeset not to use trailing whitespace.
 
+;;;; Mercurial
+
+;; changeset:   11:8ff1a4166444
+;; tag:         tip
+;; user:        Eric S. Raymond <esr@thyrsus.com>
+;; date:        Wed Dec 26 12:18:58 2007 -0500
+;; summary:     Explain keywords.  Add markup fixes.
+;; 
+;; changeset:   10:20abc7ab09c3
+;; user:        Eric S. Raymond <esr@thyrsus.com>
+;; date:        Wed Dec 26 11:37:28 2007 -0500
+;; summary:     Typo fixes.
+;; 
+;; changeset:   9:ada9f4da88aa
+;; user:        Eric S. Raymond <esr@thyrsus.com>
+;; date:        Wed Dec 26 11:23:00 2007 -0500
+;; summary:     Add RCS example session.
+
 ;;; Todo:
 
 ;; - add ability to modify a log-entry (via cvs-mode-admin ;-)
 
 (eval-when-compile (require 'cl))
 (require 'pcvs-util)
-(autoload 'vc-find-version "vc")
+(autoload 'vc-find-revision "vc")
 (autoload 'vc-version-diff "vc")
 
 (defvar cvs-minor-wrap-function)
 (easy-mmode-defmap log-view-mode-map
   '(("q" . quit-window)
     ("z" . kill-this-buffer)
-    ("m" . set-mark-command)
-    ;; ("e" . cvs-mode-edit-log)
+    ("m" . log-view-toggle-mark-entry)
+    ("e" . log-view-modify-change-comment)
     ("d" . log-view-diff)
-    ("f" . log-view-find-version)
+    ("a" . log-view-annotate-version)
+    ("f" . log-view-find-revision)
     ("n" . log-view-msg-next)
     ("p" . log-view-msg-prev)
+    ("\t" . log-view-msg-next)
+    ([backtab] . log-view-msg-prev)
     ("N" . log-view-file-next)
     ("P" . log-view-file-prev)
     ("\M-n" . log-view-file-next)
     ;; XXX Do we need menu entries for these?
     ;; ["Quit"  quit-window]
     ;; ["Kill This Buffer"  kill-this-buffer]
-    ["Mark Log Entry for Diff"  set-mark-command]
-    ["Diff Revisions"  log-view-diff]
-    ["Visit Version"  log-view-find-version]
-    ["Next Log Entry"  log-view-msg-next]
-    ["Previous Log Entry"  log-view-msg-prev]
-    ["Next File"  log-view-file-next]
-    ["Previous File"  log-view-file-prev]))
+    ["Mark Log Entry for Diff"  set-mark-command
+     :help ""]
+    ["Diff Revisions"  log-view-diff
+     :help "Get the diff between two revisions"]
+    ["Visit Version"  log-view-find-revision
+     :help "Visit the version at point"]
+    ["Annotate Version"  log-view-annotate-version
+     :help "Annotate the version at point"]
+    ["Modify Log Comment" log-view-modify-change-comment
+     :help "Edit the change comment displayed at point"]
+    "-----"
+    ["Next Log Entry"  log-view-msg-next
+     :help "Go to the next count'th log message"]
+    ["Previous Log Entry"  log-view-msg-prev
+     :help "Go to the previous count'th log message"]
+    ["Next File"  log-view-file-next
+     :help "Go to the next count'th file"]
+    ["Previous File"  log-view-file-prev
+     :help "Go to the previous count'th file"]))
 
 (defvar log-view-mode-hook nil
   "Hook run at the end of `log-view-mode'.")
@@ -174,6 +227,7 @@ The match group number 1 should match the revision number itself.")
               (1 (if (boundp 'cvs-filename-face) cvs-filename-face))
               (0 log-view-file-face append)))
     (eval . `(,log-view-message-re . log-view-message-face))))
+
 (defconst log-view-font-lock-defaults
   '(log-view-font-lock-keywords t nil nil nil))
 
@@ -186,6 +240,10 @@ The match group number 1 should match the revision number itself.")
   "Major mode for browsing CVS log output."
   (setq buffer-read-only t)
   (set (make-local-variable 'font-lock-defaults) log-view-font-lock-defaults)
+  (set (make-local-variable 'beginning-of-defun-function) 
+       'log-view-beginning-of-defun)
+  (set (make-local-variable 'end-of-defun-function) 
+       'log-view-end-of-defun)
   (set (make-local-variable 'cvs-minor-wrap-function) 'log-view-minor-wrap))
 
 ;;;;
@@ -213,7 +271,8 @@ The match group number 1 should match the revision number itself.")
   (save-excursion
     (forward-line 1)
     (or (re-search-backward log-view-file-re nil t)
-       (re-search-forward log-view-file-re))
+       (re-search-forward log-view-file-re nil t)
+       (error "Unable to determine the current file"))
     (let* ((file (match-string 1))
           (cvsdir (and (re-search-backward log-view-dir-re nil t)
                        (match-string 1)))
@@ -232,10 +291,98 @@ The match group number 1 should match the revision number itself.")
     (forward-line 1)
     (let ((pt (point)))
       (when (re-search-backward log-view-message-re nil t)
-       (let ((rev (match-string 1)))
+       (let ((rev (match-string-no-properties 1)))
          (unless (re-search-forward log-view-file-re pt t)
            rev))))))
 
+(defun log-view-toggle-mark-entry ()
+  "Toggle the marked state for the log entry at point.
+Individual log entries can be marked and unmarked. The marked
+entries are denoted by changing their background color.
+`log-view-get-marked' returns the list of tags for the marked
+log entries."
+  (interactive)
+  (save-excursion
+    (forward-line 1)
+    (let ((pt (point)))
+      (when (re-search-backward log-view-message-re nil t)
+       (let ((beg (match-beginning 0))
+             end ov ovlist found tag)
+         (unless (re-search-forward log-view-file-re pt t)
+           ;; Look to see if the current entry is marked.
+           (setq found (get-char-property (point) 'log-view-self))
+           (if found
+               (delete-overlay found)
+             ;; Create an overlay that covers this entry and change
+             ;; its color.
+             (setq tag (log-view-current-tag (point)))
+             (forward-line 1)
+             (setq end
+                   (if (re-search-forward log-view-message-re nil t)
+                       (match-beginning 0)
+                     (point-max)))
+             (setq ov (make-overlay beg end))
+             (overlay-put ov 'face 'log-view-file)
+             ;; This is used to check if the overlay is present.
+             (overlay-put ov 'log-view-self ov)
+             (overlay-put ov 'log-view-marked tag))))))))
+
+(defun log-view-get-marked ()
+  "Return the list of tags for the marked log entries."
+  (save-excursion
+    (let ((pos (point-min))
+         marked-list ov)
+      (while (setq pos (next-single-property-change pos 'face))
+       (when (setq ov (get-char-property pos 'log-view-self))
+         (push (overlay-get ov 'log-view-marked) marked-list)
+         (setq pos (overlay-end ov))))
+      marked-list)))
+
+(defun log-view-beginning-of-defun ()
+  ;; This assumes that a log entry starts with a line matching
+  ;; `log-view-message-re'.  Modes that derive from `log-view-mode'
+  ;; for which this assumption is not valid will have to provide
+  ;; another implementation of this function.  `log-view-msg-prev'
+  ;; does a similar job to this function, we can't use it here
+  ;; directly because it prints messages that are not appropriate in
+  ;; this context and it does not move to the beginning of the buffer
+  ;; when the point is before the first log entry.
+
+  ;; `log-view-beginning-of-defun' and `log-view-end-of-defun' have
+  ;; been checked to work with logs produced by RCS, CVS, git,
+  ;; mercurial and subversion.
+
+  (re-search-backward log-view-message-re nil 'move))
+
+(defun log-view-end-of-defun ()
+  ;; The idea in this function is to search for the beginning of the
+  ;; next log entry using `log-view-message-re' and then go back one
+  ;; line when finding it.  Modes that derive from `log-view-mode' for
+  ;; which this assumption is not valid will have to provide another
+  ;; implementation of this function.
+
+  ;; Look back and if there is no entry there it means we are before
+  ;; the first log entry, so go forward until finding one.
+  (unless (save-excursion (re-search-backward log-view-message-re nil t))
+    (re-search-forward log-view-message-re nil t))
+
+  ;; In case we are at the end of log entry going forward a line will
+  ;; make us find the next entry when searching. If we are inside of
+  ;; an entry going forward a line will still keep the point inside
+  ;; the same entry.
+  (forward-line 1)
+
+  ;; In case we are at the beginning of an entry, move past it.
+  (when (looking-at log-view-message-re)
+    (goto-char (match-end 0))
+    (forward-line 1))
+
+  ;; Search for the start of the next log entry.  Go to the end of the
+  ;; buffer if we could not find a next entry.
+  (when (re-search-forward log-view-message-re nil 'move)
+    (goto-char (match-beginning 0))
+    (forward-line -1)))
+
 (defvar cvs-minor-current-files)
 (defvar cvs-branch-prefix)
 (defvar cvs-secondary-branch-prefix)
@@ -267,14 +414,49 @@ The match group number 1 should match the revision number itself.")
          (cvs-force-command "/F"))
       (funcall f))))
 
-(defun log-view-find-version (pos)
+(defun log-view-find-revision (pos)
   "Visit the version at point."
   (interactive "d")
   (save-excursion
     (goto-char pos)
-    (switch-to-buffer (vc-find-version (log-view-current-file)
+    (switch-to-buffer (vc-find-revision (log-view-current-file)
                                        (log-view-current-tag)))))
 
+
+(defun log-view-extract-comment ()
+  "Parse comment from around the current point in the log."
+  (save-excursion
+    (let (st en (backend (vc-backend (log-view-current-file))))
+      (log-view-end-of-defun)
+      (cond ((eq backend 'SVN)
+            (forward-line -1)))
+      (setq en (point))
+      (log-view-beginning-of-defun)
+      (cond ((memq backend '(SCCS RCS CVS MCVS SVN))
+            (forward-line 2))
+           ((eq backend 'Hg)
+            (forward-line 4)
+            (re-search-forward "summary: *" nil t)))      
+      (setq st (point))
+      (buffer-substring st en))))
+
+(declare-function vc-modify-change-comment "vc" (files rev oldcomment))
+
+(defun log-view-modify-change-comment ()
+  "Edit the change comment displayed at point."
+  (interactive)
+  (vc-modify-change-comment (list (log-view-current-file))
+                         (log-view-current-tag)
+                         (log-view-extract-comment)))
+
+(defun log-view-annotate-version (pos)
+  "Annotate the version at point."
+  (interactive "d")
+  (save-excursion
+    (goto-char pos)
+    (switch-to-buffer (vc-annotate (log-view-current-file)
+                                  (log-view-current-tag)))))
+
 ;;
 ;; diff
 ;;
@@ -295,7 +477,7 @@ and ends."
         (goto-char end)
         (log-view-msg-next)
         (setq to (log-view-current-tag))))
-    (vc-version-diff (log-view-current-file) to fr)))
+    (vc-version-diff (list (log-view-current-file)) to fr)))
 
 (provide 'log-view)