Update years in copyright notice; nfc.
[bpt/emacs.git] / lisp / log-view.el
CommitLineData
e57a1038 1;;; log-view.el --- Major mode for browsing RCS/CVS/SCCS log output
5b467bf4 2
aaef169d
TTN
3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4;; 2006 Free Software Foundation, Inc.
5b467bf4
SM
5
6;; Author: Stefan Monnier <monnier@cs.yale.edu>
e57a1038 7;; Keywords: rcs sccs cvs log version-control
5b467bf4
SM
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
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
5b467bf4
SM
25
26;;; Commentary:
27
aa230d94
SM
28;; Major mode to browse revision log histories.
29;; Currently supports the format output by:
62c5f375 30;; RCS, SCCS, CVS, Subversion, and DaRCS.
aa230d94
SM
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
62c5f375
SM
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
aa230d94 69;;; Todo:
5b467bf4 70
5b467bf4 71;; - add ability to modify a log-entry (via cvs-mode-admin ;-)
e57a1038 72;; - remove references to cvs-*
aa230d94 73;; - make it easier to add support for new backends without changing the code.
5b467bf4
SM
74
75;;; Code:
76
77(eval-when-compile (require 'cl))
5b467bf4 78(require 'pcvs-util)
efa7e86f 79(autoload 'vc-find-version "vc")
99cb8c8b 80(autoload 'vc-version-diff "vc")
5b467bf4 81
71f6f911
JB
82(defvar cvs-minor-wrap-function)
83
5b467bf4 84(defgroup log-view nil
e57a1038 85 "Major mode for browsing log output of RCS/CVS/SCCS."
5b467bf4
SM
86 :group 'pcl-cvs
87 :prefix "log-view-")
88
89(easy-mmode-defmap log-view-mode-map
99cb8c8b
SS
90 '(("q" . quit-window)
91 ("z" . kill-this-buffer)
92 ("m" . set-mark-command)
2a673b03 93 ;; ("e" . cvs-mode-edit-log)
99cb8c8b 94 ("d" . log-view-diff)
c0313667 95 ("f" . log-view-find-version)
99cb8c8b 96 ("n" . log-view-msg-next)
cdbb990f
SM
97 ("p" . log-view-msg-prev)
98 ("N" . log-view-file-next)
99 ("P" . log-view-file-prev)
e2c2a3e2
KG
100 ("\M-n" . log-view-file-next)
101 ("\M-p" . log-view-file-prev))
5b467bf4
SM
102 "Log-View's keymap."
103 :group 'log-view
e57a1038
SM
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))
5b467bf4
SM
107
108(defvar log-view-mode-hook nil
109 "Hook run at the end of `log-view-mode'.")
110
d842de85 111(defface log-view-file
5b467bf4 112 '((((class color) (background light))
1fd714a4
RS
113 (:background "grey70" :weight bold))
114 (t (:weight bold)))
5b467bf4
SM
115 "Face for the file header line in `log-view-mode'."
116 :group 'log-view)
d842de85
MB
117;; backward-compatibility alias
118(put 'log-view-file-face 'face-alias 'log-view-file)
119(defvar log-view-file-face 'log-view-file)
5b467bf4 120
d842de85 121(defface log-view-message
5b467bf4
SM
122 '((((class color) (background light))
123 (:background "grey85"))
1fd714a4 124 (t (:weight bold)))
5b467bf4
SM
125 "Face for the message header line in `log-view-mode'."
126 :group 'log-view)
d842de85
MB
127;; backward-compatibility alias
128(put 'log-view-message-face 'face-alias 'log-view-message)
129(defvar log-view-message-face 'log-view-message)
5b467bf4
SM
130
131(defconst log-view-file-re
aa230d94 132 (concat "^\\(?:Working file: \\(.+\\)" ;RCS and CVS.
62c5f375 133 "\\|\\(?:SCCS/s\\.\\|Changes to \\)\\(.+\\):" ;SCCS and Darcs.
aa230d94
SM
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.
62c5f375
SM
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\\(?: \\* \\(.*\\)\\)?")
aa230d94 149 "\\)$"))
5b467bf4
SM
150
151(defconst log-view-font-lock-keywords
152 `((,log-view-file-re
aa230d94 153 (1 (if (boundp 'cvs-filename-face) cvs-filename-face) nil t)
e57a1038 154 (2 (if (boundp 'cvs-filename-face) cvs-filename-face) nil t)
e57a1038 155 (0 log-view-file-face append))
5b467bf4
SM
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
edb33387 160;;;;
5b467bf4 161;;;; Actual code
edb33387 162;;;;
5b467bf4
SM
163
164;;;###autoload
cdbb990f 165(define-derived-mode log-view-mode fundamental-mode "Log-View"
5b467bf4 166 "Major mode for browsing CVS log output."
99cb8c8b 167 (setq buffer-read-only t)
5b467bf4
SM
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
cdbb990f
SM
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")
5b467bf4 178
3e87f5fc
SM
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
5b467bf4
SM
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))
efa7e86f 197 (let* ((file (or (match-string 1) (match-string 2)))
5b467bf4
SM
198 (cvsdir (and (re-search-backward log-view-dir-re nil t)
199 (match-string 1)))
e57a1038
SM
200 (pcldir (and (boundp 'cvs-pcl-cvs-dirchange-re)
201 (re-search-backward cvs-pcl-cvs-dirchange-re nil t)
5b467bf4
SM
202 (match-string 1)))
203 (dir ""))
204 (let ((default-directory ""))
205 (when pcldir (setq dir (expand-file-name pcldir dir)))
99cb8c8b
SS
206 (when cvsdir (setq dir (expand-file-name cvsdir dir))))
207 (expand-file-name file dir))))
5b467bf4 208
99cb8c8b 209(defun log-view-current-tag (&optional where)
cdbb990f 210 (save-excursion
99cb8c8b 211 (when where (goto-char where))
cdbb990f
SM
212 (forward-line 1)
213 (let ((pt (point)))
214 (when (re-search-backward log-view-message-re nil t)
aa230d94
SM
215 (let (rev)
216 ;; Find the subgroup that matched.
efa7e86f 217 (dotimes (i (/ (length (match-data 'integers)) 2))
aa230d94 218 (setq rev (or rev (match-string (1+ i)))))
cdbb990f
SM
219 (unless (re-search-forward log-view-file-re pt t)
220 rev))))))
5b467bf4 221
aa230d94
SM
222(defvar cvs-minor-current-files)
223(defvar cvs-branch-prefix)
224(defvar cvs-secondary-branch-prefix)
225
5b467bf4
SM
226(defun log-view-minor-wrap (buf f)
227 (let ((data (with-current-buffer buf
243afed7
SM
228 (let* ((beg (point))
229 (end (if mark-active (mark) (point)))
cbc98273
JL
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
243afed7
SM
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))))))
5b467bf4
SM
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
c0313667
AS
253(defun log-view-find-version (pos)
254 "Visit the version at point."
255 (interactive "d")
256 (save-excursion
257 (goto-char pos)
f1180544 258 (switch-to-buffer (vc-find-version (log-view-current-file)
c0313667
AS
259 (log-view-current-tag)))))
260
467ee23f
SM
261;;
262;; diff
263;;
99cb8c8b
SS
264
265(defun log-view-diff (beg end)
e8171d36
JL
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."
da4ae7d3
JL
271 (interactive
272 (list (if mark-active (region-beginning) (point))
273 (if mark-active (region-end) (point))))
99cb8c8b
SS
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
5b467bf4 283(provide 'log-view)
cdbb990f 284
9be92b96 285;; arch-tag: 0d64220b-ce7e-4f62-9c2a-6b04c2f81f4f
5b467bf4 286;;; log-view.el ends here