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