diff options
Diffstat (limited to 'lisp/vc.el')
-rw-r--r-- | lisp/vc.el | 413 |
1 files changed, 326 insertions, 87 deletions
diff --git a/lisp/vc.el b/lisp/vc.el index 491ff1f5da6..801cf6d5759 100644 --- a/lisp/vc.el +++ b/lisp/vc.el @@ -1,13 +1,13 @@ ;;; vc.el --- drive a version-control system from within Emacs -;; Copyright (C) 1992,93,94,95,96,97,98,2000,01,2003 +;; Copyright (C) 1992,93,94,95,96,97,98,2000,01,2003,2004 ;; Free Software Foundation, Inc. ;; Author: FSF (see below for full credits) ;; Maintainer: Andre Spiegel <spiegel@gnu.org> ;; Keywords: tools -;; $Id: vc.el,v 1.358 2003/07/06 17:28:12 monnier Exp $ +;; $Id: vc.el,v 1.374 2004/03/28 22:00:19 monnier Exp $ ;; This file is part of GNU Emacs. @@ -264,9 +264,10 @@ ;; ;; HISTORY FUNCTIONS ;; -;; * print-log (file) +;; * print-log (file &optional buffer) ;; -;; Insert the revision log of FILE into the *vc* buffer. +;; Insert the revision log of FILE into BUFFER, or the *vc* buffer +;; if BUFFER is nil. ;; ;; - show-log-entry (version) ;; @@ -301,17 +302,17 @@ ;; default implementation runs rcs2log, which handles RCS- and ;; CVS-style logs. ;; -;; * diff (file &optional rev1 rev2) +;; * diff (file &optional rev1 rev2 buffer) ;; -;; Insert the diff for FILE into the *vc-diff* buffer. If REV1 and -;; REV2 are non-nil, report differences from REV1 to REV2. If REV1 -;; is nil, use the current workfile version (as found in the -;; repository) as the older version; if REV2 is nil, use the current -;; workfile contents as the newer version. This function should -;; pass the value of (vc-switches BACKEND 'diff) to the backend -;; command. It should return a status of either 0 (no differences -;; found), or 1 (either non-empty diff or the diff is run -;; asynchronously). +;; Insert the diff for FILE into BUFFER, or the *vc-diff* buffer if +;; BUFFER is nil. If REV1 and REV2 are non-nil, report differences +;; from REV1 to REV2. If REV1 is nil, use the current workfile +;; version (as found in the repository) as the older version; if +;; REV2 is nil, use the current workfile contents as the newer +;; version. This function should pass the value of (vc-switches +;; BACKEND 'diff) to the backend command. It should return a status +;; of either 0 (no differences found), or 1 (either non-empty diff +;; or the diff is run asynchronously). ;; ;; - diff-tree (dir &optional rev1 rev2) ;; @@ -347,6 +348,13 @@ ;; time with hours, minutes, and seconds included. Probably safe to ;; ignore. Return the current-time, in units of fractional days. ;; +;; - annotate-extract-revision-at-line () +;; +;; Only required if `annotate-command' is defined for the backend. +;; Invoked from a buffer in vc-annotate-mode, return the revision +;; corresponding to the current line, or nil if there is no revision +;; corresponding to the current line. +;; ;; SNAPSHOT SYSTEM ;; ;; - create-snapshot (dir name branchp) @@ -392,7 +400,13 @@ ;; ;; - previous-version (file rev) ;; -;; Return the version number that precedes REV for FILE. +;; Return the version number that precedes REV for FILE, or nil if no such +;; version exists. +;; +;; - next-version (file rev) +;; +;; Return the version number that follows REV for FILE, or nil if no such +;; version exists. ;; ;; - check-headers () ;; @@ -419,6 +433,15 @@ ;; repository. If this function is not provided, the renaming ;; will be done by (vc-delete-file old) and (vc-register new). ;; +;; - find-file-hook () +;; +;; Operation called in current buffer when opening a file. This can +;; be used by the backend to setup some local variables it might need. +; +;; - find-file-not-found-hook () +;; +;; Operation called in current buffer when opening a non-existing file. +;; By default, this asks the user if she wants to check out the file. ;;; Code: @@ -631,6 +654,14 @@ List of factors, used to expand/compress the time scale. See `vc-annotate'." m) "Local keymap used for VC-Annotate mode.") +(define-key vc-annotate-mode-map "A" 'vc-annotate-revision-previous-to-line) +(define-key vc-annotate-mode-map "D" 'vc-annotate-show-diff-revision-at-line) +(define-key vc-annotate-mode-map "J" 'vc-annotate-revision-at-line) +(define-key vc-annotate-mode-map "L" 'vc-annotate-show-log-revision-at-line) +(define-key vc-annotate-mode-map "N" 'vc-annotate-next-version) +(define-key vc-annotate-mode-map "P" 'vc-annotate-prev-version) +(define-key vc-annotate-mode-map "W" 'vc-annotate-workfile-version) + (defvar vc-annotate-mode-menu nil "Local keymap used for VC-Annotate mode's menu bar menu.") @@ -714,9 +745,10 @@ The keys are \(BUFFER . BACKEND\). See also `vc-annotate-get-backend'.") (substring rev (match-beginning 0) (match-end 0))) (defun vc-default-previous-version (backend file rev) - "Guess the version number immediately preceding REV for FILE. -This default implementation works for <major>.<minor>-style version numbers -as used by RCS and CVS." + "Return the version number immediately preceding REV for FILE, +or nil if there is no previous version. This default +implementation works for <major>.<minor>-style version numbers as +used by RCS and CVS." (let ((branch (vc-branch-part rev)) (minor-num (string-to-number (vc-minor-part rev)))) (when branch @@ -731,6 +763,16 @@ as used by RCS and CVS." ;; return version of starting point (vc-branch-part branch)))))) +(defun vc-default-next-version (backend file rev) + "Return the version number immediately following REV for FILE, +or nil if there is no next version. This default implementation +works for <major>.<minor>-style version numbers as used by RCS +and CVS." + (when (not (string= rev (vc-workfile-version file))) + (let ((branch (vc-branch-part rev)) + (minor-num (string-to-number (vc-minor-part rev)))) + (concat branch "." (number-to-string (1+ minor-num)))))) + ;; File property caching (defun vc-clear-context () @@ -772,11 +814,11 @@ somebody else, signal error." (let ((filevar (make-symbol "file"))) `(let ((,filevar (expand-file-name ,file))) (or (vc-backend ,filevar) - (error (format "File not under version control: `%s'" file))) + (error "File not under version control: `%s'" file)) (unless (vc-editable-p ,filevar) (let ((state (vc-state ,filevar))) (if (stringp state) - (error (format "`%s' is locking `%s'" state ,filevar)) + (error "`%s' is locking `%s'" state ,filevar) (vc-checkout ,filevar t)))) (save-excursion ,@body) @@ -1635,10 +1677,10 @@ saving the buffer." (message "No changes to %s since latest version" file) (vc-version-diff file nil nil))))) -(defun vc-version-diff (file rel1 rel2) - "List the differences between FILE's versions REL1 and REL2. -If REL1 is empty or nil it means to use the current workfile version; -REL2 empty or nil means the current file contents. FILE may also be +(defun vc-version-diff (file rev1 rev2) + "List the differences between FILE's versions REV1 and REV2. +If REV1 is empty or nil it means to use the current workfile version; +REV2 empty or nil means the current file contents. FILE may also be a directory, in that case, generate diffs between the correponding versions of all registered files in or below it." (interactive @@ -1647,7 +1689,7 @@ versions of all registered files in or below it." "File or dir to diff: (default visited file) " "File or dir to diff: ") default-directory buffer-file-name t))) - (rel1-default nil) (rel2-default nil)) + (rev1-default nil) (rev2-default nil)) ;; compute default versions based on the file state (cond ;; if it's a directory, don't supply any version default @@ -1655,52 +1697,54 @@ versions of all registered files in or below it." nil) ;; if the file is not up-to-date, use current version as older version ((not (vc-up-to-date-p file)) - (setq rel1-default (vc-workfile-version file))) + (setq rev1-default (vc-workfile-version file))) ;; if the file is not locked, use last and previous version as default (t - (setq rel1-default (vc-call previous-version file + (setq rev1-default (vc-call previous-version file (vc-workfile-version file))) - (if (string= rel1-default "") (setq rel1-default nil)) - (setq rel2-default (vc-workfile-version file)))) + (if (string= rev1-default "") (setq rev1-default nil)) + (setq rev2-default (vc-workfile-version file)))) ;; construct argument list (list file - (read-string (if rel1-default + (read-string (if rev1-default (concat "Older version: (default " - rel1-default ") ") + rev1-default ") ") "Older version: ") - nil nil rel1-default) - (read-string (if rel2-default + nil nil rev1-default) + (read-string (if rev2-default (concat "Newer version: (default " - rel2-default ") ") + rev2-default ") ") "Newer version (default: current source): ") - nil nil rel2-default)))) + nil nil rev2-default)))) (if (file-directory-p file) ;; recursive directory diff (progn (vc-setup-buffer "*vc-diff*") - (if (string-equal rel1 "") (setq rel1 nil)) - (if (string-equal rel2 "") (setq rel2 nil)) + (if (string-equal rev1 "") (setq rev1 nil)) + (if (string-equal rev2 "") (setq rev2 nil)) (let ((inhibit-read-only t)) (insert "Diffs between " - (or rel1 "last version checked in") + (or rev1 "last version checked in") " and " - (or rel2 "current workfile(s)") + (or rev2 "current workfile(s)") ":\n\n")) (let ((dir (file-name-as-directory file))) (vc-call-backend (vc-responsible-backend dir) - 'diff-tree dir rel1 rel2)) + 'diff-tree dir rev1 rev2)) (vc-exec-after `(let ((inhibit-read-only t)) (insert "\nEnd of diffs.\n")))) - ;; single file diff - (vc-diff-internal file rel1 rel2)) + ;; Single file diff. It is important that the vc-controlled buffer + ;; is still current at this time, because any local settings in that + ;; buffer should affect the diff command. + (vc-diff-internal file rev1 rev2)) (set-buffer "*vc-diff*") (if (and (zerop (buffer-size)) (not (get-buffer-process (current-buffer)))) (progn - (if rel1 - (if rel2 - (message "No changes to %s between %s and %s" file rel1 rel2) - (message "No changes to %s since %s" file rel1)) + (if rev1 + (if rev2 + (message "No changes to %s between %s and %s" file rev1 rev2) + (message "No changes to %s since %s" file rev1)) (message "No changes to %s since latest version" file)) nil) (pop-to-buffer (current-buffer)) @@ -1714,29 +1758,40 @@ versions of all registered files in or below it." (shrink-window-if-larger-than-buffer))) t)) -(defun vc-diff-internal (file rel1 rel2) - "Run diff to compare FILE's revisions REL1 and REL2. -Output goes to the current buffer, which is assumed properly set up. -The exit status of the diff command is returned. +(defun vc-diff-label (file file-rev rev) + (concat (file-relative-name file) + (format-time-string "\t%d %b %Y %T %z\t" + (nth 5 (file-attributes file-rev))) + rev)) + +(defun vc-diff-internal (file rev1 rev2) + "Run diff to compare FILE's revisions REV1 and REV2. +Diff output goes to the *vc-diff* buffer. The exit status of the diff +command is returned. This function takes care to set up a proper coding system for diff output. If both revisions are available as local files, then it also does not actually call the backend, but performs a local diff." - (if (or (not rel1) (string-equal rel1 "")) - (setq rel1 (vc-workfile-version file))) - (if (string-equal rel2 "") - (setq rel2 nil)) - (let ((file-rel1 (vc-version-backup-file file rel1)) - (file-rel2 (if (not rel2) + (if (or (not rev1) (string-equal rev1 "")) + (setq rev1 (vc-workfile-version file))) + (if (string-equal rev2 "") + (setq rev2 nil)) + (let ((file-rev1 (vc-version-backup-file file rev1)) + (file-rev2 (if (not rev2) file - (vc-version-backup-file file rel2))) + (vc-version-backup-file file rev2))) (coding-system-for-read (vc-coding-system-for-diff file))) - (if (and file-rel1 file-rel2) + (if (and file-rev1 file-rev2) (apply 'vc-do-command "*vc-diff*" 1 "diff" nil (append (vc-switches nil 'diff) - (list (file-relative-name file-rel1) - (file-relative-name file-rel2)))) - (vc-call diff file rel1 rel2)))) + ;; Provide explicit labels like RCS or CVS would do + ;; so diff-mode refers to `file' rather than to + ;; `file-rev1' when trying to find/apply/undo hunks. + (list "-L" (vc-diff-label file file-rev1 rev1) + "-L" (vc-diff-label file file-rev2 rev2) + (file-relative-name file-rev1) + (file-relative-name file-rev2)))) + (vc-call diff file rev1 rev2)))) (defun vc-switches (backend op) @@ -1760,9 +1815,9 @@ actually call the backend, but performs a local diff." (defmacro vc-diff-switches-list (backend) `(vc-switches ',backend 'diff)) (make-obsolete 'vc-diff-switches-list 'vc-switches "21.4") -(defun vc-default-diff-tree (backend dir rel1 rel2) +(defun vc-default-diff-tree (backend dir rev1 rev2) "List differences for all registered files at and below DIR. -The meaning of REL1 and REL2 is the same as for `vc-version-diff'." +The meaning of REV1 and REV2 is the same as for `vc-version-diff'." ;; This implementation does an explicit tree walk, and calls ;; vc-BACKEND-diff directly for each file. An optimization ;; would be to use `vc-diff-internal', so that diffs can be local, @@ -1777,7 +1832,7 @@ The meaning of REL1 and REL2 is the same as for `vc-version-diff'." `(let ((coding-system-for-read (vc-coding-system-for-diff ',f))) (message "Looking at %s" ',f) (vc-call-backend ',(vc-backend f) - 'diff ',f ',rel1 ',rel2)))))) + 'diff ',f ',rev1 ',rev2)))))) (defun vc-coding-system-for-diff (file) "Return the coding system for reading diff output for FILE." @@ -1945,9 +2000,7 @@ See Info node `Merging'." (vc-resynch-buffer file t (not (buffer-modified-p))) (if (zerop status) (message "Merge successful") (smerge-mode 1) - (if (y-or-n-p "Conflicts detected. Resolve them now? ") - (vc-resolve-conflicts name-A name-B) - (message "File contains conflict markers")))) + (message "File contains conflicts."))) ;;;###autoload (defalias 'vc-resolve-conflicts 'smerge-ediff) @@ -2144,7 +2197,7 @@ Called by dired after any portion of a vc-dired buffer has been read in." ;; We cannot remove the top level directory. ;; Just make it look a little nicer. (forward-line 1) - (kill-line) + (or (eobp) (kill-line)) (if (not (dired-next-subdir 1 t)) (goto-char (point-max)))))) (goto-char (point-min))) @@ -2285,13 +2338,33 @@ allowed and simply skipped)." ;; Miscellaneous other entry points ;;;###autoload -(defun vc-print-log () - "List the change log of the current buffer in a window." +(defun vc-print-log (&optional focus-rev) + "List the change log of the current buffer in a window. +If FOCUS-REV is non-nil, leave the point at that revision." (interactive) (vc-ensure-vc-buffer) (let ((file buffer-file-name)) - (vc-call print-log file) - (set-buffer "*vc*") + (or focus-rev (setq focus-rev (vc-workfile-version file))) + ;; Don't switch to the output buffer before running the command, + ;; so that any buffer-local settings in the vc-controlled + ;; buffer can be accessed by the command. + (condition-case err + (progn + (vc-call print-log file "*vc-change-log*") + (set-buffer "*vc-change-log*")) + (wrong-number-of-arguments + ;; If this error came from the above call to print-log, try again + ;; without the optional buffer argument (for backward compatibility). + ;; Otherwise, resignal. + (if (or (not (eq (cadr err) + (indirect-function + (vc-find-backend-function (vc-backend file) + 'print-log)))) + (not (eq (caddr err) 2))) + (signal wrong-number-of-arguments err) + ;; for backward compatibility + (vc-call print-log file) + (set-buffer "*vc*")))) (pop-to-buffer (current-buffer)) (log-view-mode) (vc-exec-after @@ -2307,7 +2380,7 @@ allowed and simply skipped)." ;; move point to the log entry for the current version (vc-call-backend ',(vc-backend file) 'show-log-entry - ',(vc-workfile-version file)) + ',focus-rev) (set-buffer-modified-p nil))))) (defun vc-default-show-log-entry (backend rev) @@ -2453,7 +2526,7 @@ A prefix argument NOREVERT means do not revert the buffer afterwards." ((not (vc-call latest-on-branch-p file)) (error "This is not the latest version; VC cannot cancel it")) ((not (vc-up-to-date-p file)) - (error (substitute-command-keys "File is not up to date; use \\[vc-revert-buffer] to discard changes")))) + (error "%s" (substitute-command-keys "File is not up to date; use \\[vc-revert-buffer] to discard changes")))) (if (null (yes-or-no-p (format "Remove version %s from master? " target))) (error "Aborted") (setq norevert (or norevert (not @@ -2778,6 +2851,11 @@ Uses `rcs2log' which only works for RCS and CVS." (defvar vc-annotate-ratio nil "Global variable.") (defvar vc-annotate-backend nil "Global variable.") +;; internal buffer-local variables +(defvar vc-annotate-parent-file nil) +(defvar vc-annotate-parent-rev nil) +(defvar vc-annotate-parent-display-mode nil) + (defconst vc-annotate-font-lock-keywords ;; The fontification is done by vc-annotate-lines instead of font-lock. '((vc-annotate-lines))) @@ -2797,6 +2875,7 @@ menu items." (set (make-local-variable 'truncate-lines) t) (set (make-local-variable 'font-lock-defaults) '(vc-annotate-font-lock-keywords t)) + (view-mode 1) (vc-annotate-add-menu)) (defun vc-annotate-display-default (&optional ratio) @@ -2885,7 +2964,23 @@ cover the range from the oldest annotation to the newest." (unless (eq vc-annotate-display-mode 'fullscale) (vc-annotate-display-select nil 'fullscale)) :style toggle :selected - (eq vc-annotate-display-mode 'fullscale)]))) + (eq vc-annotate-display-mode 'fullscale)]) + (list "--") + (list ["Annotate previous revision" + (call-interactively 'vc-annotate-prev-version)]) + (list ["Annotate next revision" + (call-interactively 'vc-annotate-next-version)]) + (list ["Annotate revision at line" + (vc-annotate-revision-at-line)]) + (list ["Annotate revision previous to line" + (vc-annotate-revision-previous-to-line)]) + (list ["Annotate latest revision" + (vc-annotate-workfile-version)]) + (list ["Show log of revision at line" + (vc-annotate-show-log-revision-at-line)]) + (list ["Show diff of revision at line" + (vc-annotate-show-diff-revision-at-line)]))) + ;; Define the menu (if (or (featurep 'easymenu) (load "easymenu" t)) (easy-menu-define vc-annotate-mode-menu vc-annotate-mode-map @@ -2922,7 +3017,7 @@ use; you may override this using the second optional arg MODE." ;;;; the contents in BUFFER. ;;;###autoload -(defun vc-annotate (prefix) +(defun vc-annotate (prefix &optional revision display-mode) "Display the edit history of the current file using colours. This command creates a buffer that shows, for each line of the current @@ -2949,19 +3044,24 @@ mode-specific menu. `vc-annotate-color-map' and colors. `vc-annotate-background' specifies the background color." (interactive "P") (vc-ensure-vc-buffer) - (let* ((temp-buffer-name (concat "*Annotate " (buffer-name) "*")) + (let* ((temp-buffer-name nil) (temp-buffer-show-function 'vc-annotate-display-select) - (rev (vc-workfile-version buffer-file-name)) + (rev (or revision (vc-workfile-version buffer-file-name))) + (bfn buffer-file-name) (vc-annotate-version - (if prefix (read-string - (format "Annotate from version: (default %s) " rev) - nil nil rev) - rev))) - (if prefix - (setq vc-annotate-display-mode - (float (string-to-number - (read-string "Annotate span days: (default 20) " - nil nil "20"))))) + (if prefix (read-string + (format "Annotate from version: (default %s) " rev) + nil nil rev) + rev))) + (if display-mode + (setq vc-annotate-display-mode display-mode) + (if prefix + (setq vc-annotate-display-mode + (float (string-to-number + (read-string "Annotate span days: (default 20) " + nil nil "20")))))) + (setq temp-buffer-name (format "*Annotate %s (rev %s)*" + (buffer-name) vc-annotate-version)) (setq vc-annotate-backend (vc-backend buffer-file-name)) (message "Annotating...") (if (not (vc-find-backend-function vc-annotate-backend 'annotate-command)) @@ -2972,6 +3072,13 @@ colors. `vc-annotate-background' specifies the background color." buffer-file-name (get-buffer temp-buffer-name) vc-annotate-version)) + (save-excursion + (set-buffer temp-buffer-name) + (set (make-local-variable 'vc-annotate-parent-file) bfn) + (set (make-local-variable 'vc-annotate-parent-rev) vc-annotate-version) + (set (make-local-variable 'vc-annotate-parent-display-mode) + vc-annotate-display-mode)) + ;; Don't use the temp-buffer-name until the buffer is created ;; (only after `with-output-to-temp-buffer'.) (setq vc-annotate-buffers @@ -2979,6 +3086,137 @@ colors. `vc-annotate-background' specifies the background color." (list (cons (get-buffer temp-buffer-name) vc-annotate-backend)))) (message "Annotating... done"))) +(defun vc-annotate-prev-version (prefix) + "Visit the annotation of the version previous to this one. + +With a numeric prefix argument, annotate the version that many +versions previous." + (interactive "p") + (vc-annotate-warp-version (- 0 prefix))) + +(defun vc-annotate-next-version (prefix) + "Visit the annotation of the version after this one. + +With a numeric prefix argument, annotate the version that many +versions after." + (interactive "p") + (vc-annotate-warp-version prefix)) + +(defun vc-annotate-workfile-version () + "Visit the annotation of the workfile version of this file." + (interactive) + (if (not (equal major-mode 'vc-annotate-mode)) + (message "Cannot be invoked outside of a vc annotate buffer") + (let ((warp-rev (vc-workfile-version vc-annotate-parent-file))) + (if (equal warp-rev vc-annotate-parent-rev) + (message "Already at version %s" warp-rev) + (vc-annotate-warp-version warp-rev))))) + +(defun vc-annotate-extract-revision-at-line () + "Extract the revision number of the current line." + ;; This function must be invoked from a buffer in vc-annotate-mode + (save-window-excursion + (vc-ensure-vc-buffer) + (setq vc-annotate-backend (vc-backend buffer-file-name))) + (vc-call-backend vc-annotate-backend 'annotate-extract-revision-at-line)) + +(defun vc-annotate-revision-at-line () + "Visit the annotation of the version identified in the current line." + (interactive) + (if (not (equal major-mode 'vc-annotate-mode)) + (message "Cannot be invoked outside of a vc annotate buffer") + (let ((rev-at-line (vc-annotate-extract-revision-at-line))) + (if (not rev-at-line) + (message "Cannot extract revision number from the current line") + (if (equal rev-at-line vc-annotate-parent-rev) + (message "Already at version %s" rev-at-line) + (vc-annotate-warp-version rev-at-line)))))) + +(defun vc-annotate-revision-previous-to-line () + "Visit the annotation of the version before the version at line." + (interactive) + (if (not (equal major-mode 'vc-annotate-mode)) + (message "Cannot be invoked outside of a vc annotate buffer") + (let ((rev-at-line (vc-annotate-extract-revision-at-line)) + (prev-rev nil)) + (if (not rev-at-line) + (message "Cannot extract revision number from the current line") + (setq prev-rev + (vc-call previous-version vc-annotate-parent-file rev-at-line)) + (vc-annotate-warp-version prev-rev))))) + +(defun vc-annotate-show-log-revision-at-line () + "Visit the log of the version at line." + (interactive) + (if (not (equal major-mode 'vc-annotate-mode)) + (message "Cannot be invoked outside of a vc annotate buffer") + (let ((rev-at-line (vc-annotate-extract-revision-at-line))) + (if (not rev-at-line) + (message "Cannot extract revision number from the current line") + (vc-print-log rev-at-line))))) + +(defun vc-annotate-show-diff-revision-at-line () + "Visit the diff of the version at line from its previous version." + (interactive) + (if (not (equal major-mode 'vc-annotate-mode)) + (message "Cannot be invoked outside of a vc annotate buffer") + (let ((rev-at-line (vc-annotate-extract-revision-at-line)) + (prev-rev nil)) + (if (not rev-at-line) + (message "Cannot extract revision number from the current line") + (setq prev-rev + (vc-call previous-version vc-annotate-parent-file rev-at-line)) + (if (not prev-rev) + (message "Cannot diff from any version prior to %s" rev-at-line) + (save-window-excursion + (vc-version-diff vc-annotate-parent-file prev-rev rev-at-line)) + (switch-to-buffer "*vc-diff*")))))) + +(defun vc-annotate-warp-version (revspec) + "Annotate the version described by REVSPEC. + +If REVSPEC is a positive integer, warp that many versions +forward, if possible, otherwise echo a warning message. If +REVSPEC is a negative integer, warp that many versions backward, +if possible, otherwise echo a warning message. If REVSPEC is a +string, then it describes a revision number, so warp to that +revision." + (if (not (equal major-mode 'vc-annotate-mode)) + (message "Cannot be invoked outside of a vc annotate buffer") + (let* ((oldline (line-number-at-pos)) + (revspeccopy revspec) + (newrev nil)) + (cond + ((and (integerp revspec) (> revspec 0)) + (setq newrev vc-annotate-parent-rev) + (while (and (> revspec 0) newrev) + (setq newrev (vc-call next-version + vc-annotate-parent-file newrev)) + (setq revspec (1- revspec))) + (if (not newrev) + (message "Cannot increment %d versions from version %s" + revspeccopy vc-annotate-parent-rev))) + ((and (integerp revspec) (< revspec 0)) + (setq newrev vc-annotate-parent-rev) + (while (and (< revspec 0) newrev) + (setq newrev (vc-call previous-version + vc-annotate-parent-file newrev)) + (setq revspec (1+ revspec))) + (if (not newrev) + (message "Cannot decrement %d versions from version %s" + (- 0 revspeccopy) vc-annotate-parent-rev))) + ((stringp revspec) (setq newrev revspec)) + (t (error "Invalid argument to vc-annotate-warp-version"))) + (when newrev + (save-window-excursion + (find-file vc-annotate-parent-file) + (vc-annotate nil newrev vc-annotate-parent-display-mode)) + (kill-buffer (current-buffer)) ;; kill the buffer we started from + (switch-to-buffer (car (car (last vc-annotate-buffers)))) + (goto-line (min oldline (progn (goto-char (point-max)) + (previous-line) + (line-number-at-pos)))))))) + (defun vc-annotate-car-last-cons (a-list) "Return car of last cons in association list A-LIST." (if (not (eq nil (cdr a-list))) @@ -3467,4 +3705,5 @@ Invoke FUNC f ARGS on each VC-managed file f underneath it." ;; ;; Thus, there is no explicit recovery code. +;;; arch-tag: ca82c1de-3091-4e26-af92-460abc6213a6 ;;; vc.el ends here |