-;;; 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-2012 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:
;; ----------------------------
;; Change release version from 21.4 to 22.1 throughout.
;; Change development version from 21.3.50 to 22.0.50.
-;;;; SCCS:
-
;;;; Subversion:
;; ------------------------------------------------------------------------
;;; Code:
-(eval-when-compile (require 'cl))
(require 'pcvs-util)
(autoload 'vc-find-revision "vc")
(autoload 'vc-diff-internal "vc")
(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
'(log-view-font-lock-keywords t nil nil nil))
(defvar log-view-vc-fileset nil
- "Set this to the fileset corresponding to the current log.")
+ "The VC fileset corresponding to the current log.")
(defvar log-view-vc-backend nil
- "Set this to the VC backend that created the current log.")
+ "The VC backend that created the current log.")
;;;;
;;;; Actual code
(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)))
(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)
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)))))
(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."
marked-list)))
(defun log-view-toggle-entry-display ()
+ "If possible, expand the current Log View entry.
+This calls `log-view-expanded-log-entry-function' to do the work."
(interactive)
;; Don't do anything unless `log-view-expanded-log-entry-function'
;; is defined in this mode.
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)
(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)
(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)
(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)
(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)
(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)
(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)))
-
-(declare-function vc-diff-internal "vc"
- (async vc-fileset rev1 rev2 &optional verbose))
+ (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)