diff options
| author | Karl Heuer | 1995-04-26 21:42:20 +0000 |
|---|---|---|
| committer | Karl Heuer | 1995-04-26 21:42:20 +0000 |
| commit | e1c0c2d1bf45a7fd909b7865419a3013ec79b141 (patch) | |
| tree | f9a93bf9e7b6bf7d2167cfb418875744fc81a784 | |
| parent | a01c76d72b36c295a2b38db269aaf6ea838c84b6 (diff) | |
| download | emacs-e1c0c2d1bf45a7fd909b7865419a3013ec79b141.tar.gz emacs-e1c0c2d1bf45a7fd909b7865419a3013ec79b141.zip | |
(vc-default-backend, vc-path, vc-consult-headers):
(vc-mistrust-permissions, vc-keep-workfiles): Customization
variables, moved here from vc.el.
(vc-trunk-p, vc-minor-revision, vc-branch-part): Moved to vc.el.
(vc-backend): Renamed from vc-backend-deduce. Callers changed.
(vc-match-substring, vc-lock-file, vc-parse-buffer, vc-master-info):
(vc-log-info, vc-consult-rcs-headers, vc-fetch-properties):
(vc-backend-subdirectory-name, vc-locking-user, vc-true-locking-user):
(vc-latest-version, vc-your-latest-version, vc-branch-version):
(vc-workfile-version): Functions moved here from vc.el.
(vc-log-info): Log program is no longer called through vc-do-command,
to avoid including the lengthy vc-do-command here. It is done
directly through call-process now. Removed obsolete parameter LAST.
(vc-status): Replaced by the much simpler version that gets the
information from the file properties. Removed the obsolete
parameter vc-type.
(vc-parse-buffer): changed format of PATTERNS. Each pattern is now a
list of 2 to 3 elements, the first being the pattern, the remaining
ones the numbers of subexpressions to refer to.
(vc-cvs-status): New per-file property, only used in the CVS case.
(vc-cvs-status): New function.
(vc-log-info): Adapted to new version of vc-parse-buffer
(vc-fetch-properties): Adapted to new version of vc-parse-buffer.
Better search regexp for CVS latest version.
(vc-log-info): Search for branch version only in the RCS case,
since this doesn't make sense for SCCS or CVS.
(vc-fetch-properties): CVS case: set vc-cvs-status.
(vc-locking-user): CVS case: use vc-cvs-status to determine if
the file is up-to-date, thus avoiding an expensive call to
vc-workfile-unchanged-p.
(vc-mode-line): Re-activated the code that makes the buffer read-only
if the work file is unchanged. But the status of the work file
is now determined by looking at the already-computed mode string.
| -rw-r--r-- | lisp/vc-hooks.el | 702 |
1 files changed, 526 insertions, 176 deletions
diff --git a/lisp/vc-hooks.el b/lisp/vc-hooks.el index c3ca8c57c8b..83e91697ca9 100644 --- a/lisp/vc-hooks.el +++ b/lisp/vc-hooks.el | |||
| @@ -32,6 +32,18 @@ | |||
| 32 | 32 | ||
| 33 | ;;; Code: | 33 | ;;; Code: |
| 34 | 34 | ||
| 35 | ;; Customization Variables (the rest is in vc.el) | ||
| 36 | |||
| 37 | (defvar vc-default-back-end nil | ||
| 38 | "*Back-end actually used by this interface; may be SCCS or RCS. | ||
| 39 | The value is only computed when needed to avoid an expensive search.") | ||
| 40 | |||
| 41 | (defvar vc-path | ||
| 42 | (if (file-directory-p "/usr/sccs") | ||
| 43 | '("/usr/sccs") | ||
| 44 | nil) | ||
| 45 | "*List of extra directories to search for version control commands.") | ||
| 46 | |||
| 35 | (defvar vc-master-templates | 47 | (defvar vc-master-templates |
| 36 | '(("%sRCS/%s,v" . RCS) ("%s%s,v" . RCS) ("%sRCS/%s" . RCS) | 48 | '(("%sRCS/%s,v" . RCS) ("%s%s,v" . RCS) ("%sRCS/%s" . RCS) |
| 37 | ("%sSCCS/s.%s" . SCCS) ("%ss.%s". SCCS) | 49 | ("%sSCCS/s.%s" . SCCS) ("%ss.%s". SCCS) |
| @@ -48,6 +60,17 @@ If nil (the default), files covered by version control don't get backups.") | |||
| 48 | "*If non-nil, display revision number and lock status in modeline. | 60 | "*If non-nil, display revision number and lock status in modeline. |
| 49 | Otherwise, not displayed.") | 61 | Otherwise, not displayed.") |
| 50 | 62 | ||
| 63 | (defvar vc-consult-headers t | ||
| 64 | "*Identify work files by searching for version headers.") | ||
| 65 | |||
| 66 | (defvar vc-mistrust-permissions nil | ||
| 67 | "*Don't assume that permissions and ownership track version-control status.") | ||
| 68 | |||
| 69 | (defvar vc-keep-workfiles t | ||
| 70 | "*If non-nil, don't delete working files after registering changes. | ||
| 71 | If the back-end is CVS, workfiles are always kept, regardless of the | ||
| 72 | value of this flag.") | ||
| 73 | |||
| 51 | ;; Tell Emacs about this new kind of minor mode | 74 | ;; Tell Emacs about this new kind of minor mode |
| 52 | (if (not (assoc 'vc-mode minor-mode-alist)) | 75 | (if (not (assoc 'vc-mode minor-mode-alist)) |
| 53 | (setq minor-mode-alist (cons '(vc-mode vc-mode) | 76 | (setq minor-mode-alist (cons '(vc-mode vc-mode) |
| @@ -56,6 +79,24 @@ Otherwise, not displayed.") | |||
| 56 | (make-variable-buffer-local 'vc-mode) | 79 | (make-variable-buffer-local 'vc-mode) |
| 57 | (put 'vc-mode 'permanent-local t) | 80 | (put 'vc-mode 'permanent-local t) |
| 58 | 81 | ||
| 82 | |||
| 83 | ;; branch identification | ||
| 84 | |||
| 85 | (defun vc-occurrences (object sequence) | ||
| 86 | ;; return the number of occurences of OBJECT in SEQUENCE | ||
| 87 | ;; (is it really true that Emacs Lisp doesn't provide such a function?) | ||
| 88 | (let ((len (length sequence)) (index 0) (occ 0)) | ||
| 89 | (while (< index len) | ||
| 90 | (if (eq object (elt sequence index)) | ||
| 91 | (setq occ (1+ occ))) | ||
| 92 | (setq index (1+ index))) | ||
| 93 | occ)) | ||
| 94 | |||
| 95 | (defun vc-branch-p (rev) | ||
| 96 | ;; return t if REV is the branch part of a revision, | ||
| 97 | ;; i.e. a revision without a minor number | ||
| 98 | (eq 0 (% (vc-occurrences ?. rev) 2))) | ||
| 99 | |||
| 59 | ;; We need a notion of per-file properties because the version | 100 | ;; We need a notion of per-file properties because the version |
| 60 | ;; control state of a file is expensive to derive --- we compute | 101 | ;; control state of a file is expensive to derive --- we compute |
| 61 | ;; them when the file is initially found, keep them up to date | 102 | ;; them when the file is initially found, keep them up to date |
| @@ -79,35 +120,456 @@ Otherwise, not displayed.") | |||
| 79 | ;; get per-file property | 120 | ;; get per-file property |
| 80 | (get (intern file vc-file-prop-obarray) property)) | 121 | (get (intern file vc-file-prop-obarray) property)) |
| 81 | 122 | ||
| 82 | ;;; functions that operate on RCS revision numbers | 123 | (defun vc-file-clearprops (file) |
| 124 | ;; clear all properties of a given file | ||
| 125 | (setplist (intern file vc-file-prop-obarray) nil)) | ||
| 83 | 126 | ||
| 84 | (defun vc-occurrences (object sequence) | 127 | ;; basic properties |
| 85 | ;; return the number of occurences of OBJECT in SEQUENCE | ||
| 86 | ;; (is it really true that Emacs Lisp doesn't provide such a function?) | ||
| 87 | (let ((len (length sequence)) (index 0) (occ 0)) | ||
| 88 | (while (< index len) | ||
| 89 | (if (eq object (elt sequence index)) | ||
| 90 | (setq occ (1+ occ))) | ||
| 91 | (setq index (1+ index))) | ||
| 92 | occ)) | ||
| 93 | 128 | ||
| 94 | (defun vc-trunk-p (rev) | 129 | (defun vc-name (file) |
| 95 | ;; return t if REV is a revision on the trunk | 130 | "Return the master name of a file, nil if it is not registered." |
| 96 | (not (eq nil (string-match "\\`[0-9]+\\.[0-9]+\\'" rev)))) | 131 | (or (vc-file-getprop file 'vc-name) |
| 132 | (let ((name-and-type (vc-registered file))) | ||
| 133 | (if name-and-type | ||
| 134 | (progn | ||
| 135 | (vc-file-setprop file 'vc-backend (cdr name-and-type)) | ||
| 136 | (vc-file-setprop file 'vc-name (car name-and-type))))))) | ||
| 97 | 137 | ||
| 98 | (defun vc-branch-p (rev) | 138 | (defun vc-backend (file) |
| 99 | ;; return t if REV is the branch part of a revision, | 139 | "Return the version-control type of a file, nil if it is not registered." |
| 100 | ;; i.e. a revision without a minor number | 140 | (and file |
| 101 | (eq 0 (% (vc-occurrences ?. rev) 2))) | 141 | (or (vc-file-getprop file 'vc-backend) |
| 142 | (let ((name-and-type (vc-registered file))) | ||
| 143 | (if name-and-type | ||
| 144 | (progn | ||
| 145 | (vc-file-setprop file 'vc-name (car name-and-type)) | ||
| 146 | (vc-file-setprop file 'vc-backend (cdr name-and-type)))))))) | ||
| 102 | 147 | ||
| 103 | (defun vc-minor-revision (rev) | 148 | ;; Functions for querying the master and lock files. |
| 104 | ;; return the minor revision number of REV, | 149 | |
| 105 | ;; i.e. the number after the last dot. | 150 | (defun vc-match-substring (bn) |
| 106 | (substring rev (1+ (string-match "\\.[0-9]+\\'" rev)))) | 151 | (buffer-substring (match-beginning bn) (match-end bn))) |
| 152 | |||
| 153 | (defun vc-lock-file (file) | ||
| 154 | ;; Generate lock file name corresponding to FILE | ||
| 155 | (let ((master (vc-name file))) | ||
| 156 | (and | ||
| 157 | master | ||
| 158 | (string-match "\\(.*/\\)s\\.\\(.*\\)" master) | ||
| 159 | (concat | ||
| 160 | (substring master (match-beginning 1) (match-end 1)) | ||
| 161 | "p." | ||
| 162 | (substring master (match-beginning 2) (match-end 2)))))) | ||
| 163 | |||
| 164 | (defun vc-parse-buffer (patterns &optional file properties) | ||
| 165 | ;; Use PATTERNS to parse information out of the current buffer. | ||
| 166 | ;; Each element of PATTERNS is a list of 2 to 3 elements. The first element | ||
| 167 | ;; is the pattern to be matched, and the second (an integer) is the | ||
| 168 | ;; number of the subexpression that should be returned. If there's | ||
| 169 | ;; a third element (also the number of a subexpression), that | ||
| 170 | ;; subexpression is assumed to be a date field and we want the most | ||
| 171 | ;; recent entry matching the template. | ||
| 172 | ;; If FILE and PROPERTIES are given, the latter must be a list of | ||
| 173 | ;; properties of the same length as PATTERNS; each property is assigned | ||
| 174 | ;; the corresponding value. | ||
| 175 | (mapcar (function (lambda (p) | ||
| 176 | (goto-char (point-min)) | ||
| 177 | (cond | ||
| 178 | ((eq (length p) 2) ;; search for first entry | ||
| 179 | (let ((value nil)) | ||
| 180 | (if (re-search-forward (car p) nil t) | ||
| 181 | (setq value (vc-match-substring (elt p 1)))) | ||
| 182 | (if file | ||
| 183 | (progn (vc-file-setprop file (car properties) value) | ||
| 184 | (setq properties (cdr properties)))) | ||
| 185 | value)) | ||
| 186 | ((eq (length p) 3) ;; search for latest entry | ||
| 187 | (let ((latest-date "") (latest-val)) | ||
| 188 | (while (re-search-forward (car p) nil t) | ||
| 189 | (let ((date (vc-match-substring (elt p 2)))) | ||
| 190 | (if (string< latest-date date) | ||
| 191 | (progn | ||
| 192 | (setq latest-date date) | ||
| 193 | (setq latest-val | ||
| 194 | (vc-match-substring (elt p 1))))))) | ||
| 195 | (if file | ||
| 196 | (progn (vc-file-setprop file (car properties) latest-val) | ||
| 197 | (setq properties (cdr properties)))) | ||
| 198 | latest-val))))) | ||
| 199 | patterns) | ||
| 200 | ) | ||
| 201 | |||
| 202 | (defun vc-master-info (file fields &optional rfile properties) | ||
| 203 | ;; Search for information in a master file. | ||
| 204 | (if (and file (file-exists-p file)) | ||
| 205 | (save-excursion | ||
| 206 | (let ((buf)) | ||
| 207 | (setq buf (create-file-buffer file)) | ||
| 208 | (set-buffer buf)) | ||
| 209 | (erase-buffer) | ||
| 210 | (insert-file-contents file) | ||
| 211 | (set-buffer-modified-p nil) | ||
| 212 | (auto-save-mode nil) | ||
| 213 | (prog1 | ||
| 214 | (vc-parse-buffer fields rfile properties) | ||
| 215 | (kill-buffer (current-buffer))) | ||
| 216 | ) | ||
| 217 | (if rfile | ||
| 218 | (mapcar | ||
| 219 | (function (lambda (p) (vc-file-setprop rfile p nil))) | ||
| 220 | properties)) | ||
| 221 | ) | ||
| 222 | ) | ||
| 223 | |||
| 224 | (defun vc-log-info (command file flags patterns &optional properties) | ||
| 225 | ;; Search for information in log program output. | ||
| 226 | ;; If there is a string `\X' in any of the PATTERNS, replace | ||
| 227 | ;; it with a regexp to search for a branch revision. | ||
| 228 | (if (and file (file-exists-p file)) | ||
| 229 | (save-excursion | ||
| 230 | ;; Run the command (not using vc-do-command, as that is | ||
| 231 | ;; only available within vc.el) | ||
| 232 | ;; Don't switch to the *vc* buffer before running the command | ||
| 233 | ;; because that would change its default-directory. | ||
| 234 | (save-excursion (set-buffer (get-buffer-create "*vc*")) | ||
| 235 | (erase-buffer)) | ||
| 236 | (let ((exec-path (append vc-path exec-path)) | ||
| 237 | ;; Add vc-path to PATH for the execution of this command. | ||
| 238 | (process-environment | ||
| 239 | (cons (concat "PATH=" (getenv "PATH") | ||
| 240 | ":" (mapconcat 'identity vc-path ":")) | ||
| 241 | process-environment))) | ||
| 242 | (apply 'call-process command nil "*vc*" nil | ||
| 243 | (append flags (list (file-name-nondirectory file))))) | ||
| 244 | (set-buffer (get-buffer "*vc*")) | ||
| 245 | (set-buffer-modified-p nil) | ||
| 246 | ;; in the RCS case, insert branch version into | ||
| 247 | ;; any patterns that contain \X | ||
| 248 | (if (eq (vc-backend file) 'RCS) | ||
| 249 | (let ((branch | ||
| 250 | (car (vc-parse-buffer | ||
| 251 | '(("^branch:[ \t]+\\([0-9.]+\\)$" 1)))))) | ||
| 252 | (setq patterns | ||
| 253 | (mapcar | ||
| 254 | (function | ||
| 255 | (lambda (p) | ||
| 256 | (if (string-match "\\\\X" (car p)) | ||
| 257 | (if branch | ||
| 258 | (cond ((vc-branch-p branch) | ||
| 259 | (cons | ||
| 260 | (concat | ||
| 261 | (substring (car p) 0 (match-beginning 0)) | ||
| 262 | (regexp-quote branch) | ||
| 263 | "\\.[0-9]+" | ||
| 264 | (substring (car p) (match-end 0))) | ||
| 265 | (cdr p))) | ||
| 266 | (t | ||
| 267 | (cons | ||
| 268 | (concat | ||
| 269 | (substring (car p) 0 (match-beginning 0)) | ||
| 270 | (regexp-quote branch) | ||
| 271 | (substring (car p) (match-end 0))) | ||
| 272 | (cdr p)))) | ||
| 273 | ;; if there is no current branch, | ||
| 274 | ;; return a completely different regexp, | ||
| 275 | ;; which searches for the *head* | ||
| 276 | '("^head:[ \t]+\\([0-9.]+\\)$" 1)) | ||
| 277 | p))) | ||
| 278 | patterns)))) | ||
| 279 | (prog1 | ||
| 280 | (vc-parse-buffer patterns file properties) | ||
| 281 | (kill-buffer (current-buffer)) | ||
| 282 | ) | ||
| 283 | ) | ||
| 284 | (if file | ||
| 285 | (mapcar | ||
| 286 | (function (lambda (p) (vc-file-setprop file p nil))) | ||
| 287 | properties)) | ||
| 288 | ) | ||
| 289 | ) | ||
| 107 | 290 | ||
| 108 | (defun vc-branch-part (rev) | 291 | ;;; Functions that determine property values, by examining the |
| 109 | ;; return the branch part of a revision number REV | 292 | ;;; working file, the master file, or log program output |
| 110 | (substring rev 0 (string-match "\\.[0-9]+\\'" rev))) | 293 | |
| 294 | (defun vc-consult-rcs-headers (file) | ||
| 295 | ;; Search for RCS headers in FILE, and set properties | ||
| 296 | ;; accordingly. This function can be disabled by setting | ||
| 297 | ;; vc-consult-headers to nil. | ||
| 298 | ;; Returns: nil if no headers were found | ||
| 299 | ;; (or if the feature is disabled, | ||
| 300 | ;; or if there is currently no buffer | ||
| 301 | ;; visiting FILE) | ||
| 302 | ;; 'rev if a workfile revision was found | ||
| 303 | ;; 'rev-and-lock if revision and lock info was found | ||
| 304 | (cond | ||
| 305 | ((or (not vc-consult-headers) | ||
| 306 | (not (get-file-buffer file)) nil)) | ||
| 307 | ((save-excursion | ||
| 308 | (set-buffer (get-file-buffer file)) | ||
| 309 | (goto-char (point-min)) | ||
| 310 | (cond | ||
| 311 | ;; search for $Id or $Header | ||
| 312 | ;; ------------------------- | ||
| 313 | ((re-search-forward "\\$\\(Id\\|Header\\): [^ ]+ \\([0-9.]+\\) " | ||
| 314 | nil t) | ||
| 315 | ;; if found, store the revision number ... | ||
| 316 | (let ((rev (buffer-substring (match-beginning 2) | ||
| 317 | (match-end 2)))) | ||
| 318 | ;; ... and check for the locking state | ||
| 319 | (if (re-search-forward | ||
| 320 | (concat "\\=[0-9]+/[0-9]+/[0-9]+ " ; date | ||
| 321 | "[0-9]+:[0-9]+:[0-9]+ " ; time | ||
| 322 | "[^ ]+ [^ ]+ ") ; author & state | ||
| 323 | nil t) | ||
| 324 | (cond | ||
| 325 | ;; unlocked revision | ||
| 326 | ((looking-at "\\$") | ||
| 327 | (vc-file-setprop file 'vc-workfile-version rev) | ||
| 328 | (vc-file-setprop file 'vc-locking-user nil) | ||
| 329 | (vc-file-setprop file 'vc-locked-version nil) | ||
| 330 | 'rev-and-lock) | ||
| 331 | ;; revision is locked by some user | ||
| 332 | ((looking-at "\\([^ ]+\\) \\$") | ||
| 333 | (vc-file-setprop file 'vc-workfile-version rev) | ||
| 334 | (vc-file-setprop file 'vc-locking-user | ||
| 335 | (buffer-substring (match-beginning 1) | ||
| 336 | (match-end 1))) | ||
| 337 | (vc-file-setprop file 'vc-locked-version rev) | ||
| 338 | 'rev-and-lock) | ||
| 339 | ;; everything else: false | ||
| 340 | (nil)) | ||
| 341 | ;; unexpected information in | ||
| 342 | ;; keyword string --> quit | ||
| 343 | nil))) | ||
| 344 | ;; search for $Revision | ||
| 345 | ;; -------------------- | ||
| 346 | ((re-search-forward (concat "\\$" | ||
| 347 | "Revision: \\([0-9.]+\\) \\$") | ||
| 348 | nil t) | ||
| 349 | ;; if found, store the revision number ... | ||
| 350 | (let ((rev (buffer-substring (match-beginning 1) | ||
| 351 | (match-end 1)))) | ||
| 352 | ;; and see if there's any lock information | ||
| 353 | (goto-char (point-min)) | ||
| 354 | (if (re-search-forward (concat "\\$" "Locker:") nil t) | ||
| 355 | (cond ((looking-at " \\([^ ]+\\) \\$") | ||
| 356 | (vc-file-setprop file 'vc-workfile-version rev) | ||
| 357 | (vc-file-setprop file 'vc-locking-user | ||
| 358 | (buffer-substring (match-beginning 1) | ||
| 359 | (match-end 1))) | ||
| 360 | (vc-file-setprop file 'vc-locked-version rev) | ||
| 361 | 'rev-and-lock) | ||
| 362 | ((looking-at " *\\$") | ||
| 363 | (vc-file-setprop file 'vc-workfile-version rev) | ||
| 364 | (vc-file-setprop file 'vc-locking-user nil) | ||
| 365 | (vc-file-setprop file 'vc-locked-version nil) | ||
| 366 | 'rev-and-lock) | ||
| 367 | (t | ||
| 368 | (vc-file-setprop file 'vc-workfile-version rev) | ||
| 369 | 'rev-and-lock)) | ||
| 370 | (vc-file-setprop file 'vc-workfile-version rev) | ||
| 371 | 'rev))) | ||
| 372 | ;; else: nothing found | ||
| 373 | ;; ------------------- | ||
| 374 | (t nil)))))) | ||
| 375 | |||
| 376 | (defun vc-fetch-properties (file) | ||
| 377 | ;; Re-fetch some properties associated with the given file. | ||
| 378 | (cond | ||
| 379 | ((eq (vc-backend file) 'SCCS) | ||
| 380 | (progn | ||
| 381 | (vc-master-info (vc-lock-file file) | ||
| 382 | (list | ||
| 383 | '("^[^ ]+ [^ ]+ \\([^ ]+\\)" 1) | ||
| 384 | '("^\\([^ ]+\\)" 1)) | ||
| 385 | file | ||
| 386 | '(vc-locking-user vc-locked-version)) | ||
| 387 | (vc-master-info (vc-name file) | ||
| 388 | (list | ||
| 389 | '("^\001d D \\([^ ]+\\)" 1) | ||
| 390 | (list (concat "^\001d D \\([^ ]+\\) .* " | ||
| 391 | (regexp-quote (user-login-name)) " ") | ||
| 392 | 1) | ||
| 393 | ) | ||
| 394 | file | ||
| 395 | '(vc-latest-version vc-your-latest-version)) | ||
| 396 | )) | ||
| 397 | ((eq (vc-backend file) 'RCS) | ||
| 398 | (vc-log-info "rlog" file nil | ||
| 399 | (list | ||
| 400 | '("^locks: strict\n\t\\([^:]+\\)" 1) | ||
| 401 | '("^locks: strict\n\t[^:]+: \\(.+\\)" 1) | ||
| 402 | '("^revision[\t ]+\\([0-9.]+\\)\\(\n\\|[ \t].*\n\\)date: \\([ /0-9:]+\\);" 1 3) | ||
| 403 | (list | ||
| 404 | (concat | ||
| 405 | "^revision[\t ]+\\([0-9.]+\\)\\(\n\\|[ \t].*\n\\)date: \\([ /0-9:]+\\); *author: " | ||
| 406 | (regexp-quote (user-login-name)) | ||
| 407 | ";") 1 3) | ||
| 408 | ;; special regexp to search for branch revision: | ||
| 409 | ;; \X will be replaced by vc-log-info (see there) | ||
| 410 | '("^revision[\t ]+\\(\\X\\)\\(\n\\|[ \t].*\n\\)date: \\([ /0-9:]+\\);" 1 3)) | ||
| 411 | |||
| 412 | '(vc-locking-user | ||
| 413 | vc-locked-version | ||
| 414 | vc-latest-version | ||
| 415 | vc-your-latest-version | ||
| 416 | vc-branch-version))) | ||
| 417 | ((eq (vc-backend file) 'CVS) | ||
| 418 | (vc-log-info "cvs" file '("status") | ||
| 419 | ;; CVS 1.3 says "RCS Version:", other releases "RCS Revision:", | ||
| 420 | ;; and CVS 1.4a1 says "Repository revision:". | ||
| 421 | '(("\\(RCS Version\\|RCS Revision\\|Repository revision\\):[\t ]+\\([0-9.]+\\)" 2) | ||
| 422 | ("^File: [^ \t]+[ \t]+Status: \\(.*\\)" 1)) | ||
| 423 | '(vc-latest-version vc-cvs-status)) | ||
| 424 | ;; Translate those status values that are needed into symbols. | ||
| 425 | ;; Any other value is converted to nil. | ||
| 426 | (let ((status (vc-file-getprop file 'vc-cvs-status))) | ||
| 427 | (cond ((string-match "Up-to-date" status) | ||
| 428 | (vc-file-setprop file 'vc-cvs-status 'up-to-date) | ||
| 429 | (vc-file-setprop file 'vc-checkout-time | ||
| 430 | (nth 5 (file-attributes file)))) | ||
| 431 | ((string-match "Locally Modified" status) | ||
| 432 | (vc-file-setprop file 'vc-cvs-status 'locally-modified)) | ||
| 433 | ((string-match "Needs Merge" status) | ||
| 434 | (vc-file-setprop file 'vc-cvs-status 'needs-merge)) | ||
| 435 | (t (vc-file-setprop file 'vc-cvs-status nil)))) | ||
| 436 | ))) | ||
| 437 | |||
| 438 | (defun vc-backend-subdirectory-name (&optional file) | ||
| 439 | ;; Where the master and lock files for the current directory are kept | ||
| 440 | (symbol-name | ||
| 441 | (or | ||
| 442 | (and file (vc-backend file)) | ||
| 443 | vc-default-back-end | ||
| 444 | (setq vc-default-back-end (if (vc-find-binary "rcs") 'RCS 'SCCS))))) | ||
| 445 | |||
| 446 | |||
| 447 | ;;; Access functions to file properties | ||
| 448 | ;;; (Properties should be _set_ using vc-file-setprop, but | ||
| 449 | ;;; _retrieved_ only through these functions, which decide | ||
| 450 | ;;; if the property is already known or not. A property should | ||
| 451 | ;;; only be retrieved by vc-file-getprop if there is no | ||
| 452 | ;;; access function.) | ||
| 453 | |||
| 454 | ;; functions vc-name and vc-backend come earlier above, | ||
| 455 | ;; because they are needed by vc-log-info etc. | ||
| 456 | |||
| 457 | (defun vc-cvs-status (file) | ||
| 458 | ;; Return the cvs status of FILE | ||
| 459 | ;; (Status field in output of "cvs status") | ||
| 460 | (cond ((vc-file-getprop file 'vc-cvs-status)) | ||
| 461 | (t (vc-fetch-properties file) | ||
| 462 | (vc-file-getprop file 'vc-cvs-status)))) | ||
| 463 | |||
| 464 | (defun vc-locking-user (file) | ||
| 465 | "Return the name of the person currently holding a lock on FILE. | ||
| 466 | Return nil if there is no such person. | ||
| 467 | Under CVS, a file is considered locked if it has been modified since it | ||
| 468 | was checked out. Under CVS, this will sometimes return the uid of | ||
| 469 | the owner of the file (as a number) instead of a string." | ||
| 470 | ;; The property is cached. If it is non-nil, it is simply returned. | ||
| 471 | ;; The other routines clear it when the locking state changes. | ||
| 472 | (setq file (expand-file-name file));; ??? Work around bug in 19.0.4 | ||
| 473 | (cond | ||
| 474 | ((vc-file-getprop file 'vc-locking-user)) | ||
| 475 | ((eq (vc-backend file) 'CVS) | ||
| 476 | (if (eq (vc-cvs-status file) 'up-to-date) | ||
| 477 | nil | ||
| 478 | ;; The expression below should return the username of the owner | ||
| 479 | ;; of the file. It doesn't. It returns the username if it is | ||
| 480 | ;; you, or otherwise the UID of the owner of the file. The | ||
| 481 | ;; return value from this function is only used by | ||
| 482 | ;; vc-dired-reformat-line, and it does the proper thing if a UID | ||
| 483 | ;; is returned. | ||
| 484 | ;; | ||
| 485 | ;; The *proper* way to fix this would be to implement a built-in | ||
| 486 | ;; function in Emacs, say, (username UID), that returns the | ||
| 487 | ;; username of a given UID. | ||
| 488 | ;; | ||
| 489 | ;; The result of this hack is that vc-directory will print the | ||
| 490 | ;; name of the owner of the file for any files that are | ||
| 491 | ;; modified. | ||
| 492 | (let ((uid (nth 2 (file-attributes file)))) | ||
| 493 | (if (= uid (user-uid)) | ||
| 494 | (vc-file-setprop file 'vc-locking-user (user-login-name)) | ||
| 495 | (vc-file-setprop file 'vc-locking-user uid))))) | ||
| 496 | (t | ||
| 497 | (if (and (eq (vc-backend file) 'RCS) | ||
| 498 | (eq (vc-consult-rcs-headers file) 'rev-and-lock)) | ||
| 499 | (vc-file-getprop file 'vc-locking-user) | ||
| 500 | (if (or (not vc-keep-workfiles) | ||
| 501 | (eq vc-mistrust-permissions 't) | ||
| 502 | (and vc-mistrust-permissions | ||
| 503 | (funcall vc-mistrust-permissions | ||
| 504 | (vc-backend-subdirectory-name file)))) | ||
| 505 | (vc-file-setprop file 'vc-locking-user (vc-true-locking-user file)) | ||
| 506 | ;; This implementation assumes that any file which is under version | ||
| 507 | ;; control and has -rw-r--r-- is locked by its owner. This is true | ||
| 508 | ;; for both RCS and SCCS, which keep unlocked files at -r--r--r--. | ||
| 509 | ;; We have to be careful not to exclude files with execute bits on; | ||
| 510 | ;; scripts can be under version control too. Also, we must ignore | ||
| 511 | ;; the group-read and other-read bits, since paranoid users turn them off. | ||
| 512 | ;; This hack wins because calls to the very expensive vc-fetch-properties | ||
| 513 | ;; function only have to be made if (a) the file is locked by someone | ||
| 514 | ;; other than the current user, or (b) some untoward manipulation | ||
| 515 | ;; behind vc's back has changed the owner or the `group' or `other' | ||
| 516 | ;; write bits. | ||
| 517 | (let ((attributes (file-attributes file))) | ||
| 518 | (cond ((string-match ".r-..-..-." (nth 8 attributes)) | ||
| 519 | nil) | ||
| 520 | ((and (= (nth 2 attributes) (user-uid)) | ||
| 521 | (string-match ".rw..-..-." (nth 8 attributes))) | ||
| 522 | (vc-file-setprop file 'vc-locking-user (user-login-name))) | ||
| 523 | (t | ||
| 524 | (vc-file-setprop file 'vc-locking-user | ||
| 525 | (vc-true-locking-user file)))))))))) | ||
| 526 | |||
| 527 | (defun vc-true-locking-user (file) | ||
| 528 | ;; The slow but reliable version | ||
| 529 | (vc-fetch-properties file) | ||
| 530 | (vc-file-getprop file 'vc-locking-user)) | ||
| 531 | |||
| 532 | (defun vc-latest-version (file) | ||
| 533 | ;; Return version level of the latest version of FILE | ||
| 534 | (vc-fetch-properties file) | ||
| 535 | (vc-file-getprop file 'vc-latest-version)) | ||
| 536 | |||
| 537 | (defun vc-your-latest-version (file) | ||
| 538 | ;; Return version level of the latest version of FILE checked in by you | ||
| 539 | (vc-fetch-properties file) | ||
| 540 | (vc-file-getprop file 'vc-your-latest-version)) | ||
| 541 | |||
| 542 | (defun vc-branch-version (file) | ||
| 543 | ;; Return version level of the highest revision on the default branch | ||
| 544 | ;; If there is no default branch, return the highest version number | ||
| 545 | ;; on the trunk. | ||
| 546 | ;; This property is defined for RCS only. | ||
| 547 | (vc-fetch-properties file) | ||
| 548 | (vc-file-getprop file 'vc-branch-version)) | ||
| 549 | |||
| 550 | (defun vc-workfile-version (file) | ||
| 551 | ;; Return version level of the current workfile FILE | ||
| 552 | ;; This is attempted by first looking at the RCS keywords. | ||
| 553 | ;; If there are no keywords in the working file, | ||
| 554 | ;; vc-branch-version is taken. | ||
| 555 | ;; Note that this property is cached, that is, it is only | ||
| 556 | ;; looked up if it is nil. | ||
| 557 | ;; For SCCS, this property is equivalent to vc-latest-version. | ||
| 558 | (cond ((vc-file-getprop file 'vc-workfile-version)) | ||
| 559 | ((eq (vc-backend file) 'SCCS) (vc-latest-version file)) | ||
| 560 | ((eq (vc-backend file) 'RCS) | ||
| 561 | (if (vc-consult-rcs-headers file) | ||
| 562 | (vc-file-getprop file 'vc-workfile-version) | ||
| 563 | (let ((rev (cond ((vc-branch-version file)) | ||
| 564 | ((vc-latest-version file))))) | ||
| 565 | (vc-file-setprop file 'vc-workfile-version rev) | ||
| 566 | rev))) | ||
| 567 | ((eq (vc-backend file) 'CVS) | ||
| 568 | (if (vc-consult-rcs-headers file) ;; CVS | ||
| 569 | (vc-file-getprop file 'vc-workfile-version) | ||
| 570 | (vc-find-cvs-master (file-name-directory file) | ||
| 571 | (file-name-nondirectory file)) | ||
| 572 | (vc-file-getprop file 'vc-workfile-version))))) | ||
| 111 | 573 | ||
| 112 | ;;; actual version-control code starts here | 574 | ;;; actual version-control code starts here |
| 113 | 575 | ||
| @@ -187,29 +649,10 @@ Otherwise, not displayed.") | |||
| 187 | nil))) | 649 | nil))) |
| 188 | (mapcar (function kill-buffer) bufs))))) | 650 | (mapcar (function kill-buffer) bufs))))) |
| 189 | 651 | ||
| 190 | (defun vc-name (file) | ||
| 191 | "Return the master name of a file, nil if it is not registered." | ||
| 192 | (or (vc-file-getprop file 'vc-name) | ||
| 193 | (let ((name-and-type (vc-registered file))) | ||
| 194 | (if name-and-type | ||
| 195 | (progn | ||
| 196 | (vc-file-setprop file 'vc-backend (cdr name-and-type)) | ||
| 197 | (vc-file-setprop file 'vc-name (car name-and-type))))))) | ||
| 198 | |||
| 199 | (defun vc-backend-deduce (file) | ||
| 200 | "Return the version-control type of a file, nil if it is not registered." | ||
| 201 | (and file | ||
| 202 | (or (vc-file-getprop file 'vc-backend) | ||
| 203 | (let ((name-and-type (vc-registered file))) | ||
| 204 | (if name-and-type | ||
| 205 | (progn | ||
| 206 | (vc-file-setprop file 'vc-name (car name-and-type)) | ||
| 207 | (vc-file-setprop file 'vc-backend (cdr name-and-type)))))))) | ||
| 208 | |||
| 209 | (defun vc-buffer-backend () | 652 | (defun vc-buffer-backend () |
| 210 | "Return the version-control type of the visited file, or nil if none." | 653 | "Return the version-control type of the visited file, or nil if none." |
| 211 | (if (eq vc-buffer-backend t) | 654 | (if (eq vc-buffer-backend t) |
| 212 | (setq vc-buffer-backend (vc-backend-deduce (buffer-file-name))) | 655 | (setq vc-buffer-backend (vc-backend (buffer-file-name))) |
| 213 | vc-buffer-backend)) | 656 | vc-buffer-backend)) |
| 214 | 657 | ||
| 215 | (defun vc-toggle-read-only (&optional verbose) | 658 | (defun vc-toggle-read-only (&optional verbose) |
| @@ -218,7 +661,7 @@ If the buffer is visiting a file registered with version control, | |||
| 218 | then check the file in or out. Otherwise, just change the read-only flag | 661 | then check the file in or out. Otherwise, just change the read-only flag |
| 219 | of the buffer. With prefix argument, ask for version number." | 662 | of the buffer. With prefix argument, ask for version number." |
| 220 | (interactive "P") | 663 | (interactive "P") |
| 221 | (if (vc-backend-deduce (buffer-file-name)) | 664 | (if (vc-backend (buffer-file-name)) |
| 222 | (vc-next-action verbose) | 665 | (vc-next-action verbose) |
| 223 | (toggle-read-only))) | 666 | (toggle-read-only))) |
| 224 | (define-key global-map "\C-x\C-q" 'vc-toggle-read-only) | 667 | (define-key global-map "\C-x\C-q" 'vc-toggle-read-only) |
| @@ -229,14 +672,19 @@ The value is set in the current buffer, which should be the buffer | |||
| 229 | visiting FILE. Second optional arg LABEL is put in place of version | 672 | visiting FILE. Second optional arg LABEL is put in place of version |
| 230 | control system name." | 673 | control system name." |
| 231 | (interactive (list buffer-file-name nil)) | 674 | (interactive (list buffer-file-name nil)) |
| 232 | (let ((vc-type (vc-backend-deduce file))) | 675 | (let ((vc-type (vc-backend file)) |
| 676 | (vc-status-string (and vc-display-status (vc-status file)))) | ||
| 233 | (setq vc-mode | 677 | (setq vc-mode |
| 234 | (concat " " (or label (symbol-name vc-type)) | 678 | (concat " " (or label (symbol-name vc-type)) vc-status-string)) |
| 235 | (if vc-display-status (vc-status file vc-type)))) | 679 | ;; Make the buffer read-only if the file is not locked |
| 236 | ;;; ;; Make the buffer read-only if the file is not locked | 680 | ;; (or unchanged, in the CVS case). |
| 237 | ;;; ;; (or unchanged, in the CVS case). | 681 | ;; Determine this by looking at the mode string, |
| 238 | ;;; (if (not (vc-locking-user file)) | 682 | ;; so that no further external status query is necessary |
| 239 | ;;; (setq buffer-read-only t)) | 683 | (if vc-status-string |
| 684 | (if (eq (elt vc-status-string 0) ?-) | ||
| 685 | (setq buffer-read-only t)) | ||
| 686 | (if (not (vc-locking-user file)) | ||
| 687 | (setq buffer-read-only t))) | ||
| 240 | ;; Even root shouldn't modify a registered file without | 688 | ;; Even root shouldn't modify a registered file without |
| 241 | ;; locking it first. | 689 | ;; locking it first. |
| 242 | (and vc-type | 690 | (and vc-type |
| @@ -247,7 +695,7 @@ control system name." | |||
| 247 | (setq buffer-read-only t)) | 695 | (setq buffer-read-only t)) |
| 248 | (and (null vc-type) | 696 | (and (null vc-type) |
| 249 | (file-symlink-p file) | 697 | (file-symlink-p file) |
| 250 | (let ((link-type (vc-backend-deduce (file-symlink-p file)))) | 698 | (let ((link-type (vc-backend (file-symlink-p file)))) |
| 251 | (if link-type | 699 | (if link-type |
| 252 | (message | 700 | (message |
| 253 | "Warning: symbolic link to %s-controlled source file" | 701 | "Warning: symbolic link to %s-controlled source file" |
| @@ -256,130 +704,32 @@ control system name." | |||
| 256 | ;;(set-buffer-modified-p (buffer-modified-p)) ;;use this if Emacs 18 | 704 | ;;(set-buffer-modified-p (buffer-modified-p)) ;;use this if Emacs 18 |
| 257 | vc-type)) | 705 | vc-type)) |
| 258 | 706 | ||
| 259 | (defun vc-status (file vc-type) | 707 | (defun vc-status (file) |
| 260 | ;; Return string for placement in modeline by `vc-mode-line'. | 708 | ;; Return string for placement in modeline by `vc-mode-line'. |
| 261 | ;; If FILE is not registered, return nil. | 709 | ;; Format: |
| 262 | ;; If FILE is registered but not locked, return " REV" if there is a head | ||
| 263 | ;; revision and " @@" otherwise. | ||
| 264 | ;; If FILE is locked then return all locks in a string of the | ||
| 265 | ;; form " LOCKER1:REV1 LOCKER2:REV2 ...", where "LOCKERi:" is empty if you | ||
| 266 | ;; are the locker, and otherwise is the name of the locker followed by ":". | ||
| 267 | |||
| 268 | ;; Algorithm: | ||
| 269 | |||
| 270 | ;; Check for master file corresponding to FILE being visited. | ||
| 271 | ;; | ||
| 272 | ;; RCS: Insert the first few characters of the master file into a | ||
| 273 | ;; work buffer. Search work buffer for "locks...;" phrase; if not | ||
| 274 | ;; found, then keep inserting more characters until the phrase is | ||
| 275 | ;; found. Extract the locks, and remove control characters | ||
| 276 | ;; separating them, like newlines; the string " user1:revision1 | ||
| 277 | ;; user2:revision2 ..." is returned. | ||
| 278 | ;; | 710 | ;; |
| 279 | ;; SCCS: Check if the p-file exists. If it does, read it and | 711 | ;; "-REV" if the revision is not locked |
| 280 | ;; extract the locks, giving them the right format. Else use prs to | 712 | ;; ":REV" if the revision is locked by the user |
| 281 | ;; find the revision number. | 713 | ;; ":LOCKER:REV" if the revision is locked by somebody else |
| 714 | ;; " @@" for a CVS file that is added, but not yet committed | ||
| 282 | ;; | 715 | ;; |
| 283 | ;; CVS: vc-find-cvs-master has already stored the current revision | 716 | ;; In the CVS case, a "locked" working file is a |
| 284 | ;; number. Fetch it from the file property. | 717 | ;; working file that is modified with respect to the master. |
| 285 | 718 | ;; The file is "locked" from the moment when the user makes | |
| 286 | ;; Limitations: | 719 | ;; the buffer writable. |
| 287 | 720 | ;; | |
| 288 | ;; The output doesn't show which version you are actually looking at. | 721 | ;; This function assumes that the file is registered. |
| 289 | ;; The modeline can get quite cluttered when there are multiple locks. | 722 | |
| 290 | ;; The head revision is probably not what you want if you've used `rcs -b'. | 723 | (let ((locker (vc-locking-user file)) |
| 291 | 724 | (rev (vc-workfile-version file))) | |
| 292 | (let ((master (vc-name file)) | 725 | (cond ((string= "0" rev) |
| 293 | found | 726 | " @@") |
| 294 | status) | 727 | ((not locker) |
| 295 | 728 | (concat "-" rev)) | |
| 296 | ;; If master file exists, then parse its contents, otherwise we | 729 | ((string= locker (user-login-name)) |
| 297 | ;; return the nil value of this if form. | 730 | (concat ":" rev)) |
| 298 | (if (and master vc-type) | 731 | (t |
| 299 | (save-excursion | 732 | (concat ":" locker ":" rev))))) |
| 300 | |||
| 301 | ;; Create work buffer. | ||
| 302 | (set-buffer (get-buffer-create " *vc-status*")) | ||
| 303 | (setq buffer-read-only nil | ||
| 304 | default-directory (file-name-directory master)) | ||
| 305 | (erase-buffer) | ||
| 306 | |||
| 307 | ;; Set the `status' var to the return value. | ||
| 308 | (cond | ||
| 309 | |||
| 310 | ;; RCS code. | ||
| 311 | ((eq vc-type 'RCS) | ||
| 312 | ;; Check if we have enough of the header. | ||
| 313 | ;; If not, then keep including more. | ||
| 314 | (while | ||
| 315 | (not (or found | ||
| 316 | (let ((s (buffer-size))) | ||
| 317 | (goto-char (1+ s)) | ||
| 318 | (zerop (car (cdr (insert-file-contents | ||
| 319 | master nil s (+ s 8192)))))))) | ||
| 320 | (beginning-of-line) | ||
| 321 | (setq found (re-search-forward "^locks\\([^;]*\\);" nil t))) | ||
| 322 | |||
| 323 | (if found | ||
| 324 | ;; Clean control characters and self-locks from text. | ||
| 325 | (let* ((lock-pattern | ||
| 326 | (concat "[ \b\t\n\v\f\r]+\\(" | ||
| 327 | (regexp-quote (user-login-name)) | ||
| 328 | ":\\)?")) | ||
| 329 | (locks | ||
| 330 | (save-restriction | ||
| 331 | (narrow-to-region (match-beginning 1) (match-end 1)) | ||
| 332 | (goto-char (point-min)) | ||
| 333 | (while (re-search-forward lock-pattern nil t) | ||
| 334 | (replace-match (if (eobp) "" ":") t t)) | ||
| 335 | (buffer-string)))) | ||
| 336 | (setq status | ||
| 337 | (if (not (string-equal locks "")) | ||
| 338 | locks | ||
| 339 | (goto-char (point-min)) | ||
| 340 | (if (looking-at "head[ \b\t\n\v\f\r]+\\([.0-9]+\\)") | ||
| 341 | (concat "-" | ||
| 342 | (buffer-substring (match-beginning 1) | ||
| 343 | (match-end 1))) | ||
| 344 | " @@")))))) | ||
| 345 | |||
| 346 | ;; SCCS code. | ||
| 347 | ((eq vc-type 'SCCS) | ||
| 348 | ;; Build the name of the p-file and put it in the work buffer. | ||
| 349 | (insert master) | ||
| 350 | (search-backward "/s.") | ||
| 351 | (delete-char 2) | ||
| 352 | (insert "/p") | ||
| 353 | (if (not (file-exists-p (buffer-string))) | ||
| 354 | ;; No lock. | ||
| 355 | (let ((exec-path (if vc-path (append exec-path vc-path) | ||
| 356 | exec-path))) | ||
| 357 | (erase-buffer) | ||
| 358 | (insert "-") | ||
| 359 | (if (zerop (call-process "prs" nil t nil "-d:I:" master)) | ||
| 360 | (setq status (buffer-substring 1 (1- (point-max)))))) | ||
| 361 | ;; Locks exist. | ||
| 362 | (insert-file-contents (buffer-string) nil nil nil t) | ||
| 363 | (while (looking-at "[^ ]+ \\([^ ]+\\) \\([^ ]+\\).*\n") | ||
| 364 | (replace-match " \\2:\\1")) | ||
| 365 | (setq status (buffer-string)) | ||
| 366 | (aset status 0 ?:))) | ||
| 367 | ;; CVS code. | ||
| 368 | ((eq vc-type 'CVS) | ||
| 369 | (let ((version (vc-file-getprop | ||
| 370 | file 'vc-your-latest-version))) | ||
| 371 | (setq status (concat ":" (if (string= "0" version) | ||
| 372 | " @@" ;added, not yet committed. | ||
| 373 | version)))))) | ||
| 374 | |||
| 375 | ;; Clean work buffer. | ||
| 376 | (erase-buffer) | ||
| 377 | (set-buffer-modified-p nil) | ||
| 378 | status)))) | ||
| 379 | |||
| 380 | (defun vc-file-clearprops (file) | ||
| 381 | ;; clear all properties of a given file | ||
| 382 | (setplist (intern file vc-file-prop-obarray) nil)) | ||
| 383 | 733 | ||
| 384 | ;;; install a call to the above as a find-file hook | 734 | ;;; install a call to the above as a find-file hook |
| 385 | (defun vc-find-file-hook () | 735 | (defun vc-find-file-hook () |
| @@ -389,7 +739,7 @@ control system name." | |||
| 389 | (buffer-file-name | 739 | (buffer-file-name |
| 390 | (vc-file-clearprops buffer-file-name) | 740 | (vc-file-clearprops buffer-file-name) |
| 391 | (cond | 741 | (cond |
| 392 | ((vc-backend-deduce buffer-file-name) | 742 | ((vc-backend buffer-file-name) |
| 393 | (vc-mode-line buffer-file-name) | 743 | (vc-mode-line buffer-file-name) |
| 394 | (cond ((not vc-make-backup-files) | 744 | (cond ((not vc-make-backup-files) |
| 395 | ;; Use this variable, not make-backup-files, | 745 | ;; Use this variable, not make-backup-files, |
| @@ -403,7 +753,7 @@ control system name." | |||
| 403 | (defun vc-file-not-found-hook () | 753 | (defun vc-file-not-found-hook () |
| 404 | "When file is not found, try to check it out from RCS or SCCS. | 754 | "When file is not found, try to check it out from RCS or SCCS. |
| 405 | Returns t if checkout was successful, nil otherwise." | 755 | Returns t if checkout was successful, nil otherwise." |
| 406 | (if (vc-backend-deduce buffer-file-name) | 756 | (if (vc-backend buffer-file-name) |
| 407 | (save-excursion | 757 | (save-excursion |
| 408 | (require 'vc) | 758 | (require 'vc) |
| 409 | (not (vc-error-occurred (vc-checkout buffer-file-name)))))) | 759 | (not (vc-error-occurred (vc-checkout buffer-file-name)))))) |