X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/1fd3454a347c5d55b996f5ae1a334e2ca4769e0f..ca088b04376178d1305ff9d0866c20263f4a79bf:/lisp/vc-svn.el diff --git a/lisp/vc-svn.el b/lisp/vc-svn.el index 780b71746c..b6e3ac2956 100644 --- a/lisp/vc-svn.el +++ b/lisp/vc-svn.el @@ -1,6 +1,7 @@ ;;; vc-svn.el --- non-resident support for Subversion version-control -;; Copyright (C) 1995,98,99,2000,2001,2002 Free Software Foundation, Inc. +;; Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +;; Free Software Foundation, Inc. ;; Author: FSF (see vc.el for full credits) ;; Maintainer: Stefan Monnier @@ -32,10 +33,7 @@ ;;; Bugs: -;; - VC-dired is either not working or (really) dog slow. -;; - vc-print-log does not always jump to the proper log entry because -;; it tries to jump to version 1234 even if there's only an entry -;; for 1232 (because the file hasn't changed since). +;; - VC-dired is (really) slow. ;;; Code: @@ -53,7 +51,7 @@ (repeat :tag "Argument List" :value ("") string)) - :version "21.4" + :version "22.1" :group 'vc) (defcustom vc-svn-register-switches nil @@ -65,52 +63,38 @@ A string or list of strings passed to the checkin program by (repeat :tag "Argument List" :value ("") string)) - :version "21.1" + :version "22.1" :group 'vc) -(defcustom vc-svn-diff-switches nil - "*A string or list of strings specifying extra switches for svn diff under VC." - :type '(choice (const :tag "None" nil) +(defcustom vc-svn-diff-switches + t ;`svn' doesn't support common args like -c or -b. + "String or list of strings specifying extra switches for svn diff under VC. +If nil, use the value of `vc-diff-switches'. +If you want to force an empty list of arguments, use t." + :type '(choice (const :tag "Unspecified" nil) + (const :tag "None" t) (string :tag "Argument String") (repeat :tag "Argument List" :value ("") string)) - :version "21.1" + :version "22.1" :group 'vc) (defcustom vc-svn-header (or (cdr (assoc 'SVN vc-header-alist)) '("\$Id\$")) "*Header keywords to be inserted by `vc-insert-headers'." - :version "21.1" + :version "22.1" :type '(repeat string) :group 'vc) -(defcustom vc-svn-use-edit nil +(defconst vc-svn-use-edit nil + ;; Subversion does not provide this feature (yet). "*Non-nil means to use `svn edit' to \"check out\" a file. This is only meaningful if you don't use the implicit checkout model \(i.e. if you have $SVNREAD set)." - :type 'boolean - :version "21.1" - :group 'vc) - -(defcustom vc-svn-stay-local t - "*Non-nil means use local operations when possible for remote repositories. -This avoids slow queries over the network and instead uses heuristics -and past information to determine the current status of a file. - -The value can also be a regular expression or list of regular -expressions to match against the host name of a repository; then VC -only stays local for hosts that match it. Alternatively, the value -can be a list of regular expressions where the first element is the -symbol `except'; then VC always stays local except for hosts matched -by these regular expressions." - :type '(choice (const :tag "Always stay local" t) - (const :tag "Don't stay local" nil) - (list :format "\nExamine hostname and %v" :tag "Examine hostname ..." - (set :format "%v" :inline t (const :format "%t" :tag "don't" except)) - (regexp :format " stay local,\n%t: %v" :tag "if it matches") - (repeat :format "%v%i\n" :inline t (regexp :tag "or")))) - :version "21.1" - :group 'vc) + ;; :type 'boolean + ;; :version "22.1" + ;; :group 'vc + ) ;;; ;;; State-querying functions @@ -122,6 +106,9 @@ by these regular expressions." ;;;###autoload (load "vc-svn") ;;;###autoload (vc-svn-registered f))) +;;;###autoload +(add-to-list 'completion-ignored-extensions ".svn/") + (defun vc-svn-registered (file) "Check if FILE is SVN registered." (when (file-readable-p (expand-file-name ".svn/entries" @@ -131,13 +118,13 @@ by these regular expressions." (condition-case nil (vc-svn-command t 0 file "status" "-v") ;; We can't find an `svn' executable. We could also deregister SVN. - (file-error nil) + (file-error nil)) (vc-svn-parse-status t) (eq 'SVN (vc-file-getprop file 'vc-backend))))) (defun vc-svn-state (file &optional localp) "SVN-specific version of `vc-state'." - (setq localp (or localp (vc-svn-stay-local-p file))) + (setq localp (or localp (vc-stay-local-p file))) (with-temp-buffer (cd (file-name-directory file)) (vc-svn-command t 0 file "status" (if localp "-v" "-u")) @@ -150,7 +137,7 @@ by these regular expressions." (defun vc-svn-dir-state (dir &optional localp) "Find the SVN state of all files in DIR." - (setq localp (or localp (vc-svn-stay-local-p dir))) + (setq localp (or localp (vc-stay-local-p dir))) (let ((default-directory dir)) ;; Don't specify DIR in this command, the default-directory is ;; enough. Otherwise it might fail with remote repositories. @@ -171,42 +158,17 @@ by these regular expressions." ;; It looks like Subversion has no equivalent of CVSREAD. 'implicit) -(defun vc-svn-mode-line-string (file) - "Return string for placement into the modeline for FILE. -Compared to the default implementation, this function does two things: -Handle the special case of a SVN file that is added but not yet -committed and support display of sticky tags." - (let* ((state (vc-state file)) - (rev (vc-workfile-version file)) - (sticky-tag (vc-file-getprop file 'vc-svn-sticky-tag)) - (sticky-tag-printable (and sticky-tag - (not (string= sticky-tag "")) - (concat "[" sticky-tag "]")))) - (cond ((string= rev "0") - ;; A file that is added but not yet committed. - "SVN @@") - ((or (eq state 'up-to-date) - (eq state 'needs-patch)) - (concat "SVN-" rev sticky-tag-printable)) - ((stringp state) - (concat "SVN:" state ":" rev sticky-tag-printable)) - (t - ;; Not just for the 'edited state, but also a fallback - ;; for all other states. Think about different symbols - ;; for 'needs-patch and 'needs-merge. - (concat "SVN:" rev sticky-tag-printable))))) +;; vc-svn-mode-line-string doesn't exist because the default implementation +;; works just fine. (defun vc-svn-dired-state-info (file) "SVN-specific version of `vc-dired-state-info'." - (let* ((svn-state (vc-state file)) - (state (cond ((eq svn-state 'edited) "modified") - ((eq svn-state 'needs-patch) "patch") - ((eq svn-state 'needs-merge) "merge") - ;; FIXME: those two states cannot occur right now - ((eq svn-state 'unlocked-changes) "conflict") - ((eq svn-state 'locally-added) "added") - ))) - (if state (concat "(" state ")")))) + (let ((svn-state (vc-state file))) + (cond ((eq svn-state 'edited) + (if (equal (vc-workfile-version file) "0") + "(added)" "(modified)")) + ((eq svn-state 'needs-patch) "(patch)") + ((eq svn-state 'needs-merge) "(merge)")))) ;;; @@ -219,19 +181,7 @@ COMMENT can be used to provide an initial description of FILE. `vc-register-switches' and `vc-svn-register-switches' are passed to the SVN command (in that order)." - (let ((switches (append - (if (stringp vc-register-switches) - (list vc-register-switches) - vc-register-switches) - (if (stringp vc-svn-register-switches) - (list vc-svn-register-switches) - vc-svn-register-switches)))) - - (apply 'vc-svn-command nil 0 file - "add" - ;; (and comment (string-match "[^\t\n ]" comment) - ;; (concat "-m" comment)) - switches))) + (apply 'vc-svn-command nil 0 file "add" (vc-switches 'SVN 'register))) (defun vc-svn-responsible-p (file) "Return non-nil if SVN thinks it is responsible for FILE." @@ -246,18 +196,15 @@ This is only possible if SVN is responsible for FILE's directory.") (defun vc-svn-checkin (file rev comment) "SVN-specific version of `vc-backend-checkin'." - (let ((switches (if (stringp vc-checkin-switches) - (list vc-checkin-switches) - vc-checkin-switches)) - status) - (setq status (apply 'vc-svn-command nil 1 file - "ci" (list* "-m" comment switches))) + (let ((status (apply + 'vc-svn-command nil 1 file "ci" + (nconc (list "-m" comment) (vc-switches 'SVN 'checkin))))) (set-buffer "*vc*") (goto-char (point-min)) (unless (equal status 0) ;; Check checkin problem. (cond - ((re-search-forward "Up-to-date check failed" nil t) + ((search-forward "Transaction is out of date" nil t) (vc-file-setprop file 'vc-state 'needs-merge) (error (substitute-command-keys (concat "Up-to-date check failed: " @@ -279,17 +226,12 @@ This is only possible if SVN is responsible for FILE's directory.") "cat" (and rev (not (string= rev "")) (concat "-r" rev)) - (if (stringp vc-checkout-switches) - (list vc-checkout-switches) - vc-checkout-switches))) + (vc-switches 'SVN 'checkout))) (defun vc-svn-checkout (file &optional editable rev) (message "Checking out %s..." file) (with-current-buffer (or (get-file-buffer file) (current-buffer)) - (let ((switches (if (stringp vc-checkout-switches) - (list vc-checkout-switches) - vc-checkout-switches))) - (vc-call update file editable rev switches))) + (vc-call update file editable rev (vc-switches 'SVN 'checkout))) (vc-mode-line file) (message "Checking out %s...done" file)) @@ -305,15 +247,21 @@ This is only possible if SVN is responsible for FILE's directory.") ;; Check out a particular version (or recreate the file). (vc-file-setprop file 'vc-workfile-version nil) (apply 'vc-svn-command nil 0 file - "-w" "update" ;; default for verbose checkout: clear the sticky tag so ;; that the actual update will get the head of the trunk - (if (or (not rev) (string= rev "")) - "-A" - (concat "-r" rev)) + (cond + ((null rev) "-rBASE") + ((or (eq rev t) (equal rev "")) nil) + (t (concat "-r" rev))) switches))) +(defun vc-svn-delete-file (file) + (vc-svn-command nil 0 file "remove")) + +(defun vc-svn-rename-file (old new) + (vc-svn-command nil 0 new "move" (file-relative-name old))) + (defun vc-svn-revert (file &optional contents-done) "Revert FILE to the version it was based on." (unless contents-done @@ -328,14 +276,15 @@ This is only possible if SVN is responsible for FILE's directory.") "Merge changes into current working copy of FILE. The changes are between FIRST-VERSION and SECOND-VERSION." (vc-svn-command nil 0 file - "update" "-kk" - (concat "-j" first-version) - (concat "-j" second-version)) + "merge" + "-r" (if second-version + (concat first-version ":" second-version) + first-version)) (vc-file-setprop file 'vc-state 'edited) (with-current-buffer (get-buffer "*vc*") (goto-char (point-min)) - (if (re-search-forward "conflicts during merge" nil t) - 1 ; signal error + (if (looking-at "C ") + 1 ; signal conflict 0))) ; signal success (defun vc-svn-merge-news (file) @@ -350,29 +299,27 @@ The changes are between FIRST-VERSION and SECOND-VERSION." (goto-char (point-min)) ;; get new workfile version (if (re-search-forward - "^Merging differences between [0-9.]* and \\([0-9.]*\\) into" nil t) - (vc-file-setprop file 'vc-workfile-version (match-string 1)) + "^\\(Updated to\\|At\\) revision \\([0-9]+\\)" nil t) + (vc-file-setprop file 'vc-workfile-version (match-string 2)) (vc-file-setprop file 'vc-workfile-version nil)) ;; get file status + (goto-char (point-min)) (prog1 - (if (eq (buffer-size) 0) + (if (looking-at "At revision") 0 ;; there were no news; indicate success (if (re-search-forward - (concat "^\\([CMUP] \\)?" - (regexp-quote (file-name-nondirectory file)) - "\\( already contains the differences between \\)?") + (concat "^\\([CGDU] \\)?" + (regexp-quote (file-name-nondirectory file))) nil t) (cond ;; Merge successful, we are in sync with repository now - ((or (match-string 2) - (string= (match-string 1) "U ") - (string= (match-string 1) "P ")) + ((string= (match-string 1) "U ") (vc-file-setprop file 'vc-state 'up-to-date) (vc-file-setprop file 'vc-checkout-time (nth 5 (file-attributes file))) 0);; indicate success to the caller ;; Merge successful, but our own changes are still in the file - ((string= (match-string 1) "M ") + ((string= (match-string 1) "G ") (vc-file-setprop file 'vc-state 'edited) 0);; indicate success to the caller ;; Conflicts detected! @@ -389,76 +336,62 @@ The changes are between FIRST-VERSION and SECOND-VERSION." ;;; History functions ;;; -(defun vc-svn-print-log (file) +(defun vc-svn-print-log (file &optional buffer) "Get change log associated with FILE." (save-current-buffer - (vc-setup-buffer nil) + (vc-setup-buffer buffer) (let ((inhibit-read-only t)) (goto-char (point-min)) ;; Add a line to tell log-view-mode what file this is. (insert "Working file: " (file-relative-name file) "\n")) (vc-svn-command - t - (if (and (vc-svn-stay-local-p file) (fboundp 'start-process)) 'async 0) + buffer + (if (and (vc-stay-local-p file) (fboundp 'start-process)) 'async 0) file "log"))) -(defun vc-svn-diff (file &optional oldvers newvers) +(defun vc-svn-diff (file &optional oldvers newvers buffer) "Get a difference report using SVN between two versions of FILE." - (let (status (diff-switches-list (vc-diff-switches-list 'SVN))) - (if (string= (vc-workfile-version file) "0") - ;; This file is added but not yet committed; there is no master file. - (if (or oldvers newvers) - (error "No revisions of %s exist" file) - ;; We regard this as "changed". - ;; Diff it against /dev/null. - ;; Note: this is NOT a "svn diff". - (apply 'vc-do-command "*vc-diff*" - 1 "diff" file - (append diff-switches-list '("/dev/null")))) - (setq status - (apply 'vc-svn-command "*vc-diff*" - (if (and (vc-svn-stay-local-p file) - (or oldvers newvers) ; Svn diffs those locally. - (fboundp 'start-process)) - 'async - 1) - file "diff" - (append - (when oldvers - (list "-r" - (if newvers (concat oldvers ":" newvers) oldvers))) - (when diff-switches-list - (list "-x" (mapconcat 'identity diff-switches-list " ")))))) - (if (vc-svn-stay-local-p file) - 1 ;; async diff, pessimistic assumption - status)))) + (unless buffer (setq buffer "*vc-diff*")) + (if (and oldvers (equal oldvers (vc-workfile-version file))) + ;; Use nil rather than the current revision because svn handles it + ;; better (i.e. locally). + (setq oldvers nil)) + (if (string= (vc-workfile-version file) "0") + ;; This file is added but not yet committed; there is no master file. + (if (or oldvers newvers) + (error "No revisions of %s exist" file) + ;; We regard this as "changed". + ;; Diff it against /dev/null. + ;; Note: this is NOT a "svn diff". + (apply 'vc-do-command buffer + 1 "diff" file + (append (vc-switches nil 'diff) '("/dev/null"))) + ;; Even if it's empty, it's locally modified. + 1) + (let* ((switches + (if vc-svn-diff-switches + (vc-switches 'SVN 'diff) + (list "-x" (mapconcat 'identity (vc-switches nil 'diff) " ")))) + (async (and (not vc-disable-async-diff) + (vc-stay-local-p file) + (or oldvers newvers) ; Svn diffs those locally. + (fboundp 'start-process)))) + (apply 'vc-svn-command buffer + (if async 'async 0) + file "diff" + (append + switches + (when oldvers + (list "-r" (if newvers (concat oldvers ":" newvers) + oldvers))))) + (if async 1 ; async diff => pessimistic assumption + ;; For some reason `svn diff' does not return a useful + ;; status w.r.t whether the diff was empty or not. + (buffer-size (get-buffer buffer)))))) (defun vc-svn-diff-tree (dir &optional rev1 rev2) "Diff all files at and below DIR." - (with-current-buffer "*vc-diff*" - (setq default-directory dir) - (if (vc-svn-stay-local-p dir) - ;; local diff: do it filewise, and only for files that are modified - (vc-file-tree-walk - dir - (lambda (f) - (vc-exec-after - `(let ((coding-system-for-read (vc-coding-system-for-diff ',f))) - ;; possible optimization: fetch the state of all files - ;; in the tree via vc-svn-dir-state-heuristic - (unless (vc-up-to-date-p ',f) - (message "Looking at %s" ',f) - (vc-diff-internal ',f ',rev1 ',rev2)))))) - ;; svn diff: use a single call for the entire tree - (let ((coding-system-for-read (or coding-system-for-read 'undecided)) - (diff-switches-list (vc-diff-switches-list 'SVN))) - (apply 'vc-svn-command "*vc-diff*" 1 nil "diff" - (append - (when oldvers - (list "-r" - (if rev2 (concat rev1 ":" rev2) rev1))) - (when diff-switches-list - (list "-x" (mapconcat 'identity diff-switches-list " "))))))))) + (vc-svn-diff (file-name-as-directory dir) rev1 rev2)) ;;; ;;; Snapshot system @@ -467,53 +400,26 @@ The changes are between FIRST-VERSION and SECOND-VERSION." (defun vc-svn-create-snapshot (dir name branchp) "Assign to DIR's current version a given NAME. If BRANCHP is non-nil, the name is created as a branch (and the current -workspace is immediately moved to that new branch)." - (vc-svn-command nil 0 dir "tag" "-c" (if branchp "-b") name) - (when branchp (vc-svn-command nil 0 dir "update" "-r" name))) +workspace is immediately moved to that new branch). +NAME is assumed to be a URL." + (vc-svn-command nil 0 dir "copy" name) + (when branchp (vc-svn-retrieve-snapshot dir name nil))) (defun vc-svn-retrieve-snapshot (dir name update) "Retrieve a snapshot at and below DIR. NAME is the name of the snapshot; if it is empty, do a `svn update'. -If UPDATE is non-nil, then update (resynch) any affected buffers." - (with-current-buffer (get-buffer-create "*vc*") - (let ((default-directory dir) - (sticky-tag)) - (erase-buffer) - (if (or (not name) (string= name "")) - (vc-svn-command t 0 nil "update") - (vc-svn-command t 0 nil "update" "-r" name) - (setq sticky-tag name)) - (when update - (goto-char (point-min)) - (while (not (eobp)) - (if (looking-at "\\([CMUP]\\) \\(.*\\)") - (let* ((file (expand-file-name (match-string 2) dir)) - (state (match-string 1)) - (buffer (find-buffer-visiting file))) - (when buffer - (cond - ((or (string= state "U") - (string= state "P")) - (vc-file-setprop file 'vc-state 'up-to-date) - (vc-file-setprop file 'vc-workfile-version nil) - (vc-file-setprop file 'vc-checkout-time - (nth 5 (file-attributes file)))) - ((or (string= state "M") - (string= state "C")) - (vc-file-setprop file 'vc-state 'edited) - (vc-file-setprop file 'vc-workfile-version nil) - (vc-file-setprop file 'vc-checkout-time 0))) - (vc-file-setprop file 'vc-svn-sticky-tag sticky-tag) - (vc-resynch-buffer file t t)))) - (forward-line 1)))))) - +If UPDATE is non-nil, then update (resynch) any affected buffers. +NAME is assumed to be a URL." + (vc-svn-command nil 0 dir "switch" name) + ;; FIXME: parse the output and obey `update'. + ) ;;; ;;; Miscellaneous ;;; ;; Subversion makes backups for us, so don't bother. -;; (defalias 'vc-svn-make-version-backups-p 'vc-svn-stay-local-p +;; (defalias 'vc-svn-make-version-backups-p 'vc-stay-local-p ;; "Return non-nil if version backups should be made for FILE.") (defun vc-svn-check-headers () @@ -538,57 +444,22 @@ and that it passes `vc-svn-global-switches' to it before FLAGS." (append vc-svn-global-switches flags)))) -(defun vc-svn-stay-local-p (file) - "Return non-nil if VC should stay local when handling FILE. -See `vc-svn-stay-local'." - (when vc-svn-stay-local - (let* ((dirname (if (file-directory-p file) - (directory-file-name file) - (file-name-directory file))) - (prop - (or (vc-file-getprop dirname 'vc-svn-stay-local-p) - (vc-file-setprop - dirname 'vc-svn-stay-local-p - (let ((rootname (expand-file-name ".svn/entries" dirname))) - (cond - ((not (file-readable-p rootname)) 'no) - ((stringp vc-svn-stay-local) - (with-temp-buffer - (let ((coding-system-for-read - (or file-name-coding-system - default-file-name-coding-system))) - (vc-insert-file rootname)) - (goto-char (point-min)) - (when (re-search-forward - (concat "name=\"svn:this_dir\"[\n\t ]*" - "url=\"\\([^\"]+\\)\"") nil t) - (let ((hostname (match-string 1))) - (if (not hostname) - 'no - (let* ((stay-local t) - (rx - (cond - ;; vc-svn-stay-local: rx - ((stringp vc-svn-stay-local) - vc-svn-stay-local) - ;; vc-svn-stay-local: '( [except] rx ... ) - ((consp vc-svn-stay-local) - (mapconcat - 'identity - (if (not (eq (car vc-svn-stay-local) - 'except)) - vc-svn-stay-local - (setq stay-local nil) - (cdr vc-svn-stay-local)) - "\\|"))))) - (if (not rx) - 'yes - (if (not (string-match rx hostname)) - (setq stay-local (not stay-local))) - (if stay-local - 'yes - 'no)))))))))))))) - (if (eq prop 'yes) t nil)))) +(defun vc-svn-repository-hostname (dirname) + (with-temp-buffer + (let ((coding-system-for-read + (or file-name-coding-system + default-file-name-coding-system))) + (vc-insert-file (expand-file-name ".svn/entries" dirname))) + (goto-char (point-min)) + (when (re-search-forward + ;; Old `svn' used name="svn:dir", newer use just name="". + (concat "name=\"\\(?:svn:this_dir\\)?\"[\n\t ]*" + "\\(?:[-a-z]+=\"[^\"]*\"[\n\t ]*\\)*?" + "url=\"\\([^\"]+\\)\"") nil t) + ;; This is not a hostname but a URL. This may actually be considered + ;; as a feature since it allows vc-svn-stay-local to specify different + ;; behavior for different modules on the same server. + (match-string 1)))) (defun vc-svn-parse-status (localp) "Parse output of \"svn status\" command in the current buffer. @@ -597,13 +468,15 @@ essential information." (let (file status) (goto-char (point-min)) (while (re-search-forward - "^[ ADMCI?!~][ MC][ L][ +][ S]..\\([ *]\\) +\\([0-9]+\\) +\\([0-9?]+\\) +\\([^ ]+\\) +" nil t) + "^[ ADMCI?!~][ MC][ L][ +][ S]..\\([ *]\\) +\\([-0-9]+\\) +\\([0-9?]+\\) +\\([^ ]+\\) +" nil t) (setq file (expand-file-name (buffer-substring (point) (line-end-position)))) (setq status (char-after (line-beginning-position))) (unless (eq status ??) (vc-file-setprop file 'vc-backend 'SVN) - (vc-file-setprop file 'vc-workfile-version (match-string 2)) + ;; Use the last-modified revision, so that searching in vc-print-log + ;; output works. + (vc-file-setprop file 'vc-workfile-version (match-string 3)) (vc-file-setprop file 'vc-state (cond @@ -614,6 +487,8 @@ essential information." (nth 5 (file-attributes file))) 'up-to-date)) ((eq status ?A) + ;; If the file was actually copied, (match-string 2) is "-". + (vc-file-setprop file 'vc-workfile-version "0") (vc-file-setprop file 'vc-checkout-time 0) 'edited) ((memq status '(?M ?C)) @@ -639,6 +514,31 @@ essential information." (and (string-match "^[0-9]" tag) (not (string-match "[^0-9]" tag)))) +;; Support for `svn annotate' + +(defun vc-svn-annotate-command (file buf &optional rev) + (vc-svn-command buf 0 file "annotate" (if rev (concat "-r" rev)))) + +(defun vc-svn-annotate-time-of-rev (rev) + ;; Arbitrarily assume 10 commmits per day. + (/ (string-to-number rev) 10.0)) + +(defun vc-svn-annotate-current-time () + (vc-svn-annotate-time-of-rev vc-annotate-parent-rev)) + +(defconst vc-svn-annotate-re "[ \t]*\\([0-9]+\\)[ \t]+[^\t ]+ ") + +(defun vc-svn-annotate-time () + (when (looking-at vc-svn-annotate-re) + (goto-char (match-end 0)) + (vc-svn-annotate-time-of-rev (match-string 1)))) + +(defun vc-svn-annotate-extract-revision-at-line () + (save-excursion + (beginning-of-line) + (if (looking-at vc-svn-annotate-re) (match-string 1)))) + (provide 'vc-svn) +;; arch-tag: 02f10c68-2b4d-453a-90fc-1eee6cfb268d ;;; vc-svn.el ends here