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