*** empty log message ***
[bpt/emacs.git] / lisp / vc.el
CommitLineData
66321b2f 1;;; vc.el --- drive a version-control system from within Emacs
594722a8 2
891b8b69 3;; Copyright (C) 1992,93,94,95,96,97,98,2000,2001 Free Software Foundation, Inc.
594722a8 4
0e362f54
GM
5;; Author: FSF (see below for full credits)
6;; Maintainer: Andre Spiegel <spiegel@gnu.org>
284b3043 7;; Keywords: tools
594722a8 8
165e43b6 9;; $Id: vc.el,v 1.331 2002/03/06 13:51:28 gerd Exp $
045e1aa5 10
594722a8
ER
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
b578f267
EN
24;; along with GNU Emacs; see the file COPYING. If not, write to the
25;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26;; Boston, MA 02111-1307, USA.
594722a8 27
0e362f54
GM
28;;; Credits:
29
30;; VC was initially designed and implemented by Eric S. Raymond
31;; <esr@snark.thyrsus.com>. Over the years, many people have
32;; contributed substantial amounts of work to VC. These include:
33;; Per Cederqvist <ceder@lysator.liu.se>
34;; Paul Eggert <eggert@twinsun.com>
35;; Sebastian Kremer <sk@thp.uni-koeln.de>
36;; Martin Lorentzson <martinl@gnu.org>
166a0ef7 37;; Dave Love <fx@gnu.org>
0e362f54 38;; Stefan Monnier <monnier@cs.yale.edu>
6f1ecae4 39;; J.D. Smith <jdsmith@alum.mit.edu>
0e362f54
GM
40;; Andre Spiegel <spiegel@gnu.org>
41;; Richard Stallman <rms@gnu.org>
6f1ecae4 42;; Thien-Thi Nguyen <ttn@gnu.org>
0e362f54 43
594722a8
ER
44;;; Commentary:
45
1a2f456b
ER
46;; This mode is fully documented in the Emacs user's manual.
47;;
632e9525 48;; Supported version-control systems presently include SCCS, RCS, and CVS.
b0c9bc8c
AS
49;;
50;; Some features will not work with old RCS versions. Where
51;; appropriate, VC finds out which version you have, and allows or
0e362f54 52;; disallows those features (stealing locks, for example, works only
b0c9bc8c 53;; from 5.6.2 onwards).
632e9525
RS
54;; Even initial checkins will fail if your RCS version is so old that ci
55;; doesn't understand -t-; this has been known to happen to people running
0e362f54 56;; NExTSTEP 3.0.
594722a8 57;;
0e362f54 58;; You can support the RCS -x option by customizing vc-rcs-master-templates.
594722a8
ER
59;;
60;; Proper function of the SCCS diff commands requires the shellscript vcdiff
61;; to be installed somewhere on Emacs's path for executables.
62;;
1a2f456b 63;; If your site uses the ChangeLog convention supported by Emacs, the
594be62e 64;; function vc-comment-to-change-log should prove a useful checkin hook.
1a2f456b 65;;
594722a8
ER
66;; The vc code maintains some internal state in order to reduce expensive
67;; version-control operations to a minimum. Some names are only computed
34291cd2 68;; once. If you perform version control operations with RCS/SCCS/CVS while
594722a8
ER
69;; vc's back is turned, or move/rename master files while vc is running,
70;; vc may get seriously confused. Don't do these things!
71;;
72;; Developer's notes on some concurrency issues are included at the end of
73;; the file.
0e362f54 74;;
fcb500ea
AS
75;; ADDING SUPPORT FOR OTHER BACKENDS
76;;
77;; VC can use arbitrary version control systems as a backend. To add
78;; support for a new backend named SYS, write a library vc-sys.el that
79;; contains functions of the form `vc-sys-...' (note that SYS is in lower
80;; case for the function and library names). VC will use that library if
81;; you put the symbol SYS somewhere into the list of
82;; `vc-handled-backends'. Then, for example, if `vc-sys-registered'
83;; returns non-nil for a file, all SYS-specific versions of VC commands
84;; will be available for that file.
85;;
86;; VC keeps some per-file information in the form of properties (see
87;; vc-file-set/getprop in vc-hooks.el). The backend-specific functions
88;; do not generally need to be aware of these properties. For example,
89;; `vc-sys-workfile-version' should compute the workfile version and
90;; return it; it should not look it up in the property, and it needn't
91;; store it there either. However, if a backend-specific function does
92;; store a value in a property, that value takes precedence over any
99cb8c8b 93;; value that the generic code might want to set (check for uses of
fcb500ea
AS
94;; the macro `with-vc-properties' in vc.el).
95;;
96;; In the list of functions below, each identifier needs to be prepended
97;; with `vc-sys-'. Some of the functions are mandatory (marked with a
98;; `*'), others are optional (`-').
99;;
100;; STATE-QUERYING FUNCTIONS
101;;
0e362f54 102;; * registered (file)
fcb500ea
AS
103;;
104;; Return non-nil if FILE is registered in this backend.
105;;
99cb8c8b 106;; * state (file)
fcb500ea
AS
107;;
108;; Return the current version control state of FILE. For a list of
109;; possible values, see `vc-state'. This function should do a full and
110;; reliable state computation; it is usually called immediately after
111;; C-x v v. If you want to use a faster heuristic when visiting a
112;; file, put that into `state-heuristic' below.
113;;
0e362f54 114;; - state-heuristic (file)
fcb500ea
AS
115;;
116;; If provided, this function is used to estimate the version control
117;; state of FILE at visiting time. It should be considerably faster
118;; than the implementation of `state'. For a list of possible values,
119;; see the doc string of `vc-state'.
120;;
0e362f54 121;; - dir-state (dir)
fcb500ea
AS
122;;
123;; If provided, this function is used to find the version control state
124;; of all files in DIR in a fast way. The function should not return
125;; anything, but rather store the files' states into the corresponding
126;; `vc-state' properties.
127;;
aae91380 128;; * workfile-version (file)
fcb500ea
AS
129;;
130;; Return the current workfile version of FILE.
131;;
132;; - latest-on-branch-p (file)
133;;
134;; Return non-nil if the current workfile version of FILE is the latest
135;; on its branch. The default implementation always returns t, which
136;; means that working with non-current versions is not supported by
137;; default.
138;;
0e362f54 139;; * checkout-model (file)
fcb500ea
AS
140;;
141;; Indicate whether FILE needs to be "checked out" before it can be
142;; edited. See `vc-checkout-model' for a list of possible values.
143;;
aae91380 144;; - workfile-unchanged-p (file)
fcb500ea
AS
145;;
146;; Return non-nil if FILE is unchanged from its current workfile
147;; version. This function should do a brief comparison of FILE's
148;; contents with those of the master version. If the backend does not
149;; have such a brief-comparison feature, the default implementation of
150;; this function can be used, which delegates to a full
151;; vc-BACKEND-diff.
152;;
0e362f54 153;; - mode-line-string (file)
fcb500ea
AS
154;;
155;; If provided, this function should return the VC-specific mode line
156;; string for FILE. The default implementation deals well with all
157;; states that `vc-state' can return.
158;;
aae91380 159;; - dired-state-info (file)
fcb500ea
AS
160;;
161;; Translate the `vc-state' property of FILE into a string that can be
162;; used in a vc-dired buffer. The default implementation deals well
163;; with all states that `vc-state' can return.
164;;
165;; STATE-CHANGING FUNCTIONS
166;;
167;; * register (file &optional rev comment)
168;;
169;; Register FILE in this backend. Optionally, an initial revision REV
170;; and an initial description of the file, COMMENT, may be specified.
ecd50f65
AS
171;; The implementation should pass the value of vc-register-switches
172;; to the backend command.
fcb500ea 173;;
b470cb65
AS
174;; - init-version (file)
175;;
176;; The initial version to use when registering FILE if one is not
177;; specified by the user. If not provided, the variable
178;; vc-default-init-version is used instead.
179;;
099bd78a 180;; - responsible-p (file)
fcb500ea
AS
181;;
182;; Return non-nil if this backend considers itself "responsible" for
183;; FILE, which can also be a directory. This function is used to find
184;; out what backend to use for registration of new files and for things
185;; like change log generation. The default implementation always
186;; returns nil.
187;;
0e362f54 188;; - could-register (file)
fcb500ea
AS
189;;
190;; Return non-nil if FILE could be registered under this backend. The
191;; default implementation always returns t.
192;;
aae91380 193;; - receive-file (file rev)
fcb500ea
AS
194;;
195;; Let this backend "receive" a file that is already registered under
196;; another backend. The default implementation simply calls `register'
197;; for FILE, but it can be overridden to do something more specific,
198;; e.g. keep revision numbers consistent or choose editing modes for
199;; FILE that resemble those of the other backend.
200;;
201;; - unregister (file)
202;;
203;; Unregister FILE from this backend. This is only needed if this
204;; backend may be used as a "more local" backend for temporary editing.
205;;
aae91380 206;; * checkin (file rev comment)
fcb500ea
AS
207;;
208;; Commit changes in FILE to this backend. If REV is non-nil, that
209;; should become the new revision number. COMMENT is used as a
ecd50f65
AS
210;; check-in comment. The implementation should pass the value of
211;; vc-checkin-switches to the backend command.
fcb500ea
AS
212;;
213;; * checkout (file &optional editable rev destfile)
214;;
215;; Check out revision REV of FILE into the working area. If EDITABLE
216;; is non-nil, FILE should be writable by the user and if locking is
217;; used for FILE, a lock should also be set. If REV is non-nil, that
218;; is the revision to check out (default is current workfile version);
219;; if REV is the empty string, that means to check out the head of the
220;; trunk. If optional arg DESTFILE is given, it is an alternate
ecd50f65
AS
221;; filename to write the contents to. The implementation should
222;; pass the value of vc-checkout-switches to the backend command.
fcb500ea 223;;
bbfc07d3 224;; * revert (file &optional contents-done)
fcb500ea 225;;
bbfc07d3
AS
226;; Revert FILE back to the current workfile version. If optional
227;; arg CONTENTS-DONE is non-nil, then the contents of FILE have
228;; already been reverted from a version backup, and this function
229;; only needs to update the status of FILE within the backend.
fcb500ea
AS
230;;
231;; - cancel-version (file editable)
232;;
233;; Cancel the current workfile version of FILE, i.e. remove it from the
234;; master. EDITABLE non-nil means that FILE should be writable
235;; afterwards, and if locking is used for FILE, then a lock should also
236;; be set. If this function is not provided, trying to cancel a
237;; version is caught as an error.
238;;
aae91380 239;; - merge (file rev1 rev2)
fcb500ea
AS
240;;
241;; Merge the changes between REV1 and REV2 into the current working file.
242;;
aae91380 243;; - merge-news (file)
fcb500ea
AS
244;;
245;; Merge recent changes from the current branch into FILE.
246;;
aae91380 247;; - steal-lock (file &optional version)
fcb500ea
AS
248;;
249;; Steal any lock on the current workfile version of FILE, or on
250;; VERSION if that is provided. This function is only needed if
251;; locking is used for files under this backend, and if files can
252;; indeed be locked by other users.
253;;
254;; HISTORY FUNCTIONS
255;;
aae91380 256;; * print-log (file)
fcb500ea 257;;
ad339989 258;; Insert the revision log of FILE into the *vc* buffer.
fcb500ea 259;;
aae91380 260;; - show-log-entry (version)
fcb500ea
AS
261;;
262;; If provided, search the log entry for VERSION in the current buffer,
263;; and make sure it is displayed in the buffer's window. The default
264;; implementation of this function works for RCS-style logs.
265;;
aae91380 266;; - wash-log (file)
fcb500ea
AS
267;;
268;; Remove all non-comment information from the output of print-log. The
269;; default implementation of this function works for RCS-style logs.
270;;
0e362f54 271;; - logentry-check ()
fcb500ea
AS
272;;
273;; If defined, this function is run to find out whether the user
274;; entered a valid log entry for check-in. The log entry is in the
275;; current buffer, and if it is not a valid one, the function should
276;; throw an error.
277;;
aae91380 278;; - comment-history (file)
fcb500ea
AS
279;;
280;; Return a string containing all log entries that were made for FILE.
281;; This is used for transferring a file from one backend to another,
282;; retaining comment information. The default implementation of this
283;; function does this by calling print-log and then wash-log, and
284;; returning the resulting buffer contents as a string.
285;;
aae91380 286;; - update-changelog (files)
fcb500ea
AS
287;;
288;; Using recent log entries, create ChangeLog entries for FILES, or for
289;; all files at or below the default-directory if FILES is nil. The
290;; default implementation runs rcs2log, which handles RCS- and
291;; CVS-style logs.
292;;
0e362f54 293;; * diff (file &optional rev1 rev2)
fcb500ea 294;;
3f19e412
AS
295;; Insert the diff for FILE into the *vc-diff* buffer. If REV1 and
296;; REV2 are non-nil, report differences from REV1 to REV2. If REV1
297;; is nil, use the current workfile version (as found in the
298;; repository) as the older version; if REV2 is nil, use the current
299;; workfile contents as the newer version. This function should
300;; pass the value of (vc-diff-switches-list BACKEND) to the backend
301;; command. It should return a status of either 0 (no differences
302;; found), or 1 (either non-empty diff or the diff is run
303;; asynchronously).
fcb500ea 304;;
99cb8c8b 305;; - diff-tree (dir &optional rev1 rev2)
2c87edc1
AS
306;;
307;; Insert the diff for all files at and below DIR into the *vc-diff*
99cb8c8b 308;; buffer. The meaning of REV1 and REV2 is the same as for
2c87edc1
AS
309;; vc-BACKEND-diff. The default implementation does an explicit tree
310;; walk, calling vc-BACKEND-diff for each individual file.
311;;
aae91380 312;; - annotate-command (file buf rev)
fcb500ea
AS
313;;
314;; If this function is provided, it should produce an annotated version
315;; of FILE in BUF, relative to version REV. This is currently only
316;; implemented for CVS, using the `cvs annotate' command.
317;;
75665141 318;; - annotate-time ()
fcb500ea
AS
319;;
320;; Only required if `annotate-command' is defined for the backend.
75665141
AS
321;; Return the time of the next line of annotation at or after point,
322;; as a floating point fractional number of days. The helper
323;; function `vc-annotate-convert-time' may be useful for converting
324;; multi-part times as returned by `current-time' and `encode-time'
0ff9b955 325;; to this format. Return nil if no more lines of annotation appear
75665141
AS
326;; in the buffer. You can safely assume that point is placed at the
327;; beginning of each line, starting at `point-min'. The buffer that
328;; point is placed in is the Annotate output, as defined by the
329;; relevant backend.
330;;
331;; - annotate-current-time ()
332;;
333;; Only required if `annotate-command' is defined for the backend,
334;; AND you'd like the current time considered to be anything besides
335;; (vs-annotate-convert-time (current-time)) -- i.e. the current
336;; time with hours, minutes, and seconds included. Probably safe to
337;; ignore. Return the current-time, in units of fractional days.
fcb500ea
AS
338;;
339;; SNAPSHOT SYSTEM
340;;
0e362f54 341;; - create-snapshot (dir name branchp)
fcb500ea
AS
342;;
343;; Take a snapshot of the current state of files under DIR and name it
344;; NAME. This should make sure that files are up-to-date before
345;; proceeding with the action. DIR can also be a file and if BRANCHP
346;; is specified, NAME should be created as a branch and DIR should be
347;; checked out under this new branch. The default implementation does
348;; not support branches but does a sanity check, a tree traversal and
349;; for each file calls `assign-name'.
350;;
351;; - assign-name (file name)
352;;
353;; Give name NAME to the current version of FILE, assuming it is
354;; up-to-date. Only used by the default version of `create-snapshot'.
355;;
0e362f54 356;; - retrieve-snapshot (dir name update)
fcb500ea
AS
357;;
358;; Retrieve a named snapshot of all registered files at or below DIR.
359;; If UPDATE is non-nil, then update buffers of any files in the
360;; snapshot that are currently visited. The default implementation
361;; does a sanity check whether there aren't any uncommitted changes at
362;; or below DIR, and then performs a tree walk, using the `checkout'
363;; function to retrieve the corresponding versions.
364;;
365;; MISCELLANEOUS
366;;
aae91380 367;; - make-version-backups-p (file)
fcb500ea
AS
368;;
369;; Return non-nil if unmodified repository versions of FILE should be
370;; backed up locally. If this is done, VC can perform `diff' and
371;; `revert' operations itself, without calling the backend system. The
372;; default implementation always returns nil.
373;;
869131a5
AS
374;; - previous-version (file rev)
375;;
376;; Return the version number that precedes REV for FILE.
377;;
aae91380 378;; - check-headers ()
fcb500ea
AS
379;;
380;; Return non-nil if the current buffer contains any version headers.
381;;
aae91380 382;; - clear-headers ()
fcb500ea
AS
383;;
384;; In the current buffer, reset all version headers to their unexpanded
385;; form. This function should be provided if the state-querying code
386;; for this backend uses the version headers to determine the state of
387;; a file. This function will then be called whenever VC changes the
388;; version control state in such a way that the headers would give
389;; wrong information.
390;;
099bd78a 391;; - rename-file (old new)
fcb500ea
AS
392;;
393;; Rename file OLD to NEW, both in the working area and in the
394;; repository. If this function is not provided, the command
395;; `vc-rename-file' will signal an error.
aae91380 396
fcb500ea 397;;; Code:
0e362f54 398
594722a8 399(require 'vc-hooks)
8c0aaf40 400(require 'ring)
0e362f54 401(eval-when-compile
7849e179 402 (require 'cl)
099bd78a
SM
403 (require 'compile)
404 (require 'dired) ; for dired-map-over-marks macro
405 (require 'dired-aux)) ; for dired-kill-{line,tree}
8c0aaf40
ER
406
407(if (not (assoc 'vc-parent-buffer minor-mode-alist))
408 (setq minor-mode-alist
409 (cons '(vc-parent-buffer vc-parent-buffer-name)
410 minor-mode-alist)))
594722a8
ER
411
412;; General customization
413
0101cc40
RS
414(defgroup vc nil
415 "Version-control system in Emacs."
416 :group 'tools)
417
418(defcustom vc-suppress-confirm nil
419 "*If non-nil, treat user as expert; suppress yes-no prompts on some things."
420 :type 'boolean
421 :group 'vc)
422
2c4eea90
KH
423(defcustom vc-delete-logbuf-window t
424 "*If non-nil, delete the *VC-log* buffer and window after each logical action.
425If nil, bury that buffer instead.
426This is most useful if you have multiple windows on a frame and would like to
427preserve the setting."
428 :type 'boolean
429 :group 'vc)
430
0101cc40
RS
431(defcustom vc-initial-comment nil
432 "*If non-nil, prompt for initial comment when a file is registered."
433 :type 'boolean
434 :group 'vc)
435
0d53f466
AS
436(defcustom vc-default-init-version "1.1"
437 "*A string used as the default version number when a new file is registered.
b470cb65
AS
438This can be overridden by giving a prefix argument to \\[vc-register]. This
439can also be overridden by a particular VC backend."
0d53f466 440 :type 'string
cd32a7ba
DN
441 :group 'vc
442 :version "20.3")
0d53f466 443
0101cc40
RS
444(defcustom vc-command-messages nil
445 "*If non-nil, display run messages from back-end commands."
446 :type 'boolean
447 :group 'vc)
448
449(defcustom vc-checkin-switches nil
450 "*A string or list of strings specifying extra switches for checkin.
451These are passed to the checkin program by \\[vc-checkin]."
452 :type '(choice (const :tag "None" nil)
453 (string :tag "Argument String")
454 (repeat :tag "Argument List"
455 :value ("")
456 string))
457 :group 'vc)
458
459(defcustom vc-checkout-switches nil
460 "*A string or list of strings specifying extra switches for checkout.
461These are passed to the checkout program by \\[vc-checkout]."
462 :type '(choice (const :tag "None" nil)
463 (string :tag "Argument String")
464 (repeat :tag "Argument List"
465 :value ("")
466 string))
467 :group 'vc)
468
469(defcustom vc-register-switches nil
470 "*A string or list of strings; extra switches for registering a file.
471These are passed to the checkin program by \\[vc-register]."
472 :type '(choice (const :tag "None" nil)
473 (string :tag "Argument String")
474 (repeat :tag "Argument List"
475 :value ("")
476 string))
477 :group 'vc)
478
0e362f54
GM
479(defcustom vc-dired-listing-switches "-al"
480 "*Switches passed to `ls' for vc-dired. MUST contain the `l' option."
481 :type 'string
482 :group 'vc
6f41eeb5 483 :version "21.1")
0e362f54 484
3b574573
AS
485(defcustom vc-dired-recurse t
486 "*If non-nil, show directory trees recursively in VC Dired."
487 :type 'boolean
488 :group 'vc
489 :version "20.3")
490
491(defcustom vc-dired-terse-display t
492 "*If non-nil, show only locked files in VC Dired."
493 :type 'boolean
494 :group 'vc
495 :version "20.3")
496
0101cc40 497(defcustom vc-directory-exclusion-list '("SCCS" "RCS" "CVS")
6f1ecae4 498 "*List of directory names to be ignored when walking directory trees."
0101cc40
RS
499 :type '(repeat string)
500 :group 'vc)
666a0ebb 501
8c0aaf40
ER
502(defconst vc-maximum-comment-ring-size 32
503 "Maximum number of saved comments in the comment ring.")
504
acc5b122
AS
505(defcustom vc-diff-switches nil
506 "*A string or list of strings specifying switches for diff under VC.
b453817c
AS
507When running diff under a given BACKEND, VC concatenates the values of
508`diff-switches', `vc-diff-switches', and `vc-BACKEND-diff-switches' to
509get the switches for that command. Thus, `vc-diff-switches' should
510contain switches that are specific to version control, but not
511specific to any particular backend."
acc5b122
AS
512 :type '(choice (const :tag "None" nil)
513 (string :tag "Argument String")
514 (repeat :tag "Argument List"
515 :value ("")
516 string))
517 :group 'vc
518 :version "21.1")
519
7cad930d
AS
520;;;###autoload
521(defcustom vc-checkout-hook nil
6f1ecae4 522 "*Normal hook (list of functions) run after checking out a file.
7cad930d
AS
523See `run-hooks'."
524 :type 'hook
525 :group 'vc
526 :version "21.1")
527
75665141 528(defcustom vc-annotate-display-mode nil
6f1ecae4 529 "Which mode to color the output of \\[vc-annotate] with by default."
75665141
AS
530 :type '(choice (const :tag "Default" nil)
531 (const :tag "Scale to Oldest" scale)
532 (const :tag "Scale Oldest->Newest" fullscale)
533 (number :tag "Specify Fractional Number of Days"
534 :value "20.5"))
535 :group 'vc)
536
0e362f54
GM
537;;;###autoload
538(defcustom vc-checkin-hook nil
539 "*Normal hook (list of functions) run after a checkin is done.
540See `run-hooks'."
541 :type 'hook
542 :options '(vc-comment-to-change-log)
543 :group 'vc)
544
545;;;###autoload
546(defcustom vc-before-checkin-hook nil
6f1ecae4 547 "*Normal hook (list of functions) run before a file is checked in.
0e362f54
GM
548See `run-hooks'."
549 :type 'hook
550 :group 'vc)
551
552(defcustom vc-logentry-check-hook nil
553 "*Normal hook run by `vc-backend-logentry-check'.
554Use this to impose your own rules on the entry in addition to any the
555version control backend imposes itself."
556 :type 'hook
557 :group 'vc)
2e810285 558
0e362f54 559;; Annotate customization
7d2d9482 560(defcustom vc-annotate-color-map
75665141
AS
561 '(( 20. . "#FF0000")
562 ( 40. . "#FF3800")
563 ( 60. . "#FF7000")
564 ( 80. . "#FFA800")
565 (100. . "#FFE000")
566 (120. . "#E7FF00")
567 (140. . "#AFFF00")
568 (160. . "#77FF00")
569 (180. . "#3FFF00")
570 (200. . "#07FF00")
571 (220. . "#00FF31")
572 (240. . "#00FF69")
573 (260. . "#00FFA1")
574 (280. . "#00FFD9")
575 (300. . "#00EEFF")
576 (320. . "#00B6FF")
577 (340. . "#007EFF"))
6f1ecae4 578 "*Association list of age versus color, for \\[vc-annotate].
75665141
AS
579Ages are given in units of fractional days. Default is eighteen steps
580using a twenty day increment."
0e362f54 581 :type 'alist
7d2d9482
RS
582 :group 'vc)
583
584(defcustom vc-annotate-very-old-color "#0046FF"
6f1ecae4 585 "*Color for lines older than the current color range in \\[vc-annotate]]."
7d2d9482
RS
586 :type 'string
587 :group 'vc)
588
589(defcustom vc-annotate-background "black"
590 "*Background color for \\[vc-annotate].
591Default color is used if nil."
592 :type 'string
593 :group 'vc)
594
595(defcustom vc-annotate-menu-elements '(2 0.5 0.1 0.01)
596 "*Menu elements for the mode-specific menu of VC-Annotate mode.
597List of factors, used to expand/compress the time scale. See `vc-annotate'."
0e362f54 598 :type '(repeat number)
7d2d9482
RS
599 :group 'vc)
600
0e362f54
GM
601;; vc-annotate functionality (CVS only).
602(defvar vc-annotate-mode nil
603 "Variable indicating if VC-Annotate mode is active.")
f0b188ed 604
0e362f54
GM
605(defvar vc-annotate-mode-map
606 (let ((m (make-sparse-keymap)))
607 (define-key m [menu-bar] (make-sparse-keymap "VC-Annotate"))
608 m)
609 "Local keymap used for VC-Annotate mode.")
67242a23 610
0e362f54
GM
611(defvar vc-annotate-mode-menu nil
612 "Local keymap used for VC-Annotate mode's menu bar menu.")
7d2d9482 613
594722a8
ER
614;; Header-insertion hair
615
0101cc40 616(defcustom vc-static-header-alist
594722a8
ER
617 '(("\\.c$" .
618 "\n#ifndef lint\nstatic char vcid[] = \"\%s\";\n#endif /* lint */\n"))
0e362f54
GM
619 "*Associate static header string templates with file types.
620A \%s in the template is replaced with the first string associated with
099bd78a 621the file's version control type in `vc-header-alist'."
0101cc40
RS
622 :type '(repeat (cons :format "%v"
623 (regexp :tag "File Type")
624 (string :tag "Header String")))
625 :group 'vc)
7b4f934d 626
0101cc40 627(defcustom vc-comment-alist
594722a8 628 '((nroff-mode ".\\\"" ""))
6f1ecae4 629 "*Special comment delimiters for generating VC headers.
099bd78a
SM
630Add an entry in this list if you need to override the normal `comment-start'
631and `comment-end' variables. This will only be necessary if the mode language
0101cc40
RS
632is sensitive to blank lines."
633 :type '(repeat (list :format "%v"
634 (symbol :tag "Mode")
635 (string :tag "Comment Start")
636 (string :tag "Comment End")))
637 :group 'vc)
594722a8 638
0101cc40 639(defcustom vc-checkout-carefully (= (user-uid) 0)
6f1ecae4
AS
640 "*This variable is obsolete
641The corresponding checks are always done now.
642From the old doc string:
643
644Non-nil means be extra-careful in checkout.
bbf97570 645Verify that the file really is not locked
0101cc40
RS
646and that its contents match what the master file says."
647 :type 'boolean
648 :group 'vc)
bbf97570 649
0e362f54 650\f
ec402ad4 651;; The main keymap
b0c9bc8c 652
0e362f54
GM
653;; Initialization code, to be done just once at load-time
654(defvar vc-log-mode-map
655 (let ((map (make-sparse-keymap)))
656 (define-key map "\M-n" 'vc-next-comment)
657 (define-key map "\M-p" 'vc-previous-comment)
658 (define-key map "\M-r" 'vc-comment-search-reverse)
659 (define-key map "\M-s" 'vc-comment-search-forward)
660 (define-key map "\C-c\C-c" 'vc-finish-logentry)
661 map))
662;; Compatibility with old name. Should we bother ?
663(defvar vc-log-entry-mode vc-log-mode-map)
b0c9bc8c 664
0e362f54 665\f
594722a8 666;; Variables the user doesn't need to know about.
594722a8 667(defvar vc-log-operation nil)
67242a23 668(defvar vc-log-after-operation-hook nil)
0e362f54 669(defvar vc-annotate-buffers nil
099bd78a
SM
670 "Alist of current \"Annotate\" buffers and their corresponding backends.
671The keys are \(BUFFER . BACKEND\). See also `vc-annotate-get-backend'.")
dbf87856
RS
672;; In a log entry buffer, this is a local variable
673;; that points to the buffer for which it was made
674;; (either a file, or a VC dired buffer).
1a2f456b 675(defvar vc-parent-buffer nil)
0e362f54 676(put 'vc-parent-buffer 'permanent-local t)
8c0aaf40 677(defvar vc-parent-buffer-name nil)
0e362f54 678(put 'vc-parent-buffer-name 'permanent-local t)
594722a8 679
db59472c
RS
680(defvar vc-log-file)
681(defvar vc-log-version)
682
8c0aaf40 683(defvar vc-dired-mode nil)
e1f297e6
ER
684(make-variable-buffer-local 'vc-dired-mode)
685
c9b35ece 686(defvar vc-comment-ring (make-ring vc-maximum-comment-ring-size))
8c0aaf40 687(defvar vc-comment-ring-index nil)
0e362f54 688(defvar vc-last-comment-match "")
c8de1d91 689
ec402ad4
SM
690;; functions that operate on RCS revision numbers. This code should
691;; also be moved into the backends. It stays for now, however, since
692;; it is used in code below.
c8de1d91 693(defun vc-trunk-p (rev)
099bd78a 694 "Return t if REV is a revision on the trunk."
c8de1d91
AS
695 (not (eq nil (string-match "\\`[0-9]+\\.[0-9]+\\'" rev))))
696
ccb141e8 697(defun vc-branch-p (rev)
099bd78a 698 "Return t if REV is a branch revision."
ccb141e8
AS
699 (not (eq nil (string-match "\\`[0-9]+\\(\\.[0-9]+\\.[0-9]+\\)*\\'" rev))))
700
a10cd561 701;;;###autoload
c8de1d91 702(defun vc-branch-part (rev)
099bd78a 703 "Return the branch part of a revision number REV."
869131a5
AS
704 (let ((index (string-match "\\.[0-9]+\\'" rev)))
705 (if index
706 (substring rev 0 index))))
c8de1d91 707
c0d66cb2 708(defun vc-minor-part (rev)
099bd78a 709 "Return the minor version number of a revision number REV."
c0d66cb2
RS
710 (string-match "[0-9]+\\'" rev)
711 (substring rev (match-beginning 0) (match-end 0)))
712
869131a5
AS
713(defun vc-default-previous-version (backend file rev)
714 "Guess the version number immediately preceding REV for FILE.
715This default implementation works for <major>.<minor>-style version numbers
716as used by RCS and CVS."
c0d66cb2
RS
717 (let ((branch (vc-branch-part rev))
718 (minor-num (string-to-number (vc-minor-part rev))))
869131a5
AS
719 (when branch
720 (if (> minor-num 1)
721 ;; version does probably not start a branch or release
722 (concat branch "." (number-to-string (1- minor-num)))
723 (if (vc-trunk-p rev)
724 ;; we are at the beginning of the trunk --
725 ;; don't know anything to return here
726 nil
727 ;; we are at the beginning of a branch --
728 ;; return version of starting point
729 (vc-branch-part branch))))))
c0d66cb2 730
594722a8
ER
731;; File property caching
732
8c0aaf40
ER
733(defun vc-clear-context ()
734 "Clear all cached file properties and the comment ring."
735 (interactive)
fd828872 736 (fillarray vc-file-prop-obarray 0)
8c0aaf40
ER
737 ;; Note: there is potential for minor lossage here if there is an open
738 ;; log buffer with a nonzero local value of vc-comment-ring-index.
c9b35ece 739 (setq vc-comment-ring (make-ring vc-maximum-comment-ring-size)))
8c0aaf40 740
099bd78a 741(defmacro with-vc-properties (file form settings)
6f1ecae4
AS
742 "Execute FORM, then maybe set per-file properties for FILE.
743SETTINGS is an association list of property/value pairs. After
744executing FORM, set those properties from SETTINGS that have not yet
745been updated to their corresponding values."
169f0cae 746 `(let ((vc-touched-properties (list t)))
099bd78a
SM
747 ,form
748 (mapcar (lambda (setting)
a3255400 749 (let ((property (car setting)))
099bd78a 750 (unless (memq property vc-touched-properties)
169f0cae 751 (put (intern ,file vc-file-prop-obarray)
a3255400 752 property (cdr setting)))))
099bd78a
SM
753 ,settings)))
754
594722a8
ER
755;; Random helper functions
756
0e362f54 757(defsubst vc-editable-p (file)
6f1ecae4 758 "Return non-nil if FILE can be edited."
0e362f54 759 (or (eq (vc-checkout-model file) 'implicit)
7849e179 760 (memq (vc-state file) '(edited needs-merge))))
c8de1d91 761
ec402ad4 762;; Two macros for elisp programming
709822e8
AS
763;;;###autoload
764(defmacro with-vc-file (file comment &rest body)
6f1ecae4 765 "Check out a writable copy of FILE if necessary, then execute BODY.
0e362f54
GM
766Check in FILE with COMMENT (a string) after BODY has been executed.
767FILE is passed through `expand-file-name'; BODY executed within
768`save-excursion'. If FILE is not under version control, or locked by
709822e8 769somebody else, signal error."
169f0cae
AS
770 (let ((filevar (make-symbol "file")))
771 `(let ((,filevar (expand-file-name ,file)))
772 (or (vc-backend ,filevar)
773 (error (format "File not under version control: `%s'" file)))
774 (unless (vc-editable-p ,filevar)
775 (let ((state (vc-state ,filevar)))
776 (if (stringp state)
777 (error (format "`%s' is locking `%s'" state ,filevar))
778 (vc-checkout ,filevar t))))
779 (save-excursion
780 ,@body)
781 (vc-checkin ,filevar nil ,comment))))
782
783(put 'with-vc-file 'lisp-indent-function 2)
709822e8
AS
784
785;;;###autoload
786(defmacro edit-vc-file (file comment &rest body)
0e362f54
GM
787 "Edit FILE under version control, executing body.
788Checkin with COMMENT after executing BODY.
709822e8
AS
789This macro uses `with-vc-file', passing args to it.
790However, before executing BODY, find FILE, and after BODY, save buffer."
169f0cae
AS
791 (let ((filevar (make-symbol "file")))
792 `(let ((,filevar (expand-file-name ,file)))
793 (with-vc-file
794 ,filevar ,comment
795 (set-buffer (find-file-noselect ,filevar))
796 ,@body
797 (save-buffer)))))
798
799(put 'edit-vc-file 'lisp-indent-function 2)
709822e8 800
b6909007 801(defun vc-ensure-vc-buffer ()
099bd78a 802 "Make sure that the current buffer visits a version-controlled file."
b6909007
AS
803 (if vc-dired-mode
804 (set-buffer (find-file-noselect (dired-get-filename)))
805 (while vc-parent-buffer
806 (pop-to-buffer vc-parent-buffer))
807 (if (not (buffer-file-name))
808 (error "Buffer %s is not associated with a file" (buffer-name))
809 (if (not (vc-backend (buffer-file-name)))
810 (error "File %s is not under version control" (buffer-file-name))))))
7ef84cf9 811
594722a8 812(defvar vc-binary-assoc nil)
87a00c4f
EZ
813(defvar vc-binary-suffixes
814 (if (memq system-type '(ms-dos windows-nt))
815 '(".exe" ".com" ".bat" ".cmd" ".btm" "")
816 '("")))
0e362f54
GM
817
818(defun vc-process-filter (p s)
099bd78a 819 "An alternative output filter for async process P.
0e362f54
GM
820The only difference with the default filter is to insert S after markers."
821 (with-current-buffer (process-buffer p)
822 (save-excursion
823 (let ((inhibit-read-only t))
824 (goto-char (process-mark p))
825 (insert s)
826 (set-marker (process-mark p) (point))))))
827
828(defun vc-setup-buffer (&optional buf)
6f1ecae4 829 "Prepare BUF for executing a VC command and make it current.
0e362f54
GM
830BUF defaults to \"*vc*\", can be a string and will be created if necessary."
831 (unless buf (setq buf "*vc*"))
832 (let ((camefrom (current-buffer))
833 (olddir default-directory))
834 (set-buffer (get-buffer-create buf))
835 (kill-all-local-variables)
836 (set (make-local-variable 'vc-parent-buffer) camefrom)
837 (set (make-local-variable 'vc-parent-buffer-name)
838 (concat " from " (buffer-name camefrom)))
839 (setq default-directory olddir)
840 (let ((inhibit-read-only t))
841 (erase-buffer))))
842
843(defun vc-exec-after (code)
844 "Eval CODE when the current buffer's process is done.
845If the current buffer has no process, just evaluate CODE.
846Else, add CODE to the process' sentinel."
847 (let ((proc (get-buffer-process (current-buffer))))
848 (cond
849 ;; If there's no background process, just execute the code.
850 ((null proc) (eval code))
851 ;; If the background process has exited, reap it and try again
852 ((eq (process-status proc) 'exit)
853 (delete-process proc)
854 (vc-exec-after code))
855 ;; If a process is running, add CODE to the sentinel
856 ((eq (process-status proc) 'run)
857 (let ((sentinel (process-sentinel proc)))
858 (set-process-sentinel proc
859 `(lambda (p s)
860 (with-current-buffer ',(current-buffer)
861 (goto-char (process-mark p))
6f41eeb5 862 ,@(append (cdr (cdr (cdr ;strip off `with-current-buffer buf
0e362f54
GM
863 ; (goto-char...)'
864 (car (cdr (cdr ;strip off `lambda (p s)'
865 sentinel))))))
866 (list `(vc-exec-after ',code))))))))
867 (t (error "Unexpected process state"))))
868 nil)
869
870(defvar vc-post-command-functions nil
871 "Hook run at the end of `vc-do-command'.
872Each function is called inside the buffer in which the command was run
6f1ecae4 873and is passed 3 arguments: the COMMAND, the FILE and the FLAGS.")
0e362f54 874
a84b80ba 875;;;###autoload
0e362f54 876(defun vc-do-command (buffer okstatus command file &rest flags)
6f1ecae4 877 "Execute a VC command, notifying user and checking for errors.
ad339989
AS
878Output from COMMAND goes to BUFFER, or *vc* if BUFFER is nil or the
879current buffer if BUFFER is t. If the destination buffer is not
880already current, set it up properly and erase it. The command is
881considered successful if its exit status does not exceed OKSTATUS (if
882OKSTATUS is nil, that means to ignore errors, if it is 'async, that
883means not to wait for termination of the subprocess). FILE is the
884name of the working file (may also be nil, to execute commands that
885don't expect a file name). If an optional list of FLAGS is present,
0e362f54 886that is inserted into the command line before the filename."
b0c9bc8c 887 (and file (setq file (expand-file-name file)))
594722a8 888 (if vc-command-messages
02da6253 889 (message "Running %s on %s..." command file))
0e362f54 890 (save-current-buffer
ad339989
AS
891 (unless (or (eq buffer t)
892 (and (stringp buffer)
893 (string= (buffer-name) buffer))
894 (eq buffer (current-buffer)))
895 (vc-setup-buffer buffer))
0e362f54
GM
896 (let ((squeezed nil)
897 (inhibit-read-only t)
898 (status 0))
899 (setq squeezed (delq nil (copy-sequence flags)))
900 (when file
901 ;; FIXME: file-relative-name can return a bogus result because
902 ;; it doesn't look at the actual file-system to see if symlinks
903 ;; come into play.
904 (setq squeezed (append squeezed (list (file-relative-name file)))))
905 (let ((exec-path (append vc-path exec-path))
906 ;; Add vc-path to PATH for the execution of this command.
907 (process-environment
908 (cons (concat "PATH=" (getenv "PATH")
909 path-separator
910 (mapconcat 'identity vc-path path-separator))
911 process-environment))
912 (w32-quote-process-args t))
913 (if (eq okstatus 'async)
914 (let ((proc (apply 'start-process command (current-buffer) command
915 squeezed)))
d9ed4100
AS
916 (unless (active-minibuffer-window)
917 (message "Running %s in the background..." command))
0e362f54
GM
918 ;;(set-process-sentinel proc (lambda (p msg) (delete-process p)))
919 (set-process-filter proc 'vc-process-filter)
920 (vc-exec-after
d9ed4100
AS
921 `(unless (active-minibuffer-window)
922 (message "Running %s in the background... done" ',command))))
0e362f54
GM
923 (setq status (apply 'call-process command nil t nil squeezed))
924 (when (or (not (integerp status)) (and okstatus (< okstatus status)))
925 (pop-to-buffer (current-buffer))
926 (goto-char (point-min))
927 (shrink-window-if-larger-than-buffer)
928 (error "Running %s...FAILED (%s)" command
929 (if (integerp status) (format "status %d" status) status))))
930 (if vc-command-messages
931 (message "Running %s...OK" command)))
932 (vc-exec-after
933 `(run-hook-with-args 'vc-post-command-functions ',command ',file ',flags))
934 status)))
594722a8 935
c4ae7096 936(defun vc-position-context (posn)
099bd78a
SM
937 "Save a bit of the text around POSN in the current buffer.
938Used to help us find the corresponding position again later
939if markers are destroyed or corrupted."
0e362f54
GM
940 ;; A lot of this was shamelessly lifted from Sebastian Kremer's
941 ;; rcs.el mode.
c4ae7096
JB
942 (list posn
943 (buffer-size)
944 (buffer-substring posn
945 (min (point-max) (+ posn 100)))))
946
c4ae7096 947(defun vc-find-position-by-context (context)
6f1ecae4
AS
948 "Return the position of CONTEXT in the current buffer.
949If CONTEXT cannot be found, return nil."
c4ae7096
JB
950 (let ((context-string (nth 2 context)))
951 (if (equal "" context-string)
952 (point-max)
953 (save-excursion
954 (let ((diff (- (nth 1 context) (buffer-size))))
955 (if (< diff 0) (setq diff (- diff)))
956 (goto-char (nth 0 context))
957 (if (or (search-forward context-string nil t)
958 ;; Can't use search-backward since the match may continue
959 ;; after point.
960 (progn (goto-char (- (point) diff (length context-string)))
961 ;; goto-char doesn't signal an error at
962 ;; beginning of buffer like backward-char would
963 (search-forward context-string nil t)))
964 ;; to beginning of OSTRING
965 (- (point) (length context-string))))))))
966
4b398f5d 967(defun vc-context-matches-p (posn context)
099bd78a 968 "Return t if POSN matches CONTEXT, nil otherwise."
4b398f5d
AS
969 (let* ((context-string (nth 2 context))
970 (len (length context-string))
971 (end (+ posn len)))
972 (if (> end (1+ (buffer-size)))
973 nil
974 (string= context-string (buffer-substring posn end)))))
975
c8de1d91 976(defun vc-buffer-context ()
099bd78a
SM
977 "Return a list (POINT-CONTEXT MARK-CONTEXT REPARSE).
978Used by `vc-restore-buffer-context' to later restore the context."
c4ae7096 979 (let ((point-context (vc-position-context (point)))
cfadef63
RS
980 ;; Use mark-marker to avoid confusion in transient-mark-mode.
981 (mark-context (if (eq (marker-buffer (mark-marker)) (current-buffer))
982 (vc-position-context (mark-marker))))
983 ;; Make the right thing happen in transient-mark-mode.
ab877583
RM
984 (mark-active nil)
985 ;; We may want to reparse the compilation buffer after revert
986 (reparse (and (boundp 'compilation-error-list) ;compile loaded
987 (let ((curbuf (current-buffer)))
988 ;; Construct a list; each elt is nil or a buffer
989 ;; iff that buffer is a compilation output buffer
990 ;; that contains markers into the current buffer.
991 (save-excursion
0e362f54 992 (mapcar (lambda (buffer)
ab877583
RM
993 (set-buffer buffer)
994 (let ((errors (or
995 compilation-old-error-list
996 compilation-error-list))
997 (buffer-error-marked-p nil))
6fb6ab11 998 (while (and (consp errors)
ab877583 999 (not buffer-error-marked-p))
a1bda481 1000 (and (markerp (cdr (car errors)))
e9c8e248
RM
1001 (eq buffer
1002 (marker-buffer
a1bda481 1003 (cdr (car errors))))
e9c8e248 1004 (setq buffer-error-marked-p t))
ab877583 1005 (setq errors (cdr errors)))
0e362f54 1006 (if buffer-error-marked-p buffer)))
ab877583 1007 (buffer-list)))))))
c8de1d91
AS
1008 (list point-context mark-context reparse)))
1009
1010(defun vc-restore-buffer-context (context)
0e362f54 1011 "Restore point/mark, and reparse any affected compilation buffers.
099bd78a 1012CONTEXT is that which `vc-buffer-context' returns."
c8de1d91
AS
1013 (let ((point-context (nth 0 context))
1014 (mark-context (nth 1 context))
1015 (reparse (nth 2 context)))
ab877583
RM
1016 ;; Reparse affected compilation buffers.
1017 (while reparse
1018 (if (car reparse)
0e362f54 1019 (with-current-buffer (car reparse)
ab877583
RM
1020 (let ((compilation-last-buffer (current-buffer)) ;select buffer
1021 ;; Record the position in the compilation buffer of
1022 ;; the last error next-error went to.
1023 (error-pos (marker-position
1024 (car (car-safe compilation-error-list)))))
1025 ;; Reparse the error messages as far as they were parsed before.
1026 (compile-reinitialize-errors '(4) compilation-parsing-end)
1027 ;; Move the pointer up to find the error we were at before
1028 ;; reparsing. Now next-error should properly go to the next one.
1029 (while (and compilation-error-list
27f2f10b 1030 (/= error-pos (car (car compilation-error-list))))
ab877583
RM
1031 (setq compilation-error-list (cdr compilation-error-list))))))
1032 (setq reparse (cdr reparse)))
e1f297e6 1033
4b398f5d
AS
1034 ;; if necessary, restore point and mark
1035 (if (not (vc-context-matches-p (point) point-context))
1036 (let ((new-point (vc-find-position-by-context point-context)))
1037 (if new-point (goto-char new-point))))
01e02ab3
AS
1038 (and mark-active
1039 mark-context
1040 (not (vc-context-matches-p (mark) mark-context))
1041 (let ((new-mark (vc-find-position-by-context mark-context)))
1042 (if new-mark (set-mark new-mark))))))
c4ae7096 1043
c8de1d91 1044(defun vc-revert-buffer1 (&optional arg no-confirm)
6f1ecae4
AS
1045 "Revert buffer, keeping point and mark where user expects them.
1046Try to be clever in the face of changes due to expanded version control
099bd78a
SM
1047key words. This is important for typeahead to work as expected.
1048ARG and NO-CONFIRM are passed on to `revert-buffer'."
c8de1d91
AS
1049 (interactive "P")
1050 (widen)
1051 (let ((context (vc-buffer-context)))
4b398f5d
AS
1052 ;; Use save-excursion here, because it may be able to restore point
1053 ;; and mark properly even in cases where vc-restore-buffer-context
0e362f54 1054 ;; would fail. However, save-excursion might also get it wrong --
4b398f5d
AS
1055 ;; in this case, vc-restore-buffer-context gives it a second try.
1056 (save-excursion
0e362f54 1057 ;; t means don't call normal-mode;
4b398f5d
AS
1058 ;; that's to preserve various minor modes.
1059 (revert-buffer arg no-confirm t))
c8de1d91
AS
1060 (vc-restore-buffer-context context)))
1061
594722a8 1062
97d3f950 1063(defun vc-buffer-sync (&optional not-urgent)
099bd78a 1064 "Make sure the current buffer and its working file are in sync.
0e362f54 1065NOT-URGENT means it is ok to continue if the user says not to save."
bbf97570 1066 (if (buffer-modified-p)
97d3f950
RS
1067 (if (or vc-suppress-confirm
1068 (y-or-n-p (format "Buffer %s modified; save it? " (buffer-name))))
1069 (save-buffer)
0e362f54 1070 (unless not-urgent
97d3f950
RS
1071 (error "Aborted")))))
1072
2ce63cb7 1073(defun vc-workfile-unchanged-p (file)
6f1ecae4 1074 "Return non-nil if FILE has not changed since the last checkout."
2ce63cb7
AS
1075 (let ((checkout-time (vc-file-getprop file 'vc-checkout-time))
1076 (lastmod (nth 5 (file-attributes file))))
1077 (if checkout-time
1078 (equal checkout-time lastmod)
1079 (let ((unchanged (vc-call workfile-unchanged-p file)))
1080 (vc-file-setprop file 'vc-checkout-time (if unchanged lastmod 0))
1081 unchanged))))
1082
336203a2 1083(defun vc-default-workfile-unchanged-p (backend file)
6f1ecae4
AS
1084 "Check if FILE is unchanged by diffing against the master version.
1085Return non-nil if FILE is unchanged."
2ce63cb7
AS
1086 (zerop (vc-call diff file (vc-workfile-version file))))
1087
336203a2 1088(defun vc-default-latest-on-branch-p (backend file)
6f1ecae4
AS
1089 "Return non-nil if FILE is the latest on its branch.
1090This default implementation always returns non-nil, which means that
1091editing non-current versions is not supported by default."
38d88d32
AS
1092 t)
1093
0e362f54
GM
1094(defun vc-recompute-state (file)
1095 "Force a recomputation of the version control state of FILE.
1096The state is computed using the exact, and possibly expensive
1097function `vc-BACKEND-state', not the heuristic."
1098 (vc-file-setprop file 'vc-state (vc-call state file)))
e1f297e6 1099
0e362f54 1100(defun vc-next-action-on-file (file verbose &optional comment)
6f1ecae4 1101 "Do The Right Thing for a given FILE under version control.
0e362f54
GM
1102If COMMENT is specified, it will be used as an admin or checkin comment.
1103If VERBOSE is non-nil, query the user rather than using default parameters."
1104 (let ((visited (get-file-buffer file))
1105 state version)
1106 (when visited
1107 ;; Check relation of buffer and file, and make sure
1108 ;; user knows what he's doing. First, finding the file
1109 ;; will check whether the file on disk is newer.
165e43b6
AS
1110 (set-buffer visited)
1111 ;; ignore buffer-read-only during this test
1112 (let ((buffer-read-only (not (file-writable-p file))))
1113 (if vc-dired-mode
1114 (find-file-other-window file)
1115 (find-file-noselect file)))
0e362f54
GM
1116 (if (not (verify-visited-file-modtime (current-buffer)))
1117 (if (yes-or-no-p "Replace file on disk with buffer contents? ")
1118 (write-file (buffer-file-name))
1119 (error "Aborted"))
1120 ;; Now, check if we have unsaved changes.
1121 (vc-buffer-sync t)
1122 (if (buffer-modified-p)
1123 (or (y-or-n-p "Operate on disk file, keeping modified buffer? ")
1124 (error "Aborted")))))
46e33aee 1125
0e362f54 1126 ;; Do the right thing
8989ab56 1127 (if (not (vc-registered file))
0e362f54
GM
1128 (vc-register verbose comment)
1129 (vc-recompute-state file)
0ab66291 1130 (if visited (vc-mode-line file))
0e362f54
GM
1131 (setq state (vc-state file))
1132 (cond
1133 ;; up-to-date
1134 ((or (eq state 'up-to-date)
1135 (and verbose (eq state 'needs-patch)))
1136 (cond
1137 (verbose
1138 ;; go to a different version
ceec5a0c 1139 (setq version
1d502d5a 1140 (read-string "Branch, version, or backend to move to: "))
ceec5a0c 1141 (let ((vsym (intern-soft (upcase version))))
1d502d5a
AS
1142 (if (member vsym vc-handled-backends)
1143 (vc-transfer-file file vsym)
ceec5a0c 1144 (vc-checkout file (eq (vc-checkout-model file) 'implicit)
1d502d5a 1145 version))))
0e362f54
GM
1146 ((not (eq (vc-checkout-model file) 'implicit))
1147 ;; check the file out
1148 (vc-checkout file t))
1149 (t
1150 ;; do nothing
1151 (message "%s is up-to-date" file))))
46e33aee 1152
0e362f54 1153 ;; Abnormal: edited but read-only
fd8092f0
SM
1154 ((and visited (eq state 'edited)
1155 buffer-read-only (not (file-writable-p file)))
0e362f54
GM
1156 ;; Make the file+buffer read-write. If the user really wanted to
1157 ;; commit, he'll get a chance to do that next time around, anyway.
1158 (message "File is edited but read-only; making it writable")
1159 (set-file-modes buffer-file-name
1160 (logior (file-modes buffer-file-name) 128))
1161 (toggle-read-only -1))
46e33aee 1162
0e362f54
GM
1163 ;; edited
1164 ((eq state 'edited)
6f41eeb5 1165 (cond
0e362f54
GM
1166 ;; For files with locking, if the file does not contain
1167 ;; any changes, just let go of the lock, i.e. revert.
1168 ((and (not (eq (vc-checkout-model file) 'implicit))
1169 (vc-workfile-unchanged-p file)
1170 ;; If buffer is modified, that means the user just
1171 ;; said no to saving it; in that case, don't revert,
1172 ;; because the user might intend to save after
1173 ;; finishing the log entry.
1174 (not (and visited (buffer-modified-p))))
1175 ;; DO NOT revert the file without asking the user!
1176 (if (not visited) (find-file-other-window file))
1177 (if (yes-or-no-p "Revert to master version? ")
1178 (vc-revert-buffer)))
1179 (t ;; normal action
1d502d5a
AS
1180 (if (not verbose)
1181 (vc-checkin file nil comment)
1182 (setq version (read-string "New version or backend: "))
1183 (let ((vsym (intern (upcase version))))
1184 (if (member vsym vc-handled-backends)
1185 (vc-transfer-file file vsym)
1186 (vc-checkin file version comment)))))))
46e33aee 1187
0e362f54
GM
1188 ;; locked by somebody else
1189 ((stringp state)
1190 (if comment
1191 (error "Sorry, you can't steal the lock on %s this way"
1192 (file-name-nondirectory file)))
1193 (vc-steal-lock file
1194 (if verbose (read-string "Version to steal: ")
1195 (vc-workfile-version file))
1196 state))
46e33aee 1197
0e362f54
GM
1198 ;; needs-patch
1199 ((eq state 'needs-patch)
6f41eeb5 1200 (if (yes-or-no-p (format
0e362f54
GM
1201 "%s is not up-to-date. Get latest version? "
1202 (file-name-nondirectory file)))
1203 (vc-checkout file (eq (vc-checkout-model file) 'implicit) "")
1204 (if (and (not (eq (vc-checkout-model file) 'implicit))
1205 (yes-or-no-p "Lock this version? "))
1206 (vc-checkout file t)
1207 (error "Aborted"))))
46e33aee 1208
0e362f54
GM
1209 ;; needs-merge
1210 ((eq state 'needs-merge)
6f41eeb5 1211 (if (yes-or-no-p (format
0e362f54
GM
1212 "%s is not up-to-date. Merge in changes now? "
1213 (file-name-nondirectory file)))
1214 (vc-maybe-resolve-conflicts file (vc-call merge-news file))
1215 (error "Aborted")))
46e33aee 1216
0e362f54
GM
1217 ;; unlocked-changes
1218 ((eq state 'unlocked-changes)
1219 (if (not visited) (find-file-other-window file))
1220 (if (save-window-excursion
1221 (vc-version-diff file (vc-workfile-version file) nil)
1222 (goto-char (point-min))
ceec5a0c 1223 (let ((inhibit-read-only t))
f4f34b33 1224 (insert
ceec5a0c 1225 (format "Changes to %s since last lock:\n\n" file)))
0e362f54
GM
1226 (not (beep))
1227 (yes-or-no-p (concat "File has unlocked changes. "
1228 "Claim lock retaining changes? ")))
1229 (progn (vc-call steal-lock file)
165e43b6 1230 (clear-visited-file-modtime)
0e362f54
GM
1231 ;; Must clear any headers here because they wouldn't
1232 ;; show that the file is locked now.
1233 (vc-clear-headers file)
165e43b6 1234 (write-file (buffer-file-name))
0e362f54
GM
1235 (vc-mode-line file))
1236 (if (not (yes-or-no-p
1237 "Revert to checked-in version, instead? "))
1238 (error "Checkout aborted")
1239 (vc-revert-buffer1 t t)
1240 (vc-checkout file t))))))))
e1f297e6 1241
beba4bd9
AS
1242(defvar vc-dired-window-configuration)
1243
e1f297e6 1244(defun vc-next-action-dired (file rev comment)
099bd78a
SM
1245 "Call `vc-next-action-on-file' on all the marked files.
1246Ignores FILE and REV, but passes on COMMENT."
3d30b8bc 1247 (let ((dired-buffer (current-buffer))
8dd71345 1248 (dired-dir default-directory))
632e9525 1249 (dired-map-over-marks
3b574573 1250 (let ((file (dired-get-filename)))
b0c9bc8c 1251 (message "Processing %s..." file)
0e362f54
GM
1252 (vc-next-action-on-file file nil comment)
1253 (set-buffer dired-buffer)
3d30b8bc 1254 (set-window-configuration vc-dired-window-configuration)
b0c9bc8c 1255 (message "Processing %s...done" file))
3d30b8bc
RS
1256 nil t))
1257 (dired-move-to-filename))
e1f297e6 1258
637a8ae9 1259;; Here's the major entry point.
594722a8 1260
637a8ae9 1261;;;###autoload
594722a8 1262(defun vc-next-action (verbose)
6f1ecae4 1263 "Do the next logical version control operation on the current file.
0e362f54
GM
1264
1265If you call this from within a VC dired buffer with no files marked,
c6d4f628 1266it will operate on the file in the current line.
0e362f54
GM
1267
1268If you call this from within a VC dired buffer, and one or more
c6d4f628
RS
1269files are marked, it will accept a log message and then operate on
1270each one. The log message will be used as a comment for any register
1271or checkin operations, but ignored when doing checkouts. Attempted
1272lock steals will raise an error.
0e362f54
GM
1273
1274A prefix argument lets you specify the version number to use.
80688f5c
RS
1275
1276For RCS and SCCS files:
594722a8 1277 If the file is not already registered, this registers it for version
4b81132c 1278control.
594722a8 1279 If the file is registered and not locked by anyone, this checks out
34291cd2 1280a writable and locked file ready for editing.
594722a8
ER
1281 If the file is checked out and locked by the calling user, this
1282first checks to see if the file has changed since checkout. If not,
1283it performs a revert.
e1f297e6
ER
1284 If the file has been changed, this pops up a buffer for entry
1285of a log message; when the message has been entered, it checks in the
594722a8 1286resulting changes along with the log message as change commentary. If
34291cd2 1287the variable `vc-keep-workfiles' is non-nil (which is its default), a
594722a8
ER
1288read-only copy of the changed file is left in place afterwards.
1289 If the file is registered and locked by someone else, you are given
e1f297e6 1290the option to steal the lock.
80688f5c
RS
1291
1292For CVS files:
1293 If the file is not already registered, this registers it for version
1294control. This does a \"cvs add\", but no \"cvs commit\".
1295 If the file is added but not committed, it is committed.
80688f5c
RS
1296 If your working file is changed, but the repository file is
1297unchanged, this pops up a buffer for entry of a log message; when the
1298message has been entered, it checks in the resulting changes along
1299with the logmessage as change commentary. A writable file is retained.
1300 If the repository file is changed, you are asked if you want to
c6d4f628 1301merge in the changes into your working copy."
bbf97570 1302
594722a8 1303 (interactive "P")
8c0aaf40
ER
1304 (catch 'nogo
1305 (if vc-dired-mode
1306 (let ((files (dired-get-marked-files)))
3d30b8bc
RS
1307 (set (make-local-variable 'vc-dired-window-configuration)
1308 (current-window-configuration))
0e362f54 1309 (if (string= ""
8dd71345 1310 (mapconcat
0e362f54
GM
1311 (lambda (f)
1312 (if (not (vc-up-to-date-p f)) "@" ""))
b0c9bc8c
AS
1313 files ""))
1314 (vc-next-action-dired nil nil "dummy")
0ab66291 1315 (vc-start-entry nil nil nil nil
b0c9bc8c
AS
1316 "Enter a change comment for the marked files."
1317 'vc-next-action-dired))
8dd71345 1318 (throw 'nogo nil)))
dc08a6b5
AS
1319 (while vc-parent-buffer
1320 (pop-to-buffer vc-parent-buffer))
1321 (if buffer-file-name
1322 (vc-next-action-on-file buffer-file-name verbose)
1323 (error "Buffer %s is not associated with a file" (buffer-name)))))
594722a8 1324
ec402ad4 1325;; These functions help the vc-next-action entry point
594722a8 1326
637a8ae9 1327;;;###autoload
0e362f54 1328(defun vc-register (&optional set-version comment)
099bd78a 1329 "Register the current file into a version control system.
e1d95cc4 1330With prefix argument SET-VERSION, allow user to specify initial version
0e362f54
GM
1331level. If COMMENT is present, use that as an initial comment.
1332
e1d95cc4 1333The version control system to use is found by cycling through the list
0e362f54
GM
1334`vc-handled-backends'. The first backend in that list which declares
1335itself responsible for the file (usually because other files in that
1336directory are already registered under that backend) will be used to
1337register the file. If no backend declares itself responsible, the
1338first backend that could register the file is used."
594722a8 1339 (interactive "P")
099bd78a 1340 (unless buffer-file-name (error "No visited file"))
0e362f54
GM
1341 (when (vc-backend buffer-file-name)
1342 (if (vc-registered buffer-file-name)
1343 (error "This file is already registered")
1344 (unless (y-or-n-p "Previous master file has vanished. Make a new one? ")
1345 (error "Aborted"))))
02da6253
PE
1346 ;; Watch out for new buffers of size 0: the corresponding file
1347 ;; does not exist yet, even though buffer-modified-p is nil.
1348 (if (and (not (buffer-modified-p))
1349 (zerop (buffer-size))
1350 (not (file-exists-p buffer-file-name)))
1351 (set-buffer-modified-p t))
594722a8 1352 (vc-buffer-sync)
46e33aee 1353
0e362f54
GM
1354 (vc-start-entry buffer-file-name
1355 (if set-version
1d502d5a
AS
1356 (read-string (format "Initial version level for %s: "
1357 (buffer-name)))
b470cb65
AS
1358 (let ((backend (vc-responsible-backend buffer-file-name)))
1359 (if (vc-find-backend-function backend 'init-version)
1360 (vc-call-backend backend 'init-version)
1361 vc-default-init-version)))
0e362f54 1362 (or comment (not vc-initial-comment))
0ab66291 1363 nil
0e362f54
GM
1364 "Enter initial comment."
1365 (lambda (file rev comment)
1366 (message "Registering %s... " file)
8989ab56 1367 (let ((backend (vc-responsible-backend file t)))
e1d95cc4 1368 (vc-file-clearprops file)
0e362f54
GM
1369 (vc-call-backend backend 'register file rev comment)
1370 (vc-file-setprop file 'vc-backend backend)
1371 (unless vc-make-backup-files
1372 (make-local-variable 'backup-inhibited)
1373 (setq backup-inhibited t)))
1374 (message "Registering %s... done" file))))
1375
8989ab56
AS
1376
1377(defun vc-responsible-backend (file &optional register)
1378 "Return the name of a backend system that is responsible for FILE.
46e33aee 1379The optional argument REGISTER means that a backend suitable for
8989ab56
AS
1380registration should be found.
1381
1382If REGISTER is nil, then if FILE is already registered, return the
1383backend of FILE. If FILE is not registered, or a directory, then the
1384first backend in `vc-handled-backends' that declares itself
1385responsible for FILE is returned. If no backend declares itself
1386responsible, return the first backend.
1387
1388If REGISTER is non-nil, return the first responsible backend under
1389which FILE is not yet registered. If there is no such backend, return
1390the first backend under which FILE is not yet registered, but could
1391be registered."
1392 (if (not vc-handled-backends)
1393 (error "No handled backends"))
1394 (or (and (not (file-directory-p file)) (not register) (vc-backend file))
1395 (catch 'found
1396 ;; First try: find a responsible backend. If this is for registration,
1397 ;; it must be a backend under which FILE is not yet registered.
1398 (dolist (backend vc-handled-backends)
1399 (and (or (not register)
1400 (not (vc-call-backend backend 'registered file)))
1401 (vc-call-backend backend 'responsible-p file)
1402 (throw 'found backend)))
1403 ;; no responsible backend
1404 (if (not register)
1405 ;; if this is not for registration, the first backend must do
1406 (car vc-handled-backends)
46e33aee 1407 ;; for registration, we need to find a new backend that
8989ab56
AS
1408 ;; could register FILE
1409 (dolist (backend vc-handled-backends)
1410 (and (not (vc-call-backend backend 'registered file))
1411 (vc-call-backend backend 'could-register file)
1412 (throw 'found backend)))
1413 (error "No backend that could register")))))
0e362f54 1414
099bd78a 1415(defun vc-default-responsible-p (backend file)
46e33aee 1416 "Indicate whether BACKEND is reponsible for FILE.
099bd78a
SM
1417The default is to return nil always."
1418 nil)
1419
0e362f54 1420(defun vc-default-could-register (backend file)
6f41eeb5 1421 "Return non-nil if BACKEND could be used to register FILE.
0e362f54
GM
1422The default implementation returns t for all files."
1423 t)
594722a8 1424
624b4662 1425(defun vc-resynch-window (file &optional keep noquery)
099bd78a
SM
1426 "If FILE is in the current buffer, either revert or unvisit it.
1427The choice between revert (to see expanded keywords) and unvisit depends on
1428`vc-keep-workfiles'. NOQUERY if non-nil inhibits confirmation for
0e362f54
GM
1429reverting. NOQUERY should be t *only* if it is known the only
1430difference between the buffer and the file is due to version control
1431rather than user editing!"
594722a8
ER
1432 (and (string= buffer-file-name file)
1433 (if keep
1434 (progn
1ab31687 1435 (vc-revert-buffer1 t noquery)
0e362f54
GM
1436 ;; TODO: Adjusting view mode might no longer be necessary
1437 ;; after RMS change to files.el of 1999-08-08. Investigate
1438 ;; this when we install the new VC.
f8791ebe
AS
1439 (and view-read-only
1440 (if (file-writable-p file)
1441 (and view-mode
1442 (let ((view-old-buffer-read-only nil))
1443 (view-mode-exit)))
1444 (and (not view-mode)
1445 (not (eq (get major-mode 'mode-class) 'special))
1446 (view-mode-enter))))
594722a8 1447 (vc-mode-line buffer-file-name))
88a2ffaf 1448 (kill-buffer (current-buffer)))))
594722a8 1449
503b5c85 1450(defun vc-resynch-buffer (file &optional keep noquery)
0e362f54 1451 "If FILE is currently visited, resynch its buffer."
4b398f5d
AS
1452 (if (string= buffer-file-name file)
1453 (vc-resynch-window file keep noquery)
1454 (let ((buffer (get-file-buffer file)))
1455 (if buffer
0e362f54
GM
1456 (with-current-buffer buffer
1457 (vc-resynch-window file keep noquery)))))
1458 (vc-dired-resynch-file file))
503b5c85 1459
0ab66291 1460(defun vc-start-entry (file rev comment initial-contents msg action &optional after-hook)
46e33aee 1461 "Accept a comment for an operation on FILE revision REV.
6f41eeb5 1462If COMMENT is nil, pop up a VC-log buffer, emit MSG, and set the
0ab66291
AS
1463action on close to ACTION. If COMMENT is a string and
1464INITIAL-CONTENTS is non-nil, then COMMENT is used as the initial
1465contents of the log entry buffer. If COMMENT is a string and
1466INITIAL-CONTENTS is nil, do action immediately as if the user had
1467entered COMMENT. If COMMENT is t, also do action immediately with an
46e33aee
TTN
1468empty comment. Remember the file's buffer in `vc-parent-buffer'
1469\(current one if no file). AFTER-HOOK specifies the local value
0ab66291
AS
1470for vc-log-operation-hook."
1471 (let ((parent (or (and file (get-file-buffer file)) (current-buffer))))
f0b188ed
RS
1472 (if vc-before-checkin-hook
1473 (if file
0e362f54 1474 (with-current-buffer parent
f0b188ed
RS
1475 (run-hooks 'vc-before-checkin-hook))
1476 (run-hooks 'vc-before-checkin-hook)))
0ab66291 1477 (if (and comment (not initial-contents))
e1f297e6
ER
1478 (set-buffer (get-buffer-create "*VC-log*"))
1479 (pop-to-buffer (get-buffer-create "*VC-log*")))
8c0aaf40
ER
1480 (set (make-local-variable 'vc-parent-buffer) parent)
1481 (set (make-local-variable 'vc-parent-buffer-name)
1482 (concat " from " (buffer-name vc-parent-buffer)))
7e869659 1483 (if file (vc-mode-line file))
099bd78a 1484 (vc-log-edit file)
b965445f
RS
1485 (make-local-variable 'vc-log-after-operation-hook)
1486 (if after-hook
1487 (setq vc-log-after-operation-hook after-hook))
e1f297e6 1488 (setq vc-log-operation action)
e1f297e6 1489 (setq vc-log-version rev)
347bef30
SM
1490 (when comment
1491 (erase-buffer)
1492 (when (stringp comment) (insert comment)))
1493 (if (or (not comment) initial-contents)
1494 (message "%s Type C-c C-c when done" msg)
1495 (vc-finish-logentry (eq comment t)))))
e1f297e6 1496
c6d4f628 1497(defun vc-checkout (file &optional writable rev)
099bd78a
SM
1498 "Retrieve a copy of the revision REV of FILE.
1499If WRITABLE is non-nil, make sure the retrieved file is writable.
133a84aa
AS
1500REV defaults to the latest revision.
1501
1502After check-out, runs the normal hook `vc-checkout-hook'."
ffda0460
AS
1503 (and writable
1504 (not rev)
10b48cc4 1505 (vc-call make-version-backups-p file)
ffda0460 1506 (vc-up-to-date-p file)
10b48cc4 1507 (vc-make-version-backup file))
099bd78a
SM
1508 (with-vc-properties
1509 file
1510 (condition-case err
1511 (vc-call checkout file writable rev)
1512 (file-error
1513 ;; Maybe the backend is not installed ;-(
1514 (when writable
1515 (let ((buf (get-file-buffer file)))
1516 (when buf (with-current-buffer buf (toggle-read-only -1)))))
1517 (signal (car err) (cdr err))))
a3255400
SM
1518 `((vc-state . ,(if (or (eq (vc-checkout-model file) 'implicit)
1519 (not writable))
1520 (if (vc-call latest-on-branch-p file)
1521 'up-to-date
1522 'needs-patch)
1523 'edited))
1524 (vc-checkout-time . ,(nth 5 (file-attributes file)))))
7cad930d
AS
1525 (vc-resynch-buffer file t t)
1526 (run-hooks 'vc-checkout-hook))
594722a8 1527
0e362f54 1528(defun vc-steal-lock (file rev owner)
099bd78a 1529 "Steal the lock on FILE."
29fc1ce9 1530 (let (file-description)
29fc1ce9
RS
1531 (if rev
1532 (setq file-description (format "%s:%s" file rev))
1533 (setq file-description file))
4bc504c8
RS
1534 (if (not (yes-or-no-p (format "Steal the lock on %s from %s? "
1535 file-description owner)))
0e362f54 1536 (error "Steal canceled"))
869131a5
AS
1537 (message "Stealing lock on %s..." file)
1538 (with-vc-properties
1539 file
1540 (vc-call steal-lock file rev)
1541 `((vc-state . edited)))
1542 (vc-resynch-buffer file t t)
1543 (message "Stealing lock on %s...done" file)
1544 ;; Write mail after actually stealing, because if the stealing
1545 ;; goes wrong, we don't want to send any mail.
1546 (compose-mail owner (format "Stolen lock on %s" file-description))
29fc1ce9 1547 (setq default-directory (expand-file-name "~/"))
29fc1ce9
RS
1548 (goto-char (point-max))
1549 (insert
1550 (format "I stole the lock on %s, " file-description)
1551 (current-time-string)
1552 ".\n")
1553 (message "Please explain why you stole the lock. Type C-c C-c when done.")))
594722a8 1554
0ab66291 1555(defun vc-checkin (file &optional rev comment initial-contents)
6f41eeb5 1556 "Check in FILE.
0e362f54
GM
1557The optional argument REV may be a string specifying the new version
1558level (if nil increment the current level). COMMENT is a comment
0ab66291
AS
1559string; if omitted, a buffer is popped up to accept a comment. If
1560INITIAL-CONTENTS is non-nil, then COMMENT is used as the initial contents
1561of the log entry buffer.
0e362f54
GM
1562
1563If `vc-keep-workfiles' is nil, FILE is deleted afterwards, provided
1564that the version control system supports this mode of operation.
861f3c29
DL
1565
1566Runs the normal hook `vc-checkin-hook'."
6f41eeb5 1567 (vc-start-entry
0ab66291 1568 file rev comment initial-contents
6f41eeb5 1569 "Enter a change comment."
0e362f54
GM
1570 (lambda (file rev comment)
1571 (message "Checking in %s..." file)
1572 ;; "This log message intentionally left almost blank".
1573 ;; RCS 5.7 gripes about white-space-only comments too.
1574 (or (and comment (string-match "[^\t\n ]" comment))
1575 (setq comment "*** empty log message ***"))
46e33aee 1576 (with-vc-properties
099bd78a
SM
1577 file
1578 ;; Change buffers to get local value of vc-checkin-switches.
1579 (with-current-buffer (or (get-file-buffer file) (current-buffer))
ab750f9c 1580 (progn
ffda0460 1581 (vc-call checkin file rev comment)
ab750f9c 1582 (vc-delete-automatic-version-backups file)))
a3255400
SM
1583 `((vc-state . up-to-date)
1584 (vc-checkout-time . ,(nth 5 (file-attributes file)))
1585 (vc-workfile-version . nil)))
0e362f54
GM
1586 (message "Checking in %s...done" file))
1587 'vc-checkin-hook))
594722a8 1588
3b4dd9a9 1589(defun vc-comment-to-change-log (&optional whoami file-name)
6f1ecae4
AS
1590 "Enter last VC comment into the change log for the current file.
1591WHOAMI (interactive prefix) non-nil means prompt for user name
1592and site. FILE-NAME is the name of the change log; if nil, use
1593`change-log-default-name'.
861f3c29 1594
6f1ecae4
AS
1595This may be useful as a `vc-checkin-hook' to update change logs
1596automatically."
43cea1ab
RM
1597 (interactive (if current-prefix-arg
1598 (list current-prefix-arg
1599 (prompt-for-change-log-name))))
41208291
KH
1600 ;; Make sure the defvar for add-log-current-defun-function has been executed
1601 ;; before binding it.
1602 (require 'add-log)
3b4dd9a9
RM
1603 (let (;; Extract the comment first so we get any error before doing anything.
1604 (comment (ring-ref vc-comment-ring 0))
43cea1ab 1605 ;; Don't let add-change-log-entry insert a defun name.
3b4dd9a9
RM
1606 (add-log-current-defun-function 'ignore)
1607 end)
1608 ;; Call add-log to do half the work.
43cea1ab 1609 (add-change-log-entry whoami file-name t t)
3b4dd9a9
RM
1610 ;; Insert the VC comment, leaving point before it.
1611 (setq end (save-excursion (insert comment) (point-marker)))
1612 (if (looking-at "\\s *\\s(")
1613 ;; It starts with an open-paren, as in "(foo): Frobbed."
43cea1ab 1614 ;; So remove the ": " add-log inserted.
3b4dd9a9
RM
1615 (delete-char -2))
1616 ;; Canonicalize the white space between the file name and comment.
1617 (just-one-space)
1618 ;; Indent rest of the text the same way add-log indented the first line.
1619 (let ((indentation (current-indentation)))
1620 (save-excursion
1621 (while (< (point) end)
1622 (forward-line 1)
1623 (indent-to indentation))
c124b1b4 1624 (setq end (point))))
3b4dd9a9 1625 ;; Fill the inserted text, preserving open-parens at bol.
6b60c5d1
BG
1626 (let ((paragraph-separate (concat paragraph-separate "\\|\\s *\\s("))
1627 (paragraph-start (concat paragraph-start "\\|\\s *\\s(")))
43cea1ab 1628 (beginning-of-line)
c124b1b4
RM
1629 (fill-region (point) end))
1630 ;; Canonicalize the white space at the end of the entry so it is
1631 ;; separated from the next entry by a single blank line.
1632 (skip-syntax-forward " " end)
1633 (delete-char (- (skip-syntax-backward " ")))
1634 (or (eobp) (looking-at "\n\n")
1635 (insert "\n"))))
3b4dd9a9 1636
8c0aaf40 1637(defun vc-finish-logentry (&optional nocomment)
6f1ecae4
AS
1638 "Complete the operation implied by the current log entry.
1639Use the contents of the current buffer as a check-in or registration
1640comment. If the optional arg NOCOMMENT is non-nil, then don't check
1641the buffer contents as a comment, and don't add it to
1642`vc-comment-ring'."
594722a8 1643 (interactive)
8c0aaf40 1644 ;; Check and record the comment, if any.
0e362f54
GM
1645 (unless nocomment
1646 ;; Comment too long?
1647 (vc-call-backend (or (and vc-log-file (vc-backend vc-log-file))
1648 (vc-responsible-backend default-directory))
1649 'logentry-check)
1650 (run-hooks 'vc-logentry-check-hook)
1651 ;; Record the comment in the comment ring
1652 (let ((comment (buffer-string)))
1653 (unless (and (ring-p vc-comment-ring)
1654 (not (ring-empty-p vc-comment-ring))
1655 (equal comment (ring-ref vc-comment-ring 0)))
1656 (ring-insert vc-comment-ring comment))))
b2396d1f 1657 ;; Sync parent buffer in case the user modified it while editing the comment.
cdaf7a1a 1658 ;; But not if it is a vc-dired buffer.
0e362f54
GM
1659 (with-current-buffer vc-parent-buffer
1660 (or vc-dired-mode (vc-buffer-sync)))
61dee1e7
AS
1661 (if (not vc-log-operation) (error "No log operation is pending"))
1662 ;; save the parameters held in buffer-local variables
1663 (let ((log-operation vc-log-operation)
1664 (log-file vc-log-file)
1665 (log-version vc-log-version)
1666 (log-entry (buffer-string))
2c4eea90
KH
1667 (after-hook vc-log-after-operation-hook)
1668 (tmp-vc-parent-buffer vc-parent-buffer))
e2bef5c3 1669 (pop-to-buffer vc-parent-buffer)
61dee1e7
AS
1670 ;; OK, do it to it
1671 (save-excursion
0e362f54 1672 (funcall log-operation
61dee1e7
AS
1673 log-file
1674 log-version
1675 log-entry))
df1e7b91
KH
1676 ;; Remove checkin window (after the checkin so that if that fails
1677 ;; we don't zap the *VC-log* buffer and the typing therein).
1678 (let ((logbuf (get-buffer "*VC-log*")))
2c4eea90
KH
1679 (cond ((and logbuf vc-delete-logbuf-window)
1680 (delete-windows-on logbuf (selected-frame))
262c8cea 1681 ;; Kill buffer and delete any other dedicated windows/frames.
2c4eea90 1682 (kill-buffer logbuf))
0ab66291
AS
1683 (logbuf (pop-to-buffer "*VC-log*")
1684 (bury-buffer)
1685 (pop-to-buffer tmp-vc-parent-buffer))))
e2bef5c3 1686 ;; Now make sure we see the expanded headers
46e33aee 1687 (if log-file
0ab66291 1688 (vc-resynch-buffer log-file vc-keep-workfiles t))
0e362f54 1689 (if vc-dired-mode
0ab66291 1690 (dired-move-to-filename))
37667a5c 1691 (run-hooks after-hook 'vc-finish-logentry-hook)))
594722a8
ER
1692
1693;; Code for access to the comment ring
1694
0e362f54 1695(defun vc-new-comment-index (stride len)
6f1ecae4
AS
1696 "Return the comment index STRIDE elements from the current one.
1697LEN is the length of `vc-comment-ring'."
0e362f54
GM
1698 (mod (cond
1699 (vc-comment-ring-index (+ vc-comment-ring-index stride))
1700 ;; Initialize the index on the first use of this command
1701 ;; so that the first M-p gets index 0, and the first M-n gets
1702 ;; index -1.
1703 ((> stride 0) (1- stride))
1704 (t stride))
1705 len))
1706
8c0aaf40 1707(defun vc-previous-comment (arg)
6f1ecae4
AS
1708 "Cycle backwards through comment history.
1709With a numeric prefix ARG, go back ARG comments."
8c0aaf40
ER
1710 (interactive "*p")
1711 (let ((len (ring-length vc-comment-ring)))
0e362f54
GM
1712 (if (<= len 0)
1713 (progn (message "Empty comment ring") (ding))
1714 (erase-buffer)
1715 (setq vc-comment-ring-index (vc-new-comment-index arg len))
1716 (message "Comment %d" (1+ vc-comment-ring-index))
1717 (insert (ring-ref vc-comment-ring vc-comment-ring-index)))))
8c0aaf40
ER
1718
1719(defun vc-next-comment (arg)
6f1ecae4
AS
1720 "Cycle forwards through comment history.
1721With a numeric prefix ARG, go forward ARG comments."
8c0aaf40
ER
1722 (interactive "*p")
1723 (vc-previous-comment (- arg)))
1724
0e362f54 1725(defun vc-comment-search-reverse (str &optional stride)
6f1ecae4
AS
1726 "Search backwards through comment history for substring match of STR.
1727If the optional argument STRIDE is present, that is a step-width to use
1728when going through the comment ring."
0e362f54
GM
1729 ;; Why substring rather than regexp ? -sm
1730 (interactive
1731 (list (read-string "Comment substring: " nil nil vc-last-comment-match)))
1732 (unless stride (setq stride 1))
8c0aaf40
ER
1733 (if (string= str "")
1734 (setq str vc-last-comment-match)
1735 (setq vc-last-comment-match str))
0e362f54
GM
1736 (let* ((str (regexp-quote str))
1737 (len (ring-length vc-comment-ring))
1738 (n (vc-new-comment-index stride len)))
1739 (while (progn (when (or (>= n len) (< n 0)) (error "Not found"))
1740 (not (string-match str (ring-ref vc-comment-ring n))))
1741 (setq n (+ n stride)))
1742 (setq vc-comment-ring-index n)
1743 (vc-previous-comment 0)))
8c0aaf40
ER
1744
1745(defun vc-comment-search-forward (str)
6f1ecae4 1746 "Search forwards through comment history for a substring match of STR."
0e362f54
GM
1747 (interactive
1748 (list (read-string "Comment substring: " nil nil vc-last-comment-match)))
1749 (vc-comment-search-reverse str -1))
594722a8
ER
1750
1751;; Additional entry points for examining version histories
1752
637a8ae9 1753;;;###autoload
97d3f950 1754(defun vc-diff (historic &optional not-urgent)
e8ee1ccf 1755 "Display diffs between file versions.
6f1ecae4
AS
1756Normally this compares the current file and buffer with the most
1757recent checked in version of that file. This uses no arguments. With
1758a prefix argument HISTORIC, it reads the file name to use and two
1759version designators specifying which versions to compare. The
1760optional argument NOT-URGENT non-nil means it is ok to say no to
1761saving the buffer."
48078f8f 1762 (interactive (list current-prefix-arg t))
594722a8
ER
1763 (if historic
1764 (call-interactively 'vc-version-diff)
2c87edc1 1765 (vc-ensure-vc-buffer)
0e362f54 1766 (let ((file buffer-file-name))
c0d66cb2 1767 (vc-buffer-sync not-urgent)
0e362f54
GM
1768 (if (vc-workfile-unchanged-p buffer-file-name)
1769 (message "No changes to %s since latest version" file)
1770 (vc-version-diff file nil nil)))))
594722a8
ER
1771
1772(defun vc-version-diff (file rel1 rel2)
6f1ecae4
AS
1773 "List the differences between FILE's versions REL1 and REL2.
1774If REL1 is empty or nil it means to use the current workfile version;
1775REL2 empty or nil means the current file contents. FILE may also be
1776a directory, in that case, generate diffs between the correponding
1777versions of all registered files in or below it."
0e362f54 1778 (interactive
4e6473c8
GM
1779 (let ((file (expand-file-name
1780 (read-file-name (if buffer-file-name
1781 "File or dir to diff: (default visited file) "
1782 "File or dir to diff: ")
1783 default-directory buffer-file-name t)))
c0d66cb2
RS
1784 (rel1-default nil) (rel2-default nil))
1785 ;; compute default versions based on the file state
1786 (cond
0e362f54
GM
1787 ;; if it's a directory, don't supply any version default
1788 ((file-directory-p file)
c0d66cb2 1789 nil)
0e362f54
GM
1790 ;; if the file is not up-to-date, use current version as older version
1791 ((not (vc-up-to-date-p file))
c0d66cb2
RS
1792 (setq rel1-default (vc-workfile-version file)))
1793 ;; if the file is not locked, use last and previous version as default
1794 (t
869131a5
AS
1795 (setq rel1-default (vc-call previous-version file
1796 (vc-workfile-version file)))
0e362f54 1797 (if (string= rel1-default "") (setq rel1-default nil))
c0d66cb2
RS
1798 (setq rel2-default (vc-workfile-version file))))
1799 ;; construct argument list
0e362f54 1800 (list file
8e710301
RS
1801 (read-string (if rel1-default
1802 (concat "Older version: (default "
1803 rel1-default ") ")
1804 "Older version: ")
1805 nil nil rel1-default)
1806 (read-string (if rel2-default
1807 (concat "Newer version: (default "
1808 rel2-default ") ")
ba27415c 1809 "Newer version (default: current source): ")
8e710301 1810 nil nil rel2-default))))
594722a8 1811 (if (file-directory-p file)
ffda0460 1812 ;; recursive directory diff
ad339989
AS
1813 (progn
1814 (vc-setup-buffer "*vc-diff*")
ffda0460
AS
1815 (if (string-equal rel1 "") (setq rel1 nil))
1816 (if (string-equal rel2 "") (setq rel2 nil))
ad339989
AS
1817 (let ((inhibit-read-only t))
1818 (insert "Diffs between "
1819 (or rel1 "last version checked in")
1820 " and "
1821 (or rel2 "current workfile(s)")
1822 ":\n\n"))
2c87edc1
AS
1823 (let ((dir (file-name-as-directory file)))
1824 (vc-call-backend (vc-responsible-backend dir)
1825 'diff-tree dir rel1 rel2))
0e362f54
GM
1826 (vc-exec-after `(let ((inhibit-read-only t))
1827 (insert "\nEnd of diffs.\n"))))
ffda0460 1828 ;; single file diff
2c87edc1 1829 (vc-diff-internal file rel1 rel2))
ad339989 1830 (set-buffer "*vc-diff*")
0e362f54
GM
1831 (if (and (zerop (buffer-size))
1832 (not (get-buffer-process (current-buffer))))
1833 (progn
1834 (if rel1
1835 (if rel2
1836 (message "No changes to %s between %s and %s" file rel1 rel2)
1837 (message "No changes to %s since %s" file rel1))
1838 (message "No changes to %s since latest version" file))
1839 nil)
1840 (pop-to-buffer (current-buffer))
1841 ;; Gnus-5.8.5 sets up an autoload for diff-mode, even if it's
1842 ;; not available. Work around that.
1843 (if (require 'diff-mode nil t) (diff-mode))
66321b2f
SM
1844 (vc-exec-after '(let ((inhibit-read-only t))
1845 (if (eq (buffer-size) 0)
1846 (insert "No differences found.\n"))
1847 (goto-char (point-min))
1848 (shrink-window-if-larger-than-buffer)))
0e362f54 1849 t))
594722a8 1850
2c87edc1
AS
1851(defun vc-diff-internal (file rel1 rel2)
1852 "Run diff to compare FILE's revisions REL1 and REL2.
1853Output goes to the current buffer, which is assumed properly set up.
1854The exit status of the diff command is returned.
1855
1856This function takes care to set up a proper coding system for diff output.
1857If both revisions are available as local files, then it also does not
1858actually call the backend, but performs a local diff."
1859 (if (or (not rel1) (string-equal rel1 ""))
1860 (setq rel1 (vc-workfile-version file)))
1861 (if (string-equal rel2 "")
1862 (setq rel2 nil))
1863 (let ((file-rel1 (vc-version-backup-file file rel1))
1864 (file-rel2 (if (not rel2)
1865 file
1866 (vc-version-backup-file file rel2)))
1867 (coding-system-for-read (vc-coding-system-for-diff file)))
1868 (if (and file-rel1 file-rel2)
1869 (apply 'vc-do-command "*vc-diff*" 1 "diff" nil
1870 (append (if (listp diff-switches)
1871 diff-switches
1872 (list diff-switches))
1873 (if (listp vc-diff-switches)
1874 vc-diff-switches
1875 (list vc-diff-switches))
1876 (list (file-relative-name file-rel1)
1877 (file-relative-name file-rel2))))
1878 (vc-call diff file rel1 rel2))))
1879
acc5b122 1880(defmacro vc-diff-switches-list (backend)
6f1ecae4 1881 "Return the list of switches to use for executing diff under BACKEND."
99cb8c8b 1882 `(append
acc5b122
AS
1883 (if (listp diff-switches) diff-switches (list diff-switches))
1884 (if (listp vc-diff-switches) vc-diff-switches (list vc-diff-switches))
b470cb65 1885 (let* ((backend-switches-symbol
4e5f52e5 1886 (intern (concat "vc-" (downcase (symbol-name ,backend))
b470cb65
AS
1887 "-diff-switches")))
1888 (backend-switches
1889 (if (boundp backend-switches-symbol)
1890 (eval backend-switches-symbol)
1891 nil)))
acc5b122
AS
1892 (if (listp backend-switches) backend-switches (list backend-switches)))))
1893
2c87edc1 1894(defun vc-default-diff-tree (backend dir rel1 rel2)
6f1ecae4 1895 "List differences for all registered files at and below DIR.
2c87edc1 1896The meaning of REL1 and REL2 is the same as for `vc-version-diff'."
99cb8c8b 1897 ;; This implementation does an explicit tree walk, and calls
2c87edc1
AS
1898 ;; vc-BACKEND-diff directly for each file. An optimization
1899 ;; would be to use `vc-diff-internal', so that diffs can be local,
1900 ;; and to call it only for files that are actually changed.
1901 ;; However, this is expensive for some backends, and so it is left
1902 ;; to backend-specific implementations.
1903 (setq default-directory dir)
1904 (vc-file-tree-walk
1905 default-directory
1906 (lambda (f)
1907 (vc-exec-after
99cb8c8b 1908 `(let ((coding-system-for-read (vc-coding-system-for-diff ',f)))
2c87edc1 1909 (message "Looking at %s" ',f)
99cb8c8b 1910 (vc-call-backend ',(vc-backend f)
2c87edc1
AS
1911 'diff ',f ',rel1 ',rel2))))))
1912
1913(defun vc-coding-system-for-diff (file)
1914 "Return the coding system for reading diff output for FILE."
1915 (or coding-system-for-read
99cb8c8b 1916 ;; if we already have this file open,
2c87edc1
AS
1917 ;; use the buffer's coding system
1918 (let ((buf (find-buffer-visiting file)))
1919 (if buf (with-current-buffer buf
1920 buffer-file-coding-system)))
1921 ;; otherwise, try to find one based on the file name
1922 (car (find-operation-coding-system 'insert-file-contents
1923 file))
1924 ;; and a final fallback
1925 'undecided))
1926
f1818994
PE
1927;;;###autoload
1928(defun vc-version-other-window (rev)
6f1ecae4
AS
1929 "Visit version REV of the current file in another window.
1930If the current file is named `F', the version is named `F.~REV~'.
1931If `F.~REV~' already exists, use it instead of checking it out again."
0e362f54 1932 (interactive "sVersion to visit (default is workfile version): ")
b6909007 1933 (vc-ensure-vc-buffer)
5e011cb2
SM
1934 (let* ((file buffer-file-name)
1935 (version (if (string-equal rev "")
1936 (vc-workfile-version file)
ac0aae44
AS
1937 rev)))
1938 (switch-to-buffer-other-window (vc-find-version file version))))
1939
1940(defun vc-find-version (file version)
1941 "Read VERSION of FILE into a buffer and return the buffer."
1942 (let ((automatic-backup (vc-version-backup-file-name file version))
1943 (manual-backup (vc-version-backup-file-name file version 'manual)))
10b48cc4
AS
1944 (unless (file-exists-p manual-backup)
1945 (if (file-exists-p automatic-backup)
f9b59b2b 1946 (rename-file automatic-backup manual-backup nil)
5e011cb2 1947 (vc-call checkout file nil version manual-backup)))
ac0aae44 1948 (find-file-noselect manual-backup)))
f1818994 1949
594722a8
ER
1950;; Header-insertion code
1951
637a8ae9 1952;;;###autoload
594722a8 1953(defun vc-insert-headers ()
6f1ecae4 1954 "Insert headers into a file for use with a version control system.
b524ce9f 1955Headers desired are inserted at point, and are pulled from
0e362f54 1956the variable `vc-BACKEND-header'."
594722a8 1957 (interactive)
b6909007 1958 (vc-ensure-vc-buffer)
594722a8
ER
1959 (save-excursion
1960 (save-restriction
1961 (widen)
1962 (if (or (not (vc-check-headers))
820bde8d 1963 (y-or-n-p "Version headers already exist. Insert another set? "))
594722a8
ER
1964 (progn
1965 (let* ((delims (cdr (assq major-mode vc-comment-alist)))
1966 (comment-start-vc (or (car delims) comment-start "#"))
1967 (comment-end-vc (or (car (cdr delims)) comment-end ""))
0e362f54
GM
1968 (hdsym (vc-make-backend-sym (vc-backend (buffer-file-name))
1969 'header))
1970 (hdstrings (and (boundp hdsym) (symbol-value hdsym))))
1971 (mapcar (lambda (s)
1972 (insert comment-start-vc "\t" s "\t"
1973 comment-end-vc "\n"))
594722a8
ER
1974 hdstrings)
1975 (if vc-static-header-alist
0e362f54
GM
1976 (mapcar (lambda (f)
1977 (if (string-match (car f) buffer-file-name)
1978 (insert (format (cdr f) (car hdstrings)))))
594722a8
ER
1979 vc-static-header-alist))
1980 )
1981 )))))
1982
0e362f54 1983(defun vc-clear-headers (&optional file)
099bd78a 1984 "Clear all version headers in the current buffer (or FILE).
6f1ecae4 1985The headers are reset to their non-expanded form."
0e362f54
GM
1986 (let* ((filename (or file buffer-file-name))
1987 (visited (find-buffer-visiting filename))
1988 (backend (vc-backend filename)))
1989 (when (vc-find-backend-function backend 'clear-headers)
6f41eeb5 1990 (if visited
0e362f54
GM
1991 (let ((context (vc-buffer-context)))
1992 ;; save-excursion may be able to relocate point and mark
1993 ;; properly. If it fails, vc-restore-buffer-context
1994 ;; will give it a second try.
1995 (save-excursion
1996 (vc-call-backend backend 'clear-headers))
1997 (vc-restore-buffer-context context))
7849e179 1998 (set-buffer (find-file-noselect filename))
0e362f54
GM
1999 (vc-call-backend backend 'clear-headers)
2000 (kill-buffer filename)))))
c8de1d91 2001
b6909007 2002;;;###autoload
099bd78a
SM
2003(defun vc-merge ()
2004 "Merge changes between two versions into the current buffer's file.
2005This asks for two versions to merge from in the minibuffer. If the
2006first version is a branch number, then merge all changes from that
2007branch. If the first version is empty, merge news, i.e. recent changes
2008from the current branch.
0e362f54
GM
2009
2010See Info node `Merging'."
099bd78a 2011 (interactive)
ccb141e8
AS
2012 (vc-ensure-vc-buffer)
2013 (vc-buffer-sync)
2014 (let* ((file buffer-file-name)
2015 (backend (vc-backend file))
0e362f54 2016 (state (vc-state file))
099bd78a 2017 first-version second-version status)
0e362f54 2018 (cond
0e362f54
GM
2019 ((stringp state)
2020 (error "File is locked by %s" state))
2021 ((not (vc-editable-p file))
2022 (if (y-or-n-p
2023 "File must be checked out for merging. Check out now? ")
2024 (vc-checkout file t)
2025 (error "Merge aborted"))))
46e33aee 2026 (setq first-version
099bd78a
SM
2027 (read-string (concat "Branch or version to merge from "
2028 "(default: news on current branch): ")))
2029 (if (string= first-version "")
2030 (if (not (vc-find-backend-function backend 'merge-news))
2031 (error "Sorry, merging news is not implemented for %s" backend)
2032 (setq status (vc-call merge-news file)))
2033 (if (not (vc-find-backend-function backend 'merge))
2034 (error "Sorry, merging is not implemented for %s" backend)
2035 (if (not (vc-branch-p first-version))
46e33aee
TTN
2036 (setq second-version
2037 (read-string "Second version: "
099bd78a
SM
2038 (concat (vc-branch-part first-version) ".")))
2039 ;; We want to merge an entire branch. Set versions
2040 ;; accordingly, so that vc-BACKEND-merge understands us.
2041 (setq second-version first-version)
2042 ;; first-version must be the starting point of the branch
2043 (setq first-version (vc-branch-part first-version)))
2044 (setq status (vc-call merge file first-version second-version))))
2045 (vc-maybe-resolve-conflicts file status "WORKFILE" "MERGE SOURCE")))
0e362f54
GM
2046
2047(defun vc-maybe-resolve-conflicts (file status &optional name-A name-B)
2048 (vc-resynch-buffer file t (not (buffer-modified-p)))
2049 (if (zerop status) (message "Merge successful")
2050 (if (fboundp 'smerge-mode) (smerge-mode 1))
2051 (if (y-or-n-p "Conflicts detected. Resolve them now? ")
2052 (if (fboundp 'smerge-ediff)
2053 (smerge-ediff)
2054 (vc-resolve-conflicts name-A name-B))
2055 (message "File contains conflict markers"))))
ccb141e8 2056
beba4bd9
AS
2057(defvar vc-ediff-windows)
2058(defvar vc-ediff-result)
0e362f54
GM
2059(eval-when-compile
2060 (defvar ediff-buffer-A)
2061 (defvar ediff-buffer-B)
2062 (defvar ediff-buffer-C)
2063 (require 'ediff-util))
ccb141e8
AS
2064;;;###autoload
2065(defun vc-resolve-conflicts (&optional name-A name-B)
18483cf0
AS
2066 "Invoke ediff to resolve conflicts in the current buffer.
2067The conflicts must be marked with rcsmerge conflict markers."
2068 (interactive)
b6909007 2069 (vc-ensure-vc-buffer)
18483cf0
AS
2070 (let* ((found nil)
2071 (file-name (file-name-nondirectory buffer-file-name))
0e362f54
GM
2072 (your-buffer (generate-new-buffer
2073 (concat "*" file-name
ccb141e8 2074 " " (or name-A "WORKFILE") "*")))
0e362f54
GM
2075 (other-buffer (generate-new-buffer
2076 (concat "*" file-name
ccb141e8 2077 " " (or name-B "CHECKED-IN") "*")))
18483cf0 2078 (result-buffer (current-buffer)))
0e362f54 2079 (save-excursion
18483cf0
AS
2080 (set-buffer your-buffer)
2081 (erase-buffer)
2082 (insert-buffer result-buffer)
2083 (goto-char (point-min))
0e362f54 2084 (while (re-search-forward (concat "^<<<<<<< "
18483cf0
AS
2085 (regexp-quote file-name) "\n") nil t)
2086 (setq found t)
2087 (replace-match "")
2088 (if (not (re-search-forward "^=======\n" nil t))
2089 (error "Malformed conflict marker"))
2090 (replace-match "")
2091 (let ((start (point)))
2092 (if (not (re-search-forward "^>>>>>>> [0-9.]+\n" nil t))
2093 (error "Malformed conflict marker"))
2094 (delete-region start (point))))
2095 (if (not found)
2096 (progn
2097 (kill-buffer your-buffer)
2098 (kill-buffer other-buffer)
2099 (error "No conflict markers found")))
2100 (set-buffer other-buffer)
2101 (erase-buffer)
2102 (insert-buffer result-buffer)
2103 (goto-char (point-min))
0e362f54 2104 (while (re-search-forward (concat "^<<<<<<< "
18483cf0
AS
2105 (regexp-quote file-name) "\n") nil t)
2106 (let ((start (match-beginning 0)))
2107 (if (not (re-search-forward "^=======\n" nil t))
2108 (error "Malformed conflict marker"))
2109 (delete-region start (point))
2110 (if (not (re-search-forward "^>>>>>>> [0-9.]+\n" nil t))
2111 (error "Malformed conflict marker"))
2112 (replace-match "")))
2113 (let ((config (current-window-configuration))
2114 (ediff-default-variant 'default-B))
2115
2116 ;; Fire up ediff.
2117
2118 (set-buffer (ediff-merge-buffers your-buffer other-buffer))
2119
2120 ;; Ediff is now set up, and we are in the control buffer.
2121 ;; Do a few further adjustments and take precautions for exit.
2122
2123 (make-local-variable 'vc-ediff-windows)
2124 (setq vc-ediff-windows config)
2125 (make-local-variable 'vc-ediff-result)
0e362f54 2126 (setq vc-ediff-result result-buffer)
18483cf0 2127 (make-local-variable 'ediff-quit-hook)
6f41eeb5 2128 (setq ediff-quit-hook
0e362f54
GM
2129 (lambda ()
2130 (let ((buffer-A ediff-buffer-A)
2131 (buffer-B ediff-buffer-B)
2132 (buffer-C ediff-buffer-C)
2133 (result vc-ediff-result)
2134 (windows vc-ediff-windows))
2135 (ediff-cleanup-mess)
2136 (set-buffer result)
2137 (erase-buffer)
2138 (insert-buffer buffer-C)
2139 (kill-buffer buffer-A)
2140 (kill-buffer buffer-B)
2141 (kill-buffer buffer-C)
2142 (set-window-configuration windows)
2143 (message "Conflict resolution finished; you may save the buffer"))))
18483cf0
AS
2144 (message "Please resolve conflicts now; exit ediff when done")
2145 nil))))
2146
2f119435 2147;; The VC directory major mode. Coopt Dired for this.
e1f297e6
ER
2148;; All VC commands get mapped into logical equivalents.
2149
beba4bd9
AS
2150(defvar vc-dired-switches)
2151(defvar vc-dired-terse-mode)
2152
0e362f54
GM
2153(defvar vc-dired-mode-map
2154 (let ((map (make-sparse-keymap))
2155 (vmap (make-sparse-keymap)))
ec402ad4 2156 (define-key map "\C-xv" vmap)
0e362f54 2157 (define-key map "v" vmap)
ec402ad4 2158 (set-keymap-parent vmap vc-prefix-map)
0e362f54
GM
2159 (define-key vmap "t" 'vc-dired-toggle-terse-mode)
2160 map))
2161
2f119435 2162(define-derived-mode vc-dired-mode dired-mode "Dired under VC"
0e362f54
GM
2163 "The major mode used in VC directory buffers.
2164
2165It works like Dired, but lists only files under version control, with
2166the current VC state of each file being indicated in the place of the
2167file's link count, owner, group and size. Subdirectories are also
2168listed, and you may insert them into the buffer as desired, like in
2169Dired.
2170
2171All Dired commands operate normally, with the exception of `v', which
2172is redefined as the version control prefix, so that you can type
3d30b8bc
RS
2173`vl', `v=' etc. to invoke `vc-print-log', `vc-diff', and the like on
2174the file named in the current Dired buffer line. `vv' invokes
2175`vc-next-action' on this file, or on all files currently marked.
2176There is a special command, `*l', to mark all files currently locked."
099bd78a
SM
2177 ;; define-derived-mode does it for us in Emacs-21, but not in Emacs-20.
2178 ;; We do it here because dired might not be loaded yet
2179 ;; when vc-dired-mode-map is initialized.
2180 (set-keymap-parent vc-dired-mode-map dired-mode-map)
421f0bfe 2181 (add-hook 'dired-after-readin-hook 'vc-dired-hook nil t)
edcb979f
AS
2182 ;; The following is slightly modified from dired.el,
2183 ;; because file lines look a bit different in vc-dired-mode.
2184 (set (make-local-variable 'dired-move-to-filename-regexp)
0e362f54 2185 (let*
edcb979f
AS
2186 ((l "\\([A-Za-z]\\|[^\0-\177]\\)")
2187 ;; In some locales, month abbreviations are as short as 2 letters,
2188 ;; and they can be padded on the right with spaces.
2189 (month (concat l l "+ *"))
0e362f54 2190 ;; Recognize any non-ASCII character.
edcb979f
AS
2191 ;; The purpose is to match a Kanji character.
2192 (k "[^\0-\177]")
2193 ;; (k "[^\x00-\x7f\x80-\xff]")
2194 (s " ")
2195 (yyyy "[0-9][0-9][0-9][0-9]")
2196 (mm "[ 0-1][0-9]")
2197 (dd "[ 0-3][0-9]")
2198 (HH:MM "[ 0-2][0-9]:[0-5][0-9]")
2199 (western (concat "\\(" month s dd "\\|" dd s month "\\)"
61d6c25d 2200 s "\\(" HH:MM "\\|" s yyyy"\\|" yyyy s "\\)"))
edcb979f 2201 (japanese (concat mm k s dd k s "\\(" s HH:MM "\\|" yyyy k "\\)")))
0e362f54
GM
2202 ;; the .* below ensures that we find the last match on a line
2203 (concat ".*" s "\\(" western "\\|" japanese "\\)" s)))
a0019b45
AS
2204 (and (boundp 'vc-dired-switches)
2205 vc-dired-switches
2206 (set (make-local-variable 'dired-actual-switches)
2207 vc-dired-switches))
3b574573 2208 (set (make-local-variable 'vc-dired-terse-mode) vc-dired-terse-display)
2f119435
AS
2209 (setq vc-dired-mode t))
2210
3b574573
AS
2211(defun vc-dired-toggle-terse-mode ()
2212 "Toggle terse display in VC Dired."
2213 (interactive)
2214 (if (not vc-dired-mode)
2215 nil
2216 (setq vc-dired-terse-mode (not vc-dired-terse-mode))
2217 (if vc-dired-terse-mode
2218 (vc-dired-hook)
2219 (revert-buffer))))
2220
3d30b8bc
RS
2221(defun vc-dired-mark-locked ()
2222 "Mark all files currently locked."
2223 (interactive)
2224 (dired-mark-if (let ((f (dired-get-filename nil t)))
2225 (and f
2226 (not (file-directory-p f))
0e362f54 2227 (not (vc-up-to-date-p f))))
3d30b8bc
RS
2228 "locked file"))
2229
2230(define-key vc-dired-mode-map "*l" 'vc-dired-mark-locked)
2231
0e362f54
GM
2232(defun vc-default-dired-state-info (backend file)
2233 (let ((state (vc-state file)))
2234 (cond
2235 ((stringp state) (concat "(" state ")"))
2236 ((eq state 'edited) (concat "(" (vc-user-login-name) ")"))
2237 ((eq state 'needs-merge) "(merge)")
2238 ((eq state 'needs-patch) "(patch)")
2239 ((eq state 'unlocked-changes) "(stale)"))))
b0c9bc8c 2240
8c0aaf40 2241(defun vc-dired-reformat-line (x)
0e362f54
GM
2242 "Reformat a directory-listing line.
2243Replace various columns with version control information.
2244This code, like dired, assumes UNIX -l format."
3d30b8bc 2245 (beginning-of-line)
edcb979f 2246 (let ((pos (point)) limit perm date-and-file)
2f119435
AS
2247 (end-of-line)
2248 (setq limit (point))
2249 (goto-char pos)
edcb979f
AS
2250 (when
2251 (or
2252 (re-search-forward ;; owner and group
2253 "^\\(..[drwxlts-]+ \\) *[0-9]+ [^ ]+ +[^ ]+ +[0-9]+\\( .*\\)"
0e362f54 2254 limit t)
edcb979f 2255 (re-search-forward ;; only owner displayed
0e362f54 2256 "^\\(..[drwxlts-]+ \\) *[0-9]+ [^ ]+ +[0-9]+\\( .*\\)"
edcb979f
AS
2257 limit t)
2258 (re-search-forward ;; OS/2 -l format, no links, owner, group
2259 "^\\(..[drwxlts-]+ \\) *[0-9]+\\( .*\\)"
2260 limit t))
2f119435 2261 (setq perm (match-string 1)
edcb979f
AS
2262 date-and-file (match-string 2))
2263 (setq x (substring (concat x " ") 0 10))
2264 (replace-match (concat perm x date-and-file)))))
3d30b8bc
RS
2265
2266(defun vc-dired-hook ()
0e362f54
GM
2267 "Reformat the listing according to version control.
2268Called by dired after any portion of a vc-dired buffer has been read in."
3d30b8bc 2269 (message "Getting version information... ")
eccceb78 2270 (let (subdir filename (buffer-read-only nil) cvs-dir)
3d30b8bc 2271 (goto-char (point-min))
0e362f54
GM
2272 (while (not (eobp))
2273 (cond
3d30b8bc
RS
2274 ;; subdir header line
2275 ((setq subdir (dired-get-subdir))
0e362f54
GM
2276 ;; if the backend supports it, get the state
2277 ;; of all files in this directory at once
2278 (let ((backend (vc-responsible-backend subdir)))
2279 (if (vc-find-backend-function backend 'dir-state)
2280 (vc-call-backend backend 'dir-state subdir)))
3d30b8bc
RS
2281 (forward-line 1)
2282 ;; erase (but don't remove) the "total" line
0e362f54
GM
2283 (delete-region (point) (line-end-position))
2284 (beginning-of-line)
2285 (forward-line 1))
2286 ;; file line
3d30b8bc
RS
2287 ((setq filename (dired-get-filename nil t))
2288 (cond
3b574573 2289 ;; subdir
3d30b8bc 2290 ((file-directory-p filename)
0e362f54
GM
2291 (cond
2292 ((member (file-name-nondirectory filename)
3b574573
AS
2293 vc-directory-exclusion-list)
2294 (let ((pos (point)))
2295 (dired-kill-tree filename)
2296 (goto-char pos)
2297 (dired-kill-line)))
2298 (vc-dired-terse-mode
633cee46
AS
2299 ;; Don't show directories in terse mode. Don't use
2300 ;; dired-kill-line to remove it, because in recursive listings,
2301 ;; that would remove the directory contents as well.
0e362f54 2302 (delete-region (line-beginning-position)
633cee46 2303 (progn (forward-line 1) (point))))
3b574573
AS
2304 ((string-match "\\`\\.\\.?\\'" (file-name-nondirectory filename))
2305 (dired-kill-line))
2306 (t
3d30b8bc 2307 (vc-dired-reformat-line nil)
3b574573
AS
2308 (forward-line 1))))
2309 ;; ordinary file
0e362f54
GM
2310 ((and (vc-backend filename)
2311 (not (and vc-dired-terse-mode
2312 (vc-up-to-date-p filename))))
2313 (vc-dired-reformat-line (vc-call dired-state-info filename))
3d30b8bc 2314 (forward-line 1))
0e362f54 2315 (t
3d30b8bc
RS
2316 (dired-kill-line))))
2317 ;; any other line
3b574573
AS
2318 (t (forward-line 1))))
2319 (vc-dired-purge))
2320 (message "Getting version information... done")
2321 (save-restriction
2322 (widen)
633cee46
AS
2323 (cond ((eq (count-lines (point-min) (point-max)) 1)
2324 (goto-char (point-min))
2325 (message "No files locked under %s" default-directory)))))
3b574573
AS
2326
2327(defun vc-dired-purge ()
0e362f54 2328 "Remove empty subdirs."
3b574573
AS
2329 (let (subdir)
2330 (goto-char (point-min))
2331 (while (setq subdir (dired-get-subdir))
2332 (forward-line 2)
2333 (if (dired-get-filename nil t)
2334 (if (not (dired-next-subdir 1 t))
2335 (goto-char (point-max)))
2336 (forward-line -2)
2337 (if (not (string= (dired-current-directory) default-directory))
2338 (dired-do-kill-lines t "")
633cee46
AS
2339 ;; We cannot remove the top level directory.
2340 ;; Just make it look a little nicer.
2341 (forward-line 1)
2342 (kill-line)
3b574573
AS
2343 (if (not (dired-next-subdir 1 t))
2344 (goto-char (point-max))))))
2345 (goto-char (point-min))))
2f119435 2346
0e362f54
GM
2347(defun vc-dired-buffers-for-dir (dir)
2348 "Return a list of all vc-dired buffers that currently display DIR."
2349 (let (result)
099bd78a
SM
2350 ;; Check whether dired is loaded.
2351 (when (fboundp 'dired-buffers-for-dir)
2352 (mapcar (lambda (buffer)
2353 (with-current-buffer buffer
2354 (if vc-dired-mode
2355 (setq result (append result (list buffer))))))
2356 (dired-buffers-for-dir dir)))
0e362f54
GM
2357 result))
2358
2359(defun vc-dired-resynch-file (file)
2360 "Update the entries for FILE in any VC Dired buffers that list it."
2361 (let ((buffers (vc-dired-buffers-for-dir (file-name-directory file))))
2362 (when buffers
2363 (mapcar (lambda (buffer)
2364 (with-current-buffer buffer
2365 (if (dired-goto-file file)
2366 ;; bind vc-dired-terse-mode to nil so that
2367 ;; files won't vanish when they are checked in
2368 (let ((vc-dired-terse-mode nil))
2369 (dired-do-redisplay 1)))))
2370 buffers))))
2371
637a8ae9 2372;;;###autoload
0e362f54
GM
2373(defun vc-directory (dir read-switches)
2374 "Create a buffer in VC Dired Mode for directory DIR.
2375
2376See Info node `VC Dired Mode'.
2377
2378With prefix arg READ-SWITCHES, specify a value to override
2379`dired-listing-switches' when generating the listing."
2f119435 2380 (interactive "DDired under VC (directory): \nP")
0e362f54 2381 (let ((vc-dired-switches (concat vc-dired-listing-switches
3b574573 2382 (if vc-dired-recurse "R" ""))))
0e362f54 2383 (if read-switches
3b574573
AS
2384 (setq vc-dired-switches
2385 (read-string "Dired listing switches: "
2386 vc-dired-switches)))
3d30b8bc
RS
2387 (require 'dired)
2388 (require 'dired-aux)
0e362f54
GM
2389 (switch-to-buffer
2390 (dired-internal-noselect (expand-file-name (file-name-as-directory dir))
2391 vc-dired-switches
3d30b8bc 2392 'vc-dired-mode))))
e70bdc98 2393
594722a8
ER
2394
2395;; Named-configuration entry points
2396
0e362f54 2397(defun vc-snapshot-precondition (dir)
6f1ecae4 2398 "Scan the tree below DIR, looking for files not up-to-date.
099bd78a
SM
2399If any file is not up-to-date, return the name of the first such file.
2400\(This means, neither snapshot creation nor retrieval is allowed.\)
2401If one or more of the files are currently visited, return `visited'.
2402Otherwise, return nil."
503b5c85
RS
2403 (let ((status nil))
2404 (catch 'vc-locked-example
2405 (vc-file-tree-walk
0e362f54
GM
2406 dir
2407 (lambda (f)
2408 (if (not (vc-up-to-date-p f)) (throw 'vc-locked-example f)
2409 (if (get-file-buffer f) (setq status 'visited)))))
503b5c85 2410 status)))
594722a8 2411
637a8ae9 2412;;;###autoload
0e362f54 2413(defun vc-create-snapshot (dir name branchp)
6f41eeb5 2414 "Descending recursively from DIR, make a snapshot called NAME.
0e362f54
GM
2415For each registered file, the version level of its latest version
2416becomes part of the named configuration. If the prefix argument
2417BRANCHP is given, the snapshot is made as a new branch and the files
2418are checked out in that new branch."
2419 (interactive
2420 (list (read-file-name "Directory: " default-directory default-directory t)
2421 (read-string "New snapshot name: ")
2422 current-prefix-arg))
2423 (message "Making %s... " (if branchp "branch" "snapshot"))
2424 (if (file-directory-p dir) (setq dir (file-name-as-directory dir)))
2425 (vc-call-backend (vc-responsible-backend dir)
2426 'create-snapshot dir name branchp)
2427 (message "Making %s... done" (if branchp "branch" "snapshot")))
2428
2429(defun vc-default-create-snapshot (backend dir name branchp)
6f41eeb5 2430 (when branchp
0e362f54
GM
2431 (error "VC backend %s does not support module branches" backend))
2432 (let ((result (vc-snapshot-precondition dir)))
503b5c85 2433 (if (stringp result)
0e362f54 2434 (error "File %s is not up-to-date" result)
1dabb4e6 2435 (vc-file-tree-walk
0e362f54
GM
2436 dir
2437 (lambda (f)
2438 (vc-call assign-name f name))))))
594722a8 2439
637a8ae9 2440;;;###autoload
0e362f54 2441(defun vc-retrieve-snapshot (dir name)
099bd78a
SM
2442 "Descending recursively from DIR, retrieve the snapshot called NAME.
2443If NAME is empty, it refers to the latest versions.
2444If locking is used for the files in DIR, then there must not be any
2445locked files at or below DIR (but if NAME is empty, locked files are
2446allowed and simply skipped)."
0e362f54
GM
2447 (interactive
2448 (list (read-file-name "Directory: " default-directory default-directory t)
2449 (read-string "Snapshot name to retrieve (default latest versions): ")))
2450 (let ((update (yes-or-no-p "Update any affected buffers? "))
2451 (msg (if (or (not name) (string= name ""))
2452 (format "Updating %s... " (abbreviate-file-name dir))
2453 (format "Retrieving snapshot into %s... "
2454 (abbreviate-file-name dir)))))
2455 (message msg)
2456 (vc-call-backend (vc-responsible-backend dir)
2457 'retrieve-snapshot dir name update)
2458 (message (concat msg "done"))))
2459
2460(defun vc-default-retrieve-snapshot (backend dir name update)
2461 (if (string= name "")
2462 (progn
2463 (vc-file-tree-walk
2464 dir
2465 (lambda (f) (and
2466 (vc-up-to-date-p f)
2467 (vc-error-occurred
2468 (vc-call checkout f nil "")
2469 (if update (vc-resynch-buffer f t t)))))))
2470 (let ((result (vc-snapshot-precondition dir)))
2471 (if (stringp result)
2472 (error "File %s is locked" result)
2473 (setq update (and (eq result 'visited) update))
2474 (vc-file-tree-walk
2475 dir
fd8092f0
SM
2476 (lambda (f) (vc-error-occurred
2477 (vc-call checkout f nil name)
2478 (if update (vc-resynch-buffer f t t)))))))))
594722a8
ER
2479
2480;; Miscellaneous other entry points
2481
637a8ae9 2482;;;###autoload
594722a8
ER
2483(defun vc-print-log ()
2484 "List the change log of the current buffer in a window."
2485 (interactive)
b6909007
AS
2486 (vc-ensure-vc-buffer)
2487 (let ((file buffer-file-name))
0e362f54 2488 (vc-call print-log file)
ad339989 2489 (set-buffer "*vc*")
0e362f54
GM
2490 (pop-to-buffer (current-buffer))
2491 (if (fboundp 'log-view-mode) (log-view-mode))
2492 (vc-exec-after
99cb8c8b 2493 `(let ((inhibit-read-only t))
0e362f54
GM
2494 (goto-char (point-max)) (forward-line -1)
2495 (while (looking-at "=*\n")
2496 (delete-char (- (match-end 0) (match-beginning 0)))
2497 (forward-line -1))
2498 (goto-char (point-min))
2499 (if (looking-at "[\b\t\n\v\f\r ]+")
2500 (delete-char (- (match-end 0) (match-beginning 0))))
2501 (shrink-window-if-larger-than-buffer)
2502 ;; move point to the log entry for the current version
2503 (if (fboundp 'log-view-goto-rev)
2504 (log-view-goto-rev ',(vc-workfile-version file))
2505 (if (vc-find-backend-function ',(vc-backend file) 'show-log-entry)
6f41eeb5
DL
2506 (vc-call-backend ',(vc-backend file)
2507 'show-log-entry
99cb8c8b
SS
2508 ',(vc-workfile-version file))))
2509 (set-buffer-modified-p nil)))))
594722a8 2510
0ab66291 2511(defun vc-default-comment-history (backend file)
6f1ecae4 2512 "Return a string with all log entries stored in BACKEND for FILE."
0ab66291
AS
2513 (if (vc-find-backend-function backend 'print-log)
2514 (with-temp-buffer
2515 (vc-call print-log file)
2516 (vc-call wash-log file)
2517 (buffer-string))))
2518
2519(defun vc-default-wash-log (backend file)
2520 "Remove all non-comment information from log output.
2521This default implementation works for RCS logs; backends should override
2522it if their logs are not in RCS format."
2523 (let ((separator (concat "^-+\nrevision [0-9.]+\ndate: .*\n"
2524 "\\(branches: .*;\n\\)?"
2525 "\\(\\*\\*\\* empty log message \\*\\*\\*\n\\)?")))
2526 (goto-char (point-max)) (forward-line -1)
2527 (while (looking-at "=*\n")
2528 (delete-char (- (match-end 0) (match-beginning 0)))
2529 (forward-line -1))
2530 (goto-char (point-min))
2531 (if (looking-at "[\b\t\n\v\f\r ]+")
2532 (delete-char (- (match-end 0) (match-beginning 0))))
2533 (goto-char (point-min))
2534 (re-search-forward separator nil t)
2535 (delete-region (point-min) (point))
2536 (while (re-search-forward separator nil t)
2537 (delete-region (match-beginning 0) (match-end 0)))))
2538
637a8ae9 2539;;;###autoload
594722a8 2540(defun vc-revert-buffer ()
6f1ecae4 2541 "Revert the current buffer's file to the version it was based on.
9c95ac44 2542This asks for confirmation if the buffer contents are not identical
7849e179
SM
2543to that version. This function does not automatically pick up newer
2544changes found in the master file; use \\[universal-argument] \\[vc-next-action] to do so."
594722a8 2545 (interactive)
b6909007 2546 (vc-ensure-vc-buffer)
d607ebcc
AS
2547 ;; Make sure buffer is saved. If the user says `no', abort since
2548 ;; we cannot show the changes and ask for confirmation to discard them.
2549 (vc-buffer-sync nil)
594722a8 2550 (let ((file buffer-file-name)
221cc4f4
RS
2551 ;; This operation should always ask for confirmation.
2552 (vc-suppress-confirm nil)
ffda0460
AS
2553 (obuf (current-buffer))
2554 status)
c96da2b0
AS
2555 (if (vc-up-to-date-p file)
2556 (unless (yes-or-no-p "File seems up-to-date. Revert anyway? ")
2557 (error "Revert canceled")))
0e362f54 2558 (unless (vc-workfile-unchanged-p file)
a3255400
SM
2559 ;; vc-diff selects the new window, which is not what we want:
2560 ;; if the new window is on another frame, that'd require the user
2561 ;; moving her mouse to answer the yes-or-no-p question.
2562 (let ((win (save-selected-window
2563 (setq status (vc-diff nil t)) (selected-window))))
2564 (vc-exec-after `(message nil))
2565 (when status
2566 (unwind-protect
2567 (unless (yes-or-no-p "Discard changes? ")
ffda0460 2568 (error "Revert canceled"))
a3255400
SM
2569 (select-window win)
2570 (if (one-window-p t)
2571 (if (window-dedicated-p (selected-window))
2572 (make-frame-invisible))
2573 (delete-window))))))
751fa747 2574 (set-buffer obuf)
0e362f54
GM
2575 ;; Do the reverting
2576 (message "Reverting %s..." file)
045e1aa5 2577 (vc-revert-file file)
0e362f54 2578 (message "Reverting %s...done" file)))
594722a8 2579
9f30fc99
AS
2580;;;###autoload
2581(defun vc-update ()
2582 "Update the current buffer's file to the latest version on its branch.
2583If the file contains no changes, and is not locked, then this simply replaces
2584the working file with the latest version on its branch. If the file contains
2585changes, and the backend supports merging news, then any recent changes from
2586the current branch are merged into the working file."
2587 (interactive)
2588 (vc-ensure-vc-buffer)
2589 (vc-buffer-sync nil)
2590 (let ((file buffer-file-name))
2591 (if (vc-up-to-date-p file)
2592 (vc-checkout file nil "")
2593 (if (eq (vc-checkout-model file) 'locking)
2594 (if (eq (vc-state file) 'edited)
2595 (error
2596 (substitute-command-keys
2597 "File is locked--type \\[vc-revert-buffer] to discard changes"))
2598 (error
2599 (substitute-command-keys
2600 "Unexpected file state (%s)--type \\[vc-next-action] to correct")
2601 (vc-state file)))
2602 (if (not (vc-find-backend-function (vc-backend file) 'merge-news))
2603 (error "Sorry, merging news is not implemented for %s"
2604 (vc-backend file))
2605 (vc-call merge-news file)
2606 (vc-resynch-window file t t))))))
2607
ffda0460 2608(defun vc-version-backup-file (file &optional rev)
66321b2f
SM
2609 "Return name of backup file for revision REV of FILE.
2610If version backups should be used for FILE, and there exists
ffda0460 2611such a backup for REV or the current workfile version of file,
66321b2f 2612return its name; otherwise return nil."
10b48cc4 2613 (when (vc-call make-version-backups-p file)
ffda0460 2614 (let ((backup-file (vc-version-backup-file-name file rev)))
10b48cc4
AS
2615 (if (file-exists-p backup-file)
2616 backup-file
2617 ;; there is no automatic backup, but maybe the user made one manually
2618 (setq backup-file (vc-version-backup-file-name file rev 'manual))
2619 (if (file-exists-p backup-file)
2620 backup-file)))))
ffda0460 2621
045e1aa5
AS
2622(defun vc-revert-file (file)
2623 "Revert FILE back to the version it was based on."
045e1aa5
AS
2624 (with-vc-properties
2625 file
ffda0460 2626 (let ((backup-file (vc-version-backup-file file)))
bbfc07d3 2627 (when backup-file
ffda0460 2628 (copy-file backup-file file 'ok-if-already-exists 'keep-date)
bbfc07d3
AS
2629 (vc-delete-automatic-version-backups file))
2630 (vc-call revert file backup-file))
a3255400
SM
2631 `((vc-state . up-to-date)
2632 (vc-checkout-time . ,(nth 5 (file-attributes file)))))
045e1aa5
AS
2633 (vc-resynch-buffer file t t))
2634
637a8ae9 2635;;;###autoload
594722a8 2636(defun vc-cancel-version (norevert)
34291cd2 2637 "Get rid of most recently checked in version of this file.
099bd78a 2638A prefix argument NOREVERT means do not revert the buffer afterwards."
594722a8 2639 (interactive "P")
b6909007 2640 (vc-ensure-vc-buffer)
099bd78a
SM
2641 (let* ((file (buffer-file-name))
2642 (backend (vc-backend file))
2643 (target (vc-workfile-version file))
7e48e092 2644 (config (current-window-configuration)) done)
0e362f54 2645 (cond
099bd78a 2646 ((not (vc-find-backend-function backend 'cancel-version))
0e362f54 2647 (error "Sorry, canceling versions is not supported under %s" backend))
099bd78a 2648 ((not (vc-call latest-on-branch-p file))
0e362f54 2649 (error "This is not the latest version; VC cannot cancel it"))
099bd78a 2650 ((not (vc-up-to-date-p file))
0e362f54 2651 (error (substitute-command-keys "File is not up to date; use \\[vc-revert-buffer] to discard changes"))))
7e48e092 2652 (if (null (yes-or-no-p (format "Remove version %s from master? " target)))
099bd78a 2653 (error "Aborted")
0e362f54
GM
2654 (setq norevert (or norevert (not
2655 (yes-or-no-p "Revert buffer to most recent remaining version? "))))
2656
099bd78a
SM
2657 (message "Removing last change from %s..." file)
2658 (with-vc-properties
2659 file
2660 (vc-call cancel-version file norevert)
a3255400 2661 `((vc-state . ,(if norevert 'edited 'up-to-date))
46e33aee
TTN
2662 (vc-checkout-time . ,(if norevert
2663 0
099bd78a 2664 (nth 5 (file-attributes file))))
a3255400 2665 (vc-workfile-version . nil)))
099bd78a
SM
2666 (message "Removing last change from %s...done" file)
2667
2668 (cond
2669 (norevert ;; clear version headers and mark the buffer modified
2670 (set-visited-file-name file)
2671 (when (not vc-make-backup-files)
2672 ;; inhibit backup for this buffer
2673 (make-local-variable 'backup-inhibited)
2674 (setq backup-inhibited t))
2675 (setq buffer-read-only nil)
2676 (vc-clear-headers)
2677 (vc-mode-line file)
2678 (vc-dired-resynch-file file))
2679 (t ;; revert buffer to file on disk
2680 (vc-resynch-buffer file t t)))
0e362f54
GM
2681 (message "Version %s has been removed from the master" target))))
2682
76e5906d 2683;;;###autoload
1d502d5a 2684(defun vc-switch-backend (file backend)
7849e179 2685 "Make BACKEND the current version control system for FILE.
1d502d5a
AS
2686FILE must already be registered in BACKEND. The change is not
2687permanent, only for the current session. This function only changes
7849e179
SM
2688VC's perspective on FILE, it does not register or unregister it.
2689By default, this command cycles through the registered backends.
2690To get a prompt, use a prefix argument."
2691 (interactive
1d502d5a
AS
2692 (list
2693 buffer-file-name
7849e179
SM
2694 (let ((backend (vc-backend buffer-file-name))
2695 (backends nil))
2696 ;; Find the registered backends.
2697 (dolist (backend vc-handled-backends)
2698 (when (vc-call-backend backend 'registered buffer-file-name)
2699 (push backend backends)))
2700 ;; Find the next backend.
ceec5a0c 2701 (let ((def (car (delq backend (append (memq backend backends) backends))))
7849e179
SM
2702 (others (delete backend backends)))
2703 (cond
2704 ((null others) (error "No other backend to switch to"))
2705 (current-prefix-arg
2706 (intern
2707 (upcase
2708 (completing-read
2709 (format "Switch to backend [%s]: " def)
2710 (mapcar (lambda (b) (list (downcase (symbol-name b)))) backends)
2711 nil t nil nil (downcase (symbol-name def))))))
2712 (t def))))))
ceec5a0c 2713 (unless (eq backend (vc-backend file))
ceec5a0c
SM
2714 (vc-file-clearprops file)
2715 (vc-file-setprop file 'vc-backend backend)
2716 ;; Force recomputation of the state
a3255400
SM
2717 (unless (vc-call-backend backend 'registered file)
2718 (vc-file-clearprops file)
2719 (error "%s is not registered in %s" file backend))
ceec5a0c 2720 (vc-mode-line file)))
1d502d5a 2721
21b50296 2722;;;###autoload
1d502d5a 2723(defun vc-transfer-file (file new-backend)
ceec5a0c 2724 "Transfer FILE to another version control system NEW-BACKEND.
1d502d5a 2725If NEW-BACKEND has a higher precedence than FILE's current backend
ceec5a0c 2726\(i.e. it comes earlier in `vc-handled-backends'), then register FILE in
1d502d5a
AS
2727NEW-BACKEND, using the version number from the current backend as the
2728base level. If NEW-BACKEND has a lower precedence than the current
2729backend, then commit all changes that were made under the current
2730backend to NEW-BACKEND, and unregister FILE from the current backend.
2731\(If FILE is not yet registered under NEW-BACKEND, register it.)"
72cfc5fb
AS
2732 (let* ((old-backend (vc-backend file))
2733 (edited (memq (vc-state file) '(edited needs-merge)))
2734 (registered (vc-call-backend new-backend 'registered file))
2735 (move
2736 (and registered ; Never move if not registered in new-backend yet.
2737 ;; move if new-backend comes later in vc-handled-backends
2738 (or (memq new-backend (memq old-backend vc-handled-backends))
ffda0460 2739 (y-or-n-p "Final transfer? "))))
72cfc5fb 2740 (comment nil))
1d502d5a 2741 (if (eq old-backend new-backend)
72cfc5fb
AS
2742 (error "%s is the current backend of %s" new-backend file))
2743 (if registered
2744 (set-file-modes file (logior (file-modes file) 128))
2745 ;; `registered' might have switched under us.
2746 (vc-switch-backend file old-backend)
ffda0460 2747 (let* ((rev (vc-workfile-version file))
c1b1b393 2748 (modified-file (and edited (make-temp-file file)))
ffda0460 2749 (unmodified-file (and modified-file (vc-version-backup-file file))))
72cfc5fb
AS
2750 ;; Go back to the base unmodified file.
2751 (unwind-protect
2752 (progn
ffda0460 2753 (when modified-file
c1b1b393 2754 (copy-file file modified-file 'ok-if-already-exists)
ffda0460
AS
2755 ;; If we have a local copy of the unmodified file, handle that
2756 ;; here and not in vc-revert-file because we don't want to
2757 ;; delete that copy -- it is still useful for OLD-BACKEND.
2758 (if unmodified-file
2759 (copy-file unmodified-file file 'ok-if-already-exists)
2760 (if (y-or-n-p "Get base version from master? ")
2761 (vc-revert-file file))))
72cfc5fb 2762 (vc-call-backend new-backend 'receive-file file rev))
ffda0460 2763 (when modified-file
72cfc5fb
AS
2764 (vc-switch-backend file new-backend)
2765 (unless (eq (vc-checkout-model file) 'implicit)
2766 (vc-checkout file t nil))
ffda0460
AS
2767 (rename-file modified-file file 'ok-if-already-exists)
2768 (vc-file-setprop file 'vc-checkout-time nil)))))
72cfc5fb
AS
2769 (when move
2770 (vc-switch-backend file old-backend)
2771 (setq comment (vc-call comment-history file))
2772 (vc-call unregister file))
2773 (vc-switch-backend file new-backend)
2774 (when (or move edited)
1d502d5a 2775 (vc-file-setprop file 'vc-state 'edited)
ffda0460 2776 (vc-mode-line file)
0ab66291 2777 (vc-checkin file nil comment (stringp comment)))))
1d502d5a 2778
72cfc5fb
AS
2779(defun vc-default-unregister (backend file)
2780 "Default implementation of `vc-unregister', signals an error."
2781 (error "Unregistering files is not supported for %s" backend))
2782
2783(defun vc-default-receive-file (backend file rev)
2784 "Let BACKEND receive FILE from another version control system."
2785 (vc-call-backend backend 'register file rev ""))
2786
0e362f54
GM
2787(defun vc-rename-master (oldmaster newfile templates)
2788 "Rename OLDMASTER to be the master file for NEWFILE based on TEMPLATES."
2789 (let* ((dir (file-name-directory (expand-file-name oldmaster)))
2790 (newdir (or (file-name-directory newfile) ""))
2791 (newbase (file-name-nondirectory newfile))
2792 (masters
2793 ;; List of potential master files for `newfile'
2794 (mapcar
2795 (lambda (s) (vc-possible-master s newdir newbase))
2796 templates)))
2797 (if (or (file-symlink-p oldmaster)
2798 (file-symlink-p (file-name-directory oldmaster)))
6f1ecae4 2799 (error "This is unsafe in the presence of symbolic links"))
0e362f54
GM
2800 (rename-file
2801 oldmaster
2802 (catch 'found
2803 ;; If possible, keep the master file in the same directory.
2804 (mapcar (lambda (f)
2805 (if (and f (string= (file-name-directory (expand-file-name f))
2806 dir))
2807 (throw 'found f)))
2808 masters)
2809 ;; If not, just use the first possible place.
2810 (mapcar (lambda (f)
2811 (and f
2812 (or (not (setq dir (file-name-directory f)))
2813 (file-directory-p dir))
2814 (throw 'found f)))
2815 masters)
2816 (error "New file lacks a version control directory")))))
594722a8 2817
29fc1ce9 2818;;;###autoload
594722a8 2819(defun vc-rename-file (old new)
34291cd2
RS
2820 "Rename file OLD to NEW, and rename its master file likewise."
2821 (interactive "fVC rename file: \nFRename to: ")
0e362f54
GM
2822 (let ((oldbuf (get-file-buffer old))
2823 (backend (vc-backend old)))
2824 (unless (or (null backend) (vc-find-backend-function backend 'rename-file))
2825 (error "Renaming files under %s is not supported in VC" backend))
d52f0de9 2826 (if (and oldbuf (buffer-modified-p oldbuf))
590cc449 2827 (error "Please save files before moving them"))
594722a8 2828 (if (get-file-buffer new)
590cc449 2829 (error "Already editing new file name"))
d52f0de9
RS
2830 (if (file-exists-p new)
2831 (error "New file already exists"))
0e362f54
GM
2832 (when backend
2833 (if (and backend (not (vc-up-to-date-p old)))
2834 (error "Please check in files before moving them"))
2835 (vc-call-backend backend 'rename-file old new))
2836 ;; Move the actual file (unless the backend did it already)
2837 (if (or (not backend) (file-exists-p old))
2838 (rename-file old new))
2839 ;; ?? Renaming a file might change its contents due to keyword expansion.
2840 ;; We should really check out a new copy if the old copy was precisely equal
2841 ;; to some checked in version. However, testing for this is tricky....
594722a8 2842 (if oldbuf
0e362f54 2843 (with-current-buffer oldbuf
4c145b9e
RS
2844 (let ((buffer-read-only buffer-read-only))
2845 (set-visited-file-name new))
2846 (vc-backend new)
2847 (vc-mode-line new)
0e362f54
GM
2848 (set-buffer-modified-p nil)))))
2849
2850;; Only defined in very recent Emacsen
2851(defvar small-temporary-file-directory nil)
594722a8 2852
637a8ae9 2853;;;###autoload
f35ecf88 2854(defun vc-update-change-log (&rest args)
0e362f54 2855 "Find change log file and add entries from recent version control logs.
d68e6990 2856Normally, find log entries for all registered files in the default
0e362f54 2857directory.
d68e6990 2858
099bd78a 2859With prefix arg of \\[universal-argument], only find log entries for the current buffer's file.
d68e6990
RS
2860
2861With any numeric prefix arg, find log entries for all currently visited
2862files that are under version control. This puts all the entries in the
2863log for the default directory, which may not be appropriate.
2864
099bd78a 2865From a program, any ARGS are assumed to be filenames for which
0e362f54 2866log entries should be gathered."
67242a23
RM
2867 (interactive
2868 (cond ((consp current-prefix-arg) ;C-u
2869 (list buffer-file-name))
2870 (current-prefix-arg ;Numeric argument.
2871 (let ((files nil)
2872 (buffers (buffer-list))
2873 file)
2874 (while buffers
2875 (setq file (buffer-file-name (car buffers)))
f3c61d82 2876 (and file (vc-backend file)
4b40fdea 2877 (setq files (cons file files)))
67242a23 2878 (setq buffers (cdr buffers)))
4b40fdea
PE
2879 files))
2880 (t
0e362f54
GM
2881 ;; Don't supply any filenames to backend; this means
2882 ;; it should find all relevant files relative to
2883 ;; the default-directory.
73a9679c 2884 nil)))
0e362f54
GM
2885 (vc-call-backend (vc-responsible-backend default-directory)
2886 'update-changelog args))
2887
2888(defun vc-default-update-changelog (backend files)
099bd78a
SM
2889 "Default implementation of update-changelog.
2890Uses `rcs2log' which only works for RCS and CVS."
0e362f54 2891 ;; FIXME: We (c|sh)ould add support for cvs2cl
449decf5 2892 (let ((odefault default-directory)
124c852b
RS
2893 (changelog (find-change-log))
2894 ;; Presumably not portable to non-Unixy systems, along with rcs2log:
c1b1b393 2895 (tempfile (make-temp-file
57c298c4
EZ
2896 (expand-file-name "vc"
2897 (or small-temporary-file-directory
2898 temporary-file-directory))))
b91916f3 2899 (full-name (or add-log-full-name
8172cd86
AS
2900 (user-full-name)
2901 (user-login-name)
2902 (format "uid%d" (number-to-string (user-uid)))))
b91916f3
RS
2903 (mailing-address (or add-log-mailing-address
2904 user-mail-address)))
124c852b 2905 (find-file-other-window changelog)
41dfb835
RS
2906 (barf-if-buffer-read-only)
2907 (vc-buffer-sync)
2908 (undo-boundary)
2909 (goto-char (point-min))
2910 (push-mark)
2911 (message "Computing change log entries...")
4b40fdea 2912 (message "Computing change log entries... %s"
124c852b
RS
2913 (unwind-protect
2914 (progn
0e362f54 2915 (setq default-directory odefault)
6f41eeb5
DL
2916 (if (eq 0 (apply 'call-process
2917 (expand-file-name "rcs2log"
2918 exec-directory)
0e362f54
GM
2919 nil (list t tempfile) nil
2920 "-c" changelog
2921 "-u" (concat (vc-user-login-name)
2922 "\t" full-name
2923 "\t" mailing-address)
2924 (mapcar
2925 (lambda (f)
2926 (file-relative-name
2927 (if (file-name-absolute-p f)
2928 f
2929 (concat odefault f))))
2930 files)))
2931 "done"
124c852b
RS
2932 (pop-to-buffer
2933 (set-buffer (get-buffer-create "*vc*")))
2934 (erase-buffer)
2935 (insert-file tempfile)
2936 "failed"))
0e362f54 2937 (setq default-directory (file-name-directory changelog))
124c852b 2938 (delete-file tempfile)))))
7d2d9482 2939
ec402ad4 2940;; Annotate functionality
7d2d9482 2941
f80f7bc2
RS
2942;; Declare globally instead of additional parameter to
2943;; temp-buffer-show-function (not possible to pass more than one
75665141
AS
2944;; parameter). The use of annotate-ratio is deprecated in favor of
2945;; annotate-mode, which replaces it with the more sensible "span-to
2946;; days", along with autoscaling support.
099bd78a
SM
2947(defvar vc-annotate-ratio nil "Global variable.")
2948(defvar vc-annotate-backend nil "Global variable.")
0e362f54
GM
2949
2950(defun vc-annotate-get-backend (buffer)
099bd78a 2951 "Return the backend matching \"Annotate\" buffer BUFFER.
0ff9b955 2952Return nil if no match made. Associations are made based on
0e362f54
GM
2953`vc-annotate-buffers'."
2954 (cdr (assoc buffer vc-annotate-buffers)))
7d2d9482 2955
0e362f54 2956(define-derived-mode vc-annotate-mode fundamental-mode "Annotate"
6f1ecae4 2957 "Major mode for output buffers of the `vc-annotate' command.
7d2d9482
RS
2958
2959You can use the mode-specific menu to alter the time-span of the used
2960colors. See variable `vc-annotate-menu-elements' for customizing the
2961menu items."
7d2d9482
RS
2962 (vc-annotate-add-menu))
2963
75665141 2964(defun vc-annotate-display-default (&optional ratio)
6f1ecae4
AS
2965 "Display the output of \\[vc-annotate] using the default color range.
2966The color range is given by `vc-annotate-color-map', scaled by RATIO
2967if present. The current time is used as the offset."
0e362f54 2968 (interactive "e")
f80f7bc2 2969 (message "Redisplaying annotation...")
99cb8c8b 2970 (vc-annotate-display
75665141 2971 (if ratio (vc-annotate-time-span vc-annotate-color-map ratio)))
f80f7bc2 2972 (message "Redisplaying annotation...done"))
7d2d9482 2973
75665141 2974(defun vc-annotate-display-autoscale (&optional full)
6f1ecae4
AS
2975 "Highlight the output of \\[vc-annotate]] using an autoscaled color map.
2976Autoscaling means that the map is scaled from the current time to the
2977oldest annotation in the buffer, or, with argument FULL non-nil, to
2978cover the range from the oldest annotation to the newest."
75665141
AS
2979 (interactive)
2980 (let ((newest 0.0)
2981 (oldest 999999.) ;Any CVS users at the founding of Rome?
2982 (current (vc-annotate-convert-time (current-time)))
2983 date)
2984 (message "Redisplaying annotation...")
2985 ;; Run through this file and find the oldest and newest dates annotated.
2986 (save-excursion
2987 (goto-char (point-min))
2988 (while (setq date (vc-call-backend vc-annotate-backend 'annotate-time))
2989 (if (> date newest)
2990 (setq newest date))
2991 (if (< date oldest)
2992 (setq oldest date))))
2993 (vc-annotate-display
2994 (vc-annotate-time-span ;return the scaled colormap.
2995 vc-annotate-color-map
99cb8c8b 2996 (/ (- (if full newest current) oldest)
75665141
AS
2997 (vc-annotate-car-last-cons vc-annotate-color-map)))
2998 (if full newest))
99cb8c8b
SS
2999 (message "Redisplaying annotation...done \(%s\)"
3000 (if full
3001 (format "Spanned from %.1f to %.1f days old"
75665141
AS
3002 (- current oldest)
3003 (- current newest))
3004 (format "Spanned to %.1f days old" (- current oldest))))))
3005
3006;; Menu -- Using easymenu.el
7d2d9482 3007(defun vc-annotate-add-menu ()
0e362f54 3008 "Add the menu 'Annotate' to the menu bar in VC-Annotate mode."
75665141
AS
3009 (let ((menu-elements vc-annotate-menu-elements)
3010 (menu-def
3011 '("VC-Annotate"
3012 ["Default" (unless (null vc-annotate-display-mode)
3013 (setq vc-annotate-display-mode nil)
3014 (vc-annotate-display-select))
3015 :style toggle :selected (null vc-annotate-display-mode)]))
3016 (oldest-in-map (vc-annotate-car-last-cons vc-annotate-color-map)))
7d2d9482
RS
3017 (while menu-elements
3018 (let* ((element (car menu-elements))
75665141 3019 (days (* element oldest-in-map)))
7d2d9482 3020 (setq menu-elements (cdr menu-elements))
99cb8c8b
SS
3021 (setq menu-def
3022 (append menu-def
75665141
AS
3023 `([,(format "Span %.1f days" days)
3024 (unless (and (numberp vc-annotate-display-mode)
3025 (= vc-annotate-display-mode ,days))
3026 (vc-annotate-display-select nil ,days))
99cb8c8b 3027 :style toggle :selected
75665141
AS
3028 (and (numberp vc-annotate-display-mode)
3029 (= vc-annotate-display-mode ,days)) ])))))
99cb8c8b
SS
3030 (setq menu-def
3031 (append menu-def
75665141
AS
3032 (list
3033 ["Span ..."
99cb8c8b 3034 (let ((days
75665141
AS
3035 (float (string-to-number
3036 (read-string "Span how many days? ")))))
3037 (vc-annotate-display-select nil days)) t])
3038 (list "--")
99cb8c8b
SS
3039 (list
3040 ["Span to Oldest"
75665141
AS
3041 (unless (eq vc-annotate-display-mode 'scale)
3042 (vc-annotate-display-select nil 'scale))
99cb8c8b 3043 :style toggle :selected
75665141 3044 (eq vc-annotate-display-mode 'scale)])
99cb8c8b
SS
3045 (list
3046 ["Span Oldest->Newest"
75665141
AS
3047 (unless (eq vc-annotate-display-mode 'fullscale)
3048 (vc-annotate-display-select nil 'fullscale))
99cb8c8b 3049 :style toggle :selected
75665141
AS
3050 (eq vc-annotate-display-mode 'fullscale)])))
3051 ;; Define the menu
3052 (if (or (featurep 'easymenu) (load "easymenu" t))
99cb8c8b 3053 (easy-menu-define vc-annotate-mode-menu vc-annotate-mode-map
75665141
AS
3054 "VC Annotate Display Menu" menu-def))))
3055
3056(defun vc-annotate-display-select (&optional buffer mode)
6f1ecae4
AS
3057 "Highlight the output of \\[vc-annotate].
3058By default, the current buffer is highlighted, unless overridden by
3059BUFFER. `vc-annotate-display-mode' specifies the highlighting mode to
3060use; you may override this using the second optional arg MODE."
3061 (interactive)
75665141
AS
3062 (if mode (setq vc-annotate-display-mode mode))
3063 (when buffer
3064 (set-buffer buffer)
3065 (display-buffer buffer))
3066 (if (not vc-annotate-mode) ; Turn on vc-annotate-mode if not done
3067 (vc-annotate-mode))
99cb8c8b 3068 (cond ((null vc-annotate-display-mode) (vc-annotate-display-default
75665141
AS
3069 vc-annotate-ratio))
3070 ((symbolp vc-annotate-display-mode) ; One of the auto-scaling modes
3071 (cond ((eq vc-annotate-display-mode 'scale)
3072 (vc-annotate-display-autoscale))
99cb8c8b 3073 ((eq vc-annotate-display-mode 'fullscale)
75665141 3074 (vc-annotate-display-autoscale t))
99cb8c8b 3075 (t (error "No such display mode: %s"
75665141
AS
3076 vc-annotate-display-mode))))
3077 ((numberp vc-annotate-display-mode) ; A fixed number of days lookback
3078 (vc-annotate-display-default
99cb8c8b 3079 (/ vc-annotate-display-mode (vc-annotate-car-last-cons
75665141
AS
3080 vc-annotate-color-map))))
3081 (t (error "Error in display mode select"))))
0e362f54
GM
3082
3083;;;; (defun vc-BACKEND-annotate-command (file buffer) ...)
3084;;;; Execute "annotate" on FILE by using `call-process' and insert
3085;;;; the contents in BUFFER.
3086
7d2d9482 3087;;;###autoload
afe35502 3088(defun vc-annotate (prefix)
1cec418c
AS
3089 "Display the edit history of the current file using colours.
3090
3091This command creates a buffer that shows, for each line of the current
3092file, when it was last edited and by whom. Additionally, colours are
3093used to show the age of each line--blue means oldest, red means
3094youngest, and intermediate colours indicate intermediate ages. By
3095default, the time scale stretches back one year into the past;
3096everything that is older than that is shown in blue.
3097
3098With a prefix argument, this command asks two questions in the
3099minibuffer. First, you may enter a version number; then the buffer
3100displays and annotates that version instead of the current version
eb407e67 3101\(type RET in the minibuffer to leave that default unchanged). Then,
ecd50f65
AS
3102you are prompted for the time span in days which the color range
3103should cover. For example, a time span of 20 days means that changes
3104over the past 20 days are shown in red to blue, according to their
3105age, and everything that is older than that is shown in blue.
1cec418c
AS
3106
3107Customization variables:
7d2d9482
RS
3108
3109`vc-annotate-menu-elements' customizes the menu elements of the
3110mode-specific menu. `vc-annotate-color-map' and
3111`vc-annotate-very-old-color' defines the mapping of time to
3112colors. `vc-annotate-background' specifies the background color."
afe35502 3113 (interactive "P")
b6909007 3114 (vc-ensure-vc-buffer)
08eab195 3115 (let* ((temp-buffer-name (concat "*Annotate " (buffer-name) "*"))
75665141 3116 (temp-buffer-show-function 'vc-annotate-display-select)
08eab195 3117 (rev (vc-workfile-version (buffer-file-name)))
99cb8c8b
SS
3118 (vc-annotate-version
3119 (if prefix (read-string
3120 (format "Annotate from version: (default %s) " rev)
08eab195 3121 nil nil rev)
75665141 3122 rev)))
99cb8c8b 3123 (if prefix
75665141
AS
3124 (setq vc-annotate-display-mode
3125 (float (string-to-number
99cb8c8b 3126 (read-string "Annotate span days: (default 20) "
75665141
AS
3127 nil nil "20")))))
3128 (setq vc-annotate-backend (vc-backend (buffer-file-name)))
afe35502 3129 (message "Annotating...")
099bd78a
SM
3130 (if (not (vc-find-backend-function vc-annotate-backend 'annotate-command))
3131 (error "Sorry, annotating is not implemented for %s"
3132 vc-annotate-backend))
46e33aee 3133 (with-output-to-temp-buffer temp-buffer-name
0e362f54
GM
3134 (vc-call-backend vc-annotate-backend 'annotate-command
3135 (file-name-nondirectory (buffer-file-name))
afe35502
AS
3136 (get-buffer temp-buffer-name)
3137 vc-annotate-version))
0e362f54
GM
3138 ;; Don't use the temp-buffer-name until the buffer is created
3139 ;; (only after `with-output-to-temp-buffer'.)
6f41eeb5 3140 (setq vc-annotate-buffers
0e362f54 3141 (append vc-annotate-buffers
08eab195
AS
3142 (list (cons (get-buffer temp-buffer-name) vc-annotate-backend))))
3143 (message "Annotating... done")))
7d2d9482 3144
f70419a8
RS
3145(defun vc-annotate-car-last-cons (a-list)
3146 "Return car of last cons in association list A-LIST."
3147 (if (not (eq nil (cdr a-list)))
3148 (vc-annotate-car-last-cons (cdr a-list))
3149 (car (car a-list))))
3150
3151(defun vc-annotate-time-span (a-list span &optional quantize)
6f1ecae4 3152 "Apply factor SPAN to the time-span of association list A-LIST.
0e362f54
GM
3153Return the new alist.
3154Optionally quantize to the factor of QUANTIZE."
7d2d9482 3155 ;; Apply span to each car of every cons
0e362f54 3156 (if (not (eq nil a-list))
f70419a8
RS
3157 (append (list (cons (* (car (car a-list)) span)
3158 (cdr (car a-list))))
0e362f54
GM
3159 (vc-annotate-time-span (nthcdr (or quantize ; optional
3160 1) ; Default to cdr
f70419a8
RS
3161 a-list) span quantize))))
3162
3163(defun vc-annotate-compcar (threshold a-list)
6f1ecae4
AS
3164 "Test successive cons cells of A-LIST against THRESHOLD.
3165Return the first cons cell with a car that is not less than THRESHOLD,
3166nil if no such cell exists."
f70419a8
RS
3167 (let ((i 1)
3168 (tmp-cons (car a-list)))
3169 (while (and tmp-cons (< (car tmp-cons) threshold))
3170 (setq tmp-cons (car (nthcdr i a-list)))
3171 (setq i (+ i 1)))
3172 tmp-cons)) ; Return the appropriate value
3173
75665141 3174(defun vc-annotate-convert-time (time)
6f1ecae4
AS
3175 "Convert a time value to a floating-point number of days.
3176The argument TIME is a list as returned by `current-time' or
3177`encode-time', only the first two elements of that list are considered."
75665141
AS
3178 (/ (+ (* (float (car time)) (lsh 1 16)) (cadr time)) 24 3600))
3179
3180(defun vc-annotate-difference (&optional offset)
6f1ecae4
AS
3181 "Return the time span in days to the next annotation.
3182This calls the backend function annotate-time, and returns the
3183difference in days between the time returned and the current time,
3184or OFFSET if present."
75665141
AS
3185 (let ((next-time (vc-call-backend vc-annotate-backend 'annotate-time)))
3186 (if next-time
99cb8c8b 3187 (- (or offset
75665141
AS
3188 (vc-call-backend vc-annotate-backend 'annotate-current-time))
3189 next-time))))
3190
3191(defun vc-default-annotate-current-time (backend)
3192 "Return the current time, encoded as fractional days."
3193 (vc-annotate-convert-time (current-time)))
99cb8c8b 3194
75665141 3195(defun vc-annotate-display (&optional color-map offset)
6f1ecae4
AS
3196 "Highlight `vc-annotate' output in the current buffer.
3197COLOR-MAP, if present, overrides `vc-annotate-color-map'. The
3198annotations are relative to the current time, unless overridden by
3199OFFSET.
3200
3201This function is obsolete, and has been replaced by
3202`vc-annotate-select'."
75665141 3203 (save-excursion
0e362f54
GM
3204 (goto-char (point-min)) ; Position at the top of the buffer.
3205 ;; Delete old overlays
3206 (mapcar
3207 (lambda (overlay)
3208 (if (overlay-get overlay 'vc-annotation)
3209 (delete-overlay overlay)))
3210 (overlays-in (point-min) (point-max)))
3211 (goto-char (point-min)) ; Position at the top of the buffer.
75665141
AS
3212 (let (difference)
3213 (while (setq difference (vc-annotate-difference offset))
0e362f54
GM
3214 (let*
3215 ((color (or (vc-annotate-compcar
3216 difference (or color-map vc-annotate-color-map))
3217 (cons nil vc-annotate-very-old-color)))
3218 ;; substring from index 1 to remove any leading `#' in the name
3219 (face-name (concat "vc-annotate-face-" (substring (cdr color) 1)))
3220 ;; Make the face if not done.
3221 (face (or (intern-soft face-name)
3222 (let ((tmp-face (make-face (intern face-name))))
3223 (set-face-foreground tmp-face (cdr color))
3224 (if vc-annotate-background
99cb8c8b 3225 (set-face-background tmp-face
75665141 3226 vc-annotate-background))
0e362f54
GM
3227 tmp-face))) ; Return the face
3228 (point (point))
3229 overlay)
f70419a8 3230 (forward-line 1)
05dad1e6
AS
3231 (setq overlay (make-overlay point (point)))
3232 (overlay-put overlay 'face face)
75665141 3233 (overlay-put overlay 'vc-annotation t))))))
7d2d9482 3234\f
c6d4f628 3235;; Collect back-end-dependent stuff here
594722a8 3236
0e362f54 3237(defalias 'vc-default-logentry-check 'ignore)
594722a8 3238
594722a8
ER
3239(defun vc-check-headers ()
3240 "Check if the current file has any headers in it."
3241 (interactive)
0e362f54 3242 (vc-call-backend (vc-backend buffer-file-name) 'check-headers))
594722a8 3243
aae91380
AS
3244(defun vc-default-check-headers (backend)
3245 "Default implementation of check-headers; always returns nil."
3246 nil)
3247
594722a8
ER
3248;; Back-end-dependent stuff ends here.
3249
3250;; Set up key bindings for use while editing log messages
3251
099bd78a 3252(define-derived-mode vc-log-mode text-mode "VC-Log"
0e362f54 3253 "Major mode for editing VC log entries.
594722a8
ER
3254These bindings are added to the global keymap when you enter this mode:
3255\\[vc-next-action] perform next logical version-control operation on current file
0e362f54 3256\\[vc-register] register current file
594722a8
ER
3257\\[vc-insert-headers] insert version-control headers in current file
3258\\[vc-print-log] display change history of current file
3259\\[vc-revert-buffer] revert buffer to latest version
3260\\[vc-cancel-version] undo latest checkin
3261\\[vc-diff] show diffs between file versions
f1818994 3262\\[vc-version-other-window] visit old version in another window
594722a8 3263\\[vc-directory] show all files locked by any user in or below .
0e362f54 3264\\[vc-annotate] colorful display of the cvs annotate command
594722a8
ER
3265\\[vc-update-change-log] add change log entry from recent checkins
3266
3267While you are entering a change log message for a version, the following
3268additional bindings will be in effect.
3269
3270\\[vc-finish-logentry] proceed with check in, ending log message entry
3271
3272Whenever you do a checkin, your log comment is added to a ring of
3273saved comments. These can be recalled as follows:
3274
3275\\[vc-next-comment] replace region with next message in comment ring
3276\\[vc-previous-comment] replace region with previous message in comment ring
8c0aaf40
ER
3277\\[vc-comment-search-reverse] search backward for regexp in the comment ring
3278\\[vc-comment-search-forward] search backward for regexp in the comment ring
594722a8 3279
0e362f54
GM
3280Entry to the change-log submode calls the value of `text-mode-hook', then
3281the value of `vc-log-mode-hook'.
594722a8
ER
3282
3283Global user options:
0e362f54 3284 `vc-initial-comment' If non-nil, require user to enter a change
594722a8
ER
3285 comment upon first checkin of the file.
3286
0e362f54 3287 `vc-keep-workfiles' Non-nil value prevents workfiles from being
594722a8
ER
3288 deleted when changes are checked in
3289
c96da2b0 3290 `vc-suppress-confirm' Suppresses some confirmation prompts.
594722a8 3291
0e362f54 3292 vc-BACKEND-header Which keywords to insert when adding headers
594722a8 3293 with \\[vc-insert-headers]. Defaults to
0e362f54 3294 '(\"\%\W\%\") under SCCS, '(\"\$Id\$\") under
80688f5c 3295 RCS and CVS.
594722a8 3296
0e362f54 3297 `vc-static-header-alist' By default, version headers inserted in C files
594722a8 3298 get stuffed in a static string area so that
80688f5c
RS
3299 ident(RCS/CVS) or what(SCCS) can see them in
3300 the compiled object code. You can override
3301 this by setting this variable to nil, or change
594722a8
ER
3302 the header template by changing it.
3303
0e362f54 3304 `vc-command-messages' if non-nil, display run messages from the
594722a8
ER
3305 actual version-control utilities (this is
3306 intended primarily for people hacking vc
099bd78a
SM
3307 itself)."
3308 (make-local-variable 'vc-comment-ring-index))
0e362f54
GM
3309
3310(defun vc-log-edit (file)
099bd78a
SM
3311 "Set up `log-edit' for use with VC on FILE.
3312If `log-edit' is not available, resort to `vc-log-mode'."
3313 (setq default-directory
3314 (if file (file-name-directory file)
3315 (with-current-buffer vc-parent-buffer default-directory)))
3316 (if (fboundp 'log-edit)
3317 (log-edit 'vc-finish-logentry nil
3318 (if file `(lambda () ',(list (file-name-nondirectory file)))
3319 ;; If FILE is nil, we were called from vc-dired.
3320 (lambda ()
3321 (with-current-buffer vc-parent-buffer
3322 (dired-get-marked-files t)))))
3323 (vc-log-mode))
0e362f54
GM
3324 (set (make-local-variable 'vc-log-file) file)
3325 (make-local-variable 'vc-log-version)
099bd78a 3326 (set-buffer-modified-p nil)
0e362f54 3327 (setq buffer-file-name nil))
594722a8 3328
ec402ad4 3329;; These things should probably be generally available
594722a8 3330
2f119435
AS
3331(defun vc-file-tree-walk (dirname func &rest args)
3332 "Walk recursively through DIRNAME.
0e362f54 3333Invoke FUNC f ARGS on each VC-managed file f underneath it."
2f119435
AS
3334 (vc-file-tree-walk-internal (expand-file-name dirname) func args)
3335 (message "Traversing directory %s...done" dirname))
02da6253
PE
3336
3337(defun vc-file-tree-walk-internal (file func args)
3338 (if (not (file-directory-p file))
0e362f54 3339 (if (vc-backend file) (apply func file args))
993a1a44 3340 (message "Traversing directory %s..." (abbreviate-file-name file))
02da6253
PE
3341 (let ((dir (file-name-as-directory file)))
3342 (mapcar
0e362f54
GM
3343 (lambda (f) (or
3344 (string-equal f ".")
3345 (string-equal f "..")
3346 (member f vc-directory-exclusion-list)
3347 (let ((dirf (expand-file-name f dir)))
3348 (or
3349 (file-symlink-p dirf);; Avoid possible loops
3350 (vc-file-tree-walk-internal dirf func args)))))
02da6253 3351 (directory-files dir)))))
594722a8
ER
3352
3353(provide 'vc)
3354
ec402ad4
SM
3355;; DEVELOPER'S NOTES ON CONCURRENCY PROBLEMS IN THIS CODE
3356;;
ec402ad4
SM
3357;; These may be useful to anyone who has to debug or extend the package.
3358;; (Note that this information corresponds to versions 5.x. Some of it
3359;; might have been invalidated by the additions to support branching
3360;; and RCS keyword lookup. AS, 1995/03/24)
3361;;
3362;; A fundamental problem in VC is that there are time windows between
3363;; vc-next-action's computations of the file's version-control state and
3364;; the actions that change it. This is a window open to lossage in a
3365;; multi-user environment; someone else could nip in and change the state
3366;; of the master during it.
3367;;
3368;; The performance problem is that rlog/prs calls are very expensive; we want
3369;; to avoid them as much as possible.
3370;;
3371;; ANALYSIS:
3372;;
3373;; The performance problem, it turns out, simplifies in practice to the
3374;; problem of making vc-state fast. The two other functions that call
3375;; prs/rlog will not be so commonly used that the slowdown is a problem; one
3376;; makes snapshots, the other deletes the calling user's last change in the
3377;; master.
3378;;
3379;; The race condition implies that we have to either (a) lock the master
3380;; during the entire execution of vc-next-action, or (b) detect and
3381;; recover from errors resulting from dispatch on an out-of-date state.
3382;;
3383;; Alternative (a) appears to be infeasible. The problem is that we can't
3384;; guarantee that the lock will ever be removed. Suppose a user starts a
3385;; checkin, the change message buffer pops up, and the user, having wandered
3386;; off to do something else, simply forgets about it?
3387;;
3388;; Alternative (b), on the other hand, works well with a cheap way to speed up
3389;; vc-state. Usually, if a file is registered, we can read its locked/
3390;; unlocked state and its current owner from its permissions.
3391;;
3392;; This shortcut will fail if someone has manually changed the workfile's
3393;; permissions; also if developers are munging the workfile in several
3394;; directories, with symlinks to a master (in this latter case, the
3395;; permissions shortcut will fail to detect a lock asserted from another
3396;; directory).
3397;;
3398;; Note that these cases correspond exactly to the errors which could happen
3399;; because of a competing checkin/checkout race in between two instances of
3400;; vc-next-action.
3401;;
3402;; For VC's purposes, a workfile/master pair may have the following states:
3403;;
3404;; A. Unregistered. There is a workfile, there is no master.
3405;;
3406;; B. Registered and not locked by anyone.
3407;;
3408;; C. Locked by calling user and unchanged.
3409;;
3410;; D. Locked by the calling user and changed.
3411;;
3412;; E. Locked by someone other than the calling user.
3413;;
3414;; This makes for 25 states and 20 error conditions. Here's the matrix:
3415;;
3416;; VC's idea of state
3417;; |
3418;; V Actual state RCS action SCCS action Effect
3419;; A B C D E
3420;; A . 1 2 3 4 ci -u -t- admin -fb -i<file> initial admin
3421;; B 5 . 6 7 8 co -l get -e checkout
3422;; C 9 10 . 11 12 co -u unget; get revert
3423;; D 13 14 15 . 16 ci -u -m<comment> delta -y<comment>; get checkin
3424;; E 17 18 19 20 . rcs -u -M -l unget -n ; get -g steal lock
3425;;
3426;; All commands take the master file name as a last argument (not shown).
3427;;
3428;; In the discussion below, a "self-race" is a pathological situation in
3429;; which VC operations are being attempted simultaneously by two or more
3430;; Emacsen running under the same username.
3431;;
3432;; The vc-next-action code has the following windows:
3433;;
3434;; Window P:
3435;; Between the check for existence of a master file and the call to
3436;; admin/checkin in vc-buffer-admin (apparent state A). This window may
3437;; never close if the initial-comment feature is on.
3438;;
3439;; Window Q:
3440;; Between the call to vc-workfile-unchanged-p in and the immediately
3441;; following revert (apparent state C).
3442;;
3443;; Window R:
3444;; Between the call to vc-workfile-unchanged-p in and the following
3445;; checkin (apparent state D). This window may never close.
3446;;
3447;; Window S:
3448;; Between the unlock and the immediately following checkout during a
3449;; revert operation (apparent state C). Included in window Q.
3450;;
3451;; Window T:
3452;; Between vc-state and the following checkout (apparent state B).
3453;;
3454;; Window U:
3455;; Between vc-state and the following revert (apparent state C).
3456;; Includes windows Q and S.
3457;;
3458;; Window V:
3459;; Between vc-state and the following checkin (apparent state
3460;; D). This window may never be closed if the user fails to complete the
3461;; checkin message. Includes window R.
3462;;
3463;; Window W:
3464;; Between vc-state and the following steal-lock (apparent
3465;; state E). This window may never close if the user fails to complete
3466;; the steal-lock message. Includes window X.
3467;;
3468;; Window X:
3469;; Between the unlock and the immediately following re-lock during a
3470;; steal-lock operation (apparent state E). This window may never close
3471;; if the user fails to complete the steal-lock message.
3472;;
3473;; Errors:
3474;;
3475;; Apparent state A ---
3476;;
3477;; 1. File looked unregistered but is actually registered and not locked.
3478;;
3479;; Potential cause: someone else's admin during window P, with
3480;; caller's admin happening before their checkout.
3481;;
3482;; RCS: Prior to version 5.6.4, ci fails with message
3483;; "no lock set by <user>". From 5.6.4 onwards, VC uses the new
3484;; ci -i option and the message is "<file>,v: already exists".
3485;; SCCS: admin will fail with error (ad19).
3486;;
3487;; We can let these errors be passed up to the user.
3488;;
3489;; 2. File looked unregistered but is actually locked by caller, unchanged.
3490;;
3491;; Potential cause: self-race during window P.
3492;;
3493;; RCS: Prior to version 5.6.4, reverts the file to the last saved
3494;; version and unlocks it. From 5.6.4 onwards, VC uses the new
3495;; ci -i option, failing with message "<file>,v: already exists".
3496;; SCCS: will fail with error (ad19).
3497;;
3498;; Either of these consequences is acceptable.
3499;;
3500;; 3. File looked unregistered but is actually locked by caller, changed.
3501;;
3502;; Potential cause: self-race during window P.
3503;;
3504;; RCS: Prior to version 5.6.4, VC registers the caller's workfile as
3505;; a delta with a null change comment (the -t- switch will be
3506;; ignored). From 5.6.4 onwards, VC uses the new ci -i option,
3507;; failing with message "<file>,v: already exists".
3508;; SCCS: will fail with error (ad19).
3509;;
3510;; 4. File looked unregistered but is locked by someone else.
0e362f54 3511;;;
ec402ad4
SM
3512;; Potential cause: someone else's admin during window P, with
3513;; caller's admin happening *after* their checkout.
3514;;
3515;; RCS: Prior to version 5.6.4, ci fails with a
3516;; "no lock set by <user>" message. From 5.6.4 onwards,
3517;; VC uses the new ci -i option, failing with message
3518;; "<file>,v: already exists".
3519;; SCCS: will fail with error (ad19).
3520;;
3521;; We can let these errors be passed up to the user.
3522;;
3523;; Apparent state B ---
3524;;
3525;; 5. File looked registered and not locked, but is actually unregistered.
3526;;
3527;; Potential cause: master file got nuked during window P.
3528;;
3529;; RCS: will fail with "RCS/<file>: No such file or directory"
3530;; SCCS: will fail with error ut4.
3531;;
3532;; We can let these errors be passed up to the user.
3533;;
3534;; 6. File looked registered and not locked, but is actually locked by the
3535;; calling user and unchanged.
3536;;
3537;; Potential cause: self-race during window T.
3538;;
3539;; RCS: in the same directory as the previous workfile, co -l will fail
3540;; with "co error: writable foo exists; checkout aborted". In any other
3541;; directory, checkout will succeed.
3542;; SCCS: will fail with ge17.
3543;;
3544;; Either of these consequences is acceptable.
3545;;
3546;; 7. File looked registered and not locked, but is actually locked by the
3547;; calling user and changed.
3548;;
3549;; As case 6.
3550;;
3551;; 8. File looked registered and not locked, but is actually locked by another
3552;; user.
3553;;
3554;; Potential cause: someone else checks it out during window T.
3555;;
3556;; RCS: co error: revision 1.3 already locked by <user>
3557;; SCCS: fails with ge4 (in directory) or ut7 (outside it).
3558;;
3559;; We can let these errors be passed up to the user.
3560;;
3561;; Apparent state C ---
3562;;
3563;; 9. File looks locked by calling user and unchanged, but is unregistered.
3564;;
3565;; As case 5.
3566;;
3567;; 10. File looks locked by calling user and unchanged, but is actually not
3568;; locked.
3569;;
3570;; Potential cause: a self-race in window U, or by the revert's
3571;; landing during window X of some other user's steal-lock or window S
3572;; of another user's revert.
3573;;
3574;; RCS: succeeds, refreshing the file from the identical version in
3575;; the master.
3576;; SCCS: fails with error ut4 (p file nonexistent).
3577;;
3578;; Either of these consequences is acceptable.
3579;;
3580;; 11. File is locked by calling user. It looks unchanged, but is actually
3581;; changed.
3582;;
3583;; Potential cause: the file would have to be touched by a self-race
3584;; during window Q.
3585;;
3586;; The revert will succeed, removing whatever changes came with
3587;; the touch. It is theoretically possible that work could be lost.
3588;;
3589;; 12. File looks like it's locked by the calling user and unchanged, but
3590;; it's actually locked by someone else.
3591;;
3592;; Potential cause: a steal-lock in window V.
3593;;
3594;; RCS: co error: revision <rev> locked by <user>; use co -r or rcs -u
3595;; SCCS: fails with error un2
3596;;
3597;; We can pass these errors up to the user.
3598;;
3599;; Apparent state D ---
3600;;
3601;; 13. File looks like it's locked by the calling user and changed, but it's
3602;; actually unregistered.
3603;;
3604;; Potential cause: master file got nuked during window P.
3605;;
3606;; RCS: Prior to version 5.6.4, checks in the user's version as an
3607;; initial delta. From 5.6.4 onwards, VC uses the new ci -j
3608;; option, failing with message "no such file or directory".
3609;; SCCS: will fail with error ut4.
3610;;
3611;; This case is kind of nasty. Under RCS prior to version 5.6.4,
3612;; VC may fail to detect the loss of previous version information.
3613;;
3614;; 14. File looks like it's locked by the calling user and changed, but it's
3615;; actually unlocked.
3616;;
3617;; Potential cause: self-race in window V, or the checkin happening
3618;; during the window X of someone else's steal-lock or window S of
3619;; someone else's revert.
3620;;
3621;; RCS: ci will fail with "no lock set by <user>".
3622;; SCCS: delta will fail with error ut4.
3623;;
3624;; 15. File looks like it's locked by the calling user and changed, but it's
3625;; actually locked by the calling user and unchanged.
3626;;
3627;; Potential cause: another self-race --- a whole checkin/checkout
3628;; sequence by the calling user would have to land in window R.
3629;;
3630;; SCCS: checks in a redundant delta and leaves the file unlocked as usual.
3631;; RCS: reverts to the file state as of the second user's checkin, leaving
3632;; the file unlocked.
3633;;
3634;; It is theoretically possible that work could be lost under RCS.
3635;;
3636;; 16. File looks like it's locked by the calling user and changed, but it's
3637;; actually locked by a different user.
3638;;
3639;; RCS: ci error: no lock set by <user>
3640;; SCCS: unget will fail with error un2
3641;;
3642;; We can pass these errors up to the user.
3643;;
3644;; Apparent state E ---
3645;;
3646;; 17. File looks like it's locked by some other user, but it's actually
3647;; unregistered.
3648;;
3649;; As case 13.
3650;;
3651;; 18. File looks like it's locked by some other user, but it's actually
3652;; unlocked.
3653;;
3654;; Potential cause: someone released a lock during window W.
3655;;
3656;; RCS: The calling user will get the lock on the file.
3657;; SCCS: unget -n will fail with cm4.
3658;;
3659;; Either of these consequences will be OK.
3660;;
3661;; 19. File looks like it's locked by some other user, but it's actually
3662;; locked by the calling user and unchanged.
3663;;
3664;; Potential cause: the other user relinquishing a lock followed by
3665;; a self-race, both in window W.
3666;;
3667;; Under both RCS and SCCS, both unlock and lock will succeed, making
3668;; the sequence a no-op.
3669;;
3670;; 20. File looks like it's locked by some other user, but it's actually
3671;; locked by the calling user and changed.
3672;;
3673;; As case 19.
3674;;
3675;; PROBLEM CASES:
3676;;
3677;; In order of decreasing severity:
3678;;
3679;; Cases 11 and 15 are the only ones that potentially lose work.
3680;; They would require a self-race for this to happen.
3681;;
3682;; Case 13 in RCS loses information about previous deltas, retaining
3683;; only the information in the current workfile. This can only happen
3684;; if the master file gets nuked in window P.
3685;;
3686;; Case 3 in RCS and case 15 under SCCS insert a redundant delta with
3687;; no change comment in the master. This would require a self-race in
3688;; window P or R respectively.
3689;;
3690;; Cases 2, 10, 19 and 20 do extra work, but make no changes.
3691;;
3692;; Unfortunately, it appears to me that no recovery is possible in these
3693;; cases. They don't yield error messages, so there's no way to tell that
3694;; a race condition has occurred.
3695;;
3696;; All other cases don't change either the workfile or the master, and
3697;; trigger command errors which the user will see.
3698;;
3699;; Thus, there is no explicit recovery code.
594722a8
ER
3700
3701;;; vc.el ends here