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