(Bread_char): Deleted.
[bpt/emacs.git] / lisp / vc.el
CommitLineData
594722a8
ER
1;;; vc.el --- drive a version-control system from within Emacs
2
0101cc40 3;; Copyright (C) 1992, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
594722a8 4
28a25aa5
AS
5;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
6;; Maintainer: Andre Spiegel <spiegel@inf.fu-berlin.de>
594722a8
ER
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
b578f267
EN
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
594722a8
ER
24
25;;; Commentary:
26
1a2f456b
ER
27;; This mode is fully documented in the Emacs user's manual.
28;;
594722a8
ER
29;; This was designed and implemented by Eric Raymond <esr@snark.thyrsus.com>.
30;; Paul Eggert <eggert@twinsun.com>, Sebastian Kremer <sk@thp.uni-koeln.de>,
31;; and Richard Stallman contributed valuable criticism, support, and testing.
632e9525 32;; CVS support was added by Per Cederqvist <ceder@lysator.liu.se>
28a25aa5
AS
33;; in Jan-Feb 1994. Further enhancements came from ttn.netcom.com and
34;; Andre Spiegel <spiegel@inf.fu-berlin.de>.
594722a8 35;;
632e9525 36;; Supported version-control systems presently include SCCS, RCS, and CVS.
b0c9bc8c
AS
37;;
38;; Some features will not work with old RCS versions. Where
39;; appropriate, VC finds out which version you have, and allows or
40;; disallows those features (stealing locks, for example, works only
41;; from 5.6.2 onwards).
632e9525
RS
42;; Even initial checkins will fail if your RCS version is so old that ci
43;; doesn't understand -t-; this has been known to happen to people running
44;; NExTSTEP 3.0.
594722a8 45;;
6b9d0764
AS
46;; You can support the RCS -x option by adding pairs to the
47;; vc-master-templates list.
594722a8
ER
48;;
49;; Proper function of the SCCS diff commands requires the shellscript vcdiff
50;; to be installed somewhere on Emacs's path for executables.
51;;
1a2f456b 52;; If your site uses the ChangeLog convention supported by Emacs, the
594be62e 53;; function vc-comment-to-change-log should prove a useful checkin hook.
1a2f456b 54;;
594722a8 55;; This code depends on call-process passing back the subprocess exit
e1f297e6 56;; status. Thus, you need Emacs 18.58 or later to run it. For the
6ed5075c 57;; vc-directory command to work properly as documented, you need 19.
7ef84cf9 58;; You also need Emacs 19's ring.el.
594722a8
ER
59;;
60;; The vc code maintains some internal state in order to reduce expensive
61;; version-control operations to a minimum. Some names are only computed
34291cd2 62;; once. If you perform version control operations with RCS/SCCS/CVS while
594722a8
ER
63;; vc's back is turned, or move/rename master files while vc is running,
64;; vc may get seriously confused. Don't do these things!
65;;
66;; Developer's notes on some concurrency issues are included at the end of
67;; the file.
68
69;;; Code:
70
71(require 'vc-hooks)
8c0aaf40 72(require 'ring)
5c6f8be0 73(eval-when-compile (require 'dired)) ; for dired-map-over-marks macro
8c0aaf40
ER
74
75(if (not (assoc 'vc-parent-buffer minor-mode-alist))
76 (setq minor-mode-alist
77 (cons '(vc-parent-buffer vc-parent-buffer-name)
78 minor-mode-alist)))
594722a8 79
d7eff0e0
RS
80;; To implement support for a new version-control system, add another
81;; branch to the vc-backend-dispatch macro and fill it in in each
82;; call. The variable vc-master-templates in vc-hooks.el will also
83;; have to change.
84
85(defmacro vc-backend-dispatch (f s r c)
86 "Execute FORM1, FORM2 or FORM3 for SCCS, RCS or CVS respectively.
87If FORM3 is `RCS', use FORM2 for CVS as well as RCS.
88\(CVS shares some code with RCS)."
89 (list 'let (list (list 'type (list 'vc-backend f)))
90 (list 'cond
91 (list (list 'eq 'type (quote 'SCCS)) s) ;; SCCS
92 (list (list 'eq 'type (quote 'RCS)) r) ;; RCS
93 (list (list 'eq 'type (quote 'CVS)) ;; CVS
94 (if (eq c 'RCS) r c))
95 )))
96
594722a8
ER
97;; General customization
98
0101cc40
RS
99(defgroup vc nil
100 "Version-control system in Emacs."
101 :group 'tools)
102
103(defcustom vc-suppress-confirm nil
104 "*If non-nil, treat user as expert; suppress yes-no prompts on some things."
105 :type 'boolean
106 :group 'vc)
107
108(defcustom vc-initial-comment nil
109 "*If non-nil, prompt for initial comment when a file is registered."
110 :type 'boolean
111 :group 'vc)
112
113(defcustom vc-command-messages nil
114 "*If non-nil, display run messages from back-end commands."
115 :type 'boolean
116 :group 'vc)
117
118(defcustom vc-checkin-switches nil
119 "*A string or list of strings specifying extra switches for checkin.
120These are passed to the checkin program by \\[vc-checkin]."
121 :type '(choice (const :tag "None" nil)
122 (string :tag "Argument String")
123 (repeat :tag "Argument List"
124 :value ("")
125 string))
126 :group 'vc)
127
128(defcustom vc-checkout-switches nil
129 "*A string or list of strings specifying extra switches for checkout.
130These are passed to the checkout program by \\[vc-checkout]."
131 :type '(choice (const :tag "None" nil)
132 (string :tag "Argument String")
133 (repeat :tag "Argument List"
134 :value ("")
135 string))
136 :group 'vc)
137
138(defcustom vc-register-switches nil
139 "*A string or list of strings; extra switches for registering a file.
140These are passed to the checkin program by \\[vc-register]."
141 :type '(choice (const :tag "None" nil)
142 (string :tag "Argument String")
143 (repeat :tag "Argument List"
144 :value ("")
145 string))
146 :group 'vc)
147
148(defcustom vc-directory-exclusion-list '("SCCS" "RCS" "CVS")
149 "*List of directory names to be ignored while recursively walking file trees."
150 :type '(repeat string)
151 :group 'vc)
666a0ebb 152
8c0aaf40
ER
153(defconst vc-maximum-comment-ring-size 32
154 "Maximum number of saved comments in the comment ring.")
155
2e810285
RS
156;;; This is duplicated in diff.el.
157(defvar diff-switches "-c"
158 "*A string or list of strings specifying switches to be be passed to diff.")
159
7d2d9482
RS
160(defcustom vc-annotate-color-map
161 '(( 26.3672 . "#FF0000")
162 ( 52.7344 . "#FF3800")
163 ( 79.1016 . "#FF7000")
164 (105.4688 . "#FFA800")
165 (131.8359 . "#FFE000")
166 (158.2031 . "#E7FF00")
167 (184.5703 . "#AFFF00")
168 (210.9375 . "#77FF00")
169 (237.3047 . "#3FFF00")
170 (263.6719 . "#07FF00")
171 (290.0391 . "#00FF31")
172 (316.4063 . "#00FF69")
173 (342.7734 . "#00FFA1")
174 (369.1406 . "#00FFD9")
175 (395.5078 . "#00EEFF")
176 (421.8750 . "#00B6FF")
177 (448.2422 . "#007EFF"))
178 "*Association list of age versus color, for \\[vc-annotate].
179Ages are given in units of 2**-16 seconds.
180Default is eighteen steps using a twenty day increment."
181 :type 'sexp
182 :group 'vc)
183
184(defcustom vc-annotate-very-old-color "#0046FF"
185 "*Color for lines older than CAR of last cons in `vc-annotate-color-map'."
186 :type 'string
187 :group 'vc)
188
189(defcustom vc-annotate-background "black"
190 "*Background color for \\[vc-annotate].
191Default color is used if nil."
192 :type 'string
193 :group 'vc)
194
195(defcustom vc-annotate-menu-elements '(2 0.5 0.1 0.01)
196 "*Menu elements for the mode-specific menu of VC-Annotate mode.
197List of factors, used to expand/compress the time scale. See `vc-annotate'."
198 :type 'sexp
199 :group 'vc)
200
f0b188ed 201;;;###autoload
0101cc40
RS
202(defcustom vc-checkin-hook nil
203 "*Normal hook (List of functions) run after a checkin is done.
204See `run-hooks'."
205 :type 'hook
206 :group 'vc)
f0b188ed 207
67242a23 208;;;###autoload
0101cc40
RS
209(defcustom vc-before-checkin-hook nil
210 "*Normal hook (list of functions) run before a file gets checked in.
211See `run-hooks'."
212 :type 'hook
213 :group 'vc)
67242a23 214
7d2d9482
RS
215;;;###autoload
216(defcustom vc-annotate-mode-hook nil
217 "*Hooks to run when VC-Annotate mode is turned on."
218 :type 'hook
219 :group 'vc)
220
594722a8
ER
221;; Header-insertion hair
222
0101cc40 223(defcustom vc-header-alist
80688f5c 224 '((SCCS "\%W\%") (RCS "\$Id\$") (CVS "\$Id\$"))
7e48e092
AS
225 "*Header keywords to be inserted by `vc-insert-headers'.
226Must be a list of two-element lists, the first element of each must
227be `RCS', `CVS', or `SCCS'. The second element is the string to
0101cc40
RS
228be inserted for this particular backend."
229 :type '(repeat (list :format "%v"
230 (choice :tag "System"
231 (const SCCS)
232 (const RCS)
233 (const CVS))
234 (string :tag "Header")))
235 :group 'vc)
236
237(defcustom vc-static-header-alist
594722a8
ER
238 '(("\\.c$" .
239 "\n#ifndef lint\nstatic char vcid[] = \"\%s\";\n#endif /* lint */\n"))
240 "*Associate static header string templates with file types. A \%s in the
241template is replaced with the first string associated with the file's
0101cc40
RS
242version-control type in `vc-header-alist'."
243 :type '(repeat (cons :format "%v"
244 (regexp :tag "File Type")
245 (string :tag "Header String")))
246 :group 'vc)
7b4f934d 247
0101cc40 248(defcustom vc-comment-alist
594722a8
ER
249 '((nroff-mode ".\\\"" ""))
250 "*Special comment delimiters to be used in generating vc headers only.
251Add an entry in this list if you need to override the normal comment-start
252and comment-end variables. This will only be necessary if the mode language
0101cc40
RS
253is sensitive to blank lines."
254 :type '(repeat (list :format "%v"
255 (symbol :tag "Mode")
256 (string :tag "Comment Start")
257 (string :tag "Comment End")))
258 :group 'vc)
594722a8 259
bbf97570 260;; Default is to be extra careful for super-user.
0101cc40 261(defcustom vc-checkout-carefully (= (user-uid) 0)
bbf97570
RS
262 "*Non-nil means be extra-careful in checkout.
263Verify that the file really is not locked
0101cc40
RS
264and that its contents match what the master file says."
265 :type 'boolean
266 :group 'vc)
bbf97570 267
0101cc40 268(defcustom vc-rcs-release nil
b0c9bc8c 269 "*The release number of your RCS installation, as a string.
0101cc40
RS
270If nil, VC itself computes this value when it is first needed."
271 :type '(choice (const :tag "Auto" nil)
272 string)
273 :group 'vc)
b0c9bc8c 274
0101cc40 275(defcustom vc-sccs-release nil
b0c9bc8c 276 "*The release number of your SCCS installation, as a string.
0101cc40
RS
277If nil, VC itself computes this value when it is first needed."
278 :type '(choice (const :tag "Auto" nil)
279 string)
280 :group 'vc)
b0c9bc8c 281
0101cc40 282(defcustom vc-cvs-release nil
7e48e092 283 "*The release number of your CVS installation, as a string.
0101cc40
RS
284If nil, VC itself computes this value when it is first needed."
285 :type '(choice (const :tag "Auto" nil)
286 string)
287 :group 'vc)
b0c9bc8c 288
594722a8
ER
289;; Variables the user doesn't need to know about.
290(defvar vc-log-entry-mode nil)
291(defvar vc-log-operation nil)
67242a23 292(defvar vc-log-after-operation-hook nil)
34291cd2 293(defvar vc-checkout-writable-buffer-hook 'vc-checkout-writable-buffer)
dbf87856
RS
294;; In a log entry buffer, this is a local variable
295;; that points to the buffer for which it was made
296;; (either a file, or a VC dired buffer).
1a2f456b 297(defvar vc-parent-buffer nil)
8c0aaf40 298(defvar vc-parent-buffer-name nil)
594722a8 299
db59472c
RS
300(defvar vc-log-file)
301(defvar vc-log-version)
302
594722a8
ER
303(defconst vc-name-assoc-file "VC-names")
304
8c0aaf40 305(defvar vc-dired-mode nil)
e1f297e6
ER
306(make-variable-buffer-local 'vc-dired-mode)
307
c9b35ece 308(defvar vc-comment-ring (make-ring vc-maximum-comment-ring-size))
8c0aaf40
ER
309(defvar vc-comment-ring-index nil)
310(defvar vc-last-comment-match nil)
311
632e9525
RS
312;; Back-portability to Emacs 18
313
314(defun file-executable-p-18 (f)
315 (let ((modes (file-modes f)))
316 (and modes (not (zerop (logand 292))))))
317
318(defun file-regular-p-18 (f)
319 (let ((attributes (file-attributes f)))
320 (and attributes (not (car attributes)))))
321
322; Conditionally rebind some things for Emacs 18 compatibility
323(if (not (boundp 'minor-mode-map-alist))
324 (progn
325 (setq compilation-old-error-list nil)
326 (fset 'file-executable-p 'file-executable-p-18)
327 (fset 'shrink-window-if-larger-than-buffer 'beginning-of-buffer)
328 ))
329
4040437e 330(if (not (fboundp 'file-regular-p))
632e9525
RS
331 (fset 'file-regular-p 'file-regular-p-18))
332
b0c9bc8c
AS
333;;; Find and compare backend releases
334
335(defun vc-backend-release (backend)
336 ;; Returns which backend release is installed on this system.
337 (cond
338 ((eq backend 'RCS)
339 (or vc-rcs-release
2bb00bdd 340 (and (zerop (vc-do-command nil nil "rcs" nil nil "-V"))
b0c9bc8c
AS
341 (save-excursion
342 (set-buffer (get-buffer "*vc*"))
343 (setq vc-rcs-release
344 (car (vc-parse-buffer
345 '(("^RCS version \\([0-9.]+ *.*\\)" 1)))))))
346 (setq vc-rcs-release 'unknown)))
347 ((eq backend 'CVS)
348 (or vc-cvs-release
349 (and (zerop (vc-do-command nil 1 "cvs" nil nil "-v"))
350 (save-excursion
351 (set-buffer (get-buffer "*vc*"))
352 (setq vc-cvs-release
353 (car (vc-parse-buffer
354 '(("^Concurrent Versions System (CVS) \\([0-9.]+\\)"
355 1)))))))
356 (setq vc-cvs-release 'unknown)))
357 ((eq backend 'SCCS)
358 vc-sccs-release)))
359
360(defun vc-release-greater-or-equal (r1 r2)
361 ;; Compare release numbers, represented as strings.
362 ;; Release components are assumed cardinal numbers, not decimal
363 ;; fractions (5.10 is a higher release than 5.9). Omitted fields
364 ;; are considered lower (5.6.7 is earlier than 5.6.7.1).
365 ;; Comparison runs till the end of the string is found, or a
366 ;; non-numeric component shows up (5.6.7 is earlier than "5.6.7 beta",
367 ;; which is probably not what you want in some cases).
368 ;; This code is suitable for existing RCS release numbers.
369 ;; CVS releases are handled reasonably, too (1.3 < 1.4* < 1.5).
370 (let (v1 v2 i1 i2)
371 (catch 'done
372 (or (and (string-match "^\\.?\\([0-9]+\\)" r1)
373 (setq i1 (match-end 0))
374 (setq v1 (string-to-number (match-string 1 r1)))
375 (or (and (string-match "^\\.?\\([0-9]+\\)" r2)
376 (setq i2 (match-end 0))
377 (setq v2 (string-to-number (match-string 1 r2)))
378 (if (> v1 v2) (throw 'done t)
379 (if (< v1 v2) (throw 'done nil)
380 (throw 'done
381 (vc-release-greater-or-equal
382 (substring r1 i1)
383 (substring r2 i2)))))))
384 (throw 'done t)))
385 (or (and (string-match "^\\.?\\([0-9]+\\)" r2)
386 (throw 'done nil))
387 (throw 'done t)))))
388
389(defun vc-backend-release-p (backend release)
390 ;; Return t if we have RELEASE of BACKEND or better
391 (let (i r (ri 0) (ii 0) is rs (installation (vc-backend-release backend)))
392 (if (not (eq installation 'unknown))
393 (cond
394 ((or (eq backend 'RCS) (eq backend 'CVS))
395 (vc-release-greater-or-equal installation release))))))
396
c8de1d91
AS
397;;; functions that operate on RCS revision numbers
398
399(defun vc-trunk-p (rev)
400 ;; return t if REV is a revision on the trunk
401 (not (eq nil (string-match "\\`[0-9]+\\.[0-9]+\\'" rev))))
402
403(defun vc-branch-part (rev)
404 ;; return the branch part of a revision number REV
405 (substring rev 0 (string-match "\\.[0-9]+\\'" rev)))
406
594722a8
ER
407;; File property caching
408
8c0aaf40
ER
409(defun vc-clear-context ()
410 "Clear all cached file properties and the comment ring."
411 (interactive)
412 (fillarray vc-file-prop-obarray nil)
413 ;; Note: there is potential for minor lossage here if there is an open
414 ;; log buffer with a nonzero local value of vc-comment-ring-index.
c9b35ece 415 (setq vc-comment-ring (make-ring vc-maximum-comment-ring-size)))
8c0aaf40 416
88a2ffaf
RS
417(defun vc-file-clear-masterprops (file)
418 ;; clear all properties of FILE that were retrieved
419 ;; from the master file
420 (vc-file-setprop file 'vc-latest-version nil)
421 (vc-file-setprop file 'vc-your-latest-version nil)
422 (vc-backend-dispatch file
423 (progn ;; SCCS
424 (vc-file-setprop file 'vc-master-locks nil))
425 (progn ;; RCS
426 (vc-file-setprop file 'vc-default-branch nil)
427 (vc-file-setprop file 'vc-head-version nil)
8dd71345 428 (vc-file-setprop file 'vc-master-workfile-version nil)
88a2ffaf
RS
429 (vc-file-setprop file 'vc-master-locks nil))
430 (progn
431 (vc-file-setprop file 'vc-cvs-status nil))))
f3c61d82 432
c8de1d91
AS
433(defun vc-head-version (file)
434 ;; Return the RCS head version of FILE
435 (cond ((vc-file-getprop file 'vc-head-version))
436 (t (vc-fetch-master-properties file)
437 (vc-file-getprop file 'vc-head-version))))
f3c61d82 438
594722a8
ER
439;; Random helper functions
440
c8de1d91
AS
441(defun vc-latest-on-branch-p (file)
442 ;; return t iff the current workfile version of FILE is
443 ;; the latest on its branch.
444 (vc-backend-dispatch file
445 ;; SCCS
446 (string= (vc-workfile-version file) (vc-latest-version file))
447 ;; RCS
448 (let ((workfile-version (vc-workfile-version file)) tip-version)
449 (if (vc-trunk-p workfile-version)
450 (progn
451 ;; Re-fetch the head version number. This is to make
452 ;; sure that no-one has checked in a new version behind
453 ;; our back.
454 (vc-fetch-master-properties file)
455 (string= (vc-file-getprop file 'vc-head-version)
456 workfile-version))
457 ;; If we are not on the trunk, we need to examine the
7d88be52
AS
458 ;; whole current branch. (vc-master-workfile-version
459 ;; is not what we need.)
c8de1d91
AS
460 (save-excursion
461 (set-buffer (get-buffer-create "*vc-info*"))
462 (vc-insert-file (vc-name file) "^desc")
463 (setq tip-version (car (vc-parse-buffer (list (list
464 (concat "^\\(" (regexp-quote (vc-branch-part workfile-version))
465 "\\.[0-9]+\\)\ndate[ \t]+\\([0-9.]+\\);") 1 2)))))
466 (if (get-buffer "*vc-info*")
467 (kill-buffer (get-buffer "*vc-info*")))
468 (string= tip-version workfile-version))))
469 ;; CVS
8dd71345 470 t))
c8de1d91 471
7ef84cf9
RS
472(defun vc-registration-error (file)
473 (if file
590cc449
RS
474 (error "File %s is not under version control" file)
475 (error "Buffer %s is not associated with a file" (buffer-name))))
7ef84cf9 476
594722a8
ER
477(defvar vc-binary-assoc nil)
478
479(defun vc-find-binary (name)
480 "Look for a command anywhere on the subprocess-command search path."
481 (or (cdr (assoc name vc-binary-assoc))
deb9ebc6
PE
482 (catch 'found
483 (mapcar
484 (function
485 (lambda (s)
486 (if s
487 (let ((full (concat s "/" name)))
488 (if (file-executable-p full)
489 (progn
490 (setq vc-binary-assoc
491 (cons (cons name full) vc-binary-assoc))
492 (throw 'found full)))))))
493 exec-path)
494 nil)))
594722a8 495
6aa13729 496(defun vc-do-command (buffer okstatus command file last &rest flags)
594722a8 497 "Execute a version-control command, notifying user and checking for errors.
6aa13729 498Output from COMMAND goes to BUFFER, or *vc* if BUFFER is nil.
594722a8 499The command is successful if its exit status does not exceed OKSTATUS.
2bb00bdd 500 (If OKSTATUS is nil, that means to ignore errors.)
6aa13729
RS
501The last argument of the command is the master name of FILE if LAST is
502`MASTER', or the workfile of FILE if LAST is `WORKFILE'; this is appended
503to an optional list of FLAGS."
b0c9bc8c 504 (and file (setq file (expand-file-name file)))
6aa13729 505 (if (not buffer) (setq buffer "*vc*"))
594722a8 506 (if vc-command-messages
02da6253 507 (message "Running %s on %s..." command file))
1a2f456b 508 (let ((obuf (current-buffer)) (camefrom (current-buffer))
594722a8
ER
509 (squeezed nil)
510 (vc-file (and file (vc-name file)))
632e9525 511 (olddir default-directory)
594722a8 512 status)
6aa13729 513 (set-buffer (get-buffer-create buffer))
8c0aaf40
ER
514 (set (make-local-variable 'vc-parent-buffer) camefrom)
515 (set (make-local-variable 'vc-parent-buffer-name)
516 (concat " from " (buffer-name camefrom)))
632e9525 517 (setq default-directory olddir)
8c0aaf40 518
594722a8 519 (erase-buffer)
315e49ed 520
594722a8
ER
521 (mapcar
522 (function (lambda (s) (and s (setq squeezed (append squeezed (list s))))))
523 flags)
80688f5c 524 (if (and vc-file (eq last 'MASTER))
594722a8 525 (setq squeezed (append squeezed (list vc-file))))
632e9525
RS
526 (if (eq last 'WORKFILE)
527 (progn
528 (let* ((pwd (expand-file-name default-directory))
529 (preflen (length pwd)))
530 (if (string= (substring file 0 preflen) pwd)
531 (setq file (substring file preflen))))
532 (setq squeezed (append squeezed (list file)))))
46cd263f 533 (let ((exec-path (append vc-path exec-path))
eadcb02c
RS
534 ;; Add vc-path to PATH for the execution of this command.
535 (process-environment
536 (cons (concat "PATH=" (getenv "PATH")
993a1a44
RS
537 path-separator
538 (mapconcat 'identity vc-path path-separator))
bcbe4d57 539 process-environment))
b86b9918 540 (w32-quote-process-args t))
1a2f456b 541 (setq status (apply 'call-process command nil t nil squeezed)))
594722a8 542 (goto-char (point-max))
632e9525 543 (set-buffer-modified-p nil)
4805f679 544 (forward-line -1)
2bb00bdd 545 (if (or (not (integerp status)) (and okstatus (< okstatus status)))
594722a8 546 (progn
6aa13729 547 (pop-to-buffer buffer)
594722a8 548 (goto-char (point-min))
4c2d8cf9 549 (shrink-window-if-larger-than-buffer)
02da6253
PE
550 (error "Running %s...FAILED (%s)" command
551 (if (integerp status)
552 (format "status %d" status)
553 status))
594722a8
ER
554 )
555 (if vc-command-messages
02da6253 556 (message "Running %s...OK" command))
594722a8
ER
557 )
558 (set-buffer obuf)
559 status)
560 )
561
c4ae7096
JB
562;;; Save a bit of the text around POSN in the current buffer, to help
563;;; us find the corresponding position again later. This works even
564;;; if all markers are destroyed or corrupted.
c8de1d91 565;;; A lot of this was shamelessly lifted from Sebastian Kremer's rcs.el mode.
c4ae7096
JB
566(defun vc-position-context (posn)
567 (list posn
568 (buffer-size)
569 (buffer-substring posn
570 (min (point-max) (+ posn 100)))))
571
572;;; Return the position of CONTEXT in the current buffer, or nil if we
573;;; couldn't find it.
574(defun vc-find-position-by-context (context)
575 (let ((context-string (nth 2 context)))
576 (if (equal "" context-string)
577 (point-max)
578 (save-excursion
579 (let ((diff (- (nth 1 context) (buffer-size))))
580 (if (< diff 0) (setq diff (- diff)))
581 (goto-char (nth 0 context))
582 (if (or (search-forward context-string nil t)
583 ;; Can't use search-backward since the match may continue
584 ;; after point.
585 (progn (goto-char (- (point) diff (length context-string)))
586 ;; goto-char doesn't signal an error at
587 ;; beginning of buffer like backward-char would
588 (search-forward context-string nil t)))
589 ;; to beginning of OSTRING
590 (- (point) (length context-string))))))))
591
c8de1d91
AS
592(defun vc-buffer-context ()
593 ;; Return a list '(point-context mark-context reparse); from which
594 ;; vc-restore-buffer-context can later restore the context.
c4ae7096 595 (let ((point-context (vc-position-context (point)))
cfadef63
RS
596 ;; Use mark-marker to avoid confusion in transient-mark-mode.
597 (mark-context (if (eq (marker-buffer (mark-marker)) (current-buffer))
598 (vc-position-context (mark-marker))))
599 ;; Make the right thing happen in transient-mark-mode.
ab877583
RM
600 (mark-active nil)
601 ;; We may want to reparse the compilation buffer after revert
602 (reparse (and (boundp 'compilation-error-list) ;compile loaded
603 (let ((curbuf (current-buffer)))
604 ;; Construct a list; each elt is nil or a buffer
605 ;; iff that buffer is a compilation output buffer
606 ;; that contains markers into the current buffer.
607 (save-excursion
7ef84cf9
RS
608 (mapcar (function
609 (lambda (buffer)
ab877583
RM
610 (set-buffer buffer)
611 (let ((errors (or
612 compilation-old-error-list
613 compilation-error-list))
614 (buffer-error-marked-p nil))
6fb6ab11 615 (while (and (consp errors)
ab877583 616 (not buffer-error-marked-p))
a1bda481 617 (and (markerp (cdr (car errors)))
e9c8e248
RM
618 (eq buffer
619 (marker-buffer
a1bda481 620 (cdr (car errors))))
e9c8e248 621 (setq buffer-error-marked-p t))
ab877583 622 (setq errors (cdr errors)))
7ef84cf9 623 (if buffer-error-marked-p buffer))))
ab877583 624 (buffer-list)))))))
c8de1d91
AS
625 (list point-context mark-context reparse)))
626
627(defun vc-restore-buffer-context (context)
628 ;; Restore point/mark, and reparse any affected compilation buffers.
629 ;; CONTEXT is that which vc-buffer-context returns.
630 (let ((point-context (nth 0 context))
631 (mark-context (nth 1 context))
632 (reparse (nth 2 context)))
ab877583
RM
633 ;; Reparse affected compilation buffers.
634 (while reparse
635 (if (car reparse)
636 (save-excursion
637 (set-buffer (car reparse))
638 (let ((compilation-last-buffer (current-buffer)) ;select buffer
639 ;; Record the position in the compilation buffer of
640 ;; the last error next-error went to.
641 (error-pos (marker-position
642 (car (car-safe compilation-error-list)))))
643 ;; Reparse the error messages as far as they were parsed before.
644 (compile-reinitialize-errors '(4) compilation-parsing-end)
645 ;; Move the pointer up to find the error we were at before
646 ;; reparsing. Now next-error should properly go to the next one.
647 (while (and compilation-error-list
27f2f10b 648 (/= error-pos (car (car compilation-error-list))))
ab877583
RM
649 (setq compilation-error-list (cdr compilation-error-list))))))
650 (setq reparse (cdr reparse)))
e1f297e6 651
7b4f934d 652 ;; Restore point and mark
c4ae7096
JB
653 (let ((new-point (vc-find-position-by-context point-context)))
654 (if new-point (goto-char new-point)))
655 (if mark-context
656 (let ((new-mark (vc-find-position-by-context mark-context)))
657 (if new-mark (set-mark new-mark))))))
658
c8de1d91
AS
659(defun vc-revert-buffer1 (&optional arg no-confirm)
660 ;; Revert buffer, try to keep point and mark where user expects them in spite
661 ;; of changes because of expanded version-control key words.
662 ;; This is quite important since otherwise typeahead won't work as expected.
663 (interactive "P")
664 (widen)
665 (let ((context (vc-buffer-context)))
e7ffe86a
RS
666 ;; t means don't call normal-mode; that's to preserve various minor modes.
667 (revert-buffer arg no-confirm t)
c8de1d91
AS
668 (vc-restore-buffer-context context)))
669
594722a8 670
97d3f950 671(defun vc-buffer-sync (&optional not-urgent)
594722a8 672 ;; Make sure the current buffer and its working file are in sync
97d3f950 673 ;; NOT-URGENT means it is ok to continue if the user says not to save.
bbf97570 674 (if (buffer-modified-p)
97d3f950
RS
675 (if (or vc-suppress-confirm
676 (y-or-n-p (format "Buffer %s modified; save it? " (buffer-name))))
677 (save-buffer)
678 (if not-urgent
679 nil
680 (error "Aborted")))))
681
594722a8 682
9a51ed3a 683(defun vc-workfile-unchanged-p (file &optional want-differences-if-changed)
594722a8
ER
684 ;; Has the given workfile changed since last checkout?
685 (let ((checkout-time (vc-file-getprop file 'vc-checkout-time))
686 (lastmod (nth 5 (file-attributes file))))
9a51ed3a
PE
687 (or (equal checkout-time lastmod)
688 (and (or (not checkout-time) want-differences-if-changed)
689 (let ((unchanged (zerop (vc-backend-diff file nil nil
c6d4f628 690 (not want-differences-if-changed)))))
9a51ed3a
PE
691 ;; 0 stands for an unknown time; it can't match any mod time.
692 (vc-file-setprop file 'vc-checkout-time (if unchanged lastmod 0))
693 unchanged)))))
594722a8 694
e1f297e6
ER
695(defun vc-next-action-on-file (file verbose &optional comment)
696 ;;; If comment is specified, it will be used as an admin or checkin comment.
80688f5c 697 (let ((vc-file (vc-name file))
f3c61d82 698 (vc-type (vc-backend file))
8dd71345 699 owner version buffer)
e1f297e6
ER
700 (cond
701
702 ;; if there is no master file corresponding, create one
703 ((not vc-file)
632e9525
RS
704 (vc-register verbose comment)
705 (if vc-initial-comment
706 (setq vc-log-after-operation-hook
707 'vc-checkout-writable-buffer-hook)
708 (vc-checkout-writable-buffer file)))
e1f297e6 709
61dee1e7
AS
710 ;; CVS: changes to the master file need to be
711 ;; merged back into the working file
712 ((and (eq vc-type 'CVS)
713 (or (eq (vc-cvs-status file) 'needs-checkout)
714 (eq (vc-cvs-status file) 'needs-merge)))
8dd71345
AS
715 (if (or vc-dired-mode
716 (yes-or-no-p
717 (format "%s is not up-to-date. Merge in changes now? "
718 (buffer-name))))
61dee1e7 719 (progn
8dd71345
AS
720 (if vc-dired-mode
721 (and (setq buffer (get-file-buffer file))
722 (buffer-modified-p buffer)
723 (switch-to-buffer-other-window buffer)
724 (vc-buffer-sync t))
725 (setq buffer (current-buffer))
726 (vc-buffer-sync t))
727 (if (and buffer (buffer-modified-p buffer)
61dee1e7 728 (not (yes-or-no-p
8dd71345
AS
729 (format
730 "Buffer %s modified; merge file on disc anyhow? "
731 (buffer-name buffer)))))
61dee1e7
AS
732 (error "Merge aborted"))
733 (if (not (zerop (vc-backend-merge-news file)))
734 ;; Overlaps detected - what now? Should use some
735 ;; fancy RCS conflict resolving package, or maybe
736 ;; emerge, but for now, simply warn the user with a
737 ;; message.
738 (message "Conflicts detected!"))
8dd71345
AS
739 (and buffer
740 (vc-resynch-buffer file t (not (buffer-modified-p buffer)))))
61dee1e7
AS
741 (error "%s needs update" (buffer-name))))
742
4cbeb71c
RS
743 ;; If there is no lock on the file, assert one and get it.
744 ;; (With implicit checkout, make sure not to lose unsaved changes.)
745 ((progn (and (eq (vc-checkout-model file) 'implicit)
746 (buffer-modified-p buffer)
747 (vc-buffer-sync))
748 (not (setq owner (vc-locking-user file))))
bbf97570 749 (if (and vc-checkout-carefully
9a51ed3a 750 (not (vc-workfile-unchanged-p file t)))
bbf97570 751 (if (save-window-excursion
6aa13729 752 (pop-to-buffer "*vc-diff*")
bbf97570
RS
753 (goto-char (point-min))
754 (insert-string (format "Changes to %s since last lock:\n\n"
755 file))
756 (not (beep))
757 (yes-or-no-p
758 (concat "File has unlocked changes, "
759 "claim lock retaining changes? ")))
760 (progn (vc-backend-steal file)
761 (vc-mode-line file))
762 (if (not (yes-or-no-p "Revert to checked-in version, instead? "))
2c28ac43 763 (error "Checkout aborted")
bbf97570
RS
764 (vc-revert-buffer1 t t)
765 (vc-checkout-writable-buffer file))
766 )
c6d4f628
RS
767 (if verbose
768 (if (not (eq vc-type 'SCCS))
e163b283
AS
769 (vc-checkout file nil
770 (read-string "Branch or version to move to: "))
2c28ac43 771 (error "Sorry, this is not implemented for SCCS"))
9341ff29
AS
772 (if (vc-latest-on-branch-p file)
773 (vc-checkout-writable-buffer file)
774 (if (yes-or-no-p
775 "This is not the latest version. Really lock it? ")
776 (vc-checkout-writable-buffer file)
777 (if (yes-or-no-p "Lock the latest version instead? ")
778 (vc-checkout-writable-buffer file
1ba1cade
AS
779 (if (vc-trunk-p (vc-workfile-version file))
780 "" ;; this means check out latest on trunk
781 (vc-branch-part (vc-workfile-version file)))))))
9341ff29 782 )))
e1f297e6
ER
783
784 ;; a checked-out version exists, but the user may not own the lock
61dee1e7 785 ((and (not (eq vc-type 'CVS))
8172cd86 786 (not (string-equal owner (vc-user-login-name))))
e1f297e6 787 (if comment
590cc449 788 (error "Sorry, you can't steal the lock on %s this way" file))
b0c9bc8c
AS
789 (and (eq vc-type 'RCS)
790 (not (vc-backend-release-p 'RCS "5.6.2"))
2c28ac43 791 (error "File is locked by %s" owner))
e1f297e6
ER
792 (vc-steal-lock
793 file
c6d4f628
RS
794 (if verbose (read-string "Version to steal: ")
795 (vc-workfile-version file))
e1f297e6 796 owner))
80688f5c 797
c6d4f628 798 ;; OK, user owns the lock on the file
8c0aaf40 799 (t
b0c9bc8c
AS
800 (if vc-dired-mode
801 (find-file-other-window file)
802 (find-file file))
e1f297e6
ER
803
804 ;; give luser a chance to save before checking in.
805 (vc-buffer-sync)
806
807 ;; Revert if file is unchanged and buffer is too.
808 ;; If buffer is modified, that means the user just said no
809 ;; to saving it; in that case, don't revert,
810 ;; because the user might intend to save
811 ;; after finishing the log entry.
80688f5c 812 (if (and (vc-workfile-unchanged-p file)
e1f297e6 813 (not (buffer-modified-p)))
c6d4f628
RS
814 ;; DO NOT revert the file without asking the user!
815 (cond
816 ((yes-or-no-p "Revert to master version? ")
817 (vc-backend-revert file)
818 (vc-resynch-window file t t)))
e1f297e6
ER
819
820 ;; user may want to set nonstandard parameters
821 (if verbose
822 (setq version (read-string "New version level: ")))
823
824 ;; OK, let's do the checkin
825 (vc-checkin file version comment)
8c0aaf40 826 )))))
e1f297e6
ER
827
828(defun vc-next-action-dired (file rev comment)
b0c9bc8c
AS
829 ;; Do a vc-next-action-on-file on all the marked files, possibly
830 ;; passing on the log comment we've just entered.
831 (let ((configuration (current-window-configuration))
8dd71345
AS
832 (dired-buffer (current-buffer))
833 (dired-dir default-directory))
632e9525 834 (dired-map-over-marks
f008ca58
KH
835 (let ((file (dired-get-filename)) p
836 (default-directory default-directory))
b0c9bc8c 837 (message "Processing %s..." file)
8dd71345
AS
838 ;; Adjust the default directory so that checkouts
839 ;; go to the right place.
840 (setq default-directory (file-name-directory file))
b0c9bc8c
AS
841 (vc-next-action-on-file file nil comment)
842 (set-buffer dired-buffer)
8dd71345 843 (setq default-directory dired-dir)
b0c9bc8c
AS
844 (vc-dired-update-line file)
845 (set-window-configuration configuration)
846 (message "Processing %s...done" file))
847 nil t)))
e1f297e6 848
637a8ae9 849;; Here's the major entry point.
594722a8 850
637a8ae9 851;;;###autoload
594722a8
ER
852(defun vc-next-action (verbose)
853 "Do the next logical checkin or checkout operation on the current file.
c6d4f628
RS
854 If you call this from within a VC dired buffer with no files marked,
855it will operate on the file in the current line.
856 If you call this from within a VC dired buffer, and one or more
857files are marked, it will accept a log message and then operate on
858each one. The log message will be used as a comment for any register
859or checkin operations, but ignored when doing checkouts. Attempted
860lock steals will raise an error.
861 A prefix argument lets you specify the version number to use.
80688f5c
RS
862
863For RCS and SCCS files:
594722a8 864 If the file is not already registered, this registers it for version
34291cd2 865control and then retrieves a writable, locked copy for editing.
594722a8 866 If the file is registered and not locked by anyone, this checks out
34291cd2 867a writable and locked file ready for editing.
594722a8
ER
868 If the file is checked out and locked by the calling user, this
869first checks to see if the file has changed since checkout. If not,
870it performs a revert.
e1f297e6
ER
871 If the file has been changed, this pops up a buffer for entry
872of a log message; when the message has been entered, it checks in the
594722a8 873resulting changes along with the log message as change commentary. If
34291cd2 874the variable `vc-keep-workfiles' is non-nil (which is its default), a
594722a8
ER
875read-only copy of the changed file is left in place afterwards.
876 If the file is registered and locked by someone else, you are given
e1f297e6 877the option to steal the lock.
80688f5c
RS
878
879For CVS files:
880 If the file is not already registered, this registers it for version
881control. This does a \"cvs add\", but no \"cvs commit\".
882 If the file is added but not committed, it is committed.
80688f5c
RS
883 If your working file is changed, but the repository file is
884unchanged, this pops up a buffer for entry of a log message; when the
885message has been entered, it checks in the resulting changes along
886with the logmessage as change commentary. A writable file is retained.
887 If the repository file is changed, you are asked if you want to
c6d4f628 888merge in the changes into your working copy."
bbf97570 889
594722a8 890 (interactive "P")
8c0aaf40
ER
891 (catch 'nogo
892 (if vc-dired-mode
893 (let ((files (dired-get-marked-files)))
8dd71345
AS
894 (if (string= ""
895 (mapconcat
b0c9bc8c
AS
896 (function (lambda (f)
897 (if (eq (vc-backend f) 'CVS)
8dd71345
AS
898 (if (or (eq (vc-cvs-status f) 'locally-modified)
899 (eq (vc-cvs-status f) 'locally-added))
b0c9bc8c
AS
900 "@" "")
901 (if (vc-locking-user f) "@" ""))))
902 files ""))
903 (vc-next-action-dired nil nil "dummy")
904 (vc-start-entry nil nil nil
905 "Enter a change comment for the marked files."
906 'vc-next-action-dired))
8dd71345 907 (throw 'nogo nil)))
e1f297e6 908 (while vc-parent-buffer
1a2f456b 909 (pop-to-buffer vc-parent-buffer))
e1f297e6
ER
910 (if buffer-file-name
911 (vc-next-action-on-file buffer-file-name verbose)
7ef84cf9 912 (vc-registration-error nil))))
594722a8
ER
913
914;;; These functions help the vc-next-action entry point
915
c6d4f628 916(defun vc-checkout-writable-buffer (&optional file rev)
34291cd2 917 "Retrieve a writable copy of the latest version of the current buffer's file."
c6d4f628 918 (vc-checkout (or file (buffer-file-name)) t rev)
02da6253
PE
919 )
920
637a8ae9 921;;;###autoload
e1f297e6 922(defun vc-register (&optional override comment)
594722a8
ER
923 "Register the current file into your version-control system."
924 (interactive "P")
f1b82fc8
KH
925 (or buffer-file-name
926 (error "No visited file"))
e837a82f
RS
927 (let ((master (vc-name buffer-file-name)))
928 (and master (file-exists-p master)
929 (error "This file is already registered"))
930 (and master
931 (not (y-or-n-p "Previous master file has vanished. Make a new one? "))
932 (error "This file is already registered")))
02da6253
PE
933 ;; Watch out for new buffers of size 0: the corresponding file
934 ;; does not exist yet, even though buffer-modified-p is nil.
935 (if (and (not (buffer-modified-p))
936 (zerop (buffer-size))
937 (not (file-exists-p buffer-file-name)))
938 (set-buffer-modified-p t))
594722a8 939 (vc-buffer-sync)
993a1a44
RS
940 (cond ((not vc-make-backup-files)
941 ;; inhibit backup for this buffer
942 (make-local-variable 'backup-inhibited)
943 (setq backup-inhibited t)))
594722a8
ER
944 (vc-admin
945 buffer-file-name
e1f297e6
ER
946 (and override
947 (read-string
948 (format "Initial version level for %s: " buffer-file-name))))
594722a8
ER
949 )
950
624b4662 951(defun vc-resynch-window (file &optional keep noquery)
594722a8 952 ;; If the given file is in the current buffer,
a7acbbe4 953 ;; either revert on it so we see expanded keywords,
594722a8 954 ;; or unvisit it (depending on vc-keep-workfiles)
624b4662
RS
955 ;; NOQUERY if non-nil inhibits confirmation for reverting.
956 ;; NOQUERY should be t *only* if it is known the only difference
957 ;; between the buffer and the file is due to RCS rather than user editing!
594722a8
ER
958 (and (string= buffer-file-name file)
959 (if keep
960 (progn
88a2ffaf
RS
961 ;; temporarily remove vc-find-file-hook, so that
962 ;; we don't lose the properties
963 (remove-hook 'find-file-hooks 'vc-find-file-hook)
1ab31687 964 (vc-revert-buffer1 t noquery)
88a2ffaf 965 (add-hook 'find-file-hooks 'vc-find-file-hook)
594722a8 966 (vc-mode-line buffer-file-name))
88a2ffaf 967 (kill-buffer (current-buffer)))))
594722a8 968
503b5c85 969(defun vc-resynch-buffer (file &optional keep noquery)
b0c9bc8c 970 ;; if FILE is currently visited, resynch its buffer
503b5c85
RS
971 (let ((buffer (get-file-buffer file)))
972 (if buffer
973 (save-excursion
974 (set-buffer buffer)
975 (vc-resynch-window file keep noquery)))))
976
b965445f 977(defun vc-start-entry (file rev comment msg action &optional after-hook)
e1f297e6
ER
978 ;; Accept a comment for an operation on FILE revision REV. If COMMENT
979 ;; is nil, pop up a VC-log buffer, emit MSG, and set the
980 ;; action on close to ACTION; otherwise, do action immediately.
cdaf7a1a 981 ;; Remember the file's buffer in vc-parent-buffer (current one if no file).
b965445f 982 ;; AFTER-HOOK specifies the local value for vc-log-operation-hook.
e1f297e6 983 (let ((parent (if file (find-file-noselect file) (current-buffer))))
f0b188ed
RS
984 (if vc-before-checkin-hook
985 (if file
986 (save-excursion
987 (set-buffer parent)
988 (run-hooks 'vc-before-checkin-hook))
989 (run-hooks 'vc-before-checkin-hook)))
e1f297e6
ER
990 (if comment
991 (set-buffer (get-buffer-create "*VC-log*"))
992 (pop-to-buffer (get-buffer-create "*VC-log*")))
8c0aaf40
ER
993 (set (make-local-variable 'vc-parent-buffer) parent)
994 (set (make-local-variable 'vc-parent-buffer-name)
995 (concat " from " (buffer-name vc-parent-buffer)))
7e869659 996 (if file (vc-mode-line file))
37667a5c 997 (vc-log-mode file)
b965445f
RS
998 (make-local-variable 'vc-log-after-operation-hook)
999 (if after-hook
1000 (setq vc-log-after-operation-hook after-hook))
e1f297e6 1001 (setq vc-log-operation action)
e1f297e6
ER
1002 (setq vc-log-version rev)
1003 (if comment
1004 (progn
1005 (erase-buffer)
8c0aaf40
ER
1006 (if (eq comment t)
1007 (vc-finish-logentry t)
1008 (insert comment)
1009 (vc-finish-logentry nil)))
e1f297e6 1010 (message "%s Type C-c C-c when done." msg))))
594722a8 1011
e1f297e6 1012(defun vc-admin (file rev &optional comment)
624b4662 1013 "Check a file into your version-control system.
594722a8 1014FILE is the unmodified name of the file. REV should be the base version
e1f297e6 1015level to check it in under. COMMENT, if specified, is the checkin comment."
b965445f
RS
1016 (vc-start-entry file rev
1017 (or comment (not vc-initial-comment))
1018 "Enter initial comment." 'vc-backend-admin
6bcb1d4e 1019 nil))
e1f297e6 1020
c6d4f628 1021(defun vc-checkout (file &optional writable rev)
e1f297e6
ER
1022 "Retrieve a copy of the latest version of the given file."
1023 ;; If ftp is on this system and the name matches the ange-ftp format
1024 ;; for a remote file, the user is trying something that won't work.
1025 (if (and (string-match "^/[^/:]+:" file) (vc-find-binary "ftp"))
1026 (error "Sorry, you can't check out files over FTP"))
c6d4f628 1027 (vc-backend-checkout file writable rev)
b0c9bc8c 1028 (vc-resynch-buffer file t t))
594722a8
ER
1029
1030(defun vc-steal-lock (file rev &optional owner)
1031 "Steal the lock on the current workfile."
29fc1ce9
RS
1032 (let (file-description)
1033 (if (not owner)
1034 (setq owner (vc-locking-user file)))
1035 (if rev
1036 (setq file-description (format "%s:%s" file rev))
1037 (setq file-description file))
1038 (if (not (y-or-n-p (format "Take the lock on %s from %s? "
1039 file-description owner)))
1040 (error "Steal cancelled"))
1041 (pop-to-buffer (get-buffer-create "*VC-mail*"))
1042 (setq default-directory (expand-file-name "~/"))
1043 (auto-save-mode auto-save-default)
1044 (mail-mode)
1045 (erase-buffer)
1046 (mail-setup owner (format "Stolen lock on %s" file-description) nil nil nil
3e3da61f 1047 (list (list 'vc-finish-steal file rev)))
29fc1ce9
RS
1048 (goto-char (point-max))
1049 (insert
1050 (format "I stole the lock on %s, " file-description)
1051 (current-time-string)
1052 ".\n")
1053 (message "Please explain why you stole the lock. Type C-c C-c when done.")))
594722a8 1054
ad014629 1055;; This is called when the notification has been sent.
594722a8 1056(defun vc-finish-steal (file version)
594722a8 1057 (vc-backend-steal file version)
3e3da61f
RS
1058 (if (get-file-buffer file)
1059 (save-excursion
6242bee4 1060 (set-buffer (get-file-buffer file))
3e3da61f 1061 (vc-resynch-window file t t))))
594722a8 1062
594722a8
ER
1063(defun vc-checkin (file &optional rev comment)
1064 "Check in the file specified by FILE.
1065The optional argument REV may be a string specifying the new version level
67242a23 1066\(if nil increment the current level). The file is either retained with write
34291cd2 1067permissions zeroed, or deleted (according to the value of `vc-keep-workfiles').
80688f5c 1068If the back-end is CVS, a writable workfile is always kept.
594722a8
ER
1069COMMENT is a comment string; if omitted, a buffer is
1070popped up to accept a comment."
61446fe7 1071 (vc-start-entry file rev comment
b965445f
RS
1072 "Enter a change comment." 'vc-backend-checkin
1073 'vc-checkin-hook))
594722a8 1074
1a2f456b
ER
1075;;; Here is a checkin hook that may prove useful to sites using the
1076;;; ChangeLog facility supported by Emacs.
3b4dd9a9
RM
1077(defun vc-comment-to-change-log (&optional whoami file-name)
1078 "Enter last VC comment into change log file for current buffer's file.
1079Optional arg (interactive prefix) non-nil means prompt for user name and site.
1080Second arg is file name of change log. \
1081If nil, uses `change-log-default-name'."
43cea1ab
RM
1082 (interactive (if current-prefix-arg
1083 (list current-prefix-arg
1084 (prompt-for-change-log-name))))
41208291
KH
1085 ;; Make sure the defvar for add-log-current-defun-function has been executed
1086 ;; before binding it.
1087 (require 'add-log)
3b4dd9a9
RM
1088 (let (;; Extract the comment first so we get any error before doing anything.
1089 (comment (ring-ref vc-comment-ring 0))
43cea1ab 1090 ;; Don't let add-change-log-entry insert a defun name.
3b4dd9a9
RM
1091 (add-log-current-defun-function 'ignore)
1092 end)
1093 ;; Call add-log to do half the work.
43cea1ab 1094 (add-change-log-entry whoami file-name t t)
3b4dd9a9
RM
1095 ;; Insert the VC comment, leaving point before it.
1096 (setq end (save-excursion (insert comment) (point-marker)))
1097 (if (looking-at "\\s *\\s(")
1098 ;; It starts with an open-paren, as in "(foo): Frobbed."
43cea1ab 1099 ;; So remove the ": " add-log inserted.
3b4dd9a9
RM
1100 (delete-char -2))
1101 ;; Canonicalize the white space between the file name and comment.
1102 (just-one-space)
1103 ;; Indent rest of the text the same way add-log indented the first line.
1104 (let ((indentation (current-indentation)))
1105 (save-excursion
1106 (while (< (point) end)
1107 (forward-line 1)
1108 (indent-to indentation))
c124b1b4 1109 (setq end (point))))
3b4dd9a9 1110 ;; Fill the inserted text, preserving open-parens at bol.
6b60c5d1
BG
1111 (let ((paragraph-separate (concat paragraph-separate "\\|\\s *\\s("))
1112 (paragraph-start (concat paragraph-start "\\|\\s *\\s(")))
43cea1ab 1113 (beginning-of-line)
c124b1b4
RM
1114 (fill-region (point) end))
1115 ;; Canonicalize the white space at the end of the entry so it is
1116 ;; separated from the next entry by a single blank line.
1117 (skip-syntax-forward " " end)
1118 (delete-char (- (skip-syntax-backward " ")))
1119 (or (eobp) (looking-at "\n\n")
1120 (insert "\n"))))
3b4dd9a9 1121
1a2f456b 1122
8c0aaf40 1123(defun vc-finish-logentry (&optional nocomment)
594722a8
ER
1124 "Complete the operation implied by the current log entry."
1125 (interactive)
8c0aaf40
ER
1126 ;; Check and record the comment, if any.
1127 (if (not nocomment)
1128 (progn
1129 (goto-char (point-max))
1130 (if (not (bolp))
1131 (newline))
1132 ;; Comment too long?
1133 (vc-backend-logentry-check vc-log-file)
1134 ;; Record the comment in the comment ring
8c0aaf40
ER
1135 (ring-insert vc-comment-ring (buffer-string))
1136 ))
b2396d1f 1137 ;; Sync parent buffer in case the user modified it while editing the comment.
cdaf7a1a 1138 ;; But not if it is a vc-dired buffer.
b2396d1f 1139 (save-excursion
cdaf7a1a
RS
1140 (set-buffer vc-parent-buffer)
1141 (or vc-dired-mode
1142 (vc-buffer-sync)))
61dee1e7
AS
1143 (if (not vc-log-operation) (error "No log operation is pending"))
1144 ;; save the parameters held in buffer-local variables
1145 (let ((log-operation vc-log-operation)
1146 (log-file vc-log-file)
1147 (log-version vc-log-version)
1148 (log-entry (buffer-string))
1149 (after-hook vc-log-after-operation-hook))
e2bef5c3
RS
1150 ;; Return to "parent" buffer of this checkin and remove checkin window
1151 (pop-to-buffer vc-parent-buffer)
1152 (let ((logbuf (get-buffer "*VC-log*")))
1153 (delete-windows-on logbuf)
1154 (kill-buffer logbuf))
61dee1e7
AS
1155 ;; OK, do it to it
1156 (save-excursion
1157 (funcall log-operation
1158 log-file
1159 log-version
1160 log-entry))
e2bef5c3
RS
1161 ;; Now make sure we see the expanded headers
1162 (if buffer-file-name
e1f297e6 1163 (vc-resynch-window buffer-file-name vc-keep-workfiles t))
37667a5c 1164 (run-hooks after-hook 'vc-finish-logentry-hook)))
594722a8
ER
1165
1166;; Code for access to the comment ring
1167
8c0aaf40
ER
1168(defun vc-previous-comment (arg)
1169 "Cycle backwards through comment history."
1170 (interactive "*p")
1171 (let ((len (ring-length vc-comment-ring)))
1172 (cond ((<= len 0)
1173 (message "Empty comment ring")
1174 (ding))
1175 (t
1176 (erase-buffer)
1177 ;; Initialize the index on the first use of this command
1178 ;; so that the first M-p gets index 0, and the first M-n gets
1179 ;; index -1.
1180 (if (null vc-comment-ring-index)
1181 (setq vc-comment-ring-index
1182 (if (> arg 0) -1
1183 (if (< arg 0) 1 0))))
1184 (setq vc-comment-ring-index
c6bfcd12 1185 (mod (+ vc-comment-ring-index arg) len))
8c0aaf40
ER
1186 (message "%d" (1+ vc-comment-ring-index))
1187 (insert (ring-ref vc-comment-ring vc-comment-ring-index))))))
1188
1189(defun vc-next-comment (arg)
1190 "Cycle forwards through comment history."
1191 (interactive "*p")
1192 (vc-previous-comment (- arg)))
1193
1194(defun vc-comment-search-reverse (str)
1195 "Searches backwards through comment history for substring match."
1196 (interactive "sComment substring: ")
1197 (if (string= str "")
1198 (setq str vc-last-comment-match)
1199 (setq vc-last-comment-match str))
1200 (if (null vc-comment-ring-index)
1201 (setq vc-comment-ring-index -1))
1202 (let ((str (regexp-quote str))
1203 (len (ring-length vc-comment-ring))
1204 (n (1+ vc-comment-ring-index)))
1205 (while (and (< n len) (not (string-match str (ring-ref vc-comment-ring n))))
1206 (setq n (+ n 1)))
1207 (cond ((< n len)
1208 (vc-previous-comment (- n vc-comment-ring-index)))
1209 (t (error "Not found")))))
1210
1211(defun vc-comment-search-forward (str)
1212 "Searches forwards through comment history for substring match."
1213 (interactive "sComment substring: ")
1214 (if (string= str "")
1215 (setq str vc-last-comment-match)
1216 (setq vc-last-comment-match str))
1217 (if (null vc-comment-ring-index)
1218 (setq vc-comment-ring-index 0))
1219 (let ((str (regexp-quote str))
1220 (len (ring-length vc-comment-ring))
1221 (n vc-comment-ring-index))
1222 (while (and (>= n 0) (not (string-match str (ring-ref vc-comment-ring n))))
1223 (setq n (- n 1)))
1224 (cond ((>= n 0)
1225 (vc-next-comment (- n vc-comment-ring-index)))
1226 (t (error "Not found")))))
594722a8
ER
1227
1228;; Additional entry points for examining version histories
1229
637a8ae9 1230;;;###autoload
97d3f950 1231(defun vc-diff (historic &optional not-urgent)
e8ee1ccf
RS
1232 "Display diffs between file versions.
1233Normally this compares the current file and buffer with the most recent
1234checked in version of that file. This uses no arguments.
1235With a prefix argument, it reads the file name to use
1236and two version designators specifying which versions to compare."
48078f8f 1237 (interactive (list current-prefix-arg t))
e1f297e6
ER
1238 (if vc-dired-mode
1239 (set-buffer (find-file-noselect (dired-get-filename))))
8ac8c82f 1240 (while vc-parent-buffer
1a2f456b 1241 (pop-to-buffer vc-parent-buffer))
594722a8
ER
1242 (if historic
1243 (call-interactively 'vc-version-diff)
8c0aaf40 1244 (if (or (null buffer-file-name) (null (vc-name buffer-file-name)))
064726ac
JB
1245 (error
1246 "There is no version-control master associated with this buffer"))
02da6253 1247 (let ((file buffer-file-name)
594722a8 1248 unchanged)
7ef84cf9
RS
1249 (or (and file (vc-name file))
1250 (vc-registration-error file))
97d3f950 1251 (vc-buffer-sync not-urgent)
594722a8
ER
1252 (setq unchanged (vc-workfile-unchanged-p buffer-file-name))
1253 (if unchanged
7e48e092 1254 (message "No changes to %s since latest version" file)
9a51ed3a 1255 (vc-backend-diff file)
8c0aaf40
ER
1256 ;; Ideally, we'd like at this point to parse the diff so that
1257 ;; the buffer effectively goes into compilation mode and we
1258 ;; can visit the old and new change locations via next-error.
1259 ;; Unfortunately, this is just too painful to do. The basic
1260 ;; problem is that the `old' file doesn't exist to be
1261 ;; visited. This plays hell with numerous assumptions in
1262 ;; the diff.el and compile.el machinery.
7e48e092 1263 (set-buffer "*vc-diff*")
632e9525 1264 (setq default-directory (file-name-directory file))
b246f571
RS
1265 (if (= 0 (buffer-size))
1266 (progn
1267 (setq unchanged t)
7e48e092
AS
1268 (message "No changes to %s since latest version" file))
1269 (pop-to-buffer "*vc-diff*")
4c2d8cf9 1270 (goto-char (point-min))
064726ac
JB
1271 (shrink-window-if-larger-than-buffer)))
1272 (not unchanged))))
594722a8
ER
1273
1274(defun vc-version-diff (file rel1 rel2)
1275 "For FILE, report diffs between two stored versions REL1 and REL2 of it.
1276If FILE is a directory, generate diffs between versions for all registered
1277files in or below it."
3234e2a3 1278 (interactive "FFile or directory to diff: \nsOlder version: \nsNewer version: ")
594722a8
ER
1279 (if (string-equal rel1 "") (setq rel1 nil))
1280 (if (string-equal rel2 "") (setq rel2 nil))
1281 (if (file-directory-p file)
1a2f456b 1282 (let ((camefrom (current-buffer)))
594722a8 1283 (set-buffer (get-buffer-create "*vc-status*"))
8c0aaf40
ER
1284 (set (make-local-variable 'vc-parent-buffer) camefrom)
1285 (set (make-local-variable 'vc-parent-buffer-name)
1286 (concat " from " (buffer-name camefrom)))
594722a8 1287 (erase-buffer)
3234e2a3
ER
1288 (insert "Diffs between "
1289 (or rel1 "last version checked in")
1290 " and "
1291 (or rel2 "current workfile(s)")
1292 ":\n\n")
6aa13729 1293 (set-buffer (get-buffer-create "*vc-diff*"))
e1f297e6 1294 (cd file)
594722a8 1295 (vc-file-tree-walk
2f119435 1296 default-directory
594722a8 1297 (function (lambda (f)
a9a59766 1298 (message "Looking at %s" f)
594722a8 1299 (and
3234e2a3
ER
1300 (not (file-directory-p f))
1301 (vc-registered f)
02da6253
PE
1302 (vc-backend-diff f rel1 rel2)
1303 (append-to-buffer "*vc-status*" (point-min) (point-max)))
1304 )))
594722a8
ER
1305 (pop-to-buffer "*vc-status*")
1306 (insert "\nEnd of diffs.\n")
1307 (goto-char (point-min))
1308 (set-buffer-modified-p nil)
1309 )
36bed8bc
RS
1310 (if (zerop (vc-backend-diff file rel1 rel2))
1311 (message "No changes to %s between %s and %s." file rel1 rel2)
6aa13729 1312 (pop-to-buffer "*vc-diff*"))))
594722a8 1313
f1818994
PE
1314;;;###autoload
1315(defun vc-version-other-window (rev)
1316 "Visit version REV of the current buffer in another window.
1317If the current buffer is named `F', the version is named `F.~REV~'.
1318If `F.~REV~' already exists, it is used instead of being re-created."
1319 (interactive "sVersion to visit (default is latest version): ")
1320 (if vc-dired-mode
1321 (set-buffer (find-file-noselect (dired-get-filename))))
1322 (while vc-parent-buffer
1323 (pop-to-buffer vc-parent-buffer))
1324 (if (and buffer-file-name (vc-name buffer-file-name))
1325 (let* ((version (if (string-equal rev "")
1326 (vc-latest-version buffer-file-name)
1327 rev))
1328 (filename (concat buffer-file-name ".~" version "~")))
1329 (or (file-exists-p filename)
1330 (vc-backend-checkout buffer-file-name nil version filename))
1331 (find-file-other-window filename))
1332 (vc-registration-error buffer-file-name)))
1333
594722a8
ER
1334;; Header-insertion code
1335
637a8ae9 1336;;;###autoload
594722a8
ER
1337(defun vc-insert-headers ()
1338 "Insert headers in a file for use with your version-control system.
1339Headers desired are inserted at the start of the buffer, and are pulled from
34291cd2 1340the variable `vc-header-alist'."
594722a8 1341 (interactive)
e1f297e6
ER
1342 (if vc-dired-mode
1343 (find-file-other-window (dired-get-filename)))
8ac8c82f 1344 (while vc-parent-buffer
1a2f456b 1345 (pop-to-buffer vc-parent-buffer))
594722a8
ER
1346 (save-excursion
1347 (save-restriction
1348 (widen)
1349 (if (or (not (vc-check-headers))
820bde8d 1350 (y-or-n-p "Version headers already exist. Insert another set? "))
594722a8
ER
1351 (progn
1352 (let* ((delims (cdr (assq major-mode vc-comment-alist)))
1353 (comment-start-vc (or (car delims) comment-start "#"))
1354 (comment-end-vc (or (car (cdr delims)) comment-end ""))
f3c61d82 1355 (hdstrings (cdr (assoc (vc-backend (buffer-file-name)) vc-header-alist))))
594722a8
ER
1356 (mapcar (function (lambda (s)
1357 (insert comment-start-vc "\t" s "\t"
1358 comment-end-vc "\n")))
1359 hdstrings)
1360 (if vc-static-header-alist
1361 (mapcar (function (lambda (f)
1362 (if (string-match (car f) buffer-file-name)
1363 (insert (format (cdr f) (car hdstrings))))))
1364 vc-static-header-alist))
1365 )
1366 )))))
1367
c8de1d91
AS
1368(defun vc-clear-headers ()
1369 ;; Clear all version headers in the current buffer, i.e. reset them
1370 ;; to the nonexpanded form. Only implemented for RCS, yet.
1371 ;; Don't lose point and mark during this.
1372 (let ((context (vc-buffer-context)))
1373 (goto-char (point-min))
1374 (while (re-search-forward "\\$\\([A-Za-z]+\\): [^\\$]+\\$" nil t)
1375 (replace-match "$\\1$"))
1376 (vc-restore-buffer-context context)))
1377
2f119435 1378;; The VC directory major mode. Coopt Dired for this.
e1f297e6
ER
1379;; All VC commands get mapped into logical equivalents.
1380
2f119435
AS
1381(define-derived-mode vc-dired-mode dired-mode "Dired under VC"
1382 "The major mode used in VC directory buffers. It is derived from Dired.
e1f297e6 1383All Dired commands operate normally. Users currently locking listed files
ee7e9c88 1384are listed in place of the file's owner and group.
e1f297e6
ER
1385Keystrokes bound to VC commands will execute as though they had been called
1386on a buffer attached to the file named in the current Dired buffer line."
2f119435
AS
1387 (setq vc-dired-mode t))
1388
1389(define-key vc-dired-mode-map "\C-xv" vc-prefix-map)
1390(define-key vc-dired-mode-map "g" 'vc-dired-update)
1391(define-key vc-dired-mode-map "=" 'vc-diff)
594722a8 1392
b0c9bc8c
AS
1393(defun vc-dired-state-info (file)
1394 ;; Return the string that indicates the version control status
1395 ;; on a VC dired line.
1396 (let ((cvs-state (and (eq (vc-backend file) 'CVS)
1397 (vc-cvs-status file))))
1398 (if cvs-state
1399 (cond ((eq cvs-state 'up-to-date) nil)
1400 ((eq cvs-state 'needs-checkout) "patch")
1401 ((eq cvs-state 'locally-modified) "modified")
1402 ((eq cvs-state 'needs-merge) "merge")
1403 ((eq cvs-state 'unresolved-conflict) "conflict")
1404 ((eq cvs-state 'locally-added) "added"))
1405 (vc-locking-user file))))
1406
8c0aaf40
ER
1407(defun vc-dired-reformat-line (x)
1408 ;; Hack a directory-listing line, plugging in locking-user info in
34291cd2
RS
1409 ;; place of the user and group info. Should have the beneficial
1410 ;; side-effect of shortening the listing line. Each call starts with
8c0aaf40
ER
1411 ;; point immediately following the dired mark area on the line to be
1412 ;; hacked.
1413 ;;
1414 ;; Simplest possible one:
1415 ;; (insert (concat x "\t")))
1416 ;;
1417 ;; This code, like dired, assumes UNIX -l format.
2f119435
AS
1418 (let ((pos (point)) limit perm owner date-and-file)
1419 (end-of-line)
1420 (setq limit (point))
1421 (goto-char pos)
1422 (cond
1423 ((or
1424 (re-search-forward ;; owner and group
1425"\\([drwxlts-]+ \\) *[0-9]+ \\([^ ]+\\) +[^ ]+ +[0-9]+\\( [^ 0-9]+ [0-9 ][0-9] .*\\)"
1426 limit t)
1427 (re-search-forward ;; only owner displayed
1428"\\([drwxlts-]+ \\) *[0-9]+ \\([^ ]+\\) +[0-9]+\\( [^ 0-9]+ [0-9 ][0-9] .*\\)"
1429 limit t))
1430 (setq perm (match-string 1)
1431 owner (match-string 2)
1432 date-and-file (match-string 3)))
1433 ((re-search-forward ;; OS/2 -l format, no links, owner, group
1434"\\([drwxlts-]+ \\) *[0-9]+\\( [^ 0-9]+ [0-9 ][0-9] .*\\)"
1435 limit t)
1436 (setq perm (match-string 1)
1437 date-and-file (match-string 2))))
80688f5c 1438 (if x (setq x (concat "(" x ")")))
b0c9bc8c 1439 (let ((rep (substring (concat x " ") 0 10)))
2f119435
AS
1440 (replace-match (concat perm rep date-and-file)))))
1441
b0c9bc8c
AS
1442(defun vc-dired-update-line (file)
1443 ;; Update the vc-dired listing line of file -- it is assumed
8dd71345
AS
1444 ;; that point is already on this line. Don't use dired-do-redisplay
1445 ;; for this, because it cannot handle the way vc-dired deals with
1446 ;; subdirectories.
b0c9bc8c 1447 (beginning-of-line)
8dd71345
AS
1448 (forward-char 2)
1449 (let ((start (point)))
1450 (forward-line 1)
1451 (beginning-of-line)
1452 (delete-region start (point))
1453 (insert-directory file dired-listing-switches)
1454 (forward-line -1)
1455 (end-of-line)
1456 (delete-char (- (length file)))
1457 (insert (substring file (length (expand-file-name default-directory))))
1458 (goto-char start))
b0c9bc8c 1459 (vc-dired-reformat-line (vc-dired-state-info file)))
8c0aaf40 1460
2f119435
AS
1461(defun vc-dired-update (verbose)
1462 (interactive "P")
1463 (vc-directory default-directory verbose))
1464
632e9525
RS
1465;;; Note in Emacs 18 the following defun gets overridden
1466;;; with the symbol 'vc-directory-18. See below.
637a8ae9 1467;;;###autoload
2f119435 1468(defun vc-directory (dirname verbose)
632e9525
RS
1469 "Show version-control status of the current directory and subdirectories.
1470Normally it creates a Dired buffer that lists only the locked files
1471in all these directories. With a prefix argument, it lists all files."
2f119435 1472 (interactive "DDired under VC (directory): \nP")
221cc4f4 1473 (require 'dired)
2f119435
AS
1474 (setq dirname (expand-file-name dirname))
1475 ;; force a trailing slash
1476 (if (not (eq (elt dirname (1- (length dirname))) ?/))
1477 (setq dirname (concat dirname "/")))
632e9525 1478 (let (nonempty
2f119435 1479 (dl (length dirname))
b0c9bc8c 1480 (filelist nil) (statelist nil)
2f119435 1481 (old-dir default-directory)
632e9525
RS
1482 dired-buf
1483 dired-buf-mod-count)
1484 (vc-file-tree-walk
2f119435 1485 dirname
b0c9bc8c
AS
1486 (function
1487 (lambda (f)
1488 (if (vc-registered f)
1489 (let ((state (vc-dired-state-info f)))
1490 (and (or verbose state)
1491 (setq filelist (cons (substring f dl) filelist))
1492 (setq statelist (cons state statelist))))))))
1493 (save-window-excursion
1494 (save-excursion
2f119435
AS
1495 ;; This uses a semi-documented feature of dired; giving a switch
1496 ;; argument forces the buffer to refresh each time.
1497 (setq dired-buf
1498 (dired-internal-noselect
1499 (cons dirname (nreverse filelist))
1500 dired-listing-switches 'vc-dired-mode))
1501 (setq nonempty (not (eq 0 (length filelist))))))
8dd71345 1502 (switch-to-buffer dired-buf)
8dd71345
AS
1503 ;; Make a few modifications to the header
1504 (setq buffer-read-only nil)
1505 (goto-char (point-min))
1506 (forward-line 1) ;; Skip header line
1507 (let ((start (point))) ;; Erase (but don't remove) the
1508 (end-of-line) ;; "wildcard" line.
1509 (delete-region start (point)))
1510 (beginning-of-line)
594722a8
ER
1511 (if nonempty
1512 (progn
8dd71345 1513 ;; Plug the version information into the individual lines
e1f297e6 1514 (mapcar
7ef84cf9
RS
1515 (function
1516 (lambda (x)
8c0aaf40
ER
1517 (forward-char 2) ;; skip dired's mark area
1518 (vc-dired-reformat-line x)
7ef84cf9 1519 (forward-line 1))) ;; go to next line
b0c9bc8c 1520 (nreverse statelist))
e1f297e6
ER
1521 (setq buffer-read-only t)
1522 (goto-char (point-min))
8dd71345 1523 (dired-next-line 2)
e1f297e6 1524 )
8dd71345
AS
1525 (dired-next-line 1)
1526 (insert " ")
1527 (setq buffer-read-only t)
02da6253 1528 (message "No files are currently %s under %s"
2f119435 1529 (if verbose "registered" "locked") dirname))
594722a8
ER
1530 ))
1531
632e9525
RS
1532;; Emacs 18 version
1533(defun vc-directory-18 (verbose)
1534 "Show version-control status of all files under the current directory."
1535 (interactive "P")
1536 (let (nonempty (dir default-directory))
1537 (save-excursion
1538 (set-buffer (get-buffer-create "*vc-status*"))
1539 (erase-buffer)
1540 (cd dir)
1541 (vc-file-tree-walk
2f119435 1542 default-directory
632e9525
RS
1543 (function (lambda (f)
1544 (if (vc-registered f)
1545 (let ((user (vc-locking-user f)))
1546 (if (or user verbose)
1547 (insert (format
1548 "%s %s\n"
1549 (concat user) f))))))))
1550 (setq nonempty (not (zerop (buffer-size)))))
2f119435 1551
632e9525
RS
1552 (if nonempty
1553 (progn
1554 (pop-to-buffer "*vc-status*" t)
1555 (goto-char (point-min))
1556 (shrink-window-if-larger-than-buffer)))
1557 (message "No files are currently %s under %s"
1558 (if verbose "registered" "locked") default-directory))
1559 )
1560
1561(or (boundp 'minor-mode-map-alist)
1562 (fset 'vc-directory 'vc-directory-18))
e70bdc98 1563
594722a8
ER
1564;; Named-configuration support for SCCS
1565
1566(defun vc-add-triple (name file rev)
1567 (save-excursion
993a1a44
RS
1568 (find-file (expand-file-name
1569 vc-name-assoc-file
1570 (file-name-as-directory
1571 (expand-file-name (vc-backend-subdirectory-name file)
1572 (file-name-directory file)))))
594722a8
ER
1573 (goto-char (point-max))
1574 (insert name "\t:\t" file "\t" rev "\n")
1575 (basic-save-buffer)
1576 (kill-buffer (current-buffer))
1577 ))
1578
1579(defun vc-record-rename (file newname)
1580 (save-excursion
993a1a44
RS
1581 (find-file
1582 (expand-file-name
1583 vc-name-assoc-file
1584 (file-name-as-directory
1585 (expand-file-name (vc-backend-subdirectory-name file)
1586 (file-name-directory file)))))
594722a8 1587 (goto-char (point-min))
7d847440
RS
1588 ;; (replace-regexp (concat ":" (regexp-quote file) "$") (concat ":" newname))
1589 (while (re-search-forward (concat ":" (regexp-quote file) "$") nil t)
1590 (replace-match (concat ":" newname) nil nil))
594722a8
ER
1591 (basic-save-buffer)
1592 (kill-buffer (current-buffer))
1593 ))
1594
1595(defun vc-lookup-triple (file name)
7b4f934d
ER
1596 ;; Return the numeric version corresponding to a named snapshot of file
1597 ;; If name is nil or a version number string it's just passed through
47ca02a6 1598 (cond ((null name) name)
7b4f934d
ER
1599 ((let ((firstchar (aref name 0)))
1600 (and (>= firstchar ?0) (<= firstchar ?9)))
1601 name)
1602 (t
b7011339
RS
1603 (save-excursion
1604 (set-buffer (get-buffer-create "*vc-info*"))
993a1a44
RS
1605 (vc-insert-file
1606 (expand-file-name
1607 vc-name-assoc-file
1608 (file-name-as-directory
1609 (expand-file-name (vc-backend-subdirectory-name file)
1610 (file-name-directory file)))))
b7011339
RS
1611 (prog1
1612 (car (vc-parse-buffer
1613 (list (list (concat name "\t:\t" file "\t\\(.+\\)") 1))))
1614 (kill-buffer "*vc-info*"))))
1615 ))
594722a8
ER
1616
1617;; Named-configuration entry points
1618
503b5c85
RS
1619(defun vc-snapshot-precondition ()
1620 ;; Scan the tree below the current directory.
1621 ;; If any files are locked, return the name of the first such file.
1622 ;; (This means, neither snapshot creation nor retrieval is allowed.)
1623 ;; If one or more of the files are currently visited, return `visited'.
1624 ;; Otherwise, return nil.
1625 (let ((status nil))
1626 (catch 'vc-locked-example
1627 (vc-file-tree-walk
2f119435 1628 default-directory
503b5c85
RS
1629 (function (lambda (f)
1630 (and (vc-registered f)
1631 (if (vc-locking-user f) (throw 'vc-locked-example f)
1632 (if (get-file-buffer f) (setq status 'visited)))))))
1633 status)))
594722a8 1634
637a8ae9 1635;;;###autoload
594722a8
ER
1636(defun vc-create-snapshot (name)
1637 "Make a snapshot called NAME.
1638The snapshot is made from all registered files at or below the current
1639directory. For each file, the version level of its latest
1640version becomes part of the named configuration."
1641 (interactive "sNew snapshot name: ")
503b5c85
RS
1642 (let ((result (vc-snapshot-precondition)))
1643 (if (stringp result)
1644 (error "File %s is locked" result)
1dabb4e6 1645 (vc-file-tree-walk
2f119435 1646 default-directory
1dabb4e6
PE
1647 (function (lambda (f) (and
1648 (vc-name f)
1649 (vc-backend-assign-name f name)))))
1650 )))
594722a8 1651
637a8ae9 1652;;;###autoload
594722a8
ER
1653(defun vc-retrieve-snapshot (name)
1654 "Retrieve the snapshot called NAME.
1655This function fails if any files are locked at or below the current directory
1656Otherwise, all registered files are checked out (unlocked) at their version
1657levels in the snapshot."
1658 (interactive "sSnapshot name to retrieve: ")
503b5c85
RS
1659 (let ((result (vc-snapshot-precondition))
1660 (update nil))
1661 (if (stringp result)
1662 (error "File %s is locked" result)
1663 (if (eq result 'visited)
1664 (setq update (yes-or-no-p "Update the affected buffers? ")))
1dabb4e6 1665 (vc-file-tree-walk
2f119435 1666 default-directory
1dabb4e6
PE
1667 (function (lambda (f) (and
1668 (vc-name f)
1669 (vc-error-occurred
503b5c85
RS
1670 (vc-backend-checkout f nil name)
1671 (if update (vc-resynch-buffer f t t)))))))
1dabb4e6 1672 )))
594722a8
ER
1673
1674;; Miscellaneous other entry points
1675
637a8ae9 1676;;;###autoload
594722a8
ER
1677(defun vc-print-log ()
1678 "List the change log of the current buffer in a window."
1679 (interactive)
e1f297e6
ER
1680 (if vc-dired-mode
1681 (set-buffer (find-file-noselect (dired-get-filename))))
8ac8c82f 1682 (while vc-parent-buffer
1a2f456b 1683 (pop-to-buffer vc-parent-buffer))
594722a8 1684 (if (and buffer-file-name (vc-name buffer-file-name))
632e9525
RS
1685 (let ((file buffer-file-name))
1686 (vc-backend-print-log file)
594722a8 1687 (pop-to-buffer (get-buffer-create "*vc*"))
632e9525 1688 (setq default-directory (file-name-directory file))
b667752d 1689 (goto-char (point-max)) (forward-line -1)
4805f679
BF
1690 (while (looking-at "=*\n")
1691 (delete-char (- (match-end 0) (match-beginning 0)))
1692 (forward-line -1))
594722a8 1693 (goto-char (point-min))
4805f679
BF
1694 (if (looking-at "[\b\t\n\v\f\r ]+")
1695 (delete-char (- (match-end 0) (match-beginning 0))))
4c2d8cf9 1696 (shrink-window-if-larger-than-buffer)
6dfe5fe0 1697 ;; move point to the log entry for the current version
b667752d
AS
1698 (and (not (eq (vc-backend file) 'SCCS))
1699 (re-search-forward
1700 ;; also match some context, for safety
1701 (concat "----\nrevision " (vc-workfile-version file)
1702 "\\(\tlocked by:.*\n\\|\n\\)date: ") nil t)
1703 ;; set the display window so that
1704 ;; the whole log entry is displayed
1705 (let (start end lines)
1706 (beginning-of-line) (forward-line -1) (setq start (point))
1707 (if (not (re-search-forward "^----*\nrevision" nil t))
1708 (setq end (point-max))
1709 (beginning-of-line) (forward-line -1) (setq end (point)))
1710 (setq lines (count-lines start end))
1711 (cond
1712 ;; if the global information and this log entry fit
1713 ;; into the window, display from the beginning
1714 ((< (count-lines (point-min) end) (window-height))
1715 (goto-char (point-min))
1716 (recenter 0)
1717 (goto-char start))
1718 ;; if the whole entry fits into the window,
1719 ;; display it centered
1720 ((< (1+ lines) (window-height))
1721 (goto-char start)
1722 (recenter (1- (- (/ (window-height) 2) (/ lines 2)))))
1723 ;; otherwise (the entry is too large for the window),
1724 ;; display from the start
1725 (t
1726 (goto-char start)
1727 (recenter 0)))))
594722a8 1728 )
7ef84cf9 1729 (vc-registration-error buffer-file-name)
594722a8
ER
1730 )
1731 )
1732
637a8ae9 1733;;;###autoload
594722a8 1734(defun vc-revert-buffer ()
9c95ac44
RS
1735 "Revert the current buffer's file back to the latest checked-in version.
1736This asks for confirmation if the buffer contents are not identical
80688f5c
RS
1737to that version.
1738If the back-end is CVS, this will give you the most recent revision of
1739the file on the branch you are editing."
594722a8 1740 (interactive)
e1f297e6
ER
1741 (if vc-dired-mode
1742 (find-file-other-window (dired-get-filename)))
8ac8c82f 1743 (while vc-parent-buffer
1a2f456b 1744 (pop-to-buffer vc-parent-buffer))
594722a8 1745 (let ((file buffer-file-name)
221cc4f4
RS
1746 ;; This operation should always ask for confirmation.
1747 (vc-suppress-confirm nil)
97d3f950 1748 (obuf (current-buffer)) (changed (vc-diff nil t)))
221cc4f4 1749 (if (and changed (not (yes-or-no-p "Discard changes? ")))
594722a8 1750 (progn
fab2e906
RS
1751 (if (and (window-dedicated-p (selected-window))
1752 (one-window-p t 'selected-frame))
1753 (make-frame-invisible (selected-frame))
1754 (delete-window))
590cc449 1755 (error "Revert cancelled"))
594722a8
ER
1756 (set-buffer obuf))
1757 (if changed
fab2e906
RS
1758 (if (and (window-dedicated-p (selected-window))
1759 (one-window-p t 'selected-frame))
1760 (make-frame-invisible (selected-frame))
1761 (delete-window)))
594722a8 1762 (vc-backend-revert file)
624b4662 1763 (vc-resynch-window file t t)
594722a8
ER
1764 )
1765 )
1766
637a8ae9 1767;;;###autoload
594722a8 1768(defun vc-cancel-version (norevert)
34291cd2
RS
1769 "Get rid of most recently checked in version of this file.
1770A prefix argument means do not revert the buffer afterwards."
594722a8 1771 (interactive "P")
e1f297e6
ER
1772 (if vc-dired-mode
1773 (find-file-other-window (dired-get-filename)))
8ac8c82f
ER
1774 (while vc-parent-buffer
1775 (pop-to-buffer vc-parent-buffer))
c8de1d91 1776 (cond
7e48e092 1777 ((not (vc-registered (buffer-file-name)))
1694bd16
RS
1778 (vc-registration-error (buffer-file-name)))
1779 ((eq (vc-backend (buffer-file-name)) 'CVS)
c8de1d91
AS
1780 (error "Unchecking files under CVS is dangerous and not supported in VC"))
1781 ((vc-locking-user (buffer-file-name))
2c28ac43 1782 (error "This version is locked; use vc-revert-buffer to discard changes"))
c8de1d91 1783 ((not (vc-latest-on-branch-p (buffer-file-name)))
2c28ac43 1784 (error "This is not the latest version--VC cannot cancel it")))
7e48e092
AS
1785 (let* ((target (vc-workfile-version (buffer-file-name)))
1786 (recent (if (vc-trunk-p target) "" (vc-branch-part target)))
1787 (config (current-window-configuration)) done)
1788 (if (null (yes-or-no-p (format "Remove version %s from master? " target)))
7b4f934d 1789 nil
c8de1d91
AS
1790 (setq norevert (or norevert (not
1791 (yes-or-no-p "Revert buffer to most recent remaining version? "))))
7b4f934d 1792 (vc-backend-uncheck (buffer-file-name) target)
7e48e092
AS
1793 ;; Check out the most recent remaining version. If it fails, because
1794 ;; the whole branch got deleted, do a double-take and check out the
1795 ;; version where the branch started.
1796 (while (not done)
1797 (condition-case err
1798 (progn
1799 (if norevert
1800 ;; Check out locked, but only to disc, and keep
1801 ;; modifications in the buffer.
1802 (vc-backend-checkout (buffer-file-name) t recent)
1803 ;; Check out unlocked, and revert buffer.
1804 (vc-checkout (buffer-file-name) nil recent))
1805 (setq done t))
ae2506d0
AS
1806 ;; If the checkout fails, vc-do-command signals an error.
1807 ;; We catch this error, check the reason, correct the
1808 ;; version number, and try a second time.
7e48e092
AS
1809 (error (set-buffer "*vc*")
1810 (goto-char (point-min))
ae2506d0 1811 (if (search-forward "no side branches present for" nil t)
7e48e092 1812 (progn (setq recent (vc-branch-part recent))
ae2506d0
AS
1813 ;; vc-do-command popped up a window with
1814 ;; the error message. Get rid of it, by
1815 ;; restoring the old window configuration.
7e48e092
AS
1816 (set-window-configuration config))
1817 ;; No, it was some other error: re-signal it.
1818 (signal (car err) (cdr err))))))
1819 ;; If norevert, clear version headers and mark the buffer modified.
1820 (if norevert
1821 (progn
1822 (set-visited-file-name (buffer-file-name))
1823 (if (not vc-make-backup-files)
1824 ;; inhibit backup for this buffer
1825 (progn (make-local-variable 'backup-inhibited)
1826 (setq backup-inhibited t)))
1827 (if (eq (vc-backend (buffer-file-name)) 'RCS)
1828 (progn (setq buffer-read-only nil)
1829 (vc-clear-headers)))
1830 (vc-mode-line (buffer-file-name))))
1831 (message "Version %s has been removed from the master" target)
c8de1d91 1832 )))
594722a8 1833
29fc1ce9 1834;;;###autoload
594722a8 1835(defun vc-rename-file (old new)
34291cd2
RS
1836 "Rename file OLD to NEW, and rename its master file likewise."
1837 (interactive "fVC rename file: \nFRename to: ")
80688f5c
RS
1838 ;; There are several ways of renaming files under CVS 1.3, but they all
1839 ;; have serious disadvantages. See the FAQ (available from think.com in
1840 ;; pub/cvs/). I'd rather send the user an error, than do something he might
1841 ;; consider to be wrong. When the famous, long-awaited rename database is
1842 ;; implemented things might change for the better. This is unlikely to occur
1843 ;; until CVS 2.0 is released. --ceder 1994-01-23 21:27:51
f3c61d82 1844 (if (eq (vc-backend old) 'CVS)
2c28ac43 1845 (error "Renaming files under CVS is dangerous and not supported in VC"))
594722a8 1846 (let ((oldbuf (get-file-buffer old)))
d52f0de9 1847 (if (and oldbuf (buffer-modified-p oldbuf))
590cc449 1848 (error "Please save files before moving them"))
594722a8 1849 (if (get-file-buffer new)
590cc449 1850 (error "Already editing new file name"))
d52f0de9
RS
1851 (if (file-exists-p new)
1852 (error "New file already exists"))
594722a8
ER
1853 (let ((oldmaster (vc-name old)))
1854 (if oldmaster
d52f0de9
RS
1855 (progn
1856 (if (vc-locking-user old)
1857 (error "Please check in files before moving them"))
1858 (if (or (file-symlink-p oldmaster)
1859 ;; This had FILE, I changed it to OLD. -- rms.
1860 (file-symlink-p (vc-backend-subdirectory-name old)))
1861 (error "This is not a safe thing to do in the presence of symbolic links"))
1862 (rename-file
1863 oldmaster
f3c61d82 1864 (let ((backend (vc-backend old))
d52f0de9
RS
1865 (newdir (or (file-name-directory new) ""))
1866 (newbase (file-name-nondirectory new)))
1867 (catch 'found
1868 (mapcar
1869 (function
1870 (lambda (s)
1871 (if (eq backend (cdr s))
1872 (let* ((newmaster (format (car s) newdir newbase))
1873 (newmasterdir (file-name-directory newmaster)))
1874 (if (or (not newmasterdir)
1875 (file-directory-p newmasterdir))
1876 (throw 'found newmaster))))))
1877 vc-master-templates)
1878 (error "New file lacks a version control directory"))))))
594722a8
ER
1879 (if (or (not oldmaster) (file-exists-p old))
1880 (rename-file old new)))
1881; ?? Renaming a file might change its contents due to keyword expansion.
1882; We should really check out a new copy if the old copy was precisely equal
1883; to some checked in version. However, testing for this is tricky....
1884 (if oldbuf
1885 (save-excursion
1886 (set-buffer oldbuf)
4c145b9e
RS
1887 (let ((buffer-read-only buffer-read-only))
1888 (set-visited-file-name new))
1889 (vc-backend new)
1890 (vc-mode-line new)
594722a8 1891 (set-buffer-modified-p nil))))
60213ed0
RS
1892 ;; This had FILE, I changed it to OLD. -- rms.
1893 (vc-backend-dispatch old
80688f5c
RS
1894 (vc-record-rename old new) ;SCCS
1895 nil ;RCS
1896 nil ;CVS
1897 )
594722a8
ER
1898 )
1899
637a8ae9 1900;;;###autoload
f35ecf88 1901(defun vc-update-change-log (&rest args)
73a9679c 1902 "Find change log file and add entries from recent RCS/CVS logs.
d68e6990
RS
1903Normally, find log entries for all registered files in the default
1904directory using `rcs2log', which finds CVS logs preferentially.
f35ecf88 1905The mark is left at the end of the text prepended to the change log.
d68e6990 1906
f35ecf88 1907With prefix arg of C-u, only find log entries for the current buffer's file.
d68e6990
RS
1908
1909With any numeric prefix arg, find log entries for all currently visited
1910files that are under version control. This puts all the entries in the
1911log for the default directory, which may not be appropriate.
1912
73a9679c
RS
1913From a program, any arguments are assumed to be filenames and are
1914passed to the `rcs2log' script after massaging to be relative to the
1915default directory."
67242a23
RM
1916 (interactive
1917 (cond ((consp current-prefix-arg) ;C-u
1918 (list buffer-file-name))
1919 (current-prefix-arg ;Numeric argument.
1920 (let ((files nil)
1921 (buffers (buffer-list))
1922 file)
1923 (while buffers
1924 (setq file (buffer-file-name (car buffers)))
f3c61d82 1925 (and file (vc-backend file)
4b40fdea 1926 (setq files (cons file files)))
67242a23 1927 (setq buffers (cdr buffers)))
4b40fdea
PE
1928 files))
1929 (t
73a9679c
RS
1930 ;; `rcs2log' will find the relevant RCS or CVS files
1931 ;; relative to the curent directory if none supplied.
1932 nil)))
449decf5 1933 (let ((odefault default-directory)
124c852b
RS
1934 (changelog (find-change-log))
1935 ;; Presumably not portable to non-Unixy systems, along with rcs2log:
1936 (tempfile (make-temp-name
1937 (concat (file-name-as-directory
1938 (directory-file-name (or (getenv "TMPDIR")
1939 (getenv "TMP")
1940 (getenv "TEMP")
1941 "/tmp")))
1942 "vc")))
b91916f3 1943 (full-name (or add-log-full-name
8172cd86
AS
1944 (user-full-name)
1945 (user-login-name)
1946 (format "uid%d" (number-to-string (user-uid)))))
b91916f3
RS
1947 (mailing-address (or add-log-mailing-address
1948 user-mail-address)))
124c852b 1949 (find-file-other-window changelog)
41dfb835
RS
1950 (barf-if-buffer-read-only)
1951 (vc-buffer-sync)
1952 (undo-boundary)
1953 (goto-char (point-min))
1954 (push-mark)
1955 (message "Computing change log entries...")
4b40fdea 1956 (message "Computing change log entries... %s"
124c852b
RS
1957 (unwind-protect
1958 (progn
1959 (cd odefault)
1960 (if (eq 0 (apply 'call-process "rcs2log" nil
1961 (list t tempfile) nil
1962 "-c" changelog
1963 "-u" (concat (vc-user-login-name)
1964 "\t" full-name
1965 "\t" mailing-address)
1966 (mapcar
1967 (function
1968 (lambda (f)
1969 (file-relative-name
1970 (if (file-name-absolute-p f)
1971 f
1972 (concat odefault f)))))
1973 args)))
1974 "done"
1975 (pop-to-buffer
1976 (set-buffer (get-buffer-create "*vc*")))
1977 (erase-buffer)
1978 (insert-file tempfile)
1979 "failed"))
1980 (cd (file-name-directory changelog))
1981 (delete-file tempfile)))))
7d2d9482
RS
1982\f
1983;; vc-annotate functionality (CVS only).
1984(defvar vc-annotate-mode nil
1985 "Variable indicating if VC-Annotate mode is active.")
1986
1987(defvar vc-annotate-mode-map ()
1988 "Local keymap used for VC-Annotate mode.")
1989
1990;; Syntax Table
1991(defvar vc-annotate-mode-syntax-table nil
1992 "Syntax table used in VC-Annotate mode buffers.")
1993
1994(defun vc-annotate-mode-variables ()
1995 (if (not vc-annotate-mode-syntax-table)
1996 (progn (setq vc-annotate-mode-syntax-table (make-syntax-table))
1997 (set-syntax-table vc-annotate-mode-syntax-table)))
1998 (if (not vc-annotate-mode-map)
1999 (setq vc-annotate-mode-map (make-sparse-keymap))))
2000
2001(defun vc-annotate-mode ()
2002 "Major mode for buffers displaying output from the CVS `annotate' command.
2003
2004You can use the mode-specific menu to alter the time-span of the used
2005colors. See variable `vc-annotate-menu-elements' for customizing the
2006menu items."
2007 (interactive)
2008 (kill-all-local-variables) ; Recommended by RMS.
2009 (vc-annotate-mode-variables) ; This defines various variables.
2010 (use-local-map vc-annotate-mode-map) ; This provides the local keymap.
2011 (set-syntax-table vc-annotate-mode-syntax-table)
2012 (setq major-mode 'vc-annotate-mode) ; This is how `describe-mode'
2013 ; finds out what to describe.
2014 (setq mode-name "Annotate") ; This goes into the mode line.
2015 (run-hooks 'vc-annotate-mode-hook)
2016 (vc-annotate-add-menu))
2017
2018(defun vc-annotate-display-default (&optional event)
2019 "Use the default color spectrum for VC Annotate mode."
2020 (interactive)
2021 (vc-annotate-display (get-buffer (buffer-name))))
2022
2023(defun vc-annotate-add-menu ()
2024 "Adds the menu 'Annotate' to the menu bar in VC-Annotate mode."
2025 (setq vc-annotate-mode-menu (make-sparse-keymap "Annotate"))
2026 (define-key vc-annotate-mode-menu [default]
2027 '("Default" . vc-annotate-display-default))
2028 (let ((menu-elements vc-annotate-menu-elements))
2029 (while menu-elements
2030 (let* ((element (car menu-elements))
2031 (days (round (* element
2032 (vc-annotate-car-last-cons vc-annotate-color-map)
2033 0.7585))))
2034 (setq menu-elements (cdr menu-elements))
2035 (define-key vc-annotate-mode-menu
2036 (vector days)
2037 (cons (format "Span %d days"
2038 days)
2039 `(lambda ()
2040 ,(format "Use colors spanning %d days" days)
2041 (vc-annotate-display (get-buffer (buffer-name))
2042 (vc-annotate-time-span ,element)))))))))
2043
2044(defvar vc-annotate-ratio)
594722a8 2045
7d2d9482
RS
2046;;;###autoload
2047(defun vc-annotate (ratio)
2048 "Display the result of the CVS `annotate' command using colors.
2049New lines are displayed in red, old in blue.
2050A prefix argument specifies a factor for stretching the time scale.
2051
2052`vc-annotate-menu-elements' customizes the menu elements of the
2053mode-specific menu. `vc-annotate-color-map' and
2054`vc-annotate-very-old-color' defines the mapping of time to
2055colors. `vc-annotate-background' specifies the background color."
2056 (interactive "p")
2057 (if (not (eq (vc-buffer-backend) 'CVS)) ; This only works with CVS
2058 (vc-registration-error (buffer-file-name)))
2059 (message "Annotating...")
2060 (let ((temp-buffer-name (concat "*cvs annotate " (buffer-name) "*"))
2061 (temp-buffer-show-function 'vc-annotate-display)
2062 (vc-annotate-ratio ratio))
2063 (with-output-to-temp-buffer temp-buffer-name
2064 (call-process "cvs" nil (get-buffer temp-buffer-name) nil
2065 "annotate" (file-name-nondirectory (buffer-file-name)))))
2066 (message "Annotating... done"))
2067
2068(defun vc-annotate-car-last-cons (assoc-list)
2069 "Return car of last cons in ASSOC-LIST."
2070 (if (not (eq nil (cdr assoc-list)))
2071 (vc-annotate-car-last-cons (cdr assoc-list))
2072 (car (car assoc-list))))
2073
2074;; Return an association list with span factor applied to the
2075;; time-span of assoc-list. Optionaly quantize to the factor of
2076;; quantize.
2077(defun vc-annotate-time-span (assoc-list span &optional quantize)
2078 ;; Apply span to each car of every cons
2079 (if (not (eq nil assoc-list))
2080 (append (list (cons (* (car (car assoc-list)) span)
2081 (cdr (car assoc-list))))
2082 (vc-annotate-time-span (nthcdr (cond (quantize) ; optional
2083 (1)) ; Default to cdr
2084 assoc-list) span quantize))))
2085
2086(defun vc-annotate-compcar (threshold &rest args)
2087 "Test successive cars of ARGS against THRESHOLD.
2088Return the first cons which CAR is not less than THRESHOLD, nil otherwise"
2089 ;; If no list is exhausted,
2090 (if (and (not (memq 'nil args)) (< (car (car (car args))) threshold))
2091 ;; apply to CARs.
2092 (apply 'vc-annotate-compcar threshold
2093 ;; Recurse for rest of elements.
2094 (mapcar 'cdr args))
2095 ;; Return the proper result
2096 (car (car args))))
2097
2098(defun vc-annotate-display (buffer &optional color-map)
2099 "Do the VC-Annotate display in BUFFER using COLOR-MAP."
2100
2101 (if (and (not color-map) vc-annotate-ratio)
2102 (setq color-map (vc-annotate-time-span color-map vc-annotate-ratio)))
2103
2104 ;; We need a list of months and their corresponding numbers.
2105 (let* ((local-month-numbers
2106 '(("Jan" . 1) ("Feb" . 2) ("Mar" . 3) ("Apr" . 4)
2107 ("May" . 5) ("Jun" . 6) ("Jul" . 7) ("Aug" . 8)
2108 ("Sep" . 9) ("Oct" . 10) ("Nov" . 11) ("Dec" . 12)))
2109 ;; XEmacs use extents, GNU Emacs overlays.
2110 (overlay-or-extent (if (string-match "XEmacs" emacs-version)
2111 (cons 'make-extent 'set-extent-property)
2112 (cons 'make-overlay 'overlay-put)))
2113 (make-overlay-or-extent (car overlay-or-extent))
2114 (set-property-overlay-or-extent (cdr overlay-or-extent)))
2115
2116 (set-buffer buffer)
2117 (display-buffer buffer)
2118 (if (not vc-annotate-mode) ; Turn on vc-annotate-mode if not done
2119 (vc-annotate-mode))
2120 (goto-char (point-min)) ; Position at the top of the buffer.
2121 (while (re-search-forward
2122 "^[0-9]+\\(\.[0-9]+\\)*\\s-+(\\sw+\\s-+\\([0-9]+\\)-\\(\\sw+\\)-\\([0-9]+\\)): "
2123 nil t)
2124
2125 (let* (;; Unfortunately, order is important. match-string will
2126 ;; be corrupted by extent functions in XEmacs. Access
2127 ;; string-matches first.
2128 (day (string-to-number (match-string 2)))
2129 (month (cdr (assoc (match-string 3) local-month-numbers)))
2130 (year-tmp (string-to-number (match-string 4)))
2131 (year (+ (if (> 100 year-tmp) 1900 0) year-tmp)) ; Possible millenium problem
2132 (high (- (car (current-time))
2133 (car (encode-time 0 0 0 day month year))))
2134 (color (cond ((vc-annotate-compcar high (cond (color-map)
2135 (vc-annotate-color-map))))
2136 ((cons nil vc-annotate-very-old-color))))
2137 ;; substring from index 1 to remove any leading `#' in the name
2138 (face-name (concat "vc-annotate-face-" (substring (cdr color) 1)))
2139 ;; Make the face if not done.
2140 (face (cond ((intern-soft face-name))
2141 ((make-face (intern face-name)))))
2142 (point (point))
2143 (foo (forward-line 1))
2144 (overlay (cond ((if (string-match "XEmacs" emacs-version)
2145 (extent-at point)
2146 (car (overlays-at point ))))
2147 ((apply make-overlay-or-extent point (point) nil)))))
2148
2149 (if vc-annotate-background
2150 (set-face-background face vc-annotate-background))
2151 (set-face-foreground face (cdr color))
2152 (apply set-property-overlay-or-extent overlay
2153 'face face nil)))))
2154\f
c6d4f628 2155;; Collect back-end-dependent stuff here
594722a8 2156
594722a8
ER
2157(defun vc-backend-admin (file &optional rev comment)
2158 ;; Register a file into the version-control system
2159 ;; Automatically retrieves a read-only version of the file with
2160 ;; keywords expanded if vc-keep-workfiles is non-nil, otherwise
2161 ;; it deletes the workfile.
2162 (vc-file-clearprops file)
2163 (or vc-default-back-end
2164 (setq vc-default-back-end (if (vc-find-binary "rcs") 'RCS 'SCCS)))
2165 (message "Registering %s..." file)
a633d9af
RS
2166 (let ((switches
2167 (if (stringp vc-register-switches)
2168 (list vc-register-switches)
2169 vc-register-switches))
2170 (backend
594722a8
ER
2171 (cond
2172 ((file-exists-p (vc-backend-subdirectory-name)) vc-default-back-end)
2173 ((file-exists-p "RCS") 'RCS)
2174 ((file-exists-p "SCCS") 'SCCS)
80688f5c 2175 ((file-exists-p "CVS") 'CVS)
594722a8
ER
2176 (t vc-default-back-end))))
2177 (cond ((eq backend 'SCCS)
a1d713ef
AS
2178 ;; If there is no SCCS subdirectory yet, create it.
2179 ;; (SCCS could do without it, but VC requires it to be there.)
2180 (if (not (file-exists-p "SCCS")) (make-directory "SCCS"))
a633d9af
RS
2181 (apply 'vc-do-command nil 0 "admin" file 'MASTER ;; SCCS
2182 (and rev (concat "-r" rev))
2183 "-fb"
2184 (concat "-i" file)
2185 (and comment (concat "-y" comment))
2186 (format
2187 (car (rassq 'SCCS vc-master-templates))
2188 (or (file-name-directory file) "")
2189 (file-name-nondirectory file))
2190 switches)
594722a8
ER
2191 (delete-file file)
2192 (if vc-keep-workfiles
6aa13729 2193 (vc-do-command nil 0 "get" file 'MASTER)))
594722a8 2194 ((eq backend 'RCS)
a633d9af
RS
2195 (apply 'vc-do-command nil 0 "ci" file 'WORKFILE ;; RCS
2196 ;; if available, use the secure registering option
2197 (and (vc-backend-release-p 'RCS "5.6.4") "-i")
2198 (concat (if vc-keep-workfiles "-u" "-r") rev)
2199 (and comment (concat "-t-" comment))
2200 switches))
80688f5c 2201 ((eq backend 'CVS)
a633d9af
RS
2202 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE ;; CVS
2203 "add"
2204 (and comment (string-match "[^\t\n ]" comment)
2205 (concat "-m" comment))
2206 switches)
594722a8
ER
2207 )))
2208 (message "Registering %s...done" file)
2209 )
2210
f1818994 2211(defun vc-backend-checkout (file &optional writable rev workfile)
594722a8 2212 ;; Retrieve a copy of a saved version into a workfile
503b5c85
RS
2213 (let ((filename (or workfile file))
2214 (file-buffer (get-file-buffer file))
2c28ac43 2215 switches)
f1818994 2216 (message "Checking out %s..." filename)
f797cb30 2217 (save-excursion
2c28ac43 2218 ;; Change buffers to get local value of vc-checkout-switches.
503b5c85 2219 (if file-buffer (set-buffer file-buffer))
2c28ac43
RS
2220 (setq switches (if (stringp vc-checkout-switches)
2221 (list vc-checkout-switches)
2222 vc-checkout-switches))
f008ca58
KH
2223 ;; Save this buffer's default-directory
2224 ;; and use save-excursion to make sure it is restored
2225 ;; in the same buffer it was saved in.
2226 (let ((default-directory default-directory))
2227 (save-excursion
2228 ;; Adjust the default-directory so that the check-out creates
2229 ;; the file in the right place.
2230 (setq default-directory (file-name-directory filename))
2231 (vc-backend-dispatch file
2232 (progn ;; SCCS
2233 (and rev (string= rev "") (setq rev nil))
2234 (if workfile
2235 ;; Some SCCS implementations allow checking out directly to a
2236 ;; file using the -G option, but then some don't so use the
2237 ;; least common denominator approach and use the -p option
2238 ;; ala RCS.
2239 (let ((vc-modes (logior (file-modes (vc-name file))
2240 (if writable 128 0)))
2241 (failed t))
2242 (unwind-protect
2243 (progn
2244 (apply 'vc-do-command
2245 nil 0 "/bin/sh" file 'MASTER "-c"
2246 ;; Some shells make the "" dummy argument into $0
2247 ;; while others use the shell's name as $0 and
2248 ;; use the "" as $1. The if-statement
2249 ;; converts the latter case to the former.
2250 (format "if [ x\"$1\" = x ]; then shift; fi; \
29fc1ce9
RS
2251 umask %o; exec >\"$1\" || exit; \
2252 shift; umask %o; exec get \"$@\""
f008ca58
KH
2253 (logand 511 (lognot vc-modes))
2254 (logand 511 (lognot (default-file-modes))))
2255 "" ; dummy argument for shell's $0
2256 filename
2257 (if writable "-e")
2258 "-p"
2259 (and rev
2260 (concat "-r" (vc-lookup-triple file rev)))
2261 switches)
2262 (setq failed nil))
2263 (and failed (file-exists-p filename)
2264 (delete-file filename))))
2265 (apply 'vc-do-command nil 0 "get" file 'MASTER ;; SCCS
2266 (if writable "-e")
2267 (and rev (concat "-r" (vc-lookup-triple file rev)))
2268 switches)
2269 (vc-file-setprop file 'vc-workfile-version nil)))
2270 (if workfile ;; RCS
2271 ;; RCS doesn't let us check out into arbitrary file names directly.
2272 ;; Use `co -p' and make stdout point to the correct file.
2273 (let ((vc-modes (logior (file-modes (vc-name file))
2274 (if writable 128 0)))
2275 (failed t))
2276 (unwind-protect
2277 (progn
2278 (apply 'vc-do-command
2279 nil 0 "/bin/sh" file 'MASTER "-c"
2280 ;; See the SCCS case, above, regarding the
2281 ;; if-statement.
2282 (format "if [ x\"$1\" = x ]; then shift; fi; \
29fc1ce9
RS
2283 umask %o; exec >\"$1\" || exit; \
2284 shift; umask %o; exec co \"$@\""
f008ca58
KH
2285 (logand 511 (lognot vc-modes))
2286 (logand 511 (lognot (default-file-modes))))
2287 "" ; dummy argument for shell's $0
2288 filename
2289 (if writable "-l")
2290 (concat "-p" rev)
2291 switches)
2292 (setq failed nil))
2293 (and failed (file-exists-p filename) (delete-file filename))))
2294 (let (new-version)
2295 ;; if we should go to the head of the trunk,
2296 ;; clear the default branch first
2297 (and rev (string= rev "")
2298 (vc-do-command nil 0 "rcs" file 'MASTER "-b"))
2299 ;; now do the checkout
2300 (apply 'vc-do-command
2301 nil 0 "co" file 'MASTER
2302 ;; If locking is not strict, force to overwrite
2303 ;; the writable workfile.
2304 (if (eq (vc-checkout-model file) 'implicit) "-f")
2305 (if writable "-l")
2306 (if rev (concat "-r" rev)
2307 ;; if no explicit revision was specified,
2308 ;; check out that of the working file
2309 (let ((workrev (vc-workfile-version file)))
2310 (if workrev (concat "-r" workrev)
2311 nil)))
2312 switches)
2313 ;; determine the new workfile version
2314 (save-excursion
2315 (set-buffer "*vc*")
2316 (goto-char (point-min))
2317 (setq new-version
2318 (if (re-search-forward "^revision \\([0-9.]+\\).*\n" nil t)
2319 (buffer-substring (match-beginning 1) (match-end 1)))))
2320 (vc-file-setprop file 'vc-workfile-version new-version)
2321 ;; if necessary, adjust the default branch
2322 (and rev (not (string= rev ""))
2323 (vc-do-command nil 0 "rcs" file 'MASTER
2324 (concat "-b" (if (vc-latest-on-branch-p file)
2325 (if (vc-trunk-p new-version) nil
2326 (vc-branch-part new-version))
2327 new-version))))))
2328 (if workfile ;; CVS
2329 ;; CVS is much like RCS
2330 (let ((failed t))
2331 (unwind-protect
2332 (progn
2333 (apply 'vc-do-command
2334 nil 0 "/bin/sh" file 'WORKFILE "-c"
2335 "exec >\"$1\" || exit; shift; exec cvs update \"$@\""
2336 "" ; dummy argument for shell's $0
2337 workfile
2338 (concat "-r" rev)
2339 "-p"
2340 switches)
2341 (setq failed nil))
2342 (and failed (file-exists-p filename) (delete-file filename))))
2343 ;; default for verbose checkout: clear the sticky tag
2344 ;; so that the actual update will get the head of the trunk
2345 (and rev (string= rev "")
2346 (vc-do-command nil 0 "cvs" file 'WORKFILE "update" "-A"))
2347 ;; If a revision was specified, check that out.
2348 (if rev
2349 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2350 (and writable (eq (vc-checkout-model file) 'manual) "-w")
2351 "update"
2352 (and rev (not (string= rev ""))
2353 (concat "-r" rev))
2354 switches)
2355 ;; If no revision was specified, simply make the file writable.
2356 (and writable
2357 (or (eq (vc-checkout-model file) 'manual)
2358 (zerop (logand 128 (file-modes file))))
2359 (set-file-modes file (logior 128 (file-modes file)))))
2360 (if rev (vc-file-setprop file 'vc-workfile-version nil))))
2361 (cond
2362 ((not workfile)
2363 (vc-file-clear-masterprops file)
2364 (if writable
8172cd86 2365 (vc-file-setprop file 'vc-locking-user (vc-user-login-name)))
f008ca58
KH
2366 (vc-file-setprop file
2367 'vc-checkout-time (nth 5 (file-attributes file)))))
2368 (message "Checking out %s...done" filename))))))
594722a8
ER
2369
2370(defun vc-backend-logentry-check (file)
2371 (vc-backend-dispatch file
8c0aaf40 2372 (if (>= (buffer-size) 512) ;; SCCS
594722a8
ER
2373 (progn
2374 (goto-char 512)
2375 (error
590cc449 2376 "Log must be less than 512 characters; point is now at pos 512")))
80688f5c
RS
2377 nil ;; RCS
2378 nil) ;; CVS
594722a8
ER
2379 )
2380
80688f5c 2381(defun vc-backend-checkin (file rev comment)
594722a8
ER
2382 ;; Register changes to FILE as level REV with explanatory COMMENT.
2383 ;; Automatically retrieves a read-only version of the file with
2384 ;; keywords expanded if vc-keep-workfiles is non-nil, otherwise
2385 ;; it deletes the workfile.
a7acbbe4 2386 ;; Adaptation for RCS branch support: if this is an explicit checkin,
c6d4f628
RS
2387 ;; or if the checkin creates a new branch, set the master file branch
2388 ;; accordingly.
594722a8 2389 (message "Checking in %s..." file)
7d665008 2390 ;; "This log message intentionally left almost blank".
9e0cc6e6
RS
2391 ;; RCS 5.7 gripes about white-space-only comments too.
2392 (or (and comment (string-match "[^\t\n ]" comment))
2393 (setq comment "*** empty log message ***"))
2ea8ce47
RM
2394 (save-excursion
2395 ;; Change buffers to get local value of vc-checkin-switches.
2396 (set-buffer (or (get-file-buffer file) (current-buffer)))
2c28ac43 2397 (let ((switches
90681ae2
EN
2398 (if (stringp vc-checkin-switches)
2399 (list vc-checkin-switches)
2400 vc-checkin-switches)))
2c28ac43
RS
2401 ;; Clear the master-properties. Do that here, not at the
2402 ;; end, because if the check-in fails we want them to get
2403 ;; re-computed before the next try.
2404 (vc-file-clear-masterprops file)
2405 (vc-backend-dispatch file
2406 ;; SCCS
2407 (progn
2408 (apply 'vc-do-command nil 0 "delta" file 'MASTER
2409 (if rev (concat "-r" rev))
2410 (concat "-y" comment)
2411 switches)
2412 (vc-file-setprop file 'vc-locking-user 'none)
2413 (vc-file-setprop file 'vc-workfile-version nil)
2414 (if vc-keep-workfiles
2415 (vc-do-command nil 0 "get" file 'MASTER))
2416 )
2417 ;; RCS
2418 (let ((old-version (vc-workfile-version file)) new-version)
2419 (apply 'vc-do-command nil 0 "ci" file 'MASTER
2420 ;; if available, use the secure check-in option
2421 (and (vc-backend-release-p 'RCS "5.6.4") "-j")
2422 (concat (if vc-keep-workfiles "-u" "-r") rev)
2423 (concat "-m" comment)
2424 switches)
2425 (vc-file-setprop file 'vc-locking-user 'none)
2426 (vc-file-setprop file 'vc-workfile-version nil)
2427
2428 ;; determine the new workfile version
2429 (set-buffer "*vc*")
2430 (goto-char (point-min))
2431 (if (or (re-search-forward
2432 "new revision: \\([0-9.]+\\);" nil t)
2433 (re-search-forward
2434 "reverting to previous revision \\([0-9.]+\\)" nil t))
2435 (progn (setq new-version (buffer-substring (match-beginning 1)
2436 (match-end 1)))
2437 (vc-file-setprop file 'vc-workfile-version new-version)))
2438
2439 ;; if we got to a different branch, adjust the default
2440 ;; branch accordingly
2441 (cond
2442 ((and old-version new-version
2443 (not (string= (vc-branch-part old-version)
2444 (vc-branch-part new-version))))
2445 (vc-do-command nil 0 "rcs" file 'MASTER
2446 (if (vc-trunk-p new-version) "-b"
2447 (concat "-b" (vc-branch-part new-version))))
2448 ;; If this is an old RCS release, we might have
2449 ;; to remove a remaining lock.
2450 (if (not (vc-backend-release-p 'RCS "5.6.2"))
2451 ;; exit status of 1 is also accepted.
2452 ;; It means that the lock was removed before.
2453 (vc-do-command nil 1 "rcs" file 'MASTER
2454 (concat "-u" old-version))))))
2455 ;; CVS
2456 (progn
2457 ;; explicit check-in to the trunk requires a
2458 ;; double check-in (first unexplicit) (CVS-1.3)
2459 (condition-case nil
2460 (progn
2461 (if (and rev (vc-trunk-p rev))
2462 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2463 "ci" "-m" "intermediate"
2464 switches))
2465 (apply 'vc-do-command nil 0 "cvs" file 'WORKFILE
2466 "ci" (if rev (concat "-r" rev))
2467 (concat "-m" comment)
2468 switches))
2469 (error (if (eq (vc-cvs-status file) 'needs-merge)
2470 ;; The CVS output will be on top of this message.
2471 (error "Type C-x 0 C-x C-q to merge in changes")
2472 (error "Check-in failed"))))
2473 ;; determine and store the new workfile version
2474 (set-buffer "*vc*")
2475 (goto-char (point-min))
2476 (if (re-search-forward
2477 "^\\(new\\|initial\\) revision: \\([0-9.]+\\)" nil t)
2478 (vc-file-setprop file 'vc-workfile-version
2479 (buffer-substring (match-beginning 2)
2480 (match-end 2)))
2481 (vc-file-setprop file 'vc-workfile-version nil))
2482 ;; if this was an explicit check-in, remove the sticky tag
2483 (if rev
2484 (vc-do-command nil 0 "cvs" file 'WORKFILE "update" "-A"))
2485 (vc-file-setprop file 'vc-locking-user 'none)
2486 (vc-file-setprop file 'vc-checkout-time
2487 (nth 5 (file-attributes file)))))))
88a2ffaf 2488 (message "Checking in %s...done" file))
594722a8
ER
2489
2490(defun vc-backend-revert (file)
2491 ;; Revert file to latest checked-in version.
c6d4f628 2492 ;; (for RCS, to workfile version)
594722a8 2493 (message "Reverting %s..." file)
61dee1e7 2494 (vc-file-clear-masterprops file)
594722a8
ER
2495 (vc-backend-dispatch
2496 file
c6d4f628
RS
2497 ;; SCCS
2498 (progn
6aa13729
RS
2499 (vc-do-command nil 0 "unget" file 'MASTER nil)
2500 (vc-do-command nil 0 "get" file 'MASTER nil))
c6d4f628 2501 ;; RCS
6aa13729 2502 (vc-do-command nil 0 "co" file 'MASTER
c6d4f628
RS
2503 "-f" (concat "-u" (vc-workfile-version file)))
2504 ;; CVS
2505 (progn
80688f5c 2506 (delete-file file)
6aa13729 2507 (vc-do-command nil 0 "cvs" file 'WORKFILE "update")))
88a2ffaf 2508 (vc-file-setprop file 'vc-locking-user 'none)
c6d4f628 2509 (vc-file-setprop file 'vc-checkout-time (nth 5 (file-attributes file)))
594722a8
ER
2510 (message "Reverting %s...done" file)
2511 )
2512
2513(defun vc-backend-steal (file &optional rev)
2514 ;; Steal the lock on the current workfile. Needs RCS 5.6.2 or later for -M.
2515 (message "Stealing lock on %s..." file)
af1b8606 2516 (vc-backend-dispatch file
80688f5c 2517 (progn ;SCCS
6aa13729
RS
2518 (vc-do-command nil 0 "unget" file 'MASTER "-n" (if rev (concat "-r" rev)))
2519 (vc-do-command nil 0 "get" file 'MASTER "-g" (if rev (concat "-r" rev)))
d76b8d38 2520 )
6aa13729 2521 (vc-do-command nil 0 "rcs" file 'MASTER ;RCS
80688f5c 2522 "-M" (concat "-u" rev) (concat "-l" rev))
2c28ac43 2523 (error "You cannot steal a CVS lock; there are no CVS locks to steal") ;CVS
80688f5c 2524 )
8172cd86 2525 (vc-file-setprop file 'vc-locking-user (vc-user-login-name))
594722a8
ER
2526 (message "Stealing lock on %s...done" file)
2527 )
2528
2529(defun vc-backend-uncheck (file target)
c8de1d91 2530 ;; Undo the latest checkin.
594722a8
ER
2531 (message "Removing last change from %s..." file)
2532 (vc-backend-dispatch file
6aa13729
RS
2533 (vc-do-command nil 0 "rmdel" file 'MASTER (concat "-r" target))
2534 (vc-do-command nil 0 "rcs" file 'MASTER (concat "-o" target))
88a2ffaf 2535 nil ;; this is never reached under CVS
594722a8
ER
2536 )
2537 (message "Removing last change from %s...done" file)
2538 )
2539
2540(defun vc-backend-print-log (file)
6aa13729 2541 ;; Get change log associated with FILE.
80688f5c
RS
2542 (vc-backend-dispatch
2543 file
6aa13729
RS
2544 (vc-do-command nil 0 "prs" file 'MASTER)
2545 (vc-do-command nil 0 "rlog" file 'MASTER)
81b8f0e6 2546 (vc-do-command nil 0 "cvs" file 'WORKFILE "log")))
594722a8
ER
2547
2548(defun vc-backend-assign-name (file name)
2549 ;; Assign to a FILE's latest version a given NAME.
2550 (vc-backend-dispatch file
6aa13729
RS
2551 (vc-add-triple name file (vc-latest-version file)) ;; SCCS
2552 (vc-do-command nil 0 "rcs" file 'MASTER (concat "-n" name ":")) ;; RCS
2553 (vc-do-command nil 0 "cvs" file 'WORKFILE "tag" name) ;; CVS
3234e2a3 2554 )
3234e2a3 2555 )
594722a8 2556
9a51ed3a
PE
2557(defun vc-backend-diff (file &optional oldvers newvers cmp)
2558 ;; Get a difference report between two versions of FILE.
2559 ;; Get only a brief comparison report if CMP, a difference report otherwise.
eb302e54
AS
2560 (let ((backend (vc-backend file)) options status
2561 (diff-switches-list (if (listp diff-switches)
2562 diff-switches
2563 (list diff-switches))))
80688f5c
RS
2564 (cond
2565 ((eq backend 'SCCS)
7b4f934d 2566 (setq oldvers (vc-lookup-triple file oldvers))
eb302e54
AS
2567 (setq newvers (vc-lookup-triple file newvers))
2568 (setq options (append (list (and cmp "--brief") "-q"
2569 (and oldvers (concat "-r" oldvers))
2570 (and newvers (concat "-r" newvers)))
2571 (and (not cmp) diff-switches-list)))
2572 (apply 'vc-do-command "*vc-diff*" 1 "vcdiff" file 'MASTER options))
c6d4f628 2573 ((eq backend 'RCS)
99e76dda
AS
2574 (if (not oldvers) (setq oldvers (vc-workfile-version file)))
2575 ;; If we know that --brief is not supported, don't try it.
eb302e54
AS
2576 (setq cmp (and cmp (not (eq vc-rcsdiff-knows-brief 'no))))
2577 (setq options (append (list (and cmp "--brief") "-q"
2578 (concat "-r" oldvers)
2579 (and newvers (concat "-r" newvers)))
2580 (and (not cmp) diff-switches-list)))
2581 (setq status (apply 'vc-do-command "*vc-diff*" 2
2582 "rcsdiff" file 'WORKFILE options))
2583 ;; If --brief didn't work, do a double-take and remember it
2584 ;; for the future.
2585 (if (eq status 2)
2586 (prog1
2587 (apply 'vc-do-command "*vc-diff*" 1 "rcsdiff" file 'WORKFILE
2588 (if cmp (cdr options) options))
2589 (if cmp (setq vc-rcsdiff-knows-brief 'no)))
2590 ;; If --brief DID work, remember that, too.
2591 (and cmp (not vc-rcsdiff-knows-brief)
2592 (setq vc-rcsdiff-knows-brief 'yes))
2593 status))
80688f5c 2594 ;; CVS is different.
80688f5c 2595 ((eq backend 'CVS)
eb302e54 2596 (if (string= (vc-workfile-version file) "0")
80688f5c 2597 ;; This file is added but not yet committed; there is no master file.
80688f5c 2598 (if (or oldvers newvers)
b0c9bc8c
AS
2599 (error "No revisions of %s exist" file)
2600 (if cmp 1 ;; file is added but not committed,
2601 ;; we regard this as "changed".
2602 ;; diff it against /dev/null.
2603 (apply 'vc-do-command
2604 "*vc-diff*" 1 "diff" file 'WORKFILE
2605 (append (if (listp diff-switches)
2606 diff-switches
2607 (list diff-switches)) '("/dev/null")))))
2608 ;; cmp is not yet implemented -- we always do a full diff.
80688f5c 2609 (apply 'vc-do-command
6aa13729 2610 "*vc-diff*" 1 "cvs" file 'WORKFILE "diff"
80688f5c
RS
2611 (and oldvers (concat "-r" oldvers))
2612 (and newvers (concat "-r" newvers))
2613 (if (listp diff-switches)
2614 diff-switches
2615 (list diff-switches)))))
2616 (t
2617 (vc-registration-error file)))))
2618
2619(defun vc-backend-merge-news (file)
2620 ;; Merge in any new changes made to FILE.
61dee1e7
AS
2621 (message "Merging changes into %s..." file)
2622 (prog1
2623 (vc-backend-dispatch
2624 file
2625 (error "vc-backend-merge-news not meaningful for SCCS files") ;SCCS
2626 (error "vc-backend-merge-news not meaningful for RCS files") ;RCS
2627 (save-excursion ; CVS
2628 (vc-file-clear-masterprops file)
2629 (vc-file-setprop file 'vc-workfile-version nil)
2630 (vc-file-setprop file 'vc-locking-user nil)
2631 (vc-do-command nil 0 "cvs" file 'WORKFILE "update")
2632 ;; CVS doesn't return an error code if conflicts are detected.
2633 ;; Since we want to warn the user about it (and possibly start
2634 ;; emerge later), scan the output and see if this occurred.
2635 (set-buffer (get-buffer "*vc*"))
2636 (goto-char (point-min))
2637 (if (re-search-forward "^cvs update: conflicts found in .*" nil t)
2638 1 ;; error code for caller
2639 0 ;; no conflict detected
2640 )))
2641 (message "Merging changes into %s...done" file)))
594722a8
ER
2642
2643(defun vc-check-headers ()
2644 "Check if the current file has any headers in it."
2645 (interactive)
2646 (save-excursion
2647 (goto-char (point-min))
2648 (vc-backend-dispatch buffer-file-name
2649 (re-search-forward "%[MIRLBSDHTEGUYFPQCZWA]%" nil t) ;; SCCS
2650 (re-search-forward "\\$[A-Za-z\300-\326\330-\366\370-\377]+\\(: [\t -#%-\176\240-\377]*\\)?\\$" nil t) ;; RCS
80688f5c 2651 'RCS ;; CVS works like RCS in this regard.
594722a8
ER
2652 )
2653 ))
2654
2655;; Back-end-dependent stuff ends here.
2656
2657;; Set up key bindings for use while editing log messages
2658
37667a5c 2659(defun vc-log-mode (&optional file)
594722a8
ER
2660 "Minor mode for driving version-control tools.
2661These bindings are added to the global keymap when you enter this mode:
2662\\[vc-next-action] perform next logical version-control operation on current file
2663\\[vc-register] register current file
2664\\[vc-toggle-read-only] like next-action, but won't register files
2665\\[vc-insert-headers] insert version-control headers in current file
2666\\[vc-print-log] display change history of current file
2667\\[vc-revert-buffer] revert buffer to latest version
2668\\[vc-cancel-version] undo latest checkin
2669\\[vc-diff] show diffs between file versions
f1818994 2670\\[vc-version-other-window] visit old version in another window
594722a8 2671\\[vc-directory] show all files locked by any user in or below .
7d2d9482 2672\\[vc-annotate] colorful display of the cvs annotate command
594722a8
ER
2673\\[vc-update-change-log] add change log entry from recent checkins
2674
2675While you are entering a change log message for a version, the following
2676additional bindings will be in effect.
2677
2678\\[vc-finish-logentry] proceed with check in, ending log message entry
2679
2680Whenever you do a checkin, your log comment is added to a ring of
2681saved comments. These can be recalled as follows:
2682
2683\\[vc-next-comment] replace region with next message in comment ring
2684\\[vc-previous-comment] replace region with previous message in comment ring
8c0aaf40
ER
2685\\[vc-comment-search-reverse] search backward for regexp in the comment ring
2686\\[vc-comment-search-forward] search backward for regexp in the comment ring
594722a8
ER
2687
2688Entry to the change-log submode calls the value of text-mode-hook, then
2689the value of vc-log-mode-hook.
2690
2691Global user options:
2692 vc-initial-comment If non-nil, require user to enter a change
2693 comment upon first checkin of the file.
2694
2695 vc-keep-workfiles Non-nil value prevents workfiles from being
2696 deleted when changes are checked in
2697
2698 vc-suppress-confirm Suppresses some confirmation prompts,
2699 notably for reversions.
2700
7b4f934d 2701 vc-header-alist Which keywords to insert when adding headers
594722a8 2702 with \\[vc-insert-headers]. Defaults to
80688f5c
RS
2703 '(\"\%\W\%\") under SCCS, '(\"\$Id\$\") under
2704 RCS and CVS.
594722a8
ER
2705
2706 vc-static-header-alist By default, version headers inserted in C files
2707 get stuffed in a static string area so that
80688f5c
RS
2708 ident(RCS/CVS) or what(SCCS) can see them in
2709 the compiled object code. You can override
2710 this by setting this variable to nil, or change
594722a8
ER
2711 the header template by changing it.
2712
2713 vc-command-messages if non-nil, display run messages from the
2714 actual version-control utilities (this is
2715 intended primarily for people hacking vc
2716 itself).
2717"
2718 (interactive)
2719 (set-syntax-table text-mode-syntax-table)
2720 (use-local-map vc-log-entry-mode)
2721 (setq local-abbrev-table text-mode-abbrev-table)
2722 (setq major-mode 'vc-log-mode)
2723 (setq mode-name "VC-Log")
2724 (make-local-variable 'vc-log-file)
37667a5c 2725 (setq vc-log-file file)
594722a8 2726 (make-local-variable 'vc-log-version)
8c0aaf40 2727 (make-local-variable 'vc-comment-ring-index)
594722a8
ER
2728 (set-buffer-modified-p nil)
2729 (setq buffer-file-name nil)
2730 (run-hooks 'text-mode-hook 'vc-log-mode-hook)
2731)
2732
2733;; Initialization code, to be done just once at load-time
2734(if vc-log-entry-mode
2735 nil
2736 (setq vc-log-entry-mode (make-sparse-keymap))
2737 (define-key vc-log-entry-mode "\M-n" 'vc-next-comment)
2738 (define-key vc-log-entry-mode "\M-p" 'vc-previous-comment)
8c0aaf40 2739 (define-key vc-log-entry-mode "\M-r" 'vc-comment-search-reverse)
594722a8
ER
2740 (define-key vc-log-entry-mode "\M-s" 'vc-comment-search-forward)
2741 (define-key vc-log-entry-mode "\C-c\C-c" 'vc-finish-logentry)
2742 )
2743
2744;;; These things should probably be generally available
2745
2f119435
AS
2746(defun vc-file-tree-walk (dirname func &rest args)
2747 "Walk recursively through DIRNAME.
34291cd2 2748Invoke FUNC f ARGS on each non-directory file f underneath it."
2f119435
AS
2749 (vc-file-tree-walk-internal (expand-file-name dirname) func args)
2750 (message "Traversing directory %s...done" dirname))
02da6253
PE
2751
2752(defun vc-file-tree-walk-internal (file func args)
2753 (if (not (file-directory-p file))
2754 (apply func file args)
993a1a44 2755 (message "Traversing directory %s..." (abbreviate-file-name file))
02da6253
PE
2756 (let ((dir (file-name-as-directory file)))
2757 (mapcar
2758 (function
2759 (lambda (f) (or
2760 (string-equal f ".")
2761 (string-equal f "..")
632e9525 2762 (member f vc-directory-exclusion-list)
02da6253
PE
2763 (let ((dirf (concat dir f)))
2764 (or
2765 (file-symlink-p dirf) ;; Avoid possible loops
2766 (vc-file-tree-walk-internal dirf func args))))))
2767 (directory-files dir)))))
594722a8
ER
2768
2769(provide 'vc)
2770
2771;;; DEVELOPER'S NOTES ON CONCURRENCY PROBLEMS IN THIS CODE
2772;;;
2773;;; These may be useful to anyone who has to debug or extend the package.
c6d4f628
RS
2774;;; (Note that this information corresponds to versions 5.x. Some of it
2775;;; might have been invalidated by the additions to support branching
2776;;; and RCS keyword lookup. AS, 1995/03/24)
594722a8
ER
2777;;;
2778;;; A fundamental problem in VC is that there are time windows between
2779;;; vc-next-action's computations of the file's version-control state and
2780;;; the actions that change it. This is a window open to lossage in a
2781;;; multi-user environment; someone else could nip in and change the state
2782;;; of the master during it.
2783;;;
2784;;; The performance problem is that rlog/prs calls are very expensive; we want
2785;;; to avoid them as much as possible.
2786;;;
2787;;; ANALYSIS:
2788;;;
2789;;; The performance problem, it turns out, simplifies in practice to the
2790;;; problem of making vc-locking-user fast. The two other functions that call
2791;;; prs/rlog will not be so commonly used that the slowdown is a problem; one
2792;;; makes snapshots, the other deletes the calling user's last change in the
2793;;; master.
2794;;;
2795;;; The race condition implies that we have to either (a) lock the master
2796;;; during the entire execution of vc-next-action, or (b) detect and
2797;;; recover from errors resulting from dispatch on an out-of-date state.
2798;;;
a7acbbe4 2799;;; Alternative (a) appears to be infeasible. The problem is that we can't
594722a8
ER
2800;;; guarantee that the lock will ever be removed. Suppose a user starts a
2801;;; checkin, the change message buffer pops up, and the user, having wandered
2802;;; off to do something else, simply forgets about it?
2803;;;
2804;;; Alternative (b), on the other hand, works well with a cheap way to speed up
2805;;; vc-locking-user. Usually, if a file is registered, we can read its locked/
2806;;; unlocked state and its current owner from its permissions.
2807;;;
2808;;; This shortcut will fail if someone has manually changed the workfile's
2809;;; permissions; also if developers are munging the workfile in several
2810;;; directories, with symlinks to a master (in this latter case, the
2811;;; permissions shortcut will fail to detect a lock asserted from another
2812;;; directory).
2813;;;
2814;;; Note that these cases correspond exactly to the errors which could happen
2815;;; because of a competing checkin/checkout race in between two instances of
2816;;; vc-next-action.
2817;;;
2818;;; For VC's purposes, a workfile/master pair may have the following states:
2819;;;
2820;;; A. Unregistered. There is a workfile, there is no master.
2821;;;
2822;;; B. Registered and not locked by anyone.
2823;;;
2824;;; C. Locked by calling user and unchanged.
2825;;;
2826;;; D. Locked by the calling user and changed.
2827;;;
2828;;; E. Locked by someone other than the calling user.
2829;;;
2830;;; This makes for 25 states and 20 error conditions. Here's the matrix:
2831;;;
2832;;; VC's idea of state
2833;;; |
2834;;; V Actual state RCS action SCCS action Effect
2835;;; A B C D E
2836;;; A . 1 2 3 4 ci -u -t- admin -fb -i<file> initial admin
2837;;; B 5 . 6 7 8 co -l get -e checkout
2838;;; C 9 10 . 11 12 co -u unget; get revert
2839;;; D 13 14 15 . 16 ci -u -m<comment> delta -y<comment>; get checkin
b0c9bc8c 2840;;; E 17 18 19 20 . rcs -u -M -l unget -n ; get -g steal lock
594722a8
ER
2841;;;
2842;;; All commands take the master file name as a last argument (not shown).
2843;;;
2844;;; In the discussion below, a "self-race" is a pathological situation in
2845;;; which VC operations are being attempted simultaneously by two or more
2846;;; Emacsen running under the same username.
2847;;;
2848;;; The vc-next-action code has the following windows:
2849;;;
2850;;; Window P:
2851;;; Between the check for existence of a master file and the call to
2852;;; admin/checkin in vc-buffer-admin (apparent state A). This window may
2853;;; never close if the initial-comment feature is on.
2854;;;
2855;;; Window Q:
2856;;; Between the call to vc-workfile-unchanged-p in and the immediately
2857;;; following revert (apparent state C).
2858;;;
2859;;; Window R:
2860;;; Between the call to vc-workfile-unchanged-p in and the following
2861;;; checkin (apparent state D). This window may never close.
2862;;;
2863;;; Window S:
2864;;; Between the unlock and the immediately following checkout during a
2865;;; revert operation (apparent state C). Included in window Q.
2866;;;
2867;;; Window T:
2868;;; Between vc-locking-user and the following checkout (apparent state B).
2869;;;
2870;;; Window U:
2871;;; Between vc-locking-user and the following revert (apparent state C).
2872;;; Includes windows Q and S.
2873;;;
2874;;; Window V:
2875;;; Between vc-locking-user and the following checkin (apparent state
2876;;; D). This window may never be closed if the user fails to complete the
2877;;; checkin message. Includes window R.
2878;;;
2879;;; Window W:
2880;;; Between vc-locking-user and the following steal-lock (apparent
34291cd2 2881;;; state E). This window may never close if the user fails to complete
594722a8
ER
2882;;; the steal-lock message. Includes window X.
2883;;;
2884;;; Window X:
2885;;; Between the unlock and the immediately following re-lock during a
2886;;; steal-lock operation (apparent state E). This window may never cloce
2887;;; if the user fails to complete the steal-lock message.
2888;;;
2889;;; Errors:
2890;;;
2891;;; Apparent state A ---
2892;;;
2893;;; 1. File looked unregistered but is actually registered and not locked.
2894;;;
2895;;; Potential cause: someone else's admin during window P, with
2896;;; caller's admin happening before their checkout.
2897;;;
b0c9bc8c
AS
2898;;; RCS: Prior to version 5.6.4, ci fails with message
2899;;; "no lock set by <user>". From 5.6.4 onwards, VC uses the new
2900;;; ci -i option and the message is "<file>,v: already exists".
594722a8
ER
2901;;; SCCS: admin will fail with error (ad19).
2902;;;
2903;;; We can let these errors be passed up to the user.
2904;;;
2905;;; 2. File looked unregistered but is actually locked by caller, unchanged.
2906;;;
2907;;; Potential cause: self-race during window P.
2908;;;
b0c9bc8c
AS
2909;;; RCS: Prior to version 5.6.4, reverts the file to the last saved
2910;;; version and unlocks it. From 5.6.4 onwards, VC uses the new
2911;;; ci -i option, failing with message "<file>,v: already exists".
594722a8
ER
2912;;; SCCS: will fail with error (ad19).
2913;;;
2914;;; Either of these consequences is acceptable.
2915;;;
2916;;; 3. File looked unregistered but is actually locked by caller, changed.
2917;;;
2918;;; Potential cause: self-race during window P.
2919;;;
b0c9bc8c
AS
2920;;; RCS: Prior to version 5.6.4, VC registers the caller's workfile as
2921;;; a delta with a null change comment (the -t- switch will be
2922;;; ignored). From 5.6.4 onwards, VC uses the new ci -i option,
2923;;; failing with message "<file>,v: already exists".
594722a8
ER
2924;;; SCCS: will fail with error (ad19).
2925;;;
2926;;; 4. File looked unregistered but is locked by someone else.
2927;;;
2928;;; Potential cause: someone else's admin during window P, with
2929;;; caller's admin happening *after* their checkout.
2930;;;
b0c9bc8c
AS
2931;;; RCS: Prior to version 5.6.4, ci fails with a
2932;;; "no lock set by <user>" message. From 5.6.4 onwards,
2933;;; VC uses the new ci -i option, failing with message
2934;;; "<file>,v: already exists".
594722a8
ER
2935;;; SCCS: will fail with error (ad19).
2936;;;
2937;;; We can let these errors be passed up to the user.
2938;;;
2939;;; Apparent state B ---
2940;;;
2941;;; 5. File looked registered and not locked, but is actually unregistered.
2942;;;
2943;;; Potential cause: master file got nuked during window P.
2944;;;
2945;;; RCS: will fail with "RCS/<file>: No such file or directory"
2946;;; SCCS: will fail with error ut4.
2947;;;
2948;;; We can let these errors be passed up to the user.
2949;;;
2950;;; 6. File looked registered and not locked, but is actually locked by the
2951;;; calling user and unchanged.
2952;;;
2953;;; Potential cause: self-race during window T.
2954;;;
2955;;; RCS: in the same directory as the previous workfile, co -l will fail
2956;;; with "co error: writable foo exists; checkout aborted". In any other
2957;;; directory, checkout will succeed.
2958;;; SCCS: will fail with ge17.
2959;;;
2960;;; Either of these consequences is acceptable.
2961;;;
2962;;; 7. File looked registered and not locked, but is actually locked by the
2963;;; calling user and changed.
2964;;;
2965;;; As case 6.
2966;;;
2967;;; 8. File looked registered and not locked, but is actually locked by another
2968;;; user.
2969;;;
2970;;; Potential cause: someone else checks it out during window T.
2971;;;
2972;;; RCS: co error: revision 1.3 already locked by <user>
2973;;; SCCS: fails with ge4 (in directory) or ut7 (outside it).
2974;;;
2975;;; We can let these errors be passed up to the user.
2976;;;
2977;;; Apparent state C ---
2978;;;
2979;;; 9. File looks locked by calling user and unchanged, but is unregistered.
2980;;;
2981;;; As case 5.
2982;;;
2983;;; 10. File looks locked by calling user and unchanged, but is actually not
2984;;; locked.
2985;;;
2986;;; Potential cause: a self-race in window U, or by the revert's
2987;;; landing during window X of some other user's steal-lock or window S
2988;;; of another user's revert.
2989;;;
2990;;; RCS: succeeds, refreshing the file from the identical version in
2991;;; the master.
2992;;; SCCS: fails with error ut4 (p file nonexistent).
2993;;;
2994;;; Either of these consequences is acceptable.
2995;;;
2996;;; 11. File is locked by calling user. It looks unchanged, but is actually
2997;;; changed.
2998;;;
2999;;; Potential cause: the file would have to be touched by a self-race
3000;;; during window Q.
3001;;;
3002;;; The revert will succeed, removing whatever changes came with
3003;;; the touch. It is theoretically possible that work could be lost.
3004;;;
3005;;; 12. File looks like it's locked by the calling user and unchanged, but
3006;;; it's actually locked by someone else.
3007;;;
3008;;; Potential cause: a steal-lock in window V.
3009;;;
3010;;; RCS: co error: revision <rev> locked by <user>; use co -r or rcs -u
3011;;; SCCS: fails with error un2
3012;;;
3013;;; We can pass these errors up to the user.
3014;;;
3015;;; Apparent state D ---
3016;;;
3017;;; 13. File looks like it's locked by the calling user and changed, but it's
3018;;; actually unregistered.
3019;;;
3020;;; Potential cause: master file got nuked during window P.
3021;;;
b0c9bc8c
AS
3022;;; RCS: Prior to version 5.6.4, checks in the user's version as an
3023;;; initial delta. From 5.6.4 onwards, VC uses the new ci -j
3024;;; option, failing with message "no such file or directory".
594722a8
ER
3025;;; SCCS: will fail with error ut4.
3026;;;
b0c9bc8c
AS
3027;;; This case is kind of nasty. Under RCS prior to version 5.6.4,
3028;;; VC may fail to detect the loss of previous version information.
594722a8
ER
3029;;;
3030;;; 14. File looks like it's locked by the calling user and changed, but it's
3031;;; actually unlocked.
3032;;;
3033;;; Potential cause: self-race in window V, or the checkin happening
3034;;; during the window X of someone else's steal-lock or window S of
3035;;; someone else's revert.
3036;;;
3037;;; RCS: ci will fail with "no lock set by <user>".
3038;;; SCCS: delta will fail with error ut4.
3039;;;
3040;;; 15. File looks like it's locked by the calling user and changed, but it's
3041;;; actually locked by the calling user and unchanged.
3042;;;
3043;;; Potential cause: another self-race --- a whole checkin/checkout
3044;;; sequence by the calling user would have to land in window R.
3045;;;
3046;;; SCCS: checks in a redundant delta and leaves the file unlocked as usual.
3047;;; RCS: reverts to the file state as of the second user's checkin, leaving
3048;;; the file unlocked.
3049;;;
3050;;; It is theoretically possible that work could be lost under RCS.
3051;;;
3052;;; 16. File looks like it's locked by the calling user and changed, but it's
3053;;; actually locked by a different user.
3054;;;
3055;;; RCS: ci error: no lock set by <user>
3056;;; SCCS: unget will fail with error un2
3057;;;
3058;;; We can pass these errors up to the user.
3059;;;
3060;;; Apparent state E ---
3061;;;
3062;;; 17. File looks like it's locked by some other user, but it's actually
3063;;; unregistered.
3064;;;
3065;;; As case 13.
3066;;;
3067;;; 18. File looks like it's locked by some other user, but it's actually
3068;;; unlocked.
3069;;;
3070;;; Potential cause: someone released a lock during window W.
3071;;;
3072;;; RCS: The calling user will get the lock on the file.
3073;;; SCCS: unget -n will fail with cm4.
3074;;;
3075;;; Either of these consequences will be OK.
3076;;;
3077;;; 19. File looks like it's locked by some other user, but it's actually
3078;;; locked by the calling user and unchanged.
3079;;;
3080;;; Potential cause: the other user relinquishing a lock followed by
3081;;; a self-race, both in window W.
3082;;;
3083;;; Under both RCS and SCCS, both unlock and lock will succeed, making
3084;;; the sequence a no-op.
3085;;;
3086;;; 20. File looks like it's locked by some other user, but it's actually
3087;;; locked by the calling user and changed.
3088;;;
3089;;; As case 19.
3090;;;
3091;;; PROBLEM CASES:
3092;;;
3093;;; In order of decreasing severity:
3094;;;
b0c9bc8c 3095;;; Cases 11 and 15 are the only ones that potentially lose work.
594722a8
ER
3096;;; They would require a self-race for this to happen.
3097;;;
3098;;; Case 13 in RCS loses information about previous deltas, retaining
3099;;; only the information in the current workfile. This can only happen
3100;;; if the master file gets nuked in window P.
3101;;;
3102;;; Case 3 in RCS and case 15 under SCCS insert a redundant delta with
3103;;; no change comment in the master. This would require a self-race in
3104;;; window P or R respectively.
3105;;;
3106;;; Cases 2, 10, 19 and 20 do extra work, but make no changes.
3107;;;
3108;;; Unfortunately, it appears to me that no recovery is possible in these
3109;;; cases. They don't yield error messages, so there's no way to tell that
3110;;; a race condition has occurred.
3111;;;
3112;;; All other cases don't change either the workfile or the master, and
3113;;; trigger command errors which the user will see.
3114;;;
3115;;; Thus, there is no explicit recovery code.
3116
3117;;; vc.el ends here