ediff-vers.el 7.94 KB
Newer Older
Michael Kifer's avatar
Michael Kifer committed
1 2
;;; ediff-vers.el --- version control interface to Ediff

Glenn Morris's avatar
Glenn Morris committed
3
;; Copyright (C) 1995, 1996, 1997, 2001, 2002, 2003, 2004,
Glenn Morris's avatar
Glenn Morris committed
4
;;   2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Michael Kifer's avatar
Michael Kifer committed
5

6
;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
Michael Kifer's avatar
Michael Kifer committed
7 8 9

;; This file is part of GNU Emacs.

10
;; GNU Emacs is free software: you can redistribute it and/or modify
Michael Kifer's avatar
Michael Kifer committed
11
;; it under the terms of the GNU General Public License as published by
12 13
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
Michael Kifer's avatar
Michael Kifer committed
14 15 16 17 18 19 20

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
21
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
Michael Kifer's avatar
Michael Kifer committed
22

23
;;; Commentary:
Michael Kifer's avatar
Michael Kifer committed
24 25

;;; Code:
Michael Kifer's avatar
Michael Kifer committed
26 27 28 29

;; Compiler pacifier
(defvar rcs-default-co-switches)

Michael Kifer's avatar
Michael Kifer committed
30 31
(and noninteractive
     (eval-when-compile
32 33 34 35 36 37 38 39
       (condition-case nil
	   ;; for compatibility with current stable version of xemacs
	   (progn
	     ;;(require 'pcvs nil 'noerror)
	     ;;(require 'rcs nil 'noerror)
	     (require 'pcvs)
	     (require 'rcs))
	 (error nil))
40 41 42
       (require 'vc)
       (require 'ediff-init)
       ))
Michael Kifer's avatar
Michael Kifer committed
43
;; end pacifier
44

45
(defcustom ediff-keep-tmp-versions nil
Lute Kamstra's avatar
Lute Kamstra committed
46
  "If t, do not delete temporary previous versions for the files on which
47 48 49 50 51
comparison or merge operations are being performed."
  :type 'boolean
  :group 'ediff-vers
  )

52 53 54 55 56 57 58 59
(defalias 'ediff-vc-revision-other-window
      (if (fboundp 'vc-revision-other-window)
	  'vc-revision-other-window
	'vc-version-other-window))

(defalias 'ediff-vc-working-revision
  (if (fboundp 'vc-working-revision)
      'vc-working-revision
60
    'vc-workfile-version))
61

Michael Kifer's avatar
Michael Kifer committed
62
;; VC.el support
63

64 65 66 67
(eval-when-compile
  (require 'vc-hooks)) ;; for vc-call macro


68 69 70 71
(defun ediff-vc-latest-version (file)
  "Return the version level of the latest version of FILE in repository."
  (if (fboundp 'vc-latest-version)
      (vc-latest-version file)
72
    (or (vc-file-getprop file 'vc-latest-revision)
73 74
	(cond ((vc-backend file)
	       (vc-call state file)
75
	       (vc-file-getprop file 'vc-latest-revision))
76 77 78 79
	      (t (error "File %s is not under version control" file))))
    ))


Michael Kifer's avatar
Michael Kifer committed
80
(defun ediff-vc-internal (rev1 rev2 &optional startup-hooks)
81 82 83 84 85
  ;; Run Ediff on versions of the current buffer.
  ;; If REV1 is "", use the latest version of the current buffer's file.
  ;; If REV2 is "" then compare current buffer with REV1.
  ;; If the current buffer is named `F', the version is named `F.~REV~'.
  ;; If `F.~REV~' already exists, it is used instead of being re-created.
Michael Kifer's avatar
Michael Kifer committed
86
  (let (file1 file2 rev1buf rev2buf)
87
    (if (string= rev1 "")
88
	(setq rev1 (ediff-vc-latest-version (buffer-file-name))))
89 90
    (save-window-excursion
      (save-excursion
91
	(ediff-vc-revision-other-window rev1)
92 93 94 95
	(setq rev1buf (current-buffer)
	      file1 (buffer-file-name)))
      (save-excursion
	(or (string= rev2 "") 		; use current buffer
96
	    (ediff-vc-revision-other-window rev2))
97 98 99 100
	(setq rev2buf (current-buffer)
	      file2 (buffer-file-name)))
      (setq startup-hooks
	    (cons `(lambda ()
101 102
		     (ediff-delete-version-file ,file1)
		     (or ,(string= rev2 "") (ediff-delete-version-file ,file2)))
103
		  startup-hooks)))
Michael Kifer's avatar
Michael Kifer committed
104 105 106 107
    (ediff-buffers
     rev1buf rev2buf
     startup-hooks
     'ediff-revision)))
108

Michael Kifer's avatar
Michael Kifer committed
109 110 111 112
;; RCS.el support
(defun rcs-ediff-view-revision (&optional rev)
;; View previous RCS revision of current file.
;; With prefix argument, prompts for a revision name.
113
  (interactive (list (if current-prefix-arg
Michael Kifer's avatar
Michael Kifer committed
114 115 116 117 118 119 120 121
			 (read-string "Revision: "))))
  (let* ((filename (buffer-file-name (current-buffer)))
	 (switches (append '("-p")
			   (if rev (list (concat "-r" rev)) nil)))
	 (buff (concat (file-name-nondirectory filename) ".~" rev "~")))
    (message "Working ...")
    (setq filename (expand-file-name filename))
    (with-output-to-temp-buffer buff
122 123
      (ediff-with-current-buffer standard-output
	(fundamental-mode))
Michael Kifer's avatar
Michael Kifer committed
124 125
      (let ((output-buffer (ediff-rcs-get-output-buffer filename buff)))
	(delete-windows-on output-buffer)
126
	(with-current-buffer output-buffer
Michael Kifer's avatar
Michael Kifer committed
127 128 129
	  (apply 'call-process "co" nil t nil
		 ;; -q: quiet (no diagnostics)
		 (append switches rcs-default-co-switches
130
			 (list "-q" filename)))))
Michael Kifer's avatar
Michael Kifer committed
131
      (message "")
132 133
      buff)))

Michael Kifer's avatar
Michael Kifer committed
134 135 136
(defun ediff-rcs-get-output-buffer (file name)
  ;; Get a buffer for RCS output for FILE, make it writable and clean it up.
  ;; Optional NAME is name to use instead of `*RCS-output*'.
Michael Kifer's avatar
Michael Kifer committed
137
  ;; This is a modified version from rcs.el v1.1.  I use it here to make
Michael Kifer's avatar
Michael Kifer committed
138
  ;; Ediff immune to changes in rcs.el
139
  (let ((buf (get-buffer-create name)))
140
    (with-current-buffer buf
Michael Kifer's avatar
Michael Kifer committed
141 142 143 144 145
      (setq buffer-read-only nil
	    default-directory (file-name-directory (expand-file-name file)))
      (erase-buffer))
    buf))

Michael Kifer's avatar
Michael Kifer committed
146
(defun ediff-rcs-internal (rev1 rev2 &optional startup-hooks)
Michael Kifer's avatar
Michael Kifer committed
147 148
;; Run Ediff on versions of the current buffer.
;; If REV2 is "" then use current buffer.
149 150 151 152 153 154
  (let (rev2buf rev1buf)
    (save-window-excursion
      (setq rev2buf (if (string= rev2 "")
			(current-buffer)
		      (rcs-ediff-view-revision rev2))
	    rev1buf (rcs-ediff-view-revision rev1)))
155

Michael Kifer's avatar
Michael Kifer committed
156 157 158 159 160 161 162
    ;; rcs.el doesn't create temp version files, so we don't have to delete
    ;; anything in startup hooks to ediff-buffers
    (ediff-buffers rev1buf rev2buf startup-hooks 'ediff-revision)
    ))

;;; Merge with Version Control

163
(defun ediff-vc-merge-internal (rev1 rev2 ancestor-rev
Michael Kifer's avatar
Michael Kifer committed
164
				     &optional startup-hooks merge-buffer-file)
Michael Kifer's avatar
Michael Kifer committed
165 166
;; If ANCESTOR-REV non-nil, merge with ancestor
  (let (buf1 buf2 ancestor-buf)
167 168
    (save-window-excursion
      (save-excursion
169
	(ediff-vc-revision-other-window rev1)
170 171 172
	(setq buf1 (current-buffer)))
      (save-excursion
	(or (string= rev2 "")
173
	    (ediff-vc-revision-other-window rev2))
174 175 176 177
	(setq buf2 (current-buffer)))
      (if ancestor-rev
	  (save-excursion
	    (if (string= ancestor-rev "")
178 179
		(setq ancestor-rev (ediff-vc-working-revision buffer-file-name)))
	    (ediff-vc-revision-other-window ancestor-rev)
180
	    (setq ancestor-buf (current-buffer))))
181 182 183
      (setq startup-hooks
	    (cons
	     `(lambda ()
184
		(ediff-delete-version-file ,(buffer-file-name buf1))
185
		(or ,(string= rev2 "")
186
		    (ediff-delete-version-file ,(buffer-file-name buf2)))
187 188
		(or ,(string= ancestor-rev "")
		    ,(not ancestor-rev)
189
		    (ediff-delete-version-file ,(buffer-file-name ancestor-buf)))
190 191
		)
	     startup-hooks)))
Michael Kifer's avatar
Michael Kifer committed
192 193 194
    (if ancestor-rev
	(ediff-merge-buffers-with-ancestor
	 buf1 buf2 ancestor-buf
Michael Kifer's avatar
Michael Kifer committed
195 196 197
	 startup-hooks 'ediff-merge-revisions-with-ancestor merge-buffer-file)
      (ediff-merge-buffers
       buf1 buf2 startup-hooks 'ediff-merge-revisions merge-buffer-file))
Michael Kifer's avatar
Michael Kifer committed
198 199
    ))

Michael Kifer's avatar
Michael Kifer committed
200
(defun ediff-rcs-merge-internal (rev1 rev2 ancestor-rev
Michael Kifer's avatar
Michael Kifer committed
201 202
				      &optional
				      startup-hooks merge-buffer-file)
Michael Kifer's avatar
Michael Kifer committed
203 204
  ;; If ANCESTOR-REV non-nil, merge with ancestor
  (let (buf1 buf2 ancestor-buf)
205 206 207 208 209 210 211 212 213
    (save-window-excursion
      (setq buf1 (rcs-ediff-view-revision rev1)
	    buf2 (if (string= rev2 "")
		     (current-buffer)
		   (rcs-ediff-view-revision rev2))
	    ancestor-buf (if ancestor-rev
			     (if (string= ancestor-rev "")
				 (current-buffer)
			       (rcs-ediff-view-revision ancestor-rev)))))
Michael Kifer's avatar
Michael Kifer committed
214 215 216 217 218
    ;; rcs.el doesn't create temp version files, so we don't have to delete
    ;; anything in startup hooks to ediff-buffers
    (if ancestor-rev
	(ediff-merge-buffers-with-ancestor
	 buf1 buf2 ancestor-buf
Michael Kifer's avatar
Michael Kifer committed
219 220 221
	 startup-hooks 'ediff-merge-revisions-with-ancestor merge-buffer-file)
      (ediff-merge-buffers
       buf1 buf2 startup-hooks 'ediff-merge-revisions merge-buffer-file))))
Michael Kifer's avatar
Michael Kifer committed
222

223 224 225 226

;; delete version file on exit unless ediff-keep-tmp-versions is true
(defun ediff-delete-version-file (file)
  (or ediff-keep-tmp-versions (delete-file file)))
Michael Kifer's avatar
Michael Kifer committed
227

228 229 230

(provide 'ediff-vers)

231

232 233 234 235 236
;; Local Variables:
;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
;; End:
Michael Kifer's avatar
Michael Kifer committed
237

238
;; arch-tag: bbb34f0c-2a90-426a-a77a-c75f479ebbbf
Michael Kifer's avatar
Michael Kifer committed
239
;;; ediff-vers.el ends here