(init_eval_once): Bump max_lisp_eval_depth to 400.
[bpt/emacs.git] / lisp / vc-hooks.el
CommitLineData
aae56ea7 1;;; vc-hooks.el --- resident support for version-control
594722a8 2
c90f2757 3;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
d7a0267c 4;; 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
594722a8 5
0e0d9831
GM
6;; Author: FSF (see vc.el for full credits)
7;; Maintainer: Andre Spiegel <spiegel@gnu.org>
594722a8 8
ce9f8ffb 9;; $Id$
f4c72097 10
594722a8
ER
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
b578f267 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
ER
27
28;;; Commentary:
29
0e0d9831
GM
30;; This is the always-loaded portion of VC. It takes care of
31;; VC-related activities that are done when you visit a file, so that
32;; vc.el itself is loaded only when you use a VC command. See the
33;; commentary of vc.el.
594722a8
ER
34
35;;; Code:
36
c3ce5e29
AS
37(eval-when-compile
38 (require 'cl))
099bd78a 39
e1c0c2d1
KH
40;; Customization Variables (the rest is in vc.el)
41
e18cf2ee 42(defvar vc-ignore-vc-files nil)
5499f9dc 43(make-obsolete-variable 'vc-ignore-vc-files
3dab70bf 44 "set `vc-handled-backends' to nil to disable VC.")
5499f9dc 45
e18cf2ee 46(defvar vc-master-templates ())
0d2ce4ef
JB
47(make-obsolete-variable 'vc-master-templates
48 "to define master templates for a given BACKEND, use
5499f9dc 49vc-BACKEND-master-templates. To enable or disable VC for a given
3dab70bf 50BACKEND, use `vc-handled-backends'.")
5499f9dc 51
e18cf2ee
JB
52(defvar vc-header-alist ())
53(make-obsolete-variable 'vc-header-alist 'vc-BACKEND-header)
0e0d9831 54
456e749f
SM
55(defcustom vc-ignore-dir-regexp
56 ;; Stop SMB, automounter, AFS, and DFS host lookups.
57 "\\`\\(?:[\\/][\\/]\\|/\\(?:net\\|afs\\|\\.\\\.\\.\\)/\\)\\'"
43621386 58 "Regexp matching directory names that are not under VC's control.
ce9f8ffb
SM
59The default regexp prevents fruitless and time-consuming attempts
60to determine the VC status in directories in which filenames are
43621386
SM
61interpreted as hostnames."
62 :type 'regexp
63 :group 'vc)
ce9f8ffb 64
c2ba4a6b 65(defcustom vc-handled-backends '(RCS CVS SVN SCCS HG Arch MCVS)
b8d1db77 66 ;; Arch and MCVS come last because they are per-tree rather than per-dir.
0e0d9831
GM
67 "*List of version control backends for which VC will be used.
68Entries in this list will be tried in order to determine whether a
69file is under that sort of version control.
70Removing an entry from the list prevents VC from being activated
71when visiting a file managed by that backend.
72An empty list disables VC altogether."
73 :type '(repeat symbol)
099bd78a 74 :version "21.1"
50bec091 75 :group 'vc)
31888047 76
50bec091 77(defcustom vc-path
e1c0c2d1
KH
78 (if (file-directory-p "/usr/sccs")
79 '("/usr/sccs")
80 nil)
50bec091
KH
81 "*List of extra directories to search for version control commands."
82 :type '(repeat directory)
83 :group 'vc)
e1c0c2d1 84
50bec091 85(defcustom vc-make-backup-files nil
5032bd23 86 "*If non-nil, backups of registered files are made as with other files.
50bec091
KH
87If nil (the default), files covered by version control don't get backups."
88 :type 'boolean
8f383484
DL
89 :group 'vc
90 :group 'backup)
594722a8 91
50bec091 92(defcustom vc-follow-symlinks 'ask
0e0d9831
GM
93 "*What to do if visiting a symbolic link to a file under version control.
94Editing such a file through the link bypasses the version control system,
95which is dangerous and probably not what you want.
96
97If this variable is t, VC follows the link and visits the real file,
b8063212
AS
98telling you about it in the echo area. If it is `ask', VC asks for
99confirmation whether it should follow the link. If nil, the link is
50bec091 100visited and a warning displayed."
0e0d9831
GM
101 :type '(choice (const :tag "Ask for confirmation" ask)
102 (const :tag "Visit link and warn" nil)
103 (const :tag "Follow link" t))
50bec091 104 :group 'vc)
b8063212 105
50bec091 106(defcustom vc-display-status t
624c0e9d 107 "*If non-nil, display revision number and lock status in modeline.
50bec091
KH
108Otherwise, not displayed."
109 :type 'boolean
110 :group 'vc)
111
198d5c00 112
50bec091
KH
113(defcustom vc-consult-headers t
114 "*If non-nil, identify work files by searching for version headers."
115 :type 'boolean
116 :group 'vc)
e1c0c2d1 117
50bec091 118(defcustom vc-keep-workfiles t
e1c0c2d1
KH
119 "*If non-nil, don't delete working files after registering changes.
120If the back-end is CVS, workfiles are always kept, regardless of the
50bec091
KH
121value of this flag."
122 :type 'boolean
123 :group 'vc)
e1c0c2d1 124
50bec091 125(defcustom vc-mistrust-permissions nil
0e0d9831
GM
126 "*If non-nil, don't assume permissions/ownership track version-control status.
127If nil, do rely on the permissions.
50bec091
KH
128See also variable `vc-consult-headers'."
129 :type 'boolean
130 :group 'vc)
e66eac08
AS
131
132(defun vc-mistrust-permissions (file)
0e0d9831 133 "Internal access function to variable `vc-mistrust-permissions' for FILE."
e66eac08
AS
134 (or (eq vc-mistrust-permissions 't)
135 (and vc-mistrust-permissions
0e0d9831 136 (funcall vc-mistrust-permissions
e66eac08
AS
137 (vc-backend-subdirectory-name file)))))
138
113414a9
SM
139(defcustom vc-stay-local t
140 "*Non-nil means use local operations when possible for remote repositories.
141This avoids slow queries over the network and instead uses heuristics
142and past information to determine the current status of a file.
143
144The value can also be a regular expression or list of regular
145expressions to match against the host name of a repository; then VC
146only stays local for hosts that match it. Alternatively, the value
147can be a list of regular expressions where the first element is the
148symbol `except'; then VC always stays local except for hosts matched
149by these regular expressions."
150 :type '(choice (const :tag "Always stay local" t)
151 (const :tag "Don't stay local" nil)
152 (list :format "\nExamine hostname and %v" :tag "Examine hostname ..."
153 (set :format "%v" :inline t (const :format "%t" :tag "don't" except))
154 (regexp :format " stay local,\n%t: %v" :tag "if it matches")
155 (repeat :format "%v%i\n" :inline t (regexp :tag "or"))))
bf247b6e 156 :version "22.1"
113414a9
SM
157 :group 'vc)
158
159(defun vc-stay-local-p (file)
160 "Return non-nil if VC should stay local when handling FILE.
161This uses the `repository-hostname' backend operation."
162 (let* ((backend (vc-backend file))
163 (sym (vc-make-backend-sym backend 'stay-local))
164 (stay-local (if (boundp sym) (symbol-value sym) t)))
165 (if (eq stay-local t) (setq stay-local vc-stay-local))
166 (if (symbolp stay-local) stay-local
167 (let ((dirname (if (file-directory-p file)
168 (directory-file-name file)
169 (file-name-directory file))))
170 (eq 'yes
171 (or (vc-file-getprop dirname 'vc-stay-local-p)
172 (vc-file-setprop
173 dirname 'vc-stay-local-p
174 (let ((hostname (vc-call-backend
175 backend 'repository-hostname dirname)))
176 (if (not hostname)
177 'no
178 (let ((default t))
179 (if (eq (car-safe stay-local) 'except)
180 (setq default nil stay-local (cdr stay-local)))
181 (when (consp stay-local)
182 (setq stay-local
183 (mapconcat 'identity stay-local "\\|")))
184 (if (if (string-match stay-local hostname)
185 default (not default))
186 'yes 'no)))))))))))
187
9bd06e95 188;;; This is handled specially now.
594722a8 189;; Tell Emacs about this new kind of minor mode
9bd06e95 190;; (add-to-list 'minor-mode-alist '(vc-mode vc-mode))
594722a8 191
7bc2b98b 192(make-variable-buffer-local 'vc-mode)
c43e436c 193(put 'vc-mode 'permanent-local t)
594722a8 194
14fef9de
SM
195(defun vc-mode (&optional arg)
196 ;; Dummy function for C-h m
197 "Version Control minor mode.
198This minor mode is automatically activated whenever you visit a file under
199control of one of the revision control systems in `vc-handled-backends'.
200VC commands are globally reachable under the prefix `\\[vc-prefix-map]':
201\\{vc-prefix-map}")
202
099bd78a 203(defmacro vc-error-occurred (&rest body)
becd6193 204 `(condition-case nil (progn ,@body nil) (error t)))
099bd78a 205
594722a8 206;; We need a notion of per-file properties because the version
f2ee4191 207;; control state of a file is expensive to derive --- we compute
0e0d9831 208;; them when the file is initially found, keep them up to date
f2ee4191
RS
209;; during any subsequent VC operations, and forget them when
210;; the buffer is killed.
594722a8 211
becd6193 212(defvar vc-file-prop-obarray (make-vector 17 0)
594722a8
ER
213 "Obarray for per-file properties.")
214
099bd78a
SM
215(defvar vc-touched-properties nil)
216
594722a8 217(defun vc-file-setprop (file property value)
0e0d9831 218 "Set per-file VC PROPERTY for FILE to VALUE."
099bd78a
SM
219 (if (and vc-touched-properties
220 (not (memq property vc-touched-properties)))
221 (setq vc-touched-properties (append (list property)
222 vc-touched-properties)))
594722a8
ER
223 (put (intern file vc-file-prop-obarray) property value))
224
225(defun vc-file-getprop (file property)
099bd78a 226 "Get per-file VC PROPERTY for FILE."
594722a8
ER
227 (get (intern file vc-file-prop-obarray) property))
228
e1c0c2d1 229(defun vc-file-clearprops (file)
0e0d9831 230 "Clear all VC properties of FILE."
e1c0c2d1 231 (setplist (intern file vc-file-prop-obarray) nil))
f2ee4191 232
0e0d9831
GM
233\f
234;; We keep properties on each symbol naming a backend as follows:
235;; * `vc-functions': an alist mapping vc-FUNCTION to vc-BACKEND-FUNCTION.
236
237(defun vc-make-backend-sym (backend sym)
238 "Return BACKEND-specific version of VC symbol SYM."
239 (intern (concat "vc-" (downcase (symbol-name backend))
240 "-" (symbol-name sym))))
241
242(defun vc-find-backend-function (backend fun)
243 "Return BACKEND-specific implementation of FUN.
f8b72742 244If there is no such implementation, return the default implementation;
0e0d9831
GM
245if that doesn't exist either, return nil."
246 (let ((f (vc-make-backend-sym backend fun)))
247 (if (fboundp f) f
248 ;; Load vc-BACKEND.el if needed.
249 (require (intern (concat "vc-" (downcase (symbol-name backend)))))
250 (if (fboundp f) f
251 (let ((def (vc-make-backend-sym 'default fun)))
252 (if (fboundp def) (cons def backend) nil))))))
253
254(defun vc-call-backend (backend function-name &rest args)
255 "Call for BACKEND the implementation of FUNCTION-NAME with the given ARGS.
256Calls
257
258 (apply 'vc-BACKEND-FUN ARGS)
259
260if vc-BACKEND-FUN exists (after trying to find it in vc-BACKEND.el)
261and else calls
262
263 (apply 'vc-default-FUN BACKEND ARGS)
264
265It is usually called via the `vc-call' macro."
0bfb74a9
SM
266 (let ((f (assoc function-name (get backend 'vc-functions))))
267 (if f (setq f (cdr f))
0e0d9831 268 (setq f (vc-find-backend-function backend function-name))
0bfb74a9
SM
269 (push (cons function-name f) (get backend 'vc-functions)))
270 (cond
271 ((null f)
272 (error "Sorry, %s is not implemented for %s" function-name backend))
273 ((consp f) (apply (car f) (cdr f) args))
274 (t (apply f args)))))
0e0d9831
GM
275
276(defmacro vc-call (fun file &rest args)
277 ;; BEWARE!! `file' is evaluated twice!!
278 `(vc-call-backend (vc-backend ,file) ',fun ,file ,@args))
0e0d9831
GM
279\f
280(defsubst vc-parse-buffer (pattern i)
281 "Find PATTERN in the current buffer and return its Ith submatch."
282 (goto-char (point-min))
283 (if (re-search-forward pattern nil t)
284 (match-string i)))
e1c0c2d1 285
02d383eb 286(defun vc-insert-file (file &optional limit blocksize)
0e0d9831
GM
287 "Insert the contents of FILE into the current buffer.
288
289Optional argument LIMIT is a regexp. If present, the file is inserted
290in chunks of size BLOCKSIZE (default 8 kByte), until the first
f8b72742 291occurrence of LIMIT is found. Anything from the start of that occurrence
e30140ce
AS
292to the end of the buffer is then deleted. The function returns
293non-nil if FILE exists and its contents were successfully inserted."
07de4c3d 294 (erase-buffer)
ff40374a
AS
295 (when (file-exists-p file)
296 (if (not limit)
297 (insert-file-contents file)
298 (if (not blocksize) (setq blocksize 8192))
4d2806e2
SM
299 (let ((filepos 0))
300 (while
301 (and (< 0 (cadr (insert-file-contents
302 file nil filepos (incf filepos blocksize))))
303 (progn (beginning-of-line)
e30140ce
AS
304 (let ((pos (re-search-forward limit nil 'move)))
305 (if pos (delete-region (match-beginning 0)
306 (point-max)))
307 (not pos)))))))
ff40374a
AS
308 (set-buffer-modified-p nil)
309 t))
02d383eb 310
ce9f8ffb
SM
311(defun vc-find-root (file witness)
312 "Find the root of a checked out project.
313The function walks up the directory tree from FILE looking for WITNESS.
314If WITNESS if not found, return nil, otherwise return the root."
43621386
SM
315 ;; Represent /home/luser/foo as ~/foo so that we don't try to look for
316 ;; witnesses in /home or in /.
317 (setq file (abbreviate-file-name file))
6e94b3b6
GM
318 (let ((root nil)
319 (user (nth 2 (file-attributes file))))
ce9f8ffb
SM
320 (while (not (or root
321 (equal file (setq file (file-name-directory file)))
322 (null file)
6e94b3b6
GM
323 ;; As a heuristic, we stop looking up the hierarchy of
324 ;; directories as soon as we find a directory belonging
325 ;; to another user. This should save us from looking in
326 ;; things like /net and /afs. This assumes that all the
327 ;; files inside a project belong to the same user.
fdabbcb5 328 (not (equal user (nth 2 (file-attributes file))))
ce9f8ffb
SM
329 (string-match vc-ignore-dir-regexp file)))
330 (if (file-exists-p (expand-file-name witness file))
331 (setq root file)
332 (setq file (directory-file-name file))))
333 root))
334
14fef9de
SM
335;; Access functions to file properties
336;; (Properties should be _set_ using vc-file-setprop, but
337;; _retrieved_ only through these functions, which decide
338;; if the property is already known or not. A property should
339;; only be retrieved by vc-file-getprop if there is no
340;; access function.)
02d383eb 341
14fef9de 342;; properties indicating the backend being used for FILE
e1c0c2d1 343
0e0d9831
GM
344(defun vc-registered (file)
345 "Return non-nil if FILE is registered in a version control system.
346
1f22ad24
AS
347This function performs the check each time it is called. To rely
348on the result of a previous call, use `vc-backend' instead. If the
349file was previously registered under a certain backend, then that
350backend is tried first."
0e0d9831 351 (let (handler)
ce9f8ffb
SM
352 (cond
353 ((string-match vc-ignore-dir-regexp (file-name-directory file)) nil)
354 ((and (boundp 'file-name-handler-alist)
355 (setq handler (find-file-name-handler file 'vc-registered)))
356 ;; handler should set vc-backend and return t if registered
357 (funcall handler 'vc-registered file))
358 (t
0e0d9831
GM
359 ;; There is no file name handler.
360 ;; Try vc-BACKEND-registered for each handled BACKEND.
361 (catch 'found
1f22ad24
AS
362 (let ((backend (vc-file-getprop file 'vc-backend)))
363 (mapcar
364 (lambda (b)
365 (and (vc-call-backend b 'registered file)
366 (vc-file-setprop file 'vc-backend b)
367 (throw 'found t)))
f8b72742 368 (if (or (not backend) (eq backend 'none))
1f22ad24
AS
369 vc-handled-backends
370 (cons backend vc-handled-backends))))
0e0d9831
GM
371 ;; File is not registered.
372 (vc-file-setprop file 'vc-backend 'none)
ce9f8ffb 373 nil)))))
0e0d9831
GM
374
375(defun vc-backend (file)
376 "Return the version control type of FILE, nil if it is not registered."
377 ;; `file' can be nil in several places (typically due to the use of
5232a436 378 ;; code like (vc-backend buffer-file-name)).
0e0d9831
GM
379 (when (stringp file)
380 (let ((property (vc-file-getprop file 'vc-backend)))
381 ;; Note that internally, Emacs remembers unregistered
382 ;; files by setting the property to `none'.
383 (cond ((eq property 'none) nil)
384 (property)
385 ;; vc-registered sets the vc-backend property
386 (t (if (vc-registered file)
387 (vc-file-getprop file 'vc-backend)
388 nil))))))
389
390(defun vc-backend-subdirectory-name (file)
391 "Return where the master and lock FILEs for the current directory are kept."
392 (symbol-name (vc-backend file)))
e1c0c2d1 393
02d383eb 394(defun vc-name (file)
5eb2b516
DL
395 "Return the master name of FILE.
396If the file is not registered, or the master name is not known, return nil."
397 ;; TODO: This should ultimately become obsolete, at least up here
0e0d9831 398 ;; in vc-hooks.
02d383eb 399 (or (vc-file-getprop file 'vc-name)
64341022
AS
400 ;; force computation of the property by calling
401 ;; vc-BACKEND-registered explicitly
402 (if (and (vc-backend file)
403 (vc-call-backend (vc-backend file) 'registered file))
8aa81ea8 404 (vc-file-getprop file 'vc-name))))
e1c0c2d1 405
04446ed0 406(defun vc-checkout-model (file)
0e0d9831
GM
407 "Indicate how FILE is checked out.
408
cb5af02a
AS
409If FILE is not registered, this function always returns nil.
410For registered files, the possible values are:
0e0d9831 411
cb5af02a 412 'implicit FILE is always writeable, and checked out `implicitly'
0e0d9831
GM
413 when the user saves the first changes to the file.
414
cb5af02a 415 'locking FILE is read-only if up-to-date; user must type
db8afaee 416 \\[vc-next-action] before editing. Strict locking
0e0d9831
GM
417 is assumed.
418
cb5af02a 419 'announce FILE is read-only if up-to-date; user must type
db8afaee 420 \\[vc-next-action] before editing. But other users
0e0d9831
GM
421 may be editing at the same time."
422 (or (vc-file-getprop file 'vc-checkout-model)
cb5af02a
AS
423 (if (vc-backend file)
424 (vc-file-setprop file 'vc-checkout-model
425 (vc-call checkout-model file)))))
7064821c 426
8d2b9c1a
AS
427(defun vc-user-login-name (file)
428 "Return the name under which the user accesses the given FILE."
429 (or (and (eq (string-match tramp-file-name-regexp file) 0)
430 ;; tramp case: execute "whoami" via tramp
431 (let ((default-directory (file-name-directory file)))
432 (with-temp-buffer
433 (if (not (zerop (process-file "whoami" nil t)))
434 ;; fall through if "whoami" didn't work
435 nil
436 ;; remove trailing newline
437 (delete-region (1- (point-max)) (point-max))
438 (buffer-string)))))
439 ;; normal case
440 (user-login-name)
441 ;; if user-login-name is nil, return the UID as a string
442 (number-to-string (user-uid))))
0e0d9831
GM
443
444(defun vc-state (file)
445 "Return the version control state of FILE.
446
cb5af02a
AS
447If FILE is not registered, this function always returns nil.
448For registered files, the value returned is one of:
0e0d9831
GM
449
450 'up-to-date The working file is unmodified with respect to the
451 latest version on the current branch, and not locked.
452
453 'edited The working file has been edited by the user. If
454 locking is used for the file, this state means that
455 the current version is locked by the calling user.
456
457 USER The current version of the working file is locked by
458 some other USER (a string).
f8b72742 459
0e0d9831
GM
460 'needs-patch The file has not been edited by the user, but there is
461 a more recent version on the current branch stored
462 in the master file.
463
464 'needs-merge The file has been edited by the user, and there is also
465 a more recent version on the current branch stored in
466 the master file. This state can only occur if locking
467 is not used for the file.
468
469 'unlocked-changes The current version of the working file is not locked,
470 but the working file has been changed with respect
471 to that version. This state can only occur for files
472 with locking; it represents an erroneous condition that
473 should be resolved by the user (vc-next-action will
474 prompt the user to do it)."
2a3897f5
SM
475 ;; FIXME: New (sub)states needed (?):
476 ;; - `added' (i.e. `edited' but with no base version yet,
477 ;; typically represented by vc-workfile-version = "0")
478 ;; - `conflict' (i.e. `edited' with conflict markers)
479 ;; - `removed'
480 ;; - `copied' and `moved' (might be handled by `removed' and `added')
0e0d9831 481 (or (vc-file-getprop file 'vc-state)
cb5af02a
AS
482 (if (vc-backend file)
483 (vc-file-setprop file 'vc-state
484 (vc-call state-heuristic file)))))
0e0d9831 485
588c1bf9
AS
486(defun vc-recompute-state (file)
487 "Recompute the version control state of FILE, and return it.
488This calls the possibly expensive function vc-BACKEND-state,
489rather than the heuristic."
490 (vc-file-setprop file 'vc-state (vc-call state file)))
491
0e0d9831
GM
492(defsubst vc-up-to-date-p (file)
493 "Convenience function that checks whether `vc-state' of FILE is `up-to-date'."
494 (eq (vc-state file) 'up-to-date))
495
496(defun vc-default-state-heuristic (backend file)
5eb2b516
DL
497 "Default implementation of vc-state-heuristic.
498It simply calls the real state computation function `vc-BACKEND-state'
499and does not employ any heuristic at all."
0e0d9831 500 (vc-call-backend backend 'state file))
1efcbf46 501
e767004f
AS
502(defun vc-workfile-unchanged-p (file)
503 "Return non-nil if FILE has not changed since the last checkout."
504 (let ((checkout-time (vc-file-getprop file 'vc-checkout-time))
505 (lastmod (nth 5 (file-attributes file))))
04e77778
AS
506 (if (and checkout-time
507 ;; Tramp and Ange-FTP return this when they don't know the time.
508 (not (equal lastmod '(0 0))))
e767004f
AS
509 (equal checkout-time lastmod)
510 (let ((unchanged (vc-call workfile-unchanged-p file)))
511 (vc-file-setprop file 'vc-checkout-time (if unchanged lastmod 0))
512 unchanged))))
513
514(defun vc-default-workfile-unchanged-p (backend file)
515 "Check if FILE is unchanged by diffing against the master version.
516Return non-nil if FILE is unchanged."
f8836381 517 (zerop (condition-case err
4392edab
AS
518 ;; If the implementation supports it, let the output
519 ;; go to *vc*, not *vc-diff*, since this is an internal call.
520 (vc-call diff file nil nil "*vc*")
f8836381
AS
521 (wrong-number-of-arguments
522 ;; If this error came from the above call to vc-BACKEND-diff,
523 ;; try again without the optional buffer argument (for
524 ;; backward compatibility). Otherwise, resignal.
525 (if (or (not (eq (cadr err)
526 (indirect-function
527 (vc-find-backend-function (vc-backend file)
528 'diff))))
0d2ce4ef
JB
529 (not (eq (caddr err) 4)))
530 (signal (car err) (cdr err))
f8836381 531 (vc-call diff file))))))
e767004f 532
e1c0c2d1 533(defun vc-workfile-version (file)
cb5af02a
AS
534 "Return the version level of the current workfile FILE.
535If FILE is not registered, this function always returns nil."
0e0d9831 536 (or (vc-file-getprop file 'vc-workfile-version)
cb5af02a
AS
537 (if (vc-backend file)
538 (vc-file-setprop file 'vc-workfile-version
539 (vc-call workfile-version file)))))
f2ee4191 540
0e0d9831
GM
541(defun vc-default-registered (backend file)
542 "Check if FILE is registered in BACKEND using vc-BACKEND-master-templates."
543 (let ((sym (vc-make-backend-sym backend 'master-templates)))
544 (unless (get backend 'vc-templates-grabbed)
545 (put backend 'vc-templates-grabbed t)
546 (set sym (append (delq nil
547 (mapcar
548 (lambda (template)
549 (and (consp template)
550 (eq (cdr template) backend)
551 (car template)))
3756d481
AS
552 (with-no-warnings
553 vc-master-templates)))
0e0d9831
GM
554 (symbol-value sym))))
555 (let ((result (vc-check-master-templates file (symbol-value sym))))
556 (if (stringp result)
557 (vc-file-setprop file 'vc-name result)
558 nil)))) ; Not registered
559
560(defun vc-possible-master (s dirname basename)
561 (cond
562 ((stringp s) (format s dirname basename))
563 ((functionp s)
564 ;; The template is a function to invoke. If the
565 ;; function returns non-nil, that means it has found a
566 ;; master. For backward compatibility, we also handle
567 ;; the case that the function throws a 'found atom
568 ;; and a pair (cons MASTER-FILE BACKEND).
569 (let ((result (catch 'found (funcall s dirname basename))))
570 (if (consp result) (car result) result)))))
571
572(defun vc-check-master-templates (file templates)
cb5af02a 573 "Return non-nil if there is a master corresponding to FILE.
0e0d9831
GM
574
575TEMPLATES is a list of strings or functions. If an element is a
576string, it must be a control string as required by `format', with two
577string placeholders, such as \"%sRCS/%s,v\". The directory part of
578FILE is substituted for the first placeholder, the basename of FILE
579for the second. If a file with the resulting name exists, it is taken
580as the master of FILE, and returned.
581
582If an element of TEMPLATES is a function, it is called with the
583directory part and the basename of FILE as arguments. It should
584return non-nil if it finds a master; that value is then returned by
585this function."
586 (let ((dirname (or (file-name-directory file) ""))
587 (basename (file-name-nondirectory file)))
588 (catch 'found
5eb2b516 589 (mapcar
0e0d9831
GM
590 (lambda (s)
591 (let ((trial (vc-possible-master s dirname basename)))
592 (if (and trial (file-exists-p trial)
593 ;; Make sure the file we found with name
594 ;; TRIAL is not the source file itself.
595 ;; That can happen with RCS-style names if
596 ;; the file name is truncated (e.g. to 14
597 ;; chars). See if either directory or
598 ;; attributes differ.
599 (or (not (string= dirname
600 (file-name-directory trial)))
601 (not (equal (file-attributes file)
602 (file-attributes trial)))))
603 (throw 'found trial))))
604 templates))))
f2ee4191 605
c844616c 606(defun vc-toggle-read-only (&optional verbose)
c43e436c 607 "Change read-only status of current buffer, perhaps via version control.
db8afaee 608
c43e436c
RS
609If the buffer is visiting a file registered with version control,
610then check the file in or out. Otherwise, just change the read-only flag
ec44193a
KH
611of the buffer.
612With prefix argument, ask for version number to check in or check out.
613Check-out of a specified version number does not lock the file;
db8afaee
AS
614to do that, use this command a second time with no argument.
615
616If you bind this function to \\[toggle-read-only], then Emacs checks files
617in or out whenever you toggle the read-only flag."
c844616c 618 (interactive "P")
702220f3 619 (if (or (and (boundp 'vc-dired-mode) vc-dired-mode)
0e0d9831 620 ;; use boundp because vc.el might not be loaded
5232a436 621 (vc-backend buffer-file-name))
c844616c 622 (vc-next-action verbose)
594722a8
ER
623 (toggle-read-only)))
624
e896a9e1 625(defun vc-default-make-version-backups-p (backend file)
cb5af02a 626 "Return non-nil if unmodified versions should be backed up locally.
9aa10a43 627The default is to switch off this feature."
d445a975
AS
628 nil)
629
e896a9e1
AS
630(defun vc-version-backup-file-name (file &optional rev manual regexp)
631 "Return a backup file name for REV or the current version of FILE.
632If MANUAL is non-nil it means that a name for backups created by
633the user should be returned; if REGEXP is non-nil that means to return
634a regexp for matching all such backup files, regardless of the version."
e3f955b6
AS
635 (if regexp
636 (concat (regexp-quote (file-name-nondirectory file))
d4c813e9 637 "\\.~.+" (unless manual "\\.") "~")
f8b72742 638 (expand-file-name (concat (file-name-nondirectory file)
d4c813e9
SM
639 ".~" (subst-char-in-string
640 ?/ ?_ (or rev (vc-workfile-version file)))
e3f955b6
AS
641 (unless manual ".") "~")
642 (file-name-directory file))))
e896a9e1
AS
643
644(defun vc-delete-automatic-version-backups (file)
645 "Delete all existing automatic version backups for FILE."
d455f4f7
SM
646 (condition-case nil
647 (mapcar
648 'delete-file
79e954d0 649 (directory-files (or (file-name-directory file) default-directory) t
d455f4f7
SM
650 (vc-version-backup-file-name file nil nil t)))
651 ;; Don't fail when the directory doesn't exist.
652 (file-error nil)))
e896a9e1
AS
653
654(defun vc-make-version-backup (file)
655 "Make a backup copy of FILE, which is assumed in sync with the repository.
656Before doing that, check if there are any old backups and get rid of them."
48b15d3f 657 (unless (and (fboundp 'msdos-long-file-names)
ee9be3de 658 (not (with-no-warnings (msdos-long-file-names))))
48b15d3f 659 (vc-delete-automatic-version-backups file)
27707243
AS
660 (condition-case nil
661 (copy-file file (vc-version-backup-file-name file)
662 nil 'keep-date)
663 ;; It's ok if it doesn't work (e.g. directory not writable),
664 ;; since this is just for efficiency.
bf247b6e 665 (file-error
27707243
AS
666 (message
667 (concat "Warning: Cannot make version backup; "
668 "diff/revert therefore not local"))))))
d445a975
AS
669
670(defun vc-before-save ()
671 "Function to be called by `basic-save-buffer' (in files.el)."
672 ;; If the file on disk is still in sync with the repository,
673 ;; and version backups should be made, copy the file to
674 ;; another name. This enables local diffs and local reverting.
5232a436 675 (let ((file buffer-file-name))
d445a975
AS
676 (and (vc-backend file)
677 (vc-up-to-date-p file)
678 (eq (vc-checkout-model file) 'implicit)
e896a9e1
AS
679 (vc-call make-version-backups-p file)
680 (vc-make-version-backup file))))
d445a975 681
e66eac08 682(defun vc-after-save ()
0e0d9831 683 "Function to be called by `basic-save-buffer' (in files.el)."
5eb2b516 684 ;; If the file in the current buffer is under version control,
0e0d9831
GM
685 ;; up-to-date, and locking is not used for the file, set
686 ;; the state to 'edited and redisplay the mode line.
5232a436 687 (let ((file buffer-file-name))
8aa81ea8 688 (and (vc-backend file)
b23a2306
AS
689 (or (and (equal (vc-file-getprop file 'vc-checkout-time)
690 (nth 5 (file-attributes file)))
691 ;; File has been saved in the same second in which
692 ;; it was checked out. Clear the checkout-time
693 ;; to avoid confusion.
694 (vc-file-setprop file 'vc-checkout-time nil))
695 t)
0e0d9831
GM
696 (vc-up-to-date-p file)
697 (eq (vc-checkout-model file) 'implicit)
698 (vc-file-setprop file 'vc-state 'edited)
699 (vc-mode-line file)
099bd78a
SM
700 (if (featurep 'vc)
701 ;; If VC is not loaded, then there can't be
702 ;; any VC Dired buffer to synchronize.
703 (vc-dired-resynch-file file)))))
04446ed0 704
0e0d9831 705(defun vc-mode-line (file)
7bc2b98b 706 "Set `vc-mode' to display type of version control for FILE.
594722a8 707The value is set in the current buffer, which should be the buffer
0e0d9831 708visiting FILE."
67c6f446 709 (interactive (list buffer-file-name))
5232a436
SM
710 (let ((backend (vc-backend file)))
711 (if (not backend)
712 (setq vc-mode nil)
713 (setq vc-mode (concat " " (if vc-display-status
714 (vc-call mode-line-string file)
715 (symbol-name backend))))
716 ;; If the file is locked by some other user, make
717 ;; the buffer read-only. Like this, even root
718 ;; cannot modify a file that someone else has locked.
719 (and (equal file buffer-file-name)
720 (stringp (vc-state file))
721 (setq buffer-read-only t))
722 ;; If the user is root, and the file is not owner-writable,
723 ;; then pretend that we can't write it
724 ;; even though we can (because root can write anything).
2a3897f5
SM
725 ;; This way, even root cannot modify a file that isn't locked.
726 (and (equal file buffer-file-name)
727 (not buffer-read-only)
5232a436
SM
728 (zerop (user-real-uid))
729 (zerop (logand (file-modes buffer-file-name) 128))
730 (setq buffer-read-only t)))
731 (force-mode-line-update)
732 backend))
0e0d9831
GM
733
734(defun vc-default-mode-line-string (backend file)
735 "Return string for placement in modeline by `vc-mode-line' for FILE.
736Format:
737
738 \"BACKEND-REV\" if the file is up-to-date
739 \"BACKEND:REV\" if the file is edited (or locked by the calling user)
740 \"BACKEND:LOCKER:REV\" if the file is locked by somebody else
0e0d9831
GM
741
742This function assumes that the file is registered."
743 (setq backend (symbol-name backend))
744 (let ((state (vc-state file))
82c4728d 745 (state-echo nil)
0e0d9831 746 (rev (vc-workfile-version file)))
82c4728d
DN
747 (propertize
748 (cond ((or (eq state 'up-to-date)
749 (eq state 'needs-patch))
750 (setq state-echo "Up to date file")
751 (concat backend "-" rev))
752 ((stringp state)
753 (setq state-echo (concat "File locked by" state))
754 (concat backend ":" state ":" rev))
755 (t
756 ;; Not just for the 'edited state, but also a fallback
757 ;; for all other states. Think about different symbols
758 ;; for 'needs-patch and 'needs-merge.
759 (setq state-echo "Edited file")
760 (concat backend ":" rev)))
761 'mouse-face 'mode-line-highlight
762 'local-map (let ((map (make-sparse-keymap)))
763 (define-key map [mode-line down-mouse-1] 'vc-menu-map) map)
764 'help-echo (concat state-echo " under the " backend
765 " version control system\nmouse-1: VC Menu"))))
f2ee4191 766
a3a39848 767(defun vc-follow-link ()
0e0d9831
GM
768 "If current buffer visits a symbolic link, visit the real file.
769If the real file is already visited in another buffer, make that buffer
770current, and kill the buffer that visits the link."
566f2169 771 (let* ((truename (abbreviate-file-name (file-chase-links buffer-file-name)))
e7f5ddc2
RS
772 (true-buffer (find-buffer-visiting truename))
773 (this-buffer (current-buffer)))
774 (if (eq true-buffer this-buffer)
775 (progn
d8221951 776 (kill-buffer this-buffer)
e7f5ddc2
RS
777 ;; In principle, we could do something like set-visited-file-name.
778 ;; However, it can't be exactly the same as set-visited-file-name.
779 ;; I'm not going to work out the details right now. -- rms.
d8221951 780 (set-buffer (find-file-noselect truename)))
e7f5ddc2
RS
781 (set-buffer true-buffer)
782 (kill-buffer this-buffer))))
a3a39848 783
b8d1db77
SM
784(defun vc-default-find-file-hook (backend)
785 nil)
786
594722a8 787(defun vc-find-file-hook ()
be4d6a6f 788 "Function for `find-file-hook' activating VC mode if appropriate."
18c8a18e
PE
789 ;; Recompute whether file is version controlled,
790 ;; if user has killed the buffer and revisited.
060a1456
AS
791 (if vc-mode
792 (setq vc-mode nil))
0e0d9831 793 (when buffer-file-name
f2ee4191
RS
794 (vc-file-clearprops buffer-file-name)
795 (cond
e1c0c2d1 796 ((vc-backend buffer-file-name)
0bfb74a9 797 ;; Compute the state and put it in the modeline.
f2ee4191 798 (vc-mode-line buffer-file-name)
0bfb74a9
SM
799 (unless vc-make-backup-files
800 ;; Use this variable, not make-backup-files,
801 ;; because this is for things that depend on the file name.
b8d1db77
SM
802 (set (make-local-variable 'backup-inhibited) t))
803 ;; Let the backend setup any buffer-local things he needs.
804 (vc-call-backend (vc-backend buffer-file-name) 'find-file-hook))
4d11f532
SM
805 ((let ((link-type (and (file-symlink-p buffer-file-name)
806 (vc-backend (file-chase-links buffer-file-name)))))
0bfb74a9
SM
807 (cond ((not link-type) nil) ;Nothing to do.
808 ((eq vc-follow-symlinks nil)
809 (message
b8063212 810 "Warning: symbolic link to %s-controlled source file" link-type))
0bfb74a9
SM
811 ((or (not (eq vc-follow-symlinks 'ask))
812 ;; If we already visited this file by following
813 ;; the link, don't ask again if we try to visit
814 ;; it again. GUD does that, and repeated questions
815 ;; are painful.
816 (get-file-buffer
817 (abbreviate-file-name
818 (file-chase-links buffer-file-name))))
819
820 (vc-follow-link)
821 (message "Followed link to %s" buffer-file-name)
822 (vc-find-file-hook))
823 (t
824 (if (yes-or-no-p (format
b8063212 825 "Symbolic link to %s-controlled source file; follow link? " link-type))
0bfb74a9
SM
826 (progn (vc-follow-link)
827 (message "Followed link to %s" buffer-file-name)
828 (vc-find-file-hook))
829 (message
b8063212 830 "Warning: editing through the link bypasses version control")
0bfb74a9 831 ))))))))
594722a8 832
be4d6a6f 833(add-hook 'find-file-hook 'vc-find-file-hook)
594722a8 834
14fef9de 835;; more hooks, this time for file-not-found
594722a8 836(defun vc-file-not-found-hook ()
0e0d9831
GM
837 "When file is not found, try to check it out from version control.
838Returns t if checkout was successful, nil otherwise.
d3d558a9 839Used in `find-file-not-found-functions'."
5f42a1d4
RS
840 ;; When a file does not exist, ignore cached info about it
841 ;; from a previous visit.
842 (vc-file-clearprops buffer-file-name)
4a330ab7 843 (let ((backend (vc-backend buffer-file-name)))
1e87be1b 844 (if backend (vc-call-backend backend 'find-file-not-found-hook))))
4a330ab7
SM
845
846(defun vc-default-find-file-not-found-hook (backend)
847 (if (yes-or-no-p
848 (format "File %s was lost; check out from version control? "
849 (file-name-nondirectory buffer-file-name)))
850 (save-excursion
851 (require 'vc)
852 (setq default-directory (file-name-directory buffer-file-name))
853 (not (vc-error-occurred (vc-checkout buffer-file-name))))))
594722a8 854
3756d481 855(add-hook 'find-file-not-found-functions 'vc-file-not-found-hook)
594722a8 856
f2ee4191 857(defun vc-kill-buffer-hook ()
0e0d9831 858 "Discard VC info about a file when we kill its buffer."
5232a436
SM
859 (if buffer-file-name
860 (vc-file-clearprops buffer-file-name)))
f2ee4191 861
cd32d5d1 862(add-hook 'kill-buffer-hook 'vc-kill-buffer-hook)
f2ee4191 863
14fef9de
SM
864;; Now arrange for (autoloaded) bindings of the main package.
865;; Bindings for this have to go in the global map, as we'll often
866;; want to call them from random buffers.
867
868;; Autoloading works fine, but it prevents shortcuts from appearing
869;; in the menu because they don't exist yet when the menu is built.
870;; (autoload 'vc-prefix-map "vc" nil nil 'keymap)
871(defvar vc-prefix-map
872 (let ((map (make-sparse-keymap)))
873 (define-key map "a" 'vc-update-change-log)
874 (define-key map "b" 'vc-switch-backend)
875 (define-key map "c" 'vc-cancel-version)
876 (define-key map "d" 'vc-directory)
877 (define-key map "g" 'vc-annotate)
878 (define-key map "h" 'vc-insert-headers)
879 (define-key map "i" 'vc-register)
880 (define-key map "l" 'vc-print-log)
881 (define-key map "m" 'vc-merge)
882 (define-key map "r" 'vc-retrieve-snapshot)
883 (define-key map "s" 'vc-create-snapshot)
884 (define-key map "u" 'vc-revert-buffer)
885 (define-key map "v" 'vc-next-action)
886 (define-key map "=" 'vc-diff)
887 (define-key map "~" 'vc-version-other-window)
888 map))
889(fset 'vc-prefix-map vc-prefix-map)
0e0d9831 890(define-key global-map "\C-xv" 'vc-prefix-map)
624c0e9d 891
b662fbb8
RM
892(if (not (boundp 'vc-menu-map))
893 ;; Don't do the menu bindings if menu-bar.el wasn't loaded to defvar
894 ;; vc-menu-map.
895 ()
896 ;;(define-key vc-menu-map [show-files]
897 ;; '("Show Files under VC" . (vc-directory t)))
9bef02e1
RS
898 (define-key vc-menu-map [vc-retrieve-snapshot]
899 '("Retrieve Snapshot" . vc-retrieve-snapshot))
900 (define-key vc-menu-map [vc-create-snapshot]
901 '("Create Snapshot" . vc-create-snapshot))
b64ea387 902 (define-key vc-menu-map [vc-directory] '("VC Directory Listing" . vc-directory))
b662fbb8 903 (define-key vc-menu-map [separator1] '("----"))
14aa11f4 904 (define-key vc-menu-map [vc-annotate] '("Annotate" . vc-annotate))
b662fbb8
RM
905 (define-key vc-menu-map [vc-rename-file] '("Rename File" . vc-rename-file))
906 (define-key vc-menu-map [vc-version-other-window]
907 '("Show Other Version" . vc-version-other-window))
c1cd70af 908 (define-key vc-menu-map [vc-diff] '("Compare with Base Version" . vc-diff))
b662fbb8
RM
909 (define-key vc-menu-map [vc-update-change-log]
910 '("Update ChangeLog" . vc-update-change-log))
911 (define-key vc-menu-map [vc-print-log] '("Show History" . vc-print-log))
912 (define-key vc-menu-map [separator2] '("----"))
b662fbb8
RM
913 (define-key vc-menu-map [vc-insert-header]
914 '("Insert Header" . vc-insert-headers))
c1cd70af
AS
915 (define-key vc-menu-map [undo] '("Undo Last Check-In" . vc-cancel-version))
916 (define-key vc-menu-map [vc-revert-buffer]
917 '("Revert to Base Version" . vc-revert-buffer))
918 (define-key vc-menu-map [vc-update]
919 '("Update to Latest Version" . vc-update))
9314395d 920 (define-key vc-menu-map [vc-next-action] '("Check In/Out" . vc-next-action))
738efc8e
KH
921 (define-key vc-menu-map [vc-register] '("Register" . vc-register)))
922
14fef9de
SM
923;; These are not correct and it's not currently clear how doing it
924;; better (with more complicated expressions) might slow things down
925;; on older systems.
926
927;;(put 'vc-rename-file 'menu-enable 'vc-mode)
928;;(put 'vc-annotate 'menu-enable '(eq (vc-buffer-backend) 'CVS))
929;;(put 'vc-version-other-window 'menu-enable 'vc-mode)
930;;(put 'vc-diff 'menu-enable 'vc-mode)
931;;(put 'vc-update-change-log 'menu-enable
932;; '(member (vc-buffer-backend) '(RCS CVS)))
933;;(put 'vc-print-log 'menu-enable 'vc-mode)
934;;(put 'vc-cancel-version 'menu-enable 'vc-mode)
935;;(put 'vc-revert-buffer 'menu-enable 'vc-mode)
936;;(put 'vc-insert-headers 'menu-enable 'vc-mode)
937;;(put 'vc-next-action 'menu-enable 'vc-mode)
938;;(put 'vc-register 'menu-enable '(and buffer-file-name (not vc-mode)))
594722a8 939
594722a8
ER
940(provide 'vc-hooks)
941
ce9f8ffb 942;; arch-tag: 2e5a6fa7-1d30-48e2-8bd0-e3d335f04f32
594722a8 943;;; vc-hooks.el ends here