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