1;;; log-view.el --- Major mode for browsing RCS/CVS/SCCS log output 2 3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 4;; 2006, 2007 Free Software Foundation, Inc. 5 6;; Author: Stefan Monnier <monnier@iro.umontreal.ca> 7;; Keywords: rcs sccs cvs log version-control 8 9;; This file is part of GNU Emacs. 10 11;; GNU Emacs is free software; you can redistribute it and/or modify 12;; it under the terms of the GNU General Public License as published by 13;; the Free Software Foundation; either version 2, or (at your option) 14;; any later version. 15 16;; GNU Emacs is distributed in the hope that it will be useful, 17;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19;; GNU General Public License for more details. 20 21;; You should have received a copy of the GNU General Public License 22;; along with GNU Emacs; see the file COPYING. If not, write to the 23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24;; Boston, MA 02110-1301, USA. 25 26;;; Commentary: 27 28;; Major mode to browse revision log histories. 29;; Currently supports the format output by: 30;; RCS, SCCS, CVS, Subversion, and DaRCS. 31 32;; Examples of log output: 33 34;;;; RCS/CVS: 35 36;; ---------------------------- 37;; revision 1.35 locked by: turlutut 38;; date: 2005-03-22 18:48:38 +0000; author: monnier; state: Exp; lines: +6 -8 39;; (gnus-display-time-event-handler): 40;; Check display-time-timer at runtime rather than only at load time 41;; in case display-time-mode is turned off in the mean time. 42;; ---------------------------- 43;; revision 1.34 44;; date: 2005-02-09 15:50:38 +0000; author: kfstorm; state: Exp; lines: +7 -7 45;; branches: 1.34.2; 46;; Change release version from 21.4 to 22.1 throughout. 47;; Change development version from 21.3.50 to 22.0.50. 48 49;;;; SCCS: 50 51;;;; Subversion: 52 53;;;; Darcs: 54 55;; Changes to darcsum.el: 56;; 57;; Mon Nov 28 15:19:38 GMT 2005 Dave Love <fx@gnu.org> 58;; * Abstract process startup into darcsum-start-process. Use TERM=dumb. 59;; TERM=dumb avoids escape characters, at least, for any old darcs that 60;; doesn't understand DARCS_DONT_COLOR & al. 61;; 62;; Thu Nov 24 15:20:45 GMT 2005 Dave Love <fx@gnu.org> 63;; * darcsum-mode-related changes. 64;; Don't call font-lock-mode (unnecessary) or use-local-map (redundant). 65;; Use mode-class 'special. Add :group. 66;; Add trailing-whitespace option to mode hook and fix 67;; darcsum-display-changeset not to use trailing whitespace. 68 69;;; Todo: 70 71;; - add ability to modify a log-entry (via cvs-mode-admin ;-) 72;; - remove references to cvs-* 73;; - make it easier to add support for new backends without changing the code. 74 75;;; Code: 76 77(eval-when-compile (require 'cl)) 78(require 'pcvs-util) 79(autoload 'vc-find-version "vc") 80(autoload 'vc-version-diff "vc") 81 82(defvar cvs-minor-wrap-function) 83 84(defgroup log-view nil 85 "Major mode for browsing log output of RCS/CVS/SCCS." 86 :group 'pcl-cvs 87 :prefix "log-view-") 88 89(easy-mmode-defmap log-view-mode-map 90 '(("q" . quit-window) 91 ("z" . kill-this-buffer) 92 ("m" . set-mark-command) 93 ;; ("e" . cvs-mode-edit-log) 94 ("d" . log-view-diff) 95 ("f" . log-view-find-version) 96 ("n" . log-view-msg-next) 97 ("p" . log-view-msg-prev) 98 ("N" . log-view-file-next) 99 ("P" . log-view-file-prev) 100 ("\M-n" . log-view-file-next) 101 ("\M-p" . log-view-file-prev)) 102 "Log-View's keymap." 103 :group 'log-view 104 ;; Here I really need either buffer-local keymap-inheritance 105 ;; or a minor-mode-map with lower precedence than the local map. 106 :inherit (if (boundp 'cvs-mode-map) cvs-mode-map)) 107 108(defvar log-view-mode-hook nil 109 "Hook run at the end of `log-view-mode'.") 110 111(defface log-view-file 112 '((((class color) (background light)) 113 (:background "grey70" :weight bold)) 114 (t (:weight bold))) 115 "Face for the file header line in `log-view-mode'." 116 :group 'log-view) 117;; backward-compatibility alias 118(put 'log-view-file-face 'face-alias 'log-view-file) 119(defvar log-view-file-face 'log-view-file) 120 121(defface log-view-message 122 '((((class color) (background light)) 123 (:background "grey85")) 124 (t (:weight bold))) 125 "Face for the message header line in `log-view-mode'." 126 :group 'log-view) 127;; backward-compatibility alias 128(put 'log-view-message-face 'face-alias 'log-view-message) 129(defvar log-view-message-face 'log-view-message) 130 131(defconst log-view-file-re 132 (concat "^\\(?:Working file: \\(.+\\)" ;RCS and CVS. 133 "\\|\\(?:SCCS/s\\.\\|Changes to \\)\\(.+\\):" ;SCCS and Darcs. 134 "\\)\n")) ;Include the \n for font-lock reasons. 135 136(defconst log-view-message-re 137 (concat "^\\(?:revision \\([.0-9]+\\)\\(?:\t.*\\)?" ; RCS and CVS. 138 "\\|r\\([0-9]+\\) | .* | .*" ; Subversion. 139 "\\|D \\([.0-9]+\\) .*" ; SCCS. 140 ;; Darcs doesn't have revision names. VC-darcs uses patch names 141 ;; instead. Darcs patch names are hashcodes, which do not appear 142 ;; in the log output :-(, but darcs accepts any prefix of the log 143 ;; message as a patch name, so we match the first line of the log 144 ;; message. 145 ;; First loosely match the date format. 146 (concat "\\|[^ \n].*[^0-9\n][0-9][0-9]:[0-9][0-9][^0-9\n].*[^ \n]" 147 ;;Email of user and finally Msg, used as revision name. 148 " .*@.*\n\\(?: \\* \\(.*\\)\\)?") 149 "\\)$")) 150 151(defconst log-view-font-lock-keywords 152 `((,log-view-file-re 153 (1 (if (boundp 'cvs-filename-face) cvs-filename-face) nil t) 154 (2 (if (boundp 'cvs-filename-face) cvs-filename-face) nil t) 155 (0 log-view-file-face append)) 156 (,log-view-message-re . log-view-message-face))) 157(defconst log-view-font-lock-defaults 158 '(log-view-font-lock-keywords t nil nil nil)) 159 160;;;; 161;;;; Actual code 162;;;; 163 164;;;###autoload 165(define-derived-mode log-view-mode fundamental-mode "Log-View" 166 "Major mode for browsing CVS log output." 167 (setq buffer-read-only t) 168 (set (make-local-variable 'font-lock-defaults) log-view-font-lock-defaults) 169 (set (make-local-variable 'cvs-minor-wrap-function) 'log-view-minor-wrap)) 170 171;;;; 172;;;; Navigation 173;;;; 174 175;; define log-view-{msg,file}-{next,prev} 176(easy-mmode-define-navigation log-view-msg log-view-message-re "log message") 177(easy-mmode-define-navigation log-view-file log-view-file-re "file") 178 179(defun log-view-goto-rev (rev) 180 (goto-char (point-min)) 181 (ignore-errors 182 (while (not (equal rev (log-view-current-tag))) 183 (log-view-msg-next)) 184 t)) 185 186;;;; 187;;;; Linkage to PCL-CVS (mostly copied from cvs-status.el) 188;;;; 189 190(defconst log-view-dir-re "^cvs[.ex]* [a-z]+: Logging \\(.+\\)$") 191 192(defun log-view-current-file () 193 (save-excursion 194 (forward-line 1) 195 (or (re-search-backward log-view-file-re nil t) 196 (re-search-forward log-view-file-re)) 197 (let* ((file (or (match-string 1) (match-string 2))) 198 (cvsdir (and (re-search-backward log-view-dir-re nil t) 199 (match-string 1))) 200 (pcldir (and (boundp 'cvs-pcl-cvs-dirchange-re) 201 (re-search-backward cvs-pcl-cvs-dirchange-re nil t) 202 (match-string 1))) 203 (dir "")) 204 (let ((default-directory "")) 205 (when pcldir (setq dir (expand-file-name pcldir dir))) 206 (when cvsdir (setq dir (expand-file-name cvsdir dir)))) 207 (expand-file-name file dir)))) 208 209(defun log-view-current-tag (&optional where) 210 (save-excursion 211 (when where (goto-char where)) 212 (forward-line 1) 213 (let ((pt (point))) 214 (when (re-search-backward log-view-message-re nil t) 215 (let (rev) 216 ;; Find the subgroup that matched. 217 (dotimes (i (/ (length (match-data 'integers)) 2)) 218 (setq rev (or rev (match-string (1+ i))))) 219 (unless (re-search-forward log-view-file-re pt t) 220 rev)))))) 221 222(defvar cvs-minor-current-files) 223(defvar cvs-branch-prefix) 224(defvar cvs-secondary-branch-prefix) 225 226(defun log-view-minor-wrap (buf f) 227 (let ((data (with-current-buffer buf 228 (let* ((beg (point)) 229 (end (if mark-active (mark) (point))) 230 (fr (log-view-current-tag beg)) 231 (to (log-view-current-tag end))) 232 (when (string-equal fr to) 233 (save-excursion 234 (goto-char end) 235 (log-view-msg-next) 236 (setq to (log-view-current-tag)))) 237 (cons 238 ;; The first revision has to be the one at point, for 239 ;; operations that only take one revision 240 ;; (e.g. cvs-mode-edit). 241 (cons (log-view-current-file) fr) 242 (cons (log-view-current-file) to)))))) 243 (let ((cvs-branch-prefix (cdar data)) 244 (cvs-secondary-branch-prefix (and (cdar data) (cddr data))) 245 (cvs-minor-current-files 246 (cons (caar data) 247 (when (and (cadr data) (not (equal (caar data) (cadr data)))) 248 (list (cadr data))))) 249 ;; FIXME: I need to force because the fileinfos are UNKNOWN 250 (cvs-force-command "/F")) 251 (funcall f)))) 252 253(defun log-view-find-version (pos) 254 "Visit the version at point." 255 (interactive "d") 256 (save-excursion 257 (goto-char pos) 258 (switch-to-buffer (vc-find-version (log-view-current-file) 259 (log-view-current-tag))))) 260 261;; 262;; diff 263;; 264 265(defun log-view-diff (beg end) 266 "Get the diff between two revisions. 267If the mark is not active or the mark is on the revision at point, 268get the diff between the revision at point and its previous revision. 269Otherwise, get the diff between the revisions where the region starts 270and ends." 271 (interactive 272 (list (if mark-active (region-beginning) (point)) 273 (if mark-active (region-end) (point)))) 274 (let ((fr (log-view-current-tag beg)) 275 (to (log-view-current-tag end))) 276 (when (string-equal fr to) 277 (save-excursion 278 (goto-char end) 279 (log-view-msg-next) 280 (setq to (log-view-current-tag)))) 281 (vc-version-diff (log-view-current-file) to fr))) 282 283(provide 'log-view) 284 285;; arch-tag: 0d64220b-ce7e-4f62-9c2a-6b04c2f81f4f 286;;; log-view.el ends here 287