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