]> code.delx.au - gnu-emacs/blobdiff - lisp/vc/log-view.el
Update copyright year to 2015
[gnu-emacs] / lisp / vc / log-view.el
index 6514fbd22d767700e4bde575cb5325a1339509cb..98e935722063abb19f444e881cd9a66ce246d78f 100644 (file)
@@ -1,9 +1,9 @@
-;;; log-view.el --- Major mode for browsing RCS/CVS/SCCS log output -*- lexical-binding: t -*-
+;;; log-view.el --- Major mode for browsing revision log histories -*- lexical-binding: t -*-
 
-;; Copyright (C) 1999-201 Free Software Foundation, Inc.
+;; Copyright (C) 1999-2015 Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
-;; Keywords: rcs, sccs, cvs, log, vc, tools
+;; Keywords: tools, vc
 
 ;; This file is part of GNU Emacs.
 
 
 ;; Major mode to browse revision log histories.
 ;; Currently supports the format output by:
-;;  RCS, SCCS, CVS, Subversion, and DaRCS.
+;; SCCS, RCS, CVS, Subversion, DaRCS, and Mercurial.
 
 ;; Examples of log output:
 
+;;;; SCCS:
+
 ;;;; RCS/CVS:
 
 ;; ----------------------------
@@ -43,8 +45,6 @@
 ;; Change release version from 21.4 to 22.1 throughout.
 ;; Change development version from 21.3.50 to 22.0.50.
 
-;;;; SCCS:
-
 ;;;; Subversion:
 
 ;; ------------------------------------------------------------------------
 (defvar cvs-force-command)
 
 (defgroup log-view nil
-  "Major mode for browsing log output of RCS/CVS/SCCS."
+  "Major mode for browsing log output of revision log histories."
   :group 'pcl-cvs
   :prefix "log-view-")
 
 (easy-mmode-defmap log-view-mode-map
   '(
-    ;; FIXME: (copy-keymap special-mode-map) instead
-    ("z" . kill-this-buffer)
-    ("q" . quit-window)
-    ("g" . revert-buffer)
-    ("\C-m" . log-view-toggle-entry-display)
+    ("-"       .       negative-argument)
+    ("0"       .       digit-argument)
+    ("1"       .       digit-argument)
+    ("2"       .       digit-argument)
+    ("3"       .       digit-argument)
+    ("4"       .       digit-argument)
+    ("5"       .       digit-argument)
+    ("6"       .       digit-argument)
+    ("7"       .       digit-argument)
+    ("8"       .       digit-argument)
+    ("9"       .       digit-argument)
 
+    ("\C-m" . log-view-toggle-entry-display)
     ("m" . log-view-toggle-mark-entry)
     ("e" . log-view-modify-change-comment)
     ("d" . log-view-diff)
     ("\M-n" . log-view-file-next)
     ("\M-p" . log-view-file-prev))
   "Log-View's keymap."
+  :inherit special-mode-map
   :group 'log-view)
 
 (easy-menu-define log-view-mode-menu log-view-mode-map
@@ -275,6 +283,7 @@ The match group number 1 should match the revision number itself.")
 (easy-mmode-define-navigation log-view-file log-view-file-re "file")
 
 (defun log-view-goto-rev (rev)
+  "Go to revision REV."
   (goto-char (point-min))
   (ignore-errors
     (while (not (equal rev (log-view-current-tag)))
@@ -288,6 +297,7 @@ The match group number 1 should match the revision number itself.")
 (defconst log-view-dir-re "^cvs[.ex]* [a-z]+: Logging \\(.+\\)$")
 
 (defun log-view-current-file ()
+  "Return the current file."
   (save-excursion
     (forward-line 1)
     (or (re-search-backward log-view-file-re nil t)
@@ -317,7 +327,9 @@ Otherwise, don't move point."
        result)
     (save-excursion
       (when pos (goto-char pos))
-      (forward-line 1)
+      (forward-line 0)
+      ;; Treat "---" separator lines as part of the following revision.
+      (forward-line (if (looking-at "-\\{20,\\}$") 2 1))
       (while looping
        (setq pos (re-search-backward log-view-message-re nil 'move)
              looping (and pos (log-view-inside-comment-p (point)))))
@@ -338,7 +350,7 @@ if POS is omitted or nil, it defaults to point."
 
 (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
+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."
@@ -417,18 +429,31 @@ to the beginning of the ARGth following entry.
 This is Log View mode's default `beginning-of-defun-function'.
 It assumes that a log entry starts with a line matching
 `log-view-message-re'."
-  (if (or (null arg) (zerop arg))
-      (setq arg 1))
+  (when (null arg) (setf arg 1))
   (if (< arg 0)
-      (dotimes (_n (- arg))
-       (log-view-end-of-defun))
-    (catch 'beginning-of-buffer
-      (dotimes (_n arg)
-       (or (log-view-current-entry nil t)
-           (throw 'beginning-of-buffer nil)))
-      (point))))
-
-(defun log-view-end-of-defun ()
+      ;; In log view, the end of one defun is the beginning of the
+      ;; next, so punting to log-view-end-of-defun is safe in this
+      ;; context.
+      (log-view-end-of-defun (- arg))
+    (let ((found t))
+      (while (> arg 0)
+        (setf arg (1- arg))
+        (let ((cur-start (log-view-current-entry)))
+          (setf found
+                (cond ((null cur-start)
+                       (goto-char (point-min))
+                       nil)
+                      ((>= (car cur-start) (point))
+                       (unless (bobp)
+                         (forward-line -1)
+                         (setf arg (1+ arg)))
+                       nil)
+                      (t
+                       (goto-char (car cur-start))
+                       t)))))
+      found)))
+
+(defun log-view-end-of-defun-1 ()
   "Move forward to the next Log View entry."
   (let ((looping t))
     (if (looking-at log-view-message-re)
@@ -445,6 +470,16 @@ It assumes that a log entry starts with a line matching
        (setq looping nil)
        (forward-line -1))))))
 
+(defun log-view-end-of-defun (&optional arg)
+  "Move forward to the next Log View entry.
+Works like `end-of-defun'."
+  (when (null arg) (setf arg 1))
+  (if (< arg 0)
+      (log-view-beginning-of-defun (- arg))
+    (dotimes (_n arg)
+      (log-view-end-of-defun-1)
+      t)))
+
 (defvar cvs-minor-current-files)
 (defvar cvs-branch-prefix)
 (defvar cvs-secondary-branch-prefix)
@@ -452,7 +487,7 @@ It assumes that a log entry starts with a line matching
 (defun log-view-minor-wrap (buf f)
   (let ((data (with-current-buffer buf
                (let* ((beg (point))
-                      (end (if mark-active (mark) (point)))
+                      (end (if (use-region-p) (mark) (point)))
                       (fr (log-view-current-tag beg))
                       (to (log-view-current-tag end)))
                  (when (string-equal fr to)
@@ -477,7 +512,8 @@ It assumes that a log entry starts with a line matching
       (funcall f))))
 
 (defun log-view-find-revision (pos)
-  "Visit the version at point."
+  "Visit the version at POS.
+If called interactively, visit the version at point."
   (interactive "d")
   (unless log-view-per-file-logs
     (when (> (length log-view-vc-fileset) 1)
@@ -498,7 +534,8 @@ It assumes that a log entry starts with a line matching
       (cond ((eq backend 'SVN)
             (forward-line -1)))
       (setq en (point))
-      (log-view-beginning-of-defun)
+      (or (log-view-current-entry nil t)
+          (throw 'beginning-of-buffer nil))
       (cond ((memq backend '(SCCS RCS CVS MCVS SVN))
             (forward-line 2))
            ((eq backend 'Hg)
@@ -519,7 +556,8 @@ It assumes that a log entry starts with a line matching
                            (log-view-extract-comment)))
 
 (defun log-view-annotate-version (pos)
-  "Annotate the version at point."
+  "Annotate the version at POS.
+If called interactively, annotate the version at point."
   (interactive "d")
   (unless log-view-per-file-logs
     (when (> (length log-view-vc-fileset) 1)
@@ -537,54 +575,55 @@ It assumes that a log entry starts with a line matching
 
 (defun log-view-diff (beg end)
   "Get the diff between two revisions.
-If the mark is not active or the mark is on the revision at point,
-get the diff between the revision at point and its previous revision.
-Otherwise, get the diff between the revisions where the region starts
-and ends.
-Contrary to `log-view-diff-changeset', it will only show the part of the
-changeset that affected the currently considered file(s)."
+If the region is inactive or the mark is on the revision at
+point, get the diff between the revision at point and its
+previous revision.  Otherwise, get the diff between the revisions
+where the region starts and ends.
+
+Unlike `log-view-diff-changeset', this function only shows the
+part of the changeset which affected the currently considered
+file(s)."
   (interactive
-   (list (if mark-active (region-beginning) (point))
-         (if mark-active (region-end) (point))))
-  (let ((fr (log-view-current-tag beg))
-        (to (log-view-current-tag end)))
-    (when (string-equal fr to)
-      (save-excursion
-        (goto-char end)
-        (log-view-msg-next)
-        (setq to (log-view-current-tag))))
-    (vc-diff-internal
-     t (list log-view-vc-backend
-            (if log-view-per-file-logs
-                (list (log-view-current-file))
-              log-view-vc-fileset))
-     to fr)))
+   (list (if (use-region-p) (region-beginning) (point))
+         (if (use-region-p) (region-end) (point))))
+  (log-view-diff-common beg end))
 
 (defun log-view-diff-changeset (beg end)
   "Get the diff between two revisions.
-If the mark is not active or the mark is on the revision at point,
-get the diff between the revision at point and its previous revision.
-Otherwise, get the diff between the revisions where the region starts
-and ends.
-Contrary to `log-view-diff', it will show the whole changeset including
-the changes that affected other files than the currently considered file(s)."
+If the region is inactive or the mark is on the revision at
+point, get the diff between the revision at point and its
+previous revision.  Otherwise, get the diff between the revisions
+where the region starts and ends.
+
+Unlike `log-view-diff' this function shows the whole changeset,
+including changes affecting other files than the currently
+considered file(s)."
   (interactive
-   (list (if mark-active (region-beginning) (point))
-         (if mark-active (region-end) (point))))
-  (when (eq (vc-call-backend log-view-vc-backend 'revision-granularity) 'file)
+   (list (if (use-region-p) (region-beginning) (point))
+         (if (use-region-p) (region-end) (point))))
+  (log-view-diff-common beg end t))
+
+(defun log-view-diff-common (beg end &optional whole-changeset)
+  (when (and whole-changeset
+             (eq (vc-call-backend log-view-vc-backend 'revision-granularity)
+                 'file))
     (error "The %s backend does not support changeset diffs" log-view-vc-backend))
-  (let ((fr (log-view-current-tag beg))
-        (to (log-view-current-tag end)))
+  (let ((to (log-view-current-tag beg))
+        (fr (log-view-current-tag end)))
     (when (string-equal fr to)
       ;; TO and FR are the same, look at the previous revision.
-      (setq to (vc-call-backend log-view-vc-backend 'previous-revision nil fr)))
+      (setq fr (vc-call-backend log-view-vc-backend 'previous-revision nil fr)))
     (vc-diff-internal
-     t
-     ;; We want to see the diff for all the files in the changeset, so
-     ;; pass NIL for the file list.  The value passed here should
-     ;; follow what `vc-deduce-fileset' returns.
-     (list log-view-vc-backend nil)
-     to fr)))
+     t (list log-view-vc-backend
+             ;; The value passed here should follow what
+             ;; `vc-deduce-fileset' returns.  If we want to see the
+             ;; diff for all the files in the changeset, pass NIL for
+             ;; the file list.
+             (unless whole-changeset
+               (if log-view-per-file-logs
+                   (list (log-view-current-file))
+                 log-view-vc-fileset)))
+     fr to)))
 
 (provide 'log-view)