| 1 | ;;; ediff-util.el --- the core commands and utilities of ediff |
| 2 | |
| 3 | ;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
| 4 | ;; 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. |
| 5 | |
| 6 | ;; Author: Michael Kifer <kifer@cs.stonybrook.edu> |
| 7 | ;; Package: ediff |
| 8 | |
| 9 | ;; This file is part of GNU Emacs. |
| 10 | |
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 12 | ;; it under the terms of the GNU General Public License as published by |
| 13 | ;; the Free Software Foundation, either version 3 of the License, or |
| 14 | ;; (at your option) any later version. |
| 15 | |
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | ;; GNU General Public License for more details. |
| 20 | |
| 21 | ;; You should have received a copy of the GNU General Public License |
| 22 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 23 | |
| 24 | ;;; Commentary: |
| 25 | |
| 26 | ;;; Code: |
| 27 | |
| 28 | |
| 29 | (provide 'ediff-util) |
| 30 | |
| 31 | ;; Compiler pacifier |
| 32 | (defvar ediff-use-toolbar-p) |
| 33 | (defvar ediff-toolbar-height) |
| 34 | (defvar ediff-toolbar) |
| 35 | (defvar ediff-toolbar-3way) |
| 36 | (defvar bottom-toolbar) |
| 37 | (defvar bottom-toolbar-visible-p) |
| 38 | (defvar bottom-toolbar-height) |
| 39 | (defvar mark-active) |
| 40 | |
| 41 | (defvar ediff-after-quit-hook-internal nil) |
| 42 | |
| 43 | (eval-and-compile |
| 44 | (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))) |
| 45 | |
| 46 | (eval-when-compile |
| 47 | (require 'ediff)) |
| 48 | |
| 49 | ;; end pacifier |
| 50 | |
| 51 | |
| 52 | (require 'ediff-init) |
| 53 | (require 'ediff-help) |
| 54 | (require 'ediff-mult) |
| 55 | (require 'ediff-wind) |
| 56 | (require 'ediff-diff) |
| 57 | (require 'ediff-merg) |
| 58 | ;; for compatibility with current stable version of xemacs |
| 59 | (if (featurep 'xemacs) |
| 60 | (require 'ediff-tbar)) |
| 61 | |
| 62 | \f |
| 63 | ;;; Functions |
| 64 | |
| 65 | (defun ediff-mode () |
| 66 | "Ediff mode controls all operations in a single Ediff session. |
| 67 | This mode is entered through one of the following commands: |
| 68 | `ediff' |
| 69 | `ediff-files' |
| 70 | `ediff-buffers' |
| 71 | `ebuffers' |
| 72 | `ediff3' |
| 73 | `ediff-files3' |
| 74 | `ediff-buffers3' |
| 75 | `ebuffers3' |
| 76 | `ediff-merge' |
| 77 | `ediff-merge-files' |
| 78 | `ediff-merge-files-with-ancestor' |
| 79 | `ediff-merge-buffers' |
| 80 | `ediff-merge-buffers-with-ancestor' |
| 81 | `ediff-merge-revisions' |
| 82 | `ediff-merge-revisions-with-ancestor' |
| 83 | `ediff-windows-wordwise' |
| 84 | `ediff-windows-linewise' |
| 85 | `ediff-regions-wordwise' |
| 86 | `ediff-regions-linewise' |
| 87 | `epatch' |
| 88 | `ediff-patch-file' |
| 89 | `ediff-patch-buffer' |
| 90 | `epatch-buffer' |
| 91 | `erevision' |
| 92 | `ediff-revision' |
| 93 | |
| 94 | Commands: |
| 95 | \\{ediff-mode-map}" |
| 96 | (kill-all-local-variables) |
| 97 | (setq major-mode 'ediff-mode) |
| 98 | (setq mode-name "Ediff") |
| 99 | ;; We use run-hooks instead of run-mode-hooks for two reasons. |
| 100 | ;; The ediff control buffer is read-only and it is not supposed to be |
| 101 | ;; modified by minor modes and such. So, run-mode-hooks doesn't do anything |
| 102 | ;; useful here on top of what run-hooks does. |
| 103 | ;; Second, changing run-hooks to run-mode-hooks would require an |
| 104 | ;; if-statement, since XEmacs doesn't have this. |
| 105 | (run-hooks 'ediff-mode-hook)) |
| 106 | |
| 107 | |
| 108 | \f |
| 109 | ;;; Build keymaps |
| 110 | |
| 111 | (ediff-defvar-local ediff-mode-map nil |
| 112 | "Local keymap used in Ediff mode. |
| 113 | This is local to each Ediff Control Panel, so they may vary from invocation |
| 114 | to invocation.") |
| 115 | |
| 116 | ;; Set up the keymap in the control buffer |
| 117 | (defun ediff-set-keys () |
| 118 | "Set up Ediff keymap, if necessary." |
| 119 | (if (null ediff-mode-map) |
| 120 | (ediff-setup-keymap)) |
| 121 | (use-local-map ediff-mode-map)) |
| 122 | |
| 123 | ;; Reload Ediff keymap. For debugging only. |
| 124 | (defun ediff-reload-keymap () |
| 125 | (interactive) |
| 126 | (setq ediff-mode-map nil) |
| 127 | (ediff-set-keys)) |
| 128 | |
| 129 | |
| 130 | (defun ediff-setup-keymap () |
| 131 | "Set up the keymap used in the control buffer of Ediff." |
| 132 | (setq ediff-mode-map (make-sparse-keymap)) |
| 133 | (suppress-keymap ediff-mode-map) |
| 134 | |
| 135 | (define-key ediff-mode-map |
| 136 | (if (featurep 'emacs) [mouse-2] [button2]) 'ediff-help-for-quick-help) |
| 137 | (define-key ediff-mode-map "\C-m" 'ediff-help-for-quick-help) |
| 138 | |
| 139 | (define-key ediff-mode-map "p" 'ediff-previous-difference) |
| 140 | (define-key ediff-mode-map "\C-?" 'ediff-previous-difference) |
| 141 | (define-key ediff-mode-map [delete] 'ediff-previous-difference) |
| 142 | (define-key ediff-mode-map "\C-h" (if ediff-no-emacs-help-in-control-buffer |
| 143 | 'ediff-previous-difference nil)) |
| 144 | ;; must come after C-h, or else C-h wipes out backspace's binding in XEmacs |
| 145 | (define-key ediff-mode-map [backspace] 'ediff-previous-difference) |
| 146 | (define-key ediff-mode-map "n" 'ediff-next-difference) |
| 147 | (define-key ediff-mode-map " " 'ediff-next-difference) |
| 148 | (define-key ediff-mode-map "j" 'ediff-jump-to-difference) |
| 149 | (define-key ediff-mode-map "g" nil) |
| 150 | (define-key ediff-mode-map "ga" 'ediff-jump-to-difference-at-point) |
| 151 | (define-key ediff-mode-map "gb" 'ediff-jump-to-difference-at-point) |
| 152 | (define-key ediff-mode-map "q" 'ediff-quit) |
| 153 | (define-key ediff-mode-map "D" 'ediff-show-diff-output) |
| 154 | (define-key ediff-mode-map "z" 'ediff-suspend) |
| 155 | (define-key ediff-mode-map "\C-l" 'ediff-recenter) |
| 156 | (define-key ediff-mode-map "|" 'ediff-toggle-split) |
| 157 | (define-key ediff-mode-map "h" 'ediff-toggle-hilit) |
| 158 | (or ediff-word-mode |
| 159 | (define-key ediff-mode-map "@" 'ediff-toggle-autorefine)) |
| 160 | (if ediff-narrow-job |
| 161 | (define-key ediff-mode-map "%" 'ediff-toggle-narrow-region)) |
| 162 | (define-key ediff-mode-map "~" 'ediff-swap-buffers) |
| 163 | (define-key ediff-mode-map "v" 'ediff-scroll-vertically) |
| 164 | (define-key ediff-mode-map "\C-v" 'ediff-scroll-vertically) |
| 165 | (define-key ediff-mode-map "^" 'ediff-scroll-vertically) |
| 166 | (define-key ediff-mode-map "\M-v" 'ediff-scroll-vertically) |
| 167 | (define-key ediff-mode-map "V" 'ediff-scroll-vertically) |
| 168 | (define-key ediff-mode-map "<" 'ediff-scroll-horizontally) |
| 169 | (define-key ediff-mode-map ">" 'ediff-scroll-horizontally) |
| 170 | (define-key ediff-mode-map "i" 'ediff-status-info) |
| 171 | (define-key ediff-mode-map "E" 'ediff-documentation) |
| 172 | (define-key ediff-mode-map "?" 'ediff-toggle-help) |
| 173 | (define-key ediff-mode-map "!" 'ediff-update-diffs) |
| 174 | (define-key ediff-mode-map "M" 'ediff-show-current-session-meta-buffer) |
| 175 | (define-key ediff-mode-map "R" 'ediff-show-registry) |
| 176 | (or ediff-word-mode |
| 177 | (define-key ediff-mode-map "*" 'ediff-make-or-kill-fine-diffs)) |
| 178 | (define-key ediff-mode-map "a" nil) |
| 179 | (define-key ediff-mode-map "b" nil) |
| 180 | (define-key ediff-mode-map "r" nil) |
| 181 | (cond (ediff-merge-job |
| 182 | ;; Will barf if no ancestor |
| 183 | (define-key ediff-mode-map "/" 'ediff-show-ancestor) |
| 184 | ;; In merging, we allow only A->C and B->C copying. |
| 185 | (define-key ediff-mode-map "a" 'ediff-copy-A-to-C) |
| 186 | (define-key ediff-mode-map "b" 'ediff-copy-B-to-C) |
| 187 | (define-key ediff-mode-map "r" 'ediff-restore-diff-in-merge-buffer) |
| 188 | (define-key ediff-mode-map "s" 'ediff-shrink-window-C) |
| 189 | (define-key ediff-mode-map "+" 'ediff-combine-diffs) |
| 190 | (define-key ediff-mode-map "$" nil) |
| 191 | (define-key ediff-mode-map "$$" 'ediff-toggle-show-clashes-only) |
| 192 | (define-key ediff-mode-map "$*" 'ediff-toggle-skip-changed-regions) |
| 193 | (define-key ediff-mode-map "&" 'ediff-re-merge)) |
| 194 | (ediff-3way-comparison-job |
| 195 | (define-key ediff-mode-map "ab" 'ediff-copy-A-to-B) |
| 196 | (define-key ediff-mode-map "ba" 'ediff-copy-B-to-A) |
| 197 | (define-key ediff-mode-map "ac" 'ediff-copy-A-to-C) |
| 198 | (define-key ediff-mode-map "bc" 'ediff-copy-B-to-C) |
| 199 | (define-key ediff-mode-map "c" nil) |
| 200 | (define-key ediff-mode-map "ca" 'ediff-copy-C-to-A) |
| 201 | (define-key ediff-mode-map "cb" 'ediff-copy-C-to-B) |
| 202 | (define-key ediff-mode-map "ra" 'ediff-restore-diff) |
| 203 | (define-key ediff-mode-map "rb" 'ediff-restore-diff) |
| 204 | (define-key ediff-mode-map "rc" 'ediff-restore-diff) |
| 205 | (define-key ediff-mode-map "C" 'ediff-toggle-read-only)) |
| 206 | (t ; 2-way comparison |
| 207 | (define-key ediff-mode-map "a" 'ediff-copy-A-to-B) |
| 208 | (define-key ediff-mode-map "b" 'ediff-copy-B-to-A) |
| 209 | (define-key ediff-mode-map "ra" 'ediff-restore-diff) |
| 210 | (define-key ediff-mode-map "rb" 'ediff-restore-diff)) |
| 211 | ) ; cond |
| 212 | (define-key ediff-mode-map "G" 'ediff-submit-report) |
| 213 | (define-key ediff-mode-map "#" nil) |
| 214 | (define-key ediff-mode-map "#h" 'ediff-toggle-regexp-match) |
| 215 | (define-key ediff-mode-map "#f" 'ediff-toggle-regexp-match) |
| 216 | (define-key ediff-mode-map "#c" 'ediff-toggle-ignore-case) |
| 217 | (or ediff-word-mode |
| 218 | (define-key ediff-mode-map "##" 'ediff-toggle-skip-similar)) |
| 219 | (define-key ediff-mode-map "o" nil) |
| 220 | (define-key ediff-mode-map "A" 'ediff-toggle-read-only) |
| 221 | (define-key ediff-mode-map "B" 'ediff-toggle-read-only) |
| 222 | (define-key ediff-mode-map "w" nil) |
| 223 | (define-key ediff-mode-map "wa" 'ediff-save-buffer) |
| 224 | (define-key ediff-mode-map "wb" 'ediff-save-buffer) |
| 225 | (define-key ediff-mode-map "wd" 'ediff-save-buffer) |
| 226 | (define-key ediff-mode-map "=" 'ediff-inferior-compare-regions) |
| 227 | (if (and (fboundp 'ediff-show-patch-diagnostics) (ediff-patch-job)) |
| 228 | (define-key ediff-mode-map "P" 'ediff-show-patch-diagnostics)) |
| 229 | (if ediff-3way-job |
| 230 | (progn |
| 231 | (define-key ediff-mode-map "wc" 'ediff-save-buffer) |
| 232 | (define-key ediff-mode-map "gc" 'ediff-jump-to-difference-at-point) |
| 233 | )) |
| 234 | |
| 235 | (define-key ediff-mode-map "m" 'ediff-toggle-wide-display) |
| 236 | |
| 237 | ;; Allow ediff-mode-map to be referenced indirectly |
| 238 | (fset 'ediff-mode-map ediff-mode-map) |
| 239 | (run-hooks 'ediff-keymap-setup-hook)) |
| 240 | |
| 241 | |
| 242 | ;;; Setup functions |
| 243 | |
| 244 | ;; Common startup entry for all Ediff functions It now returns control buffer |
| 245 | ;; so other functions can do post-processing SETUP-PARAMETERS is a list of the |
| 246 | ;; form ((param .val) (param . val)...) This serves a similar purpose to |
| 247 | ;; STARTUP-HOOKS, but these parameters are set in the new control buffer right |
| 248 | ;; after this buf is created and before any windows are set and such. |
| 249 | (defun ediff-setup (buffer-A file-A buffer-B file-B buffer-C file-C |
| 250 | startup-hooks setup-parameters |
| 251 | &optional merge-buffer-file) |
| 252 | (run-hooks 'ediff-before-setup-hook) |
| 253 | ;; ediff-convert-standard-filename puts file names in the form appropriate |
| 254 | ;; for the OS at hand. |
| 255 | (setq file-A (ediff-convert-standard-filename (expand-file-name file-A))) |
| 256 | (setq file-B (ediff-convert-standard-filename (expand-file-name file-B))) |
| 257 | (if (stringp file-C) |
| 258 | (setq file-C |
| 259 | (ediff-convert-standard-filename (expand-file-name file-C)))) |
| 260 | (if (stringp merge-buffer-file) |
| 261 | (progn |
| 262 | (setq merge-buffer-file |
| 263 | (ediff-convert-standard-filename |
| 264 | (expand-file-name merge-buffer-file))) |
| 265 | ;; check the directory exists |
| 266 | (or (file-exists-p (file-name-directory merge-buffer-file)) |
| 267 | (error "Directory %s given as place to save the merge doesn't exist" |
| 268 | (abbreviate-file-name |
| 269 | (file-name-directory merge-buffer-file)))) |
| 270 | (if (and (file-exists-p merge-buffer-file) |
| 271 | (file-directory-p merge-buffer-file)) |
| 272 | (error "The merge buffer file %s must not be a directory" |
| 273 | (abbreviate-file-name merge-buffer-file))) |
| 274 | )) |
| 275 | (let* ((control-buffer-name |
| 276 | (ediff-unique-buffer-name "*Ediff Control Panel" "*")) |
| 277 | (control-buffer (ediff-with-current-buffer buffer-A |
| 278 | (get-buffer-create control-buffer-name)))) |
| 279 | (ediff-with-current-buffer control-buffer |
| 280 | (ediff-mode) |
| 281 | |
| 282 | (make-local-variable 'ediff-use-long-help-message) |
| 283 | (make-local-variable 'ediff-prefer-iconified-control-frame) |
| 284 | (make-local-variable 'ediff-split-window-function) |
| 285 | (make-local-variable 'ediff-default-variant) |
| 286 | (make-local-variable 'ediff-merge-window-share) |
| 287 | (make-local-variable 'ediff-window-setup-function) |
| 288 | (make-local-variable 'ediff-keep-variants) |
| 289 | |
| 290 | (make-local-variable 'window-min-height) |
| 291 | (setq window-min-height 2) |
| 292 | |
| 293 | (if (featurep 'xemacs) |
| 294 | (make-local-hook 'ediff-after-quit-hook-internal)) |
| 295 | |
| 296 | ;; unwrap set up parameters passed as argument |
| 297 | (while setup-parameters |
| 298 | (set (car (car setup-parameters)) (cdr (car setup-parameters))) |
| 299 | (setq setup-parameters (cdr setup-parameters))) |
| 300 | |
| 301 | ;; set variables classifying the current ediff job |
| 302 | ;; must come AFTER setup-parameters |
| 303 | (setq ediff-3way-comparison-job (ediff-3way-comparison-job) |
| 304 | ediff-merge-job (ediff-merge-job) |
| 305 | ediff-merge-with-ancestor-job (ediff-merge-with-ancestor-job) |
| 306 | ediff-3way-job (ediff-3way-job) |
| 307 | ediff-diff3-job (ediff-diff3-job) |
| 308 | ediff-narrow-job (ediff-narrow-job) |
| 309 | ediff-windows-job (ediff-windows-job) |
| 310 | ediff-word-mode-job (ediff-word-mode-job)) |
| 311 | |
| 312 | ;; Don't delete variants in case of ediff-buffer-* jobs without asking. |
| 313 | ;; This is because one may loose work---dangerous. |
| 314 | (if (string-match "buffer" (symbol-name ediff-job-name)) |
| 315 | (setq ediff-keep-variants t)) |
| 316 | |
| 317 | (if (featurep 'xemacs) |
| 318 | (make-local-hook 'pre-command-hook)) |
| 319 | |
| 320 | (if (ediff-window-display-p) |
| 321 | (add-hook 'pre-command-hook 'ediff-spy-after-mouse nil 'local)) |
| 322 | (setq ediff-mouse-pixel-position (mouse-pixel-position)) |
| 323 | |
| 324 | ;; adjust for merge jobs |
| 325 | (if ediff-merge-job |
| 326 | (let ((buf |
| 327 | ;; If default variant is `combined', the right stuff is |
| 328 | ;; inserted by ediff-do-merge |
| 329 | ;; Note: at some point, we tried to put ancestor buffer here |
| 330 | ;; (which is currently buffer C. This didn't work right |
| 331 | ;; because the merge buffer will contain lossage: diff regions |
| 332 | ;; in the ancestor, which correspond to revisions that agree |
| 333 | ;; in both buf A and B. |
| 334 | (cond ((eq ediff-default-variant 'default-B) |
| 335 | buffer-B) |
| 336 | (t buffer-A)))) |
| 337 | |
| 338 | (setq ediff-split-window-function |
| 339 | ediff-merge-split-window-function) |
| 340 | |
| 341 | ;; remember the ancestor buffer, if any |
| 342 | (setq ediff-ancestor-buffer buffer-C) |
| 343 | |
| 344 | (setq buffer-C |
| 345 | (get-buffer-create |
| 346 | (ediff-unique-buffer-name "*ediff-merge" "*"))) |
| 347 | (with-current-buffer buffer-C |
| 348 | (insert-buffer-substring buf) |
| 349 | (goto-char (point-min)) |
| 350 | (funcall (ediff-with-current-buffer buf major-mode)) |
| 351 | (widen) ; merge buffer is always widened |
| 352 | (add-hook 'local-write-file-hooks 'ediff-set-merge-mode nil t) |
| 353 | ))) |
| 354 | (setq buffer-read-only nil |
| 355 | ediff-buffer-A buffer-A |
| 356 | ediff-buffer-B buffer-B |
| 357 | ediff-buffer-C buffer-C |
| 358 | ediff-control-buffer control-buffer) |
| 359 | |
| 360 | (ediff-choose-syntax-table) |
| 361 | |
| 362 | (setq ediff-control-buffer-suffix |
| 363 | (if (string-match "<[0-9]*>" control-buffer-name) |
| 364 | (substring control-buffer-name |
| 365 | (match-beginning 0) (match-end 0)) |
| 366 | "") |
| 367 | ediff-control-buffer-number |
| 368 | (max |
| 369 | 0 |
| 370 | (1- |
| 371 | (string-to-number |
| 372 | (substring |
| 373 | ediff-control-buffer-suffix |
| 374 | (or |
| 375 | (string-match "[0-9]+" ediff-control-buffer-suffix) |
| 376 | 0)))))) |
| 377 | |
| 378 | (setq ediff-error-buffer |
| 379 | (get-buffer-create (ediff-unique-buffer-name "*ediff-errors" "*"))) |
| 380 | |
| 381 | (with-current-buffer ediff-error-buffer |
| 382 | (setq buffer-undo-list t)) |
| 383 | |
| 384 | (ediff-with-current-buffer buffer-A (ediff-strip-mode-line-format)) |
| 385 | (ediff-with-current-buffer buffer-B (ediff-strip-mode-line-format)) |
| 386 | (if ediff-3way-job |
| 387 | (ediff-with-current-buffer buffer-C (ediff-strip-mode-line-format))) |
| 388 | (if (ediff-buffer-live-p ediff-ancestor-buffer) |
| 389 | (ediff-with-current-buffer ediff-ancestor-buffer |
| 390 | (ediff-strip-mode-line-format))) |
| 391 | |
| 392 | (ediff-save-protected-variables) ; save variables to be restored on exit |
| 393 | |
| 394 | ;; ediff-setup-diff-regions-function must be set after setup |
| 395 | ;; parameters are processed. |
| 396 | (setq ediff-setup-diff-regions-function |
| 397 | (if ediff-diff3-job |
| 398 | 'ediff-setup-diff-regions3 |
| 399 | 'ediff-setup-diff-regions)) |
| 400 | |
| 401 | (setq ediff-wide-bounds |
| 402 | (list (ediff-make-bullet-proof-overlay |
| 403 | '(point-min) '(point-max) ediff-buffer-A) |
| 404 | (ediff-make-bullet-proof-overlay |
| 405 | '(point-min) '(point-max) ediff-buffer-B) |
| 406 | (ediff-make-bullet-proof-overlay |
| 407 | '(point-min) '(point-max) ediff-buffer-C))) |
| 408 | |
| 409 | ;; This has effect only on ediff-windows/regions |
| 410 | ;; In all other cases, ediff-visible-region sets visibility bounds to |
| 411 | ;; ediff-wide-bounds, and ediff-narrow-bounds are ignored. |
| 412 | (if ediff-start-narrowed |
| 413 | (setq ediff-visible-bounds ediff-narrow-bounds) |
| 414 | (setq ediff-visible-bounds ediff-wide-bounds)) |
| 415 | |
| 416 | (ediff-set-keys) ; comes after parameter setup |
| 417 | |
| 418 | ;; set up ediff-narrow-bounds, if not set |
| 419 | (or ediff-narrow-bounds |
| 420 | (setq ediff-narrow-bounds ediff-wide-bounds)) |
| 421 | |
| 422 | ;; All these must be inside ediff-with-current-buffer control-buffer, |
| 423 | ;; since these vars are local to control-buffer |
| 424 | ;; These won't run if there are errors in diff |
| 425 | (ediff-with-current-buffer ediff-buffer-A |
| 426 | (ediff-nuke-selective-display) |
| 427 | (run-hooks 'ediff-prepare-buffer-hook) |
| 428 | (if (ediff-with-current-buffer control-buffer ediff-merge-job) |
| 429 | (setq buffer-read-only t)) |
| 430 | ;; add control-buffer to the list of sessions--no longer used, but may |
| 431 | ;; be used again in the future |
| 432 | (or (memq control-buffer ediff-this-buffer-ediff-sessions) |
| 433 | (setq ediff-this-buffer-ediff-sessions |
| 434 | (cons control-buffer ediff-this-buffer-ediff-sessions))) |
| 435 | (if ediff-make-buffers-readonly-at-startup |
| 436 | (setq buffer-read-only t)) |
| 437 | ) |
| 438 | |
| 439 | (ediff-with-current-buffer ediff-buffer-B |
| 440 | (ediff-nuke-selective-display) |
| 441 | (run-hooks 'ediff-prepare-buffer-hook) |
| 442 | (if (ediff-with-current-buffer control-buffer ediff-merge-job) |
| 443 | (setq buffer-read-only t)) |
| 444 | ;; add control-buffer to the list of sessions |
| 445 | (or (memq control-buffer ediff-this-buffer-ediff-sessions) |
| 446 | (setq ediff-this-buffer-ediff-sessions |
| 447 | (cons control-buffer ediff-this-buffer-ediff-sessions))) |
| 448 | (if ediff-make-buffers-readonly-at-startup |
| 449 | (setq buffer-read-only t)) |
| 450 | ) |
| 451 | |
| 452 | (if ediff-3way-job |
| 453 | (ediff-with-current-buffer ediff-buffer-C |
| 454 | (ediff-nuke-selective-display) |
| 455 | ;; the merge bufer should never be narrowed |
| 456 | ;; (it can happen if it is on rmail-mode or similar) |
| 457 | (if (ediff-with-current-buffer control-buffer ediff-merge-job) |
| 458 | (widen)) |
| 459 | (run-hooks 'ediff-prepare-buffer-hook) |
| 460 | ;; add control-buffer to the list of sessions |
| 461 | (or (memq control-buffer ediff-this-buffer-ediff-sessions) |
| 462 | (setq ediff-this-buffer-ediff-sessions |
| 463 | (cons control-buffer |
| 464 | ediff-this-buffer-ediff-sessions))) |
| 465 | (if ediff-make-buffers-readonly-at-startup |
| 466 | (setq buffer-read-only t) |
| 467 | (setq buffer-read-only nil)) |
| 468 | )) |
| 469 | |
| 470 | (if (ediff-buffer-live-p ediff-ancestor-buffer) |
| 471 | (ediff-with-current-buffer ediff-ancestor-buffer |
| 472 | (ediff-nuke-selective-display) |
| 473 | (setq buffer-read-only t) |
| 474 | (run-hooks 'ediff-prepare-buffer-hook) |
| 475 | (or (memq control-buffer ediff-this-buffer-ediff-sessions) |
| 476 | (setq ediff-this-buffer-ediff-sessions |
| 477 | (cons control-buffer |
| 478 | ediff-this-buffer-ediff-sessions))) |
| 479 | )) |
| 480 | |
| 481 | ;; the following must be after setting up ediff-narrow-bounds AND after |
| 482 | ;; nuking selective display |
| 483 | (funcall ediff-setup-diff-regions-function file-A file-B file-C) |
| 484 | (setq ediff-number-of-differences (length ediff-difference-vector-A)) |
| 485 | (setq ediff-current-difference -1) |
| 486 | |
| 487 | (ediff-make-current-diff-overlay 'A) |
| 488 | (ediff-make-current-diff-overlay 'B) |
| 489 | (if ediff-3way-job |
| 490 | (ediff-make-current-diff-overlay 'C)) |
| 491 | (if ediff-merge-with-ancestor-job |
| 492 | (ediff-make-current-diff-overlay 'Ancestor)) |
| 493 | |
| 494 | (ediff-setup-windows buffer-A buffer-B buffer-C control-buffer) |
| 495 | |
| 496 | (let ((shift-A (ediff-overlay-start |
| 497 | (ediff-get-value-according-to-buffer-type |
| 498 | 'A ediff-narrow-bounds))) |
| 499 | (shift-B (ediff-overlay-start |
| 500 | (ediff-get-value-according-to-buffer-type |
| 501 | 'B ediff-narrow-bounds))) |
| 502 | (shift-C (ediff-overlay-start |
| 503 | (ediff-get-value-according-to-buffer-type |
| 504 | 'C ediff-narrow-bounds)))) |
| 505 | ;; position point in buf A |
| 506 | (save-excursion |
| 507 | (select-window ediff-window-A) |
| 508 | (goto-char shift-A)) |
| 509 | ;; position point in buf B |
| 510 | (save-excursion |
| 511 | (select-window ediff-window-B) |
| 512 | (goto-char shift-B)) |
| 513 | (if ediff-3way-job |
| 514 | (save-excursion |
| 515 | (select-window ediff-window-C) |
| 516 | (goto-char shift-C))) |
| 517 | ) |
| 518 | |
| 519 | (select-window ediff-control-window) |
| 520 | (ediff-visible-region) |
| 521 | |
| 522 | (run-hooks 'startup-hooks) |
| 523 | (ediff-arrange-autosave-in-merge-jobs merge-buffer-file) |
| 524 | |
| 525 | (ediff-refresh-mode-lines) |
| 526 | (setq buffer-read-only t) |
| 527 | (setq ediff-session-registry |
| 528 | (cons control-buffer ediff-session-registry)) |
| 529 | (ediff-update-registry) |
| 530 | (if (ediff-buffer-live-p ediff-meta-buffer) |
| 531 | (ediff-update-meta-buffer |
| 532 | ediff-meta-buffer nil ediff-meta-session-number)) |
| 533 | (run-hooks 'ediff-startup-hook) |
| 534 | ) ; eval in control-buffer |
| 535 | control-buffer)) |
| 536 | |
| 537 | |
| 538 | ;; This function assumes that we are in the window where control buffer is |
| 539 | ;; to reside. |
| 540 | (defun ediff-setup-control-buffer (ctl-buf) |
| 541 | "Set up window for control buffer." |
| 542 | (if (window-dedicated-p (selected-window)) |
| 543 | (set-buffer ctl-buf) ; we are in control frame but just in case |
| 544 | (switch-to-buffer ctl-buf)) |
| 545 | (let ((window-min-height 2)) |
| 546 | (erase-buffer) |
| 547 | (ediff-set-help-message) |
| 548 | (insert ediff-help-message) |
| 549 | (shrink-window-if-larger-than-buffer) |
| 550 | (or (ediff-multiframe-setup-p) |
| 551 | (ediff-indent-help-message)) |
| 552 | (ediff-set-help-overlays) |
| 553 | |
| 554 | (set-buffer-modified-p nil) |
| 555 | (ediff-refresh-mode-lines) |
| 556 | (setq ediff-control-window (selected-window)) |
| 557 | (setq ediff-window-config-saved |
| 558 | (format "%S%S%S%S%S%S%S" |
| 559 | ediff-control-window |
| 560 | ediff-window-A |
| 561 | ediff-window-B |
| 562 | ediff-window-C |
| 563 | ediff-split-window-function |
| 564 | (ediff-multiframe-setup-p) |
| 565 | ediff-wide-display-p)) |
| 566 | |
| 567 | (set-window-dedicated-p (selected-window) t) |
| 568 | ;; In multiframe, toolbar is set in ediff-setup-control-frame |
| 569 | (if (not (ediff-multiframe-setup-p)) |
| 570 | (ediff-make-bottom-toolbar)) ; this checks if toolbar is requested |
| 571 | (goto-char (point-min)) |
| 572 | (skip-chars-forward ediff-whitespace))) |
| 573 | |
| 574 | ;; This executes in control buffer and sets auto-save, visited file name, etc, |
| 575 | ;; in the merge buffer |
| 576 | (defun ediff-arrange-autosave-in-merge-jobs (merge-buffer-file) |
| 577 | (if (not ediff-merge-job) |
| 578 | () |
| 579 | (if (stringp merge-buffer-file) |
| 580 | (setq ediff-autostore-merges t |
| 581 | ediff-merge-store-file merge-buffer-file)) |
| 582 | (if (stringp ediff-merge-store-file) |
| 583 | (progn |
| 584 | ;; save before leaving ctl buffer |
| 585 | (ediff-verify-file-merge-buffer ediff-merge-store-file) |
| 586 | (setq merge-buffer-file ediff-merge-store-file) |
| 587 | (ediff-with-current-buffer ediff-buffer-C |
| 588 | (set-visited-file-name merge-buffer-file)))) |
| 589 | (ediff-with-current-buffer ediff-buffer-C |
| 590 | (setq buffer-offer-save t) ; ask before killing buffer |
| 591 | ;; make sure the contents is auto-saved |
| 592 | (auto-save-mode 1)) |
| 593 | )) |
| 594 | |
| 595 | \f |
| 596 | ;;; Commands for working with Ediff |
| 597 | |
| 598 | (defun ediff-update-diffs () |
| 599 | "Recompute difference regions in buffers A, B, and C. |
| 600 | Buffers are not synchronized with their respective files, so changes done |
| 601 | to these buffers are not saved at this point---the user can do this later, |
| 602 | if necessary." |
| 603 | (interactive) |
| 604 | (ediff-barf-if-not-control-buffer) |
| 605 | (if (and (ediff-buffer-live-p ediff-ancestor-buffer) |
| 606 | (not |
| 607 | (y-or-n-p |
| 608 | "Ancestor buffer will not be used. Recompute diffs anyway? "))) |
| 609 | (error "Recomputation of differences canceled")) |
| 610 | |
| 611 | (let ((point-A (ediff-with-current-buffer ediff-buffer-A (point))) |
| 612 | ;;(point-B (ediff-with-current-buffer ediff-buffer-B (point))) |
| 613 | (tmp-buffer (get-buffer-create ediff-tmp-buffer)) |
| 614 | (buf-A-file-name (buffer-file-name ediff-buffer-A)) |
| 615 | (buf-B-file-name (buffer-file-name ediff-buffer-B)) |
| 616 | ;; (null ediff-buffer-C) is no problem, as we later check if |
| 617 | ;; ediff-buffer-C is alive |
| 618 | (buf-C-file-name (buffer-file-name ediff-buffer-C)) |
| 619 | (overl-A (ediff-get-value-according-to-buffer-type |
| 620 | 'A ediff-narrow-bounds)) |
| 621 | (overl-B (ediff-get-value-according-to-buffer-type |
| 622 | 'B ediff-narrow-bounds)) |
| 623 | (overl-C (ediff-get-value-according-to-buffer-type |
| 624 | 'C ediff-narrow-bounds)) |
| 625 | beg-A end-A beg-B end-B beg-C end-C |
| 626 | file-A file-B file-C) |
| 627 | |
| 628 | (if (stringp buf-A-file-name) |
| 629 | (setq buf-A-file-name (file-name-nondirectory buf-A-file-name))) |
| 630 | (if (stringp buf-B-file-name) |
| 631 | (setq buf-B-file-name (file-name-nondirectory buf-B-file-name))) |
| 632 | (if (stringp buf-C-file-name) |
| 633 | (setq buf-C-file-name (file-name-nondirectory buf-C-file-name))) |
| 634 | |
| 635 | (ediff-unselect-and-select-difference -1) |
| 636 | |
| 637 | (setq beg-A (ediff-overlay-start overl-A) |
| 638 | beg-B (ediff-overlay-start overl-B) |
| 639 | beg-C (ediff-overlay-start overl-C) |
| 640 | end-A (ediff-overlay-end overl-A) |
| 641 | end-B (ediff-overlay-end overl-B) |
| 642 | end-C (ediff-overlay-end overl-C)) |
| 643 | |
| 644 | (if ediff-word-mode |
| 645 | (progn |
| 646 | (ediff-wordify beg-A end-A ediff-buffer-A tmp-buffer) |
| 647 | (setq file-A (ediff-make-temp-file tmp-buffer "regA")) |
| 648 | (ediff-wordify beg-B end-B ediff-buffer-B tmp-buffer) |
| 649 | (setq file-B (ediff-make-temp-file tmp-buffer "regB")) |
| 650 | (if ediff-3way-job |
| 651 | (progn |
| 652 | (ediff-wordify beg-C end-C ediff-buffer-C tmp-buffer) |
| 653 | (setq file-C (ediff-make-temp-file tmp-buffer "regC")))) |
| 654 | ) |
| 655 | ;; not word-mode |
| 656 | (setq file-A (ediff-make-temp-file ediff-buffer-A buf-A-file-name)) |
| 657 | (setq file-B (ediff-make-temp-file ediff-buffer-B buf-B-file-name)) |
| 658 | (if ediff-3way-job |
| 659 | (setq file-C (ediff-make-temp-file ediff-buffer-C buf-C-file-name))) |
| 660 | ) |
| 661 | |
| 662 | (ediff-clear-diff-vector 'ediff-difference-vector-A 'fine-diffs-also) |
| 663 | (ediff-clear-diff-vector 'ediff-difference-vector-B 'fine-diffs-also) |
| 664 | (ediff-clear-diff-vector 'ediff-difference-vector-C 'fine-diffs-also) |
| 665 | (ediff-clear-diff-vector |
| 666 | 'ediff-difference-vector-Ancestor 'fine-diffs-also) |
| 667 | ;; let them garbage collect. we can't use the ancestor after recomputing |
| 668 | ;; the diffs. |
| 669 | (setq ediff-difference-vector-Ancestor nil |
| 670 | ediff-ancestor-buffer nil |
| 671 | ediff-state-of-merge nil) |
| 672 | |
| 673 | (setq ediff-killed-diffs-alist nil) ; invalidate saved killed diff regions |
| 674 | |
| 675 | ;; In case of merge job, fool it into thinking that it is just doing |
| 676 | ;; comparison |
| 677 | (let ((ediff-setup-diff-regions-function ediff-setup-diff-regions-function) |
| 678 | (ediff-3way-comparison-job ediff-3way-comparison-job) |
| 679 | (ediff-merge-job ediff-merge-job) |
| 680 | (ediff-merge-with-ancestor-job ediff-merge-with-ancestor-job) |
| 681 | (ediff-job-name ediff-job-name)) |
| 682 | (if ediff-merge-job |
| 683 | (setq ediff-setup-diff-regions-function 'ediff-setup-diff-regions3 |
| 684 | ediff-3way-comparison-job t |
| 685 | ediff-merge-job nil |
| 686 | ediff-merge-with-ancestor-job nil |
| 687 | ediff-job-name 'ediff-files3)) |
| 688 | (funcall ediff-setup-diff-regions-function file-A file-B file-C)) |
| 689 | |
| 690 | (setq ediff-number-of-differences (length ediff-difference-vector-A)) |
| 691 | (delete-file file-A) |
| 692 | (delete-file file-B) |
| 693 | (if file-C |
| 694 | (delete-file file-C)) |
| 695 | |
| 696 | (if ediff-3way-job |
| 697 | (ediff-set-state-of-all-diffs-in-all-buffers ediff-control-buffer)) |
| 698 | |
| 699 | (ediff-jump-to-difference (ediff-diff-at-point 'A point-A)) |
| 700 | (message "") |
| 701 | )) |
| 702 | |
| 703 | ;; Not bound to any key---to dangerous. A user can do it if necessary. |
| 704 | (defun ediff-revert-buffers-then-recompute-diffs (noconfirm) |
| 705 | "Revert buffers A, B and C. Then rerun Ediff on file A and file B." |
| 706 | (interactive "P") |
| 707 | (ediff-barf-if-not-control-buffer) |
| 708 | (let ((bufA ediff-buffer-A) |
| 709 | (bufB ediff-buffer-B) |
| 710 | (bufC ediff-buffer-C) |
| 711 | (ctl-buf ediff-control-buffer) |
| 712 | (keep-variants ediff-keep-variants) |
| 713 | (ancestor-buf ediff-ancestor-buffer) |
| 714 | (ancestor-job ediff-merge-with-ancestor-job) |
| 715 | (merge ediff-merge-job) |
| 716 | (comparison ediff-3way-comparison-job)) |
| 717 | (ediff-with-current-buffer bufA |
| 718 | (revert-buffer t noconfirm)) |
| 719 | (ediff-with-current-buffer bufB |
| 720 | (revert-buffer t noconfirm)) |
| 721 | ;; this should only be executed in a 3way comparison, not in merge |
| 722 | (if comparison |
| 723 | (ediff-with-current-buffer bufC |
| 724 | (revert-buffer t noconfirm))) |
| 725 | (if merge |
| 726 | (progn |
| 727 | (set-buffer ctl-buf) |
| 728 | ;; the argument says whether to reverse the meaning of |
| 729 | ;; ediff-keep-variants, i.e., ediff-really-quit runs here with |
| 730 | ;; variants kept. |
| 731 | (ediff-really-quit (not keep-variants)) |
| 732 | (kill-buffer bufC) |
| 733 | (if ancestor-job |
| 734 | (ediff-merge-buffers-with-ancestor bufA bufB ancestor-buf) |
| 735 | (ediff-merge-buffers bufA bufB))) |
| 736 | (ediff-update-diffs)))) |
| 737 | |
| 738 | |
| 739 | ;; optional NO-REHIGHLIGHT says to not rehighlight buffers |
| 740 | (defun ediff-recenter (&optional no-rehighlight) |
| 741 | "Bring the highlighted region of all buffers being compared into view. |
| 742 | Reestablish the default three-window display." |
| 743 | (interactive) |
| 744 | (ediff-barf-if-not-control-buffer) |
| 745 | (let (buffer-read-only) |
| 746 | (if (and (ediff-buffer-live-p ediff-buffer-A) |
| 747 | (ediff-buffer-live-p ediff-buffer-B) |
| 748 | (or (not ediff-3way-job) |
| 749 | (ediff-buffer-live-p ediff-buffer-C))) |
| 750 | (ediff-setup-windows |
| 751 | ediff-buffer-A ediff-buffer-B ediff-buffer-C ediff-control-buffer) |
| 752 | (or (eq this-command 'ediff-quit) |
| 753 | (message ediff-KILLED-VITAL-BUFFER |
| 754 | (beep 1))) |
| 755 | )) |
| 756 | |
| 757 | ;; set visibility range appropriate to this invocation of Ediff. |
| 758 | (ediff-visible-region) |
| 759 | ;; raise |
| 760 | (if (and (ediff-window-display-p) |
| 761 | (symbolp this-command) |
| 762 | (symbolp last-command) |
| 763 | ;; Either one of the display-changing commands |
| 764 | (or (memq this-command |
| 765 | '(ediff-recenter |
| 766 | ediff-dir-action ediff-registry-action |
| 767 | ediff-patch-action |
| 768 | ediff-toggle-wide-display ediff-toggle-multiframe)) |
| 769 | ;; Or one of the movement cmds and prev cmd was an Ediff cmd |
| 770 | ;; This avoids raising frames unnecessarily. |
| 771 | (and (memq this-command |
| 772 | '(ediff-next-difference |
| 773 | ediff-previous-difference |
| 774 | ediff-jump-to-difference |
| 775 | ediff-jump-to-difference-at-point)) |
| 776 | (not (string-match "^ediff-" (symbol-name last-command))) |
| 777 | ))) |
| 778 | (progn |
| 779 | (if (window-live-p ediff-window-A) |
| 780 | (raise-frame (window-frame ediff-window-A))) |
| 781 | (if (window-live-p ediff-window-B) |
| 782 | (raise-frame (window-frame ediff-window-B))) |
| 783 | (if (window-live-p ediff-window-C) |
| 784 | (raise-frame (window-frame ediff-window-C))))) |
| 785 | (if (and (ediff-window-display-p) |
| 786 | (frame-live-p ediff-control-frame) |
| 787 | (not ediff-use-long-help-message) |
| 788 | (not (ediff-frame-iconified-p ediff-control-frame))) |
| 789 | (raise-frame ediff-control-frame)) |
| 790 | |
| 791 | ;; Redisplay whatever buffers are showing, if there is a selected difference |
| 792 | (let ((control-frame ediff-control-frame) |
| 793 | (control-buf ediff-control-buffer)) |
| 794 | (if (and (ediff-buffer-live-p ediff-buffer-A) |
| 795 | (ediff-buffer-live-p ediff-buffer-B) |
| 796 | (or (not ediff-3way-job) |
| 797 | (ediff-buffer-live-p ediff-buffer-C))) |
| 798 | (progn |
| 799 | (or no-rehighlight |
| 800 | (ediff-select-difference ediff-current-difference)) |
| 801 | |
| 802 | (ediff-recenter-one-window 'A) |
| 803 | (ediff-recenter-one-window 'B) |
| 804 | (if ediff-3way-job |
| 805 | (ediff-recenter-one-window 'C)) |
| 806 | |
| 807 | (ediff-with-current-buffer control-buf |
| 808 | (ediff-recenter-ancestor) ; check if ancestor is alive |
| 809 | |
| 810 | (if (and (ediff-multiframe-setup-p) |
| 811 | (not ediff-use-long-help-message) |
| 812 | (not (ediff-frame-iconified-p ediff-control-frame))) |
| 813 | ;; never grab mouse on quit in this place |
| 814 | (ediff-reset-mouse |
| 815 | control-frame |
| 816 | (eq this-command 'ediff-quit)))) |
| 817 | )) |
| 818 | |
| 819 | (or no-rehighlight |
| 820 | (ediff-restore-highlighting)) |
| 821 | (ediff-with-current-buffer control-buf (ediff-refresh-mode-lines)) |
| 822 | )) |
| 823 | |
| 824 | ;; this function returns to the window it was called from |
| 825 | ;; (which was the control window) |
| 826 | (defun ediff-recenter-one-window (buf-type) |
| 827 | (if (ediff-valid-difference-p) |
| 828 | ;; context must be saved before switching to windows A/B/C |
| 829 | (let* ((ctl-wind (selected-window)) |
| 830 | (shift (ediff-overlay-start |
| 831 | (ediff-get-value-according-to-buffer-type |
| 832 | buf-type ediff-narrow-bounds))) |
| 833 | (job-name ediff-job-name) |
| 834 | (control-buf ediff-control-buffer) |
| 835 | (window-name (ediff-get-symbol-from-alist |
| 836 | buf-type ediff-window-alist)) |
| 837 | (window (if (window-live-p (symbol-value window-name)) |
| 838 | (symbol-value window-name)))) |
| 839 | |
| 840 | (if (and window ediff-windows-job) |
| 841 | (set-window-start window shift)) |
| 842 | (if window |
| 843 | (progn |
| 844 | (select-window window) |
| 845 | (ediff-deactivate-mark) |
| 846 | (ediff-position-region |
| 847 | (ediff-get-diff-posn buf-type 'beg nil control-buf) |
| 848 | (ediff-get-diff-posn buf-type 'end nil control-buf) |
| 849 | (ediff-get-diff-posn buf-type 'beg nil control-buf) |
| 850 | job-name |
| 851 | ))) |
| 852 | (select-window ctl-wind) |
| 853 | ))) |
| 854 | |
| 855 | (defun ediff-recenter-ancestor () |
| 856 | ;; do half-hearted job by recentering the ancestor buffer, if it is alive and |
| 857 | ;; visible. |
| 858 | (if (and (ediff-buffer-live-p ediff-ancestor-buffer) |
| 859 | (ediff-valid-difference-p)) |
| 860 | (let ((window (ediff-get-visible-buffer-window ediff-ancestor-buffer)) |
| 861 | (ctl-wind (selected-window)) |
| 862 | (job-name ediff-job-name) |
| 863 | (ctl-buf ediff-control-buffer)) |
| 864 | (ediff-with-current-buffer ediff-ancestor-buffer |
| 865 | (goto-char (ediff-get-diff-posn 'Ancestor 'beg nil ctl-buf)) |
| 866 | (if window |
| 867 | (progn |
| 868 | (select-window window) |
| 869 | (ediff-position-region |
| 870 | (ediff-get-diff-posn 'Ancestor 'beg nil ctl-buf) |
| 871 | (ediff-get-diff-posn 'Ancestor 'end nil ctl-buf) |
| 872 | (ediff-get-diff-posn 'Ancestor 'beg nil ctl-buf) |
| 873 | job-name)))) |
| 874 | (select-window ctl-wind) |
| 875 | ))) |
| 876 | |
| 877 | |
| 878 | ;; This will have to be refined for 3way jobs |
| 879 | (defun ediff-toggle-split () |
| 880 | "Toggle vertical/horizontal window split. |
| 881 | Does nothing if file-A and file-B are in different frames." |
| 882 | (interactive) |
| 883 | (ediff-barf-if-not-control-buffer) |
| 884 | (let* ((wind-A (if (window-live-p ediff-window-A) ediff-window-A)) |
| 885 | (wind-B (if (window-live-p ediff-window-B) ediff-window-B)) |
| 886 | (wind-C (if (window-live-p ediff-window-C) ediff-window-C)) |
| 887 | (frame-A (if wind-A (window-frame wind-A))) |
| 888 | (frame-B (if wind-B (window-frame wind-B))) |
| 889 | (frame-C (if wind-C (window-frame wind-C)))) |
| 890 | (if (or (eq frame-A frame-B) |
| 891 | (not (frame-live-p frame-A)) |
| 892 | (not (frame-live-p frame-B)) |
| 893 | (if ediff-3way-comparison-job |
| 894 | (or (not (frame-live-p frame-C)) |
| 895 | (eq frame-A frame-C) (eq frame-B frame-C)))) |
| 896 | (setq ediff-split-window-function |
| 897 | (if (eq ediff-split-window-function 'split-window-vertically) |
| 898 | 'split-window-horizontally |
| 899 | 'split-window-vertically)) |
| 900 | (message "Buffers being compared are in different frames")) |
| 901 | (ediff-recenter 'no-rehighlight))) |
| 902 | |
| 903 | (defun ediff-toggle-hilit () |
| 904 | "Switch between highlighting using ASCII flags and highlighting using faces. |
| 905 | On a dumb terminal, switches between ASCII highlighting and no highlighting." |
| 906 | (interactive) |
| 907 | (ediff-barf-if-not-control-buffer) |
| 908 | |
| 909 | (ediff-unselect-and-select-difference |
| 910 | ediff-current-difference 'unselect-only) |
| 911 | ;; cycle through highlighting |
| 912 | (cond ((and ediff-use-faces |
| 913 | (ediff-has-face-support-p) |
| 914 | ediff-highlight-all-diffs) |
| 915 | (message "Unhighlighting unselected difference regions") |
| 916 | (setq ediff-highlight-all-diffs nil |
| 917 | ediff-highlighting-style 'face)) |
| 918 | ((or (and ediff-use-faces (ediff-has-face-support-p) |
| 919 | (eq ediff-highlighting-style 'face)) ; has face support |
| 920 | (and (not (ediff-has-face-support-p)) ; no face support |
| 921 | (eq ediff-highlighting-style 'off))) |
| 922 | (message "Highlighting with ASCII flags") |
| 923 | (setq ediff-highlighting-style 'ascii |
| 924 | ediff-highlight-all-diffs nil |
| 925 | ediff-use-faces nil)) |
| 926 | ((eq ediff-highlighting-style 'ascii) |
| 927 | (message "ASCII highlighting flags removed") |
| 928 | (setq ediff-highlighting-style 'off |
| 929 | ediff-highlight-all-diffs nil)) |
| 930 | ((ediff-has-face-support-p) ; catch-all for cases with face support |
| 931 | (message "Re-highlighting all difference regions") |
| 932 | (setq ediff-use-faces t |
| 933 | ediff-highlighting-style 'face |
| 934 | ediff-highlight-all-diffs t))) |
| 935 | |
| 936 | (if (and ediff-use-faces ediff-highlight-all-diffs) |
| 937 | (ediff-paint-background-regions) |
| 938 | (ediff-paint-background-regions 'unhighlight)) |
| 939 | |
| 940 | (ediff-unselect-and-select-difference |
| 941 | ediff-current-difference 'select-only)) |
| 942 | |
| 943 | |
| 944 | (defun ediff-toggle-autorefine () |
| 945 | "Toggle auto-refine mode." |
| 946 | (interactive) |
| 947 | (ediff-barf-if-not-control-buffer) |
| 948 | (if ediff-word-mode |
| 949 | (error "No fine differences in this mode")) |
| 950 | (cond ((eq ediff-auto-refine 'nix) |
| 951 | (setq ediff-auto-refine 'on) |
| 952 | (ediff-make-fine-diffs ediff-current-difference 'noforce) |
| 953 | (message "Auto-refining is ON")) |
| 954 | ((eq ediff-auto-refine 'on) |
| 955 | (message "Auto-refining is OFF") |
| 956 | (setq ediff-auto-refine 'off)) |
| 957 | (t ;; nix 'em |
| 958 | (ediff-set-fine-diff-properties ediff-current-difference 'default) |
| 959 | (message "Refinements are HIDDEN") |
| 960 | (setq ediff-auto-refine 'nix)) |
| 961 | )) |
| 962 | |
| 963 | (defun ediff-show-ancestor () |
| 964 | "Show the ancestor buffer in a suitable window." |
| 965 | (interactive) |
| 966 | (ediff-recenter) |
| 967 | (or (ediff-buffer-live-p ediff-ancestor-buffer) |
| 968 | (if ediff-merge-with-ancestor-job |
| 969 | (error "Lost connection to ancestor buffer...sorry") |
| 970 | (error "Not merging with ancestor"))) |
| 971 | (let (wind) |
| 972 | (cond ((setq wind (ediff-get-visible-buffer-window ediff-ancestor-buffer)) |
| 973 | (raise-frame (window-frame wind))) |
| 974 | (t (set-window-buffer ediff-window-C ediff-ancestor-buffer))))) |
| 975 | |
| 976 | (defun ediff-make-or-kill-fine-diffs (arg) |
| 977 | "Compute fine diffs. With negative prefix arg, kill fine diffs. |
| 978 | In both cases, operates on the current difference region." |
| 979 | (interactive "P") |
| 980 | (ediff-barf-if-not-control-buffer) |
| 981 | (cond ((eq arg '-) |
| 982 | (ediff-clear-fine-differences ediff-current-difference)) |
| 983 | ((and (numberp arg) (< arg 0)) |
| 984 | (ediff-clear-fine-differences ediff-current-difference)) |
| 985 | (t (ediff-make-fine-diffs)))) |
| 986 | |
| 987 | |
| 988 | (defun ediff-toggle-help () |
| 989 | "Toggle short/long help message." |
| 990 | (interactive) |
| 991 | (ediff-barf-if-not-control-buffer) |
| 992 | (let (buffer-read-only) |
| 993 | (erase-buffer) |
| 994 | (setq ediff-use-long-help-message (not ediff-use-long-help-message)) |
| 995 | (ediff-set-help-message)) |
| 996 | ;; remember the icon status of the control frame when the user requested |
| 997 | ;; full control message |
| 998 | (if (and ediff-use-long-help-message (ediff-multiframe-setup-p)) |
| 999 | (setq ediff-prefer-iconified-control-frame |
| 1000 | (ediff-frame-iconified-p ediff-control-frame))) |
| 1001 | |
| 1002 | (setq ediff-window-config-saved "") ; force redisplay |
| 1003 | (ediff-recenter 'no-rehighlight)) |
| 1004 | |
| 1005 | |
| 1006 | ;; If BUF, this is the buffer to toggle, not current buffer. |
| 1007 | (defun ediff-toggle-read-only (&optional buf) |
| 1008 | "Toggle read-only in current buffer. |
| 1009 | If buffer is under version control and locked, check it out first. |
| 1010 | If optional argument BUF is specified, toggle read-only in that buffer instead |
| 1011 | of the current buffer." |
| 1012 | (interactive) |
| 1013 | (ediff-barf-if-not-control-buffer) |
| 1014 | (let ((ctl-buf (if (null buf) (current-buffer))) |
| 1015 | (buf-type (ediff-char-to-buftype (ediff-last-command-char)))) |
| 1016 | (or buf (ediff-recenter)) |
| 1017 | (or buf |
| 1018 | (setq buf (ediff-get-buffer buf-type))) |
| 1019 | |
| 1020 | (ediff-with-current-buffer buf ; eval in buf A/B/C |
| 1021 | (let* ((file (buffer-file-name buf)) |
| 1022 | (file-writable (and file |
| 1023 | (file-exists-p file) |
| 1024 | (file-writable-p file))) |
| 1025 | (toggle-ro-cmd (cond (ediff-toggle-read-only-function) |
| 1026 | ((ediff-file-checked-out-p file) |
| 1027 | 'toggle-read-only) |
| 1028 | (file-writable 'toggle-read-only) |
| 1029 | (t (key-binding "\C-x\C-q"))))) |
| 1030 | ;; If the file is checked in, make sure we don't make buffer modifiable |
| 1031 | ;; without warning the user. The user can fool our checks by making the |
| 1032 | ;; buffer non-RO without checking the file out. We regard this as a |
| 1033 | ;; user problem. |
| 1034 | (if (and (ediff-file-checked-in-p file) |
| 1035 | ;; If ctl-buf is null, this means we called this |
| 1036 | ;; non-interactively, in which case don't ask questions |
| 1037 | ctl-buf) |
| 1038 | (cond ((not buffer-read-only) |
| 1039 | (setq toggle-ro-cmd 'toggle-read-only)) |
| 1040 | ((and (or (beep 1) t) ; always beep |
| 1041 | (y-or-n-p |
| 1042 | (format |
| 1043 | "File %s is under version control. Check it out? " |
| 1044 | (ediff-abbreviate-file-name file)))) |
| 1045 | ;; if we checked the file out, we should also change the |
| 1046 | ;; original state of buffer-read-only to nil. If we don't |
| 1047 | ;; do this, the mode line will show %%, since the file was |
| 1048 | ;; RO before ediff started, so the user will think the file |
| 1049 | ;; is checked in. |
| 1050 | (ediff-with-current-buffer ctl-buf |
| 1051 | (ediff-change-saved-variable |
| 1052 | 'buffer-read-only nil buf-type))) |
| 1053 | (t |
| 1054 | (setq toggle-ro-cmd 'toggle-read-only) |
| 1055 | (beep 1) (beep 1) |
| 1056 | (message |
| 1057 | "Boy, this is risky! Don't modify this file...") |
| 1058 | (sit-for 3)))) ; let the user see the warning |
| 1059 | (if (and toggle-ro-cmd |
| 1060 | (string-match "toggle-read-only" (symbol-name toggle-ro-cmd))) |
| 1061 | (save-excursion |
| 1062 | (save-window-excursion |
| 1063 | (select-window (ediff-get-visible-buffer-window buf)) |
| 1064 | (command-execute toggle-ro-cmd))) |
| 1065 | (error "Don't know how to toggle read-only in buffer %S" buf)) |
| 1066 | |
| 1067 | ;; Check if we made the current buffer updatable, but its file is RO. |
| 1068 | ;; Signal a warning in this case. |
| 1069 | (if (and file (not buffer-read-only) |
| 1070 | (eq this-command 'ediff-toggle-read-only) |
| 1071 | (file-exists-p file) |
| 1072 | (not (file-writable-p file))) |
| 1073 | (progn |
| 1074 | (beep 1) |
| 1075 | (message "Warning: file %s is read-only" |
| 1076 | (ediff-abbreviate-file-name file)))) |
| 1077 | )))) |
| 1078 | |
| 1079 | ;; checkout if visited file is checked in |
| 1080 | (defun ediff-maybe-checkout (buf) |
| 1081 | (let ((file (expand-file-name (buffer-file-name buf))) |
| 1082 | (checkout-function (key-binding "\C-x\C-q"))) |
| 1083 | (if (and (ediff-file-checked-in-p file) |
| 1084 | (or (beep 1) t) |
| 1085 | (y-or-n-p |
| 1086 | (format |
| 1087 | "File %s is under version control. Check it out? " |
| 1088 | (ediff-abbreviate-file-name file)))) |
| 1089 | (ediff-with-current-buffer buf |
| 1090 | (command-execute checkout-function))))) |
| 1091 | |
| 1092 | |
| 1093 | ;; This is a simple-minded check for whether a file is under version control. |
| 1094 | ;; If file,v exists but file doesn't, this file is considered to be not checked |
| 1095 | ;; in and not checked out for the purpose of patching (since patch won't be |
| 1096 | ;; able to read such a file anyway). |
| 1097 | ;; FILE is a string representing file name |
| 1098 | ;;(defun ediff-file-under-version-control (file) |
| 1099 | ;; (let* ((filedir (file-name-directory file)) |
| 1100 | ;; (file-nondir (file-name-nondirectory file)) |
| 1101 | ;; (trial (concat file-nondir ",v")) |
| 1102 | ;; (full-trial (concat filedir trial)) |
| 1103 | ;; (full-rcs-trial (concat filedir "RCS/" trial))) |
| 1104 | ;; (and (stringp file) |
| 1105 | ;; (file-exists-p file) |
| 1106 | ;; (or |
| 1107 | ;; (and |
| 1108 | ;; (file-exists-p full-trial) |
| 1109 | ;; ;; in FAT FS, `file,v' and `file' may turn out to be the same! |
| 1110 | ;; ;; don't be fooled by this! |
| 1111 | ;; (not (equal (file-attributes file) |
| 1112 | ;; (file-attributes full-trial)))) |
| 1113 | ;; ;; check if a version is in RCS/ directory |
| 1114 | ;; (file-exists-p full-rcs-trial))) |
| 1115 | ;; )) |
| 1116 | |
| 1117 | |
| 1118 | (defun ediff-file-checked-out-p (file) |
| 1119 | (or (not (featurep 'vc-hooks)) |
| 1120 | (and (vc-backend file) |
| 1121 | (if (fboundp 'vc-state) |
| 1122 | (or (memq (vc-state file) '(edited needs-merge)) |
| 1123 | (stringp (vc-state file))) |
| 1124 | ;; XEmacs has no vc-state |
| 1125 | (when (featurep 'xemacs) (vc-locking-user file))) |
| 1126 | ))) |
| 1127 | |
| 1128 | (defun ediff-file-checked-in-p (file) |
| 1129 | (and (featurep 'vc-hooks) |
| 1130 | ;; Only RCS and SCCS files are considered checked in |
| 1131 | (memq (vc-backend file) '(RCS SCCS)) |
| 1132 | (if (fboundp 'vc-state) |
| 1133 | (and |
| 1134 | (not (memq (vc-state file) '(edited needs-merge))) |
| 1135 | (not (stringp (vc-state file)))) |
| 1136 | ;; XEmacs has no vc-state |
| 1137 | (when (featurep 'xemacs) (not (vc-locking-user file)))) |
| 1138 | )) |
| 1139 | |
| 1140 | (defun ediff-file-compressed-p (file) |
| 1141 | (condition-case nil |
| 1142 | (require 'jka-compr) |
| 1143 | (error)) |
| 1144 | (if (featurep 'jka-compr) |
| 1145 | (string-match (jka-compr-build-file-regexp) file))) |
| 1146 | |
| 1147 | |
| 1148 | (defun ediff-swap-buffers () |
| 1149 | "Rotate the display of buffers A, B, and C." |
| 1150 | (interactive) |
| 1151 | (ediff-barf-if-not-control-buffer) |
| 1152 | (if (and (window-live-p ediff-window-A) (window-live-p ediff-window-B)) |
| 1153 | (let ((buf ediff-buffer-A) |
| 1154 | (values ediff-buffer-values-orig-A) |
| 1155 | (diff-vec ediff-difference-vector-A) |
| 1156 | (hide-regexp ediff-regexp-hide-A) |
| 1157 | (focus-regexp ediff-regexp-focus-A) |
| 1158 | (wide-visibility-p (eq ediff-visible-bounds ediff-wide-bounds)) |
| 1159 | (overlay (if (ediff-has-face-support-p) |
| 1160 | ediff-current-diff-overlay-A))) |
| 1161 | (if ediff-3way-comparison-job |
| 1162 | (progn |
| 1163 | (set-window-buffer ediff-window-A ediff-buffer-C) |
| 1164 | (set-window-buffer ediff-window-B ediff-buffer-A) |
| 1165 | (set-window-buffer ediff-window-C ediff-buffer-B) |
| 1166 | ) |
| 1167 | (set-window-buffer ediff-window-A ediff-buffer-B) |
| 1168 | (set-window-buffer ediff-window-B ediff-buffer-A)) |
| 1169 | ;; swap diff buffers |
| 1170 | (if ediff-3way-comparison-job |
| 1171 | (setq ediff-buffer-A ediff-buffer-C |
| 1172 | ediff-buffer-C ediff-buffer-B |
| 1173 | ediff-buffer-B buf) |
| 1174 | (setq ediff-buffer-A ediff-buffer-B |
| 1175 | ediff-buffer-B buf)) |
| 1176 | |
| 1177 | ;; swap saved buffer characteristics |
| 1178 | (if ediff-3way-comparison-job |
| 1179 | (setq ediff-buffer-values-orig-A ediff-buffer-values-orig-C |
| 1180 | ediff-buffer-values-orig-C ediff-buffer-values-orig-B |
| 1181 | ediff-buffer-values-orig-B values) |
| 1182 | (setq ediff-buffer-values-orig-A ediff-buffer-values-orig-B |
| 1183 | ediff-buffer-values-orig-B values)) |
| 1184 | |
| 1185 | ;; swap diff vectors |
| 1186 | (if ediff-3way-comparison-job |
| 1187 | (setq ediff-difference-vector-A ediff-difference-vector-C |
| 1188 | ediff-difference-vector-C ediff-difference-vector-B |
| 1189 | ediff-difference-vector-B diff-vec) |
| 1190 | (setq ediff-difference-vector-A ediff-difference-vector-B |
| 1191 | ediff-difference-vector-B diff-vec)) |
| 1192 | |
| 1193 | ;; swap hide/focus regexp |
| 1194 | (if ediff-3way-comparison-job |
| 1195 | (setq ediff-regexp-hide-A ediff-regexp-hide-C |
| 1196 | ediff-regexp-hide-C ediff-regexp-hide-B |
| 1197 | ediff-regexp-hide-B hide-regexp |
| 1198 | ediff-regexp-focus-A ediff-regexp-focus-C |
| 1199 | ediff-regexp-focus-C ediff-regexp-focus-B |
| 1200 | ediff-regexp-focus-B focus-regexp) |
| 1201 | (setq ediff-regexp-hide-A ediff-regexp-hide-B |
| 1202 | ediff-regexp-hide-B hide-regexp |
| 1203 | ediff-regexp-focus-A ediff-regexp-focus-B |
| 1204 | ediff-regexp-focus-B focus-regexp)) |
| 1205 | |
| 1206 | ;; The following is needed for XEmacs, since there one can't move |
| 1207 | ;; overlay to another buffer. In Emacs, this swap is redundant. |
| 1208 | (if (ediff-has-face-support-p) |
| 1209 | (if ediff-3way-comparison-job |
| 1210 | (setq ediff-current-diff-overlay-A ediff-current-diff-overlay-C |
| 1211 | ediff-current-diff-overlay-C ediff-current-diff-overlay-B |
| 1212 | ediff-current-diff-overlay-B overlay) |
| 1213 | (setq ediff-current-diff-overlay-A ediff-current-diff-overlay-B |
| 1214 | ediff-current-diff-overlay-B overlay))) |
| 1215 | |
| 1216 | ;; swap wide bounds |
| 1217 | (setq ediff-wide-bounds |
| 1218 | (cond (ediff-3way-comparison-job |
| 1219 | (list (nth 2 ediff-wide-bounds) |
| 1220 | (nth 0 ediff-wide-bounds) |
| 1221 | (nth 1 ediff-wide-bounds))) |
| 1222 | (ediff-3way-job |
| 1223 | (list (nth 1 ediff-wide-bounds) |
| 1224 | (nth 0 ediff-wide-bounds) |
| 1225 | (nth 2 ediff-wide-bounds))) |
| 1226 | (t |
| 1227 | (list (nth 1 ediff-wide-bounds) |
| 1228 | (nth 0 ediff-wide-bounds))))) |
| 1229 | ;; swap narrow bounds |
| 1230 | (setq ediff-narrow-bounds |
| 1231 | (cond (ediff-3way-comparison-job |
| 1232 | (list (nth 2 ediff-narrow-bounds) |
| 1233 | (nth 0 ediff-narrow-bounds) |
| 1234 | (nth 1 ediff-narrow-bounds))) |
| 1235 | (ediff-3way-job |
| 1236 | (list (nth 1 ediff-narrow-bounds) |
| 1237 | (nth 0 ediff-narrow-bounds) |
| 1238 | (nth 2 ediff-narrow-bounds))) |
| 1239 | (t |
| 1240 | (list (nth 1 ediff-narrow-bounds) |
| 1241 | (nth 0 ediff-narrow-bounds))))) |
| 1242 | (if wide-visibility-p |
| 1243 | (setq ediff-visible-bounds ediff-wide-bounds) |
| 1244 | (setq ediff-visible-bounds ediff-narrow-bounds)) |
| 1245 | )) |
| 1246 | (if ediff-3way-job |
| 1247 | (ediff-set-state-of-all-diffs-in-all-buffers ediff-control-buffer)) |
| 1248 | (ediff-recenter 'no-rehighlight) |
| 1249 | ) |
| 1250 | |
| 1251 | |
| 1252 | (defun ediff-toggle-wide-display () |
| 1253 | "Toggle wide/regular display. |
| 1254 | This is especially useful when comparing buffers side-by-side." |
| 1255 | (interactive) |
| 1256 | (ediff-barf-if-not-control-buffer) |
| 1257 | (or (ediff-window-display-p) |
| 1258 | (error "%sEmacs is not running as a window application" |
| 1259 | (if (featurep 'emacs) "" "X"))) |
| 1260 | (ediff-recenter 'no-rehighlight) ; make sure buffs are displayed in windows |
| 1261 | (let ((ctl-buf ediff-control-buffer)) |
| 1262 | (setq ediff-wide-display-p (not ediff-wide-display-p)) |
| 1263 | (if (not ediff-wide-display-p) |
| 1264 | (ediff-with-current-buffer ctl-buf |
| 1265 | (modify-frame-parameters |
| 1266 | ediff-wide-display-frame ediff-wide-display-orig-parameters) |
| 1267 | ;;(sit-for (if (featurep 'xemacs) 0.4 0)) |
| 1268 | ;; restore control buf, since ctl window may have been deleted |
| 1269 | ;; during resizing |
| 1270 | (set-buffer ctl-buf) |
| 1271 | (setq ediff-wide-display-orig-parameters nil |
| 1272 | ediff-window-B nil) ; force update of window config |
| 1273 | (ediff-recenter 'no-rehighlight)) |
| 1274 | (funcall ediff-make-wide-display-function) |
| 1275 | ;;(sit-for (if (featurep 'xemacs) 0.4 0)) |
| 1276 | (ediff-with-current-buffer ctl-buf |
| 1277 | (setq ediff-window-B nil) ; force update of window config |
| 1278 | (ediff-recenter 'no-rehighlight))))) |
| 1279 | |
| 1280 | ;;;###autoload |
| 1281 | (defun ediff-toggle-multiframe () |
| 1282 | "Switch from multiframe display to single-frame display and back. |
| 1283 | To change the default, set the variable `ediff-window-setup-function', |
| 1284 | which see." |
| 1285 | (interactive) |
| 1286 | (let (window-setup-func) |
| 1287 | (or (ediff-window-display-p) |
| 1288 | (error "%sEmacs is not running as a window application" |
| 1289 | (if (featurep 'emacs) "" "X"))) |
| 1290 | |
| 1291 | (cond ((eq ediff-window-setup-function 'ediff-setup-windows-multiframe) |
| 1292 | (setq ediff-multiframe nil) |
| 1293 | (setq window-setup-func 'ediff-setup-windows-plain)) |
| 1294 | ((eq ediff-window-setup-function 'ediff-setup-windows-plain) |
| 1295 | (if (ediff-in-control-buffer-p) |
| 1296 | (ediff-kill-bottom-toolbar)) |
| 1297 | (if (and (ediff-buffer-live-p ediff-control-buffer) |
| 1298 | (window-live-p ediff-control-window)) |
| 1299 | (set-window-dedicated-p ediff-control-window nil)) |
| 1300 | (setq ediff-multiframe t) |
| 1301 | (setq window-setup-func 'ediff-setup-windows-multiframe)) |
| 1302 | (t |
| 1303 | (if (and (ediff-buffer-live-p ediff-control-buffer) |
| 1304 | (window-live-p ediff-control-window)) |
| 1305 | (set-window-dedicated-p ediff-control-window nil)) |
| 1306 | (setq ediff-multiframe t) |
| 1307 | (setq window-setup-func 'ediff-setup-windows-multiframe)) |
| 1308 | ) |
| 1309 | |
| 1310 | ;; change default |
| 1311 | (setq-default ediff-window-setup-function window-setup-func) |
| 1312 | ;; change in all active ediff sessions |
| 1313 | (mapc (lambda(buf) (ediff-with-current-buffer buf |
| 1314 | (setq ediff-window-setup-function window-setup-func |
| 1315 | ediff-window-B nil))) |
| 1316 | ediff-session-registry) |
| 1317 | (if (ediff-in-control-buffer-p) |
| 1318 | (progn |
| 1319 | (set-window-dedicated-p (selected-window) nil) |
| 1320 | (ediff-recenter 'no-rehighlight))))) |
| 1321 | |
| 1322 | |
| 1323 | ;;;###autoload |
| 1324 | (defun ediff-toggle-use-toolbar () |
| 1325 | "Enable or disable Ediff toolbar. |
| 1326 | Works only in versions of Emacs that support toolbars. |
| 1327 | To change the default, set the variable `ediff-use-toolbar-p', which see." |
| 1328 | (interactive) |
| 1329 | (if (featurep 'ediff-tbar) |
| 1330 | (progn |
| 1331 | (or (ediff-window-display-p) |
| 1332 | (error "%sEmacs is not running as a window application" |
| 1333 | (if (featurep 'emacs) "" "X"))) |
| 1334 | (if (ediff-use-toolbar-p) |
| 1335 | (ediff-kill-bottom-toolbar)) |
| 1336 | ;; do this only after killing the toolbar |
| 1337 | (setq ediff-use-toolbar-p (not ediff-use-toolbar-p)) |
| 1338 | |
| 1339 | (mapc (lambda(buf) |
| 1340 | (ediff-with-current-buffer buf |
| 1341 | ;; force redisplay |
| 1342 | (setq ediff-window-config-saved "") |
| 1343 | )) |
| 1344 | ediff-session-registry) |
| 1345 | (if (ediff-in-control-buffer-p) |
| 1346 | (ediff-recenter 'no-rehighlight))))) |
| 1347 | |
| 1348 | |
| 1349 | ;; if was using toolbar, kill it |
| 1350 | (defun ediff-kill-bottom-toolbar () |
| 1351 | ;; Using ctl-buffer or ediff-control-window for LOCALE does not |
| 1352 | ;; work properly in XEmacs 19.14: we have to use |
| 1353 | ;;(selected-frame). |
| 1354 | ;; The problem with this is that any previous bottom-toolbar |
| 1355 | ;; will not re-appear after our cleanup here. Is there a way |
| 1356 | ;; to do "push" and "pop" toolbars ? --marcpa |
| 1357 | (if (featurep 'xemacs) |
| 1358 | (when (ediff-use-toolbar-p) |
| 1359 | (set-specifier bottom-toolbar (list (selected-frame) nil)) |
| 1360 | (set-specifier bottom-toolbar-visible-p (list (selected-frame) nil))))) |
| 1361 | |
| 1362 | ;; If wants to use toolbar, make it. |
| 1363 | ;; If not, zero the toolbar for XEmacs. |
| 1364 | ;; Do nothing for Emacs. |
| 1365 | (defun ediff-make-bottom-toolbar (&optional frame) |
| 1366 | (when (ediff-window-display-p) |
| 1367 | (setq frame (or frame (selected-frame))) |
| 1368 | (if (featurep 'xemacs) |
| 1369 | (cond ((ediff-use-toolbar-p) ; this checks for XEmacs |
| 1370 | (set-specifier |
| 1371 | bottom-toolbar |
| 1372 | (list frame (if (ediff-3way-comparison-job) |
| 1373 | ediff-toolbar-3way ediff-toolbar))) |
| 1374 | (set-specifier bottom-toolbar-visible-p (list frame t)) |
| 1375 | (set-specifier bottom-toolbar-height |
| 1376 | (list frame ediff-toolbar-height))) |
| 1377 | ((ediff-has-toolbar-support-p) |
| 1378 | (set-specifier bottom-toolbar-height (list frame 0))))))) |
| 1379 | |
| 1380 | ;; Merging |
| 1381 | |
| 1382 | (defun ediff-toggle-show-clashes-only () |
| 1383 | "Toggle the mode that shows only the merge regions where both variants differ from the ancestor." |
| 1384 | (interactive) |
| 1385 | (ediff-barf-if-not-control-buffer) |
| 1386 | (if (not ediff-merge-with-ancestor-job) |
| 1387 | (error "This command makes sense only when merging with an ancestor")) |
| 1388 | (setq ediff-show-clashes-only (not ediff-show-clashes-only)) |
| 1389 | (if ediff-show-clashes-only |
| 1390 | (message "Focus on regions where both buffers differ from the ancestor") |
| 1391 | (message "Canceling focus on regions where changes clash"))) |
| 1392 | |
| 1393 | (defun ediff-toggle-skip-changed-regions () |
| 1394 | "Toggle the mode that skips the merge regions that differ from the default." |
| 1395 | (interactive) |
| 1396 | (ediff-barf-if-not-control-buffer) |
| 1397 | (setq ediff-skip-merge-regions-that-differ-from-default |
| 1398 | (not ediff-skip-merge-regions-that-differ-from-default)) |
| 1399 | (if ediff-skip-merge-regions-that-differ-from-default |
| 1400 | (message "Skipping regions that differ from default setting") |
| 1401 | (message "Showing regions that differ from default setting"))) |
| 1402 | |
| 1403 | |
| 1404 | |
| 1405 | ;; Widening/narrowing |
| 1406 | |
| 1407 | (defun ediff-toggle-narrow-region () |
| 1408 | "Toggle narrowing in buffers A, B, and C. |
| 1409 | Used in ediff-windows/regions only." |
| 1410 | (interactive) |
| 1411 | (if (eq ediff-buffer-A ediff-buffer-B) |
| 1412 | (error ediff-NO-DIFFERENCES)) |
| 1413 | (if (eq ediff-visible-bounds ediff-wide-bounds) |
| 1414 | (setq ediff-visible-bounds ediff-narrow-bounds) |
| 1415 | (setq ediff-visible-bounds ediff-wide-bounds)) |
| 1416 | (ediff-recenter 'no-rehighlight)) |
| 1417 | |
| 1418 | ;; Narrow bufs A/B/C to ediff-visible-bounds. If this is currently set to |
| 1419 | ;; ediff-wide-bounds, then this actually widens. |
| 1420 | ;; This function does nothing if job-name is not |
| 1421 | ;; ediff-regions-wordwise/linewise or ediff-windows-wordwise/linewise. |
| 1422 | ;; Does nothing if buffer-A = buffer-B since we can't narrow |
| 1423 | ;; to two different regions in one buffer. |
| 1424 | (defun ediff-visible-region () |
| 1425 | (if (or (eq ediff-buffer-A ediff-buffer-B) |
| 1426 | (eq ediff-buffer-A ediff-buffer-C) |
| 1427 | (eq ediff-buffer-C ediff-buffer-B)) |
| 1428 | () |
| 1429 | ;; If ediff-*-regions/windows, ediff-visible-bounds is already set |
| 1430 | ;; Otherwise, always use full range. |
| 1431 | (if (not ediff-narrow-job) |
| 1432 | (setq ediff-visible-bounds ediff-wide-bounds)) |
| 1433 | (let ((overl-A (ediff-get-value-according-to-buffer-type |
| 1434 | 'A ediff-visible-bounds)) |
| 1435 | (overl-B (ediff-get-value-according-to-buffer-type |
| 1436 | 'B ediff-visible-bounds)) |
| 1437 | (overl-C (ediff-get-value-according-to-buffer-type |
| 1438 | 'C ediff-visible-bounds)) |
| 1439 | ) |
| 1440 | (ediff-with-current-buffer ediff-buffer-A |
| 1441 | (if (ediff-overlay-buffer overl-A) |
| 1442 | (narrow-to-region |
| 1443 | (ediff-overlay-start overl-A) (ediff-overlay-end overl-A)))) |
| 1444 | (ediff-with-current-buffer ediff-buffer-B |
| 1445 | (if (ediff-overlay-buffer overl-B) |
| 1446 | (narrow-to-region |
| 1447 | (ediff-overlay-start overl-B) (ediff-overlay-end overl-B)))) |
| 1448 | |
| 1449 | (if (and ediff-3way-job (ediff-overlay-buffer overl-C)) |
| 1450 | (ediff-with-current-buffer ediff-buffer-C |
| 1451 | (narrow-to-region |
| 1452 | (ediff-overlay-start overl-C) (ediff-overlay-end overl-C)))) |
| 1453 | ))) |
| 1454 | |
| 1455 | |
| 1456 | ;; Window scrolling operations |
| 1457 | |
| 1458 | ;; Performs some operation on the two file windows (if they are showing). |
| 1459 | ;; Traps all errors on the operation in windows A/B/C. |
| 1460 | ;; Usually, errors come from scrolling off the |
| 1461 | ;; beginning or end of the buffer, and this gives error messages. |
| 1462 | (defun ediff-operate-on-windows (operation arg) |
| 1463 | |
| 1464 | ;; make sure windows aren't dead |
| 1465 | (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B))) |
| 1466 | (ediff-recenter 'no-rehighlight)) |
| 1467 | (if (not (and (ediff-buffer-live-p ediff-buffer-A) |
| 1468 | (ediff-buffer-live-p ediff-buffer-B) |
| 1469 | (or (not ediff-3way-job) ediff-buffer-C) |
| 1470 | )) |
| 1471 | (error ediff-KILLED-VITAL-BUFFER)) |
| 1472 | |
| 1473 | (let* ((wind (selected-window)) |
| 1474 | (wind-A ediff-window-A) |
| 1475 | (wind-B ediff-window-B) |
| 1476 | (wind-C ediff-window-C) |
| 1477 | (coefA (ediff-get-region-size-coefficient 'A operation)) |
| 1478 | (coefB (ediff-get-region-size-coefficient 'B operation)) |
| 1479 | (three-way ediff-3way-job) |
| 1480 | (coefC (if three-way |
| 1481 | (ediff-get-region-size-coefficient 'C operation)))) |
| 1482 | |
| 1483 | (select-window wind-A) |
| 1484 | (condition-case nil |
| 1485 | (funcall operation (round (* coefA arg))) |
| 1486 | (error)) |
| 1487 | (select-window wind-B) |
| 1488 | (condition-case nil |
| 1489 | (funcall operation (round (* coefB arg))) |
| 1490 | (error)) |
| 1491 | (if three-way |
| 1492 | (progn |
| 1493 | (select-window wind-C) |
| 1494 | (condition-case nil |
| 1495 | (funcall operation (round (* coefC arg))) |
| 1496 | (error)))) |
| 1497 | (select-window wind))) |
| 1498 | |
| 1499 | (defun ediff-scroll-vertically (&optional arg) |
| 1500 | "Vertically scroll buffers A, B \(and C if appropriate\). |
| 1501 | With optional argument ARG, scroll ARG lines; otherwise scroll by nearly |
| 1502 | the one half of the height of window-A." |
| 1503 | (interactive "P") |
| 1504 | (ediff-barf-if-not-control-buffer) |
| 1505 | |
| 1506 | ;; make sure windows aren't dead |
| 1507 | (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B))) |
| 1508 | (ediff-recenter 'no-rehighlight)) |
| 1509 | (if (not (and (ediff-buffer-live-p ediff-buffer-A) |
| 1510 | (ediff-buffer-live-p ediff-buffer-B) |
| 1511 | (or (not ediff-3way-job) |
| 1512 | (ediff-buffer-live-p ediff-buffer-C)) |
| 1513 | )) |
| 1514 | (error ediff-KILLED-VITAL-BUFFER)) |
| 1515 | |
| 1516 | (ediff-operate-on-windows |
| 1517 | (if (memq (ediff-last-command-char) '(?v ?\C-v)) |
| 1518 | 'scroll-up |
| 1519 | 'scroll-down) |
| 1520 | ;; calculate argument to scroll-up/down |
| 1521 | ;; if there is an explicit argument |
| 1522 | (if (and arg (not (equal arg '-))) |
| 1523 | ;; use it |
| 1524 | (prefix-numeric-value arg) |
| 1525 | ;; if not, see if we can determine a default amount (the window height) |
| 1526 | (let (default-amount) |
| 1527 | (setq default-amount |
| 1528 | (- (/ (min (window-height ediff-window-A) |
| 1529 | (window-height ediff-window-B) |
| 1530 | (if ediff-3way-job |
| 1531 | (window-height ediff-window-C) |
| 1532 | 500)) ; some large number |
| 1533 | 2) |
| 1534 | 1 next-screen-context-lines)) |
| 1535 | ;; window found |
| 1536 | (if arg |
| 1537 | ;; C-u as argument means half of default amount |
| 1538 | (/ default-amount 2) |
| 1539 | ;; no argument means default amount |
| 1540 | default-amount))))) |
| 1541 | |
| 1542 | |
| 1543 | (defun ediff-scroll-horizontally (&optional arg) |
| 1544 | "Horizontally scroll buffers A, B \(and C if appropriate\). |
| 1545 | If an argument is given, that is how many columns are scrolled, else nearly |
| 1546 | the width of the A/B/C windows." |
| 1547 | (interactive "P") |
| 1548 | (ediff-barf-if-not-control-buffer) |
| 1549 | |
| 1550 | ;; make sure windows aren't dead |
| 1551 | (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B))) |
| 1552 | (ediff-recenter 'no-rehighlight)) |
| 1553 | (if (not (and (ediff-buffer-live-p ediff-buffer-A) |
| 1554 | (ediff-buffer-live-p ediff-buffer-B) |
| 1555 | (or (not ediff-3way-job) |
| 1556 | (ediff-buffer-live-p ediff-buffer-C)) |
| 1557 | )) |
| 1558 | (error ediff-KILLED-VITAL-BUFFER)) |
| 1559 | |
| 1560 | (ediff-operate-on-windows |
| 1561 | ;; Arrange for scroll-left and scroll-right being called |
| 1562 | ;; interactively so that they set the window's min_hscroll. |
| 1563 | ;; Otherwise, automatic hscrolling will undo the effect of |
| 1564 | ;; hscrolling. |
| 1565 | (if (= (ediff-last-command-char) ?<) |
| 1566 | (lambda (arg) |
| 1567 | (let ((prefix-arg arg)) |
| 1568 | (call-interactively 'scroll-left))) |
| 1569 | (lambda (arg) |
| 1570 | (let ((prefix-arg arg)) |
| 1571 | (call-interactively 'scroll-right)))) |
| 1572 | ;; calculate argument to scroll-left/right |
| 1573 | ;; if there is an explicit argument |
| 1574 | (if (and arg (not (equal arg '-))) |
| 1575 | ;; use it |
| 1576 | (prefix-numeric-value arg) |
| 1577 | ;; if not, see if we can determine a default amount |
| 1578 | ;; (half the window width) |
| 1579 | (if (null ediff-control-window) |
| 1580 | ;; no control window, use nil |
| 1581 | nil |
| 1582 | (let ((default-amount |
| 1583 | (- (/ (min (window-width ediff-window-A) |
| 1584 | (window-width ediff-window-B) |
| 1585 | (if ediff-3way-comparison-job |
| 1586 | (window-width ediff-window-C) |
| 1587 | 500) ; some large number |
| 1588 | ) |
| 1589 | 2) |
| 1590 | 3))) |
| 1591 | ;; window found |
| 1592 | (if arg |
| 1593 | ;; C-u as argument means half of default amount |
| 1594 | (/ default-amount 2) |
| 1595 | ;; no argument means default amount |
| 1596 | default-amount)))))) |
| 1597 | |
| 1598 | |
| 1599 | ;;BEG, END show the region to be positioned. |
| 1600 | ;;JOB-NAME holds ediff-job-name. The ediff-windows job positions regions |
| 1601 | ;;differently. |
| 1602 | (defun ediff-position-region (beg end pos job-name) |
| 1603 | (if (> end (point-max)) |
| 1604 | (setq end (point-max))) |
| 1605 | (if ediff-windows-job |
| 1606 | (if (pos-visible-in-window-p end) |
| 1607 | () ; do nothing, wind is already positioned |
| 1608 | ;; at this point, windows are positioned at the beginning of the |
| 1609 | ;; file regions (not diff-regions) being compared. |
| 1610 | (save-excursion |
| 1611 | (move-to-window-line (- (window-height) 2)) |
| 1612 | (let ((amount (+ 2 (count-lines (point) end)))) |
| 1613 | (scroll-up amount)))) |
| 1614 | (set-window-start (selected-window) beg) |
| 1615 | (if (pos-visible-in-window-p end) |
| 1616 | ;; Determine the number of lines that the region occupies |
| 1617 | (let ((lines 0) |
| 1618 | (prev-point 0)) |
| 1619 | (while ( and (> end (progn |
| 1620 | (move-to-window-line lines) |
| 1621 | (point))) |
| 1622 | ;; `end' may be beyond the window bottom, so check |
| 1623 | ;; that we are making progress |
| 1624 | (< prev-point (point))) |
| 1625 | (setq prev-point (point)) |
| 1626 | (setq lines (1+ lines))) |
| 1627 | ;; And position the beginning on the right line |
| 1628 | (goto-char beg) |
| 1629 | (recenter (/ (1+ (max (- (1- (window-height (selected-window))) |
| 1630 | lines) |
| 1631 | 1) |
| 1632 | ) |
| 1633 | 2)))) |
| 1634 | (goto-char pos) |
| 1635 | )) |
| 1636 | |
| 1637 | ;; get number of lines from window start to region end |
| 1638 | (defun ediff-get-lines-to-region-end (buf-type &optional n ctl-buf) |
| 1639 | (or n (setq n ediff-current-difference)) |
| 1640 | (or ctl-buf (setq ctl-buf ediff-control-buffer)) |
| 1641 | (ediff-with-current-buffer ctl-buf |
| 1642 | (let* ((buf (ediff-get-buffer buf-type)) |
| 1643 | (wind (eval (ediff-get-symbol-from-alist |
| 1644 | buf-type ediff-window-alist))) |
| 1645 | (beg (window-start wind)) |
| 1646 | (end (ediff-get-diff-posn buf-type 'end)) |
| 1647 | lines) |
| 1648 | (ediff-with-current-buffer buf |
| 1649 | (if (< beg end) |
| 1650 | (setq lines (count-lines beg end)) |
| 1651 | (setq lines 0)) |
| 1652 | lines |
| 1653 | )))) |
| 1654 | |
| 1655 | ;; Calculate the number of lines from window end to the start of diff region |
| 1656 | (defun ediff-get-lines-to-region-start (buf-type &optional diff-num ctl-buf) |
| 1657 | (or diff-num (setq diff-num ediff-current-difference)) |
| 1658 | (or ctl-buf (setq ctl-buf ediff-control-buffer)) |
| 1659 | (ediff-with-current-buffer ctl-buf |
| 1660 | (let* ((buf (ediff-get-buffer buf-type)) |
| 1661 | (wind (eval (ediff-get-symbol-from-alist |
| 1662 | buf-type ediff-window-alist))) |
| 1663 | (end (or (window-end wind) (window-end wind t))) |
| 1664 | (beg (ediff-get-diff-posn buf-type 'beg diff-num))) |
| 1665 | (ediff-with-current-buffer buf |
| 1666 | (if (< beg end) |
| 1667 | (count-lines (max beg (point-min)) (min end (point-max))) 0)) |
| 1668 | ))) |
| 1669 | |
| 1670 | |
| 1671 | ;; region size coefficient is a coefficient by which to adjust scrolling |
| 1672 | ;; up/down of the window displaying buffer of type BUFTYPE. |
| 1673 | ;; The purpose of this coefficient is to make the windows scroll in sync, so |
| 1674 | ;; that it won't happen that one diff region is scrolled off while the other is |
| 1675 | ;; still seen. |
| 1676 | ;; |
| 1677 | ;; If the difference region is invalid, the coefficient is 1 |
| 1678 | (defun ediff-get-region-size-coefficient (buf-type op &optional n ctl-buf) |
| 1679 | (ediff-with-current-buffer (or ctl-buf ediff-control-buffer) |
| 1680 | (if (ediff-valid-difference-p n) |
| 1681 | (let* ((func (cond ((eq op 'scroll-down) |
| 1682 | 'ediff-get-lines-to-region-start) |
| 1683 | ((eq op 'scroll-up) |
| 1684 | 'ediff-get-lines-to-region-end) |
| 1685 | (t '(lambda (a b c) 0)))) |
| 1686 | (max-lines (max (funcall func 'A n ctl-buf) |
| 1687 | (funcall func 'B n ctl-buf) |
| 1688 | (if (ediff-buffer-live-p ediff-buffer-C) |
| 1689 | (funcall func 'C n ctl-buf) |
| 1690 | 0)))) |
| 1691 | ;; this covers the horizontal coefficient as well: |
| 1692 | ;; if max-lines = 0 then coef = 1 |
| 1693 | (if (> max-lines 0) |
| 1694 | (/ (+ (funcall func buf-type n ctl-buf) 0.0) |
| 1695 | (+ max-lines 0.0)) |
| 1696 | 1)) |
| 1697 | 1))) |
| 1698 | |
| 1699 | |
| 1700 | (defun ediff-next-difference (&optional arg) |
| 1701 | "Advance to the next difference. |
| 1702 | With a prefix argument, go forward that many differences." |
| 1703 | (interactive "p") |
| 1704 | (ediff-barf-if-not-control-buffer) |
| 1705 | (if (< ediff-current-difference ediff-number-of-differences) |
| 1706 | (let ((n (min ediff-number-of-differences |
| 1707 | (+ ediff-current-difference (or arg 1)))) |
| 1708 | non-clash-skip skip-changed regexp-skip) |
| 1709 | |
| 1710 | (ediff-visible-region) |
| 1711 | (or (>= n ediff-number-of-differences) |
| 1712 | (setq regexp-skip (funcall ediff-skip-diff-region-function n)) |
| 1713 | ;; this won't exec if regexp-skip is t |
| 1714 | (setq non-clash-skip (ediff-merge-region-is-non-clash-to-skip n) |
| 1715 | skip-changed |
| 1716 | (ediff-skip-merge-region-if-changed-from-default-p n)) |
| 1717 | (ediff-install-fine-diff-if-necessary n)) |
| 1718 | ;; Skip loop |
| 1719 | (while (and (< n ediff-number-of-differences) |
| 1720 | (or |
| 1721 | ;; regexp skip |
| 1722 | regexp-skip |
| 1723 | ;; skip clashes, if necessary |
| 1724 | non-clash-skip |
| 1725 | ;; skip processed regions |
| 1726 | skip-changed |
| 1727 | ;; skip difference regions that differ in white space |
| 1728 | (and ediff-ignore-similar-regions |
| 1729 | (ediff-merge-region-is-non-clash n) |
| 1730 | (or (eq (ediff-no-fine-diffs-p n) t) |
| 1731 | (and (ediff-merge-job) |
| 1732 | (eq (ediff-no-fine-diffs-p n) 'C))) |
| 1733 | ))) |
| 1734 | (setq n (1+ n)) |
| 1735 | (if (= 0 (mod n 20)) |
| 1736 | (message "Skipped over region %d and counting ..." n)) |
| 1737 | (or (>= n ediff-number-of-differences) |
| 1738 | (setq regexp-skip (funcall ediff-skip-diff-region-function n)) |
| 1739 | ;; this won't exec if regexp-skip is t |
| 1740 | (setq non-clash-skip (ediff-merge-region-is-non-clash-to-skip n) |
| 1741 | skip-changed |
| 1742 | (ediff-skip-merge-region-if-changed-from-default-p n)) |
| 1743 | (ediff-install-fine-diff-if-necessary n)) |
| 1744 | ) |
| 1745 | (message "") |
| 1746 | (ediff-unselect-and-select-difference n) |
| 1747 | ) ; let |
| 1748 | (ediff-visible-region) |
| 1749 | (error "At end of the difference list"))) |
| 1750 | |
| 1751 | (defun ediff-previous-difference (&optional arg) |
| 1752 | "Go to the previous difference. |
| 1753 | With a prefix argument, go back that many differences." |
| 1754 | (interactive "p") |
| 1755 | (ediff-barf-if-not-control-buffer) |
| 1756 | (if (> ediff-current-difference -1) |
| 1757 | (let ((n (max -1 (- ediff-current-difference (or arg 1)))) |
| 1758 | non-clash-skip skip-changed regexp-skip) |
| 1759 | |
| 1760 | (ediff-visible-region) |
| 1761 | (or (< n 0) |
| 1762 | (setq regexp-skip (funcall ediff-skip-diff-region-function n)) |
| 1763 | ;; this won't exec if regexp-skip is t |
| 1764 | (setq non-clash-skip (ediff-merge-region-is-non-clash-to-skip n) |
| 1765 | skip-changed |
| 1766 | (ediff-skip-merge-region-if-changed-from-default-p n)) |
| 1767 | (ediff-install-fine-diff-if-necessary n)) |
| 1768 | (while (and (> n -1) |
| 1769 | (or |
| 1770 | ;; regexp skip |
| 1771 | regexp-skip |
| 1772 | ;; skip clashes, if necessary |
| 1773 | non-clash-skip |
| 1774 | ;; skipp changed regions |
| 1775 | skip-changed |
| 1776 | ;; skip difference regions that differ in white space |
| 1777 | (and ediff-ignore-similar-regions |
| 1778 | (ediff-merge-region-is-non-clash n) |
| 1779 | (or (eq (ediff-no-fine-diffs-p n) t) |
| 1780 | (and (ediff-merge-job) |
| 1781 | (eq (ediff-no-fine-diffs-p n) 'C))) |
| 1782 | ))) |
| 1783 | (if (= 0 (mod (1+ n) 20)) |
| 1784 | (message "Skipped over region %d and counting ..." (1+ n))) |
| 1785 | (setq n (1- n)) |
| 1786 | (or (< n 0) |
| 1787 | (setq regexp-skip (funcall ediff-skip-diff-region-function n)) |
| 1788 | ;; this won't exec if regexp-skip is t |
| 1789 | (setq non-clash-skip (ediff-merge-region-is-non-clash-to-skip n) |
| 1790 | skip-changed |
| 1791 | (ediff-skip-merge-region-if-changed-from-default-p n)) |
| 1792 | (ediff-install-fine-diff-if-necessary n)) |
| 1793 | ) |
| 1794 | (message "") |
| 1795 | (ediff-unselect-and-select-difference n) |
| 1796 | ) ; let |
| 1797 | (ediff-visible-region) |
| 1798 | (error "At beginning of the difference list"))) |
| 1799 | |
| 1800 | ;; The diff number is as perceived by the user (i.e., 1+ the internal |
| 1801 | ;; representation) |
| 1802 | (defun ediff-jump-to-difference (difference-number) |
| 1803 | "Go to the difference specified as a prefix argument. |
| 1804 | If the prefix is negative, count differences from the end." |
| 1805 | (interactive "p") |
| 1806 | (ediff-barf-if-not-control-buffer) |
| 1807 | (setq difference-number |
| 1808 | (cond ((< difference-number 0) |
| 1809 | (+ ediff-number-of-differences difference-number)) |
| 1810 | ((> difference-number 0) (1- difference-number)) |
| 1811 | (t -1))) |
| 1812 | ;; -1 is allowed by ediff-unselect-and-select-difference --- it is the |
| 1813 | ;; position before the first one. |
| 1814 | (if (and (>= difference-number -1) |
| 1815 | (<= difference-number ediff-number-of-differences)) |
| 1816 | (ediff-unselect-and-select-difference difference-number) |
| 1817 | (error ediff-BAD-DIFF-NUMBER |
| 1818 | this-command (1+ difference-number) ediff-number-of-differences))) |
| 1819 | |
| 1820 | (defun ediff-jump-to-difference-at-point (arg) |
| 1821 | "Go to difference closest to the point in buffer A, B, or C. |
| 1822 | The buffer depends on last command character \(a, b, or c\) that invoked this |
| 1823 | command. For instance, if the command was `ga' then the point value in buffer |
| 1824 | A is used. |
| 1825 | With a prefix argument, synchronize all files around the current point position |
| 1826 | in the specified buffer." |
| 1827 | (interactive "P") |
| 1828 | (ediff-barf-if-not-control-buffer) |
| 1829 | (let* ((buf-type (ediff-char-to-buftype (ediff-last-command-char))) |
| 1830 | (buffer (ediff-get-buffer buf-type)) |
| 1831 | (pt (ediff-with-current-buffer buffer (point))) |
| 1832 | (diff-no (ediff-diff-at-point buf-type nil (if arg 'after))) |
| 1833 | (past-last-diff (< ediff-number-of-differences diff-no)) |
| 1834 | (beg (if past-last-diff |
| 1835 | (ediff-with-current-buffer buffer (point-max)) |
| 1836 | (ediff-get-diff-posn buf-type 'beg (1- diff-no)))) |
| 1837 | ctl-wind wind-A wind-B wind-C |
| 1838 | shift) |
| 1839 | (if past-last-diff |
| 1840 | (ediff-jump-to-difference -1) |
| 1841 | (ediff-jump-to-difference diff-no)) |
| 1842 | (setq ctl-wind (selected-window) |
| 1843 | wind-A ediff-window-A |
| 1844 | wind-B ediff-window-B |
| 1845 | wind-C ediff-window-C) |
| 1846 | (if arg |
| 1847 | (progn |
| 1848 | (ediff-with-current-buffer buffer |
| 1849 | (setq shift (- beg pt))) |
| 1850 | (select-window wind-A) |
| 1851 | (if past-last-diff (goto-char (point-max))) |
| 1852 | (condition-case nil |
| 1853 | (backward-char shift) ; noerror, if beginning of buffer |
| 1854 | (error)) |
| 1855 | (recenter) |
| 1856 | (select-window wind-B) |
| 1857 | (if past-last-diff (goto-char (point-max))) |
| 1858 | (condition-case nil |
| 1859 | (backward-char shift) ; noerror, if beginning of buffer |
| 1860 | (error)) |
| 1861 | (recenter) |
| 1862 | (if (window-live-p wind-C) |
| 1863 | (progn |
| 1864 | (select-window wind-C) |
| 1865 | (if past-last-diff (goto-char (point-max))) |
| 1866 | (condition-case nil |
| 1867 | (backward-char shift) ; noerror, if beginning of buffer |
| 1868 | (error)) |
| 1869 | (recenter) |
| 1870 | )) |
| 1871 | (select-window ctl-wind) |
| 1872 | )) |
| 1873 | )) |
| 1874 | |
| 1875 | |
| 1876 | ;; find region most related to the current point position (or POS, if given) |
| 1877 | ;; returns diff number as seen by the user (i.e., 1+ the internal |
| 1878 | ;; representation) |
| 1879 | ;; The optional argument WHICH-DIFF can be `after' or `before'. If `after', |
| 1880 | ;; find the diff after the point. If `before', find the diff before the |
| 1881 | ;; point. If the point is inside a diff, return that diff. |
| 1882 | (defun ediff-diff-at-point (buf-type &optional pos which-diff) |
| 1883 | (let ((buffer (ediff-get-buffer buf-type)) |
| 1884 | (ctl-buffer ediff-control-buffer) |
| 1885 | (max-dif-num (1- ediff-number-of-differences)) |
| 1886 | (diff-no -1) |
| 1887 | (prev-beg 0) |
| 1888 | (prev-end 0) |
| 1889 | (beg 0) |
| 1890 | (end 0)) |
| 1891 | |
| 1892 | (ediff-with-current-buffer buffer |
| 1893 | (setq pos (or pos (point))) |
| 1894 | (while (and (or (< pos prev-beg) (> pos beg)) |
| 1895 | (< diff-no max-dif-num)) |
| 1896 | (setq diff-no (1+ diff-no)) |
| 1897 | (setq prev-beg beg |
| 1898 | prev-end end) |
| 1899 | (setq beg (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer) |
| 1900 | end (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer)) |
| 1901 | ) |
| 1902 | |
| 1903 | ;; boost diff-no by 1, if past the last diff region |
| 1904 | (if (and (memq which-diff '(after before)) |
| 1905 | (> pos beg) (= diff-no max-dif-num)) |
| 1906 | (setq diff-no (1+ diff-no))) |
| 1907 | |
| 1908 | (cond ((eq which-diff 'after) (1+ diff-no)) |
| 1909 | ((eq which-diff 'before) diff-no) |
| 1910 | ((< (abs (count-lines pos (max 1 prev-end))) |
| 1911 | (abs (count-lines pos (max 1 beg)))) |
| 1912 | diff-no) ; choose prev difference |
| 1913 | (t |
| 1914 | (1+ diff-no))) ; choose next difference |
| 1915 | ))) |
| 1916 | |
| 1917 | \f |
| 1918 | ;;; Copying diffs. |
| 1919 | |
| 1920 | (defun ediff-diff-to-diff (arg &optional keys) |
| 1921 | "Copy buffer-X'th difference region to buffer Y \(X,Y are A, B, or C\). |
| 1922 | If numerical prefix argument, copy the difference specified in the arg. |
| 1923 | Otherwise, copy the difference given by `ediff-current-difference'. |
| 1924 | This command assumes it is bound to a 2-character key sequence, `ab', `ba', |
| 1925 | `ac', etc., which is used to determine the types of buffers to be used for |
| 1926 | copying difference regions. The first character in the sequence specifies |
| 1927 | the source buffer and the second specifies the target. |
| 1928 | |
| 1929 | If the second optional argument, a 2-character string, is given, use it to |
| 1930 | determine the source and the target buffers instead of the command keys." |
| 1931 | (interactive "P") |
| 1932 | (ediff-barf-if-not-control-buffer) |
| 1933 | (or keys (setq keys (this-command-keys))) |
| 1934 | (if (eq arg '-) (setq arg -1)) ; translate neg arg to -1 |
| 1935 | (if (numberp arg) (ediff-jump-to-difference arg)) |
| 1936 | |
| 1937 | (let* ((key1 (aref keys 0)) |
| 1938 | (key2 (aref keys 1)) |
| 1939 | (char1 (ediff-event-key key1)) |
| 1940 | (char2 (ediff-event-key key2)) |
| 1941 | ediff-verbose-p) |
| 1942 | (ediff-copy-diff ediff-current-difference |
| 1943 | (ediff-char-to-buftype char1) |
| 1944 | (ediff-char-to-buftype char2)) |
| 1945 | ;; recenter with rehighlighting, but no messages |
| 1946 | (ediff-recenter))) |
| 1947 | |
| 1948 | (defun ediff-copy-A-to-B (arg) |
| 1949 | "Copy ARGth difference region from buffer A to B. |
| 1950 | ARG is a prefix argument. If nil, copy the current difference region." |
| 1951 | (interactive "P") |
| 1952 | (ediff-diff-to-diff arg "ab")) |
| 1953 | |
| 1954 | (defun ediff-copy-B-to-A (arg) |
| 1955 | "Copy ARGth difference region from buffer B to A. |
| 1956 | ARG is a prefix argument. If nil, copy the current difference region." |
| 1957 | (interactive "P") |
| 1958 | (ediff-diff-to-diff arg "ba")) |
| 1959 | |
| 1960 | (defun ediff-copy-A-to-C (arg) |
| 1961 | "Copy ARGth difference region from buffer A to buffer C. |
| 1962 | ARG is a prefix argument. If nil, copy the current difference region." |
| 1963 | (interactive "P") |
| 1964 | (ediff-diff-to-diff arg "ac")) |
| 1965 | |
| 1966 | (defun ediff-copy-B-to-C (arg) |
| 1967 | "Copy ARGth difference region from buffer B to buffer C. |
| 1968 | ARG is a prefix argument. If nil, copy the current difference region." |
| 1969 | (interactive "P") |
| 1970 | (ediff-diff-to-diff arg "bc")) |
| 1971 | |
| 1972 | (defun ediff-copy-C-to-B (arg) |
| 1973 | "Copy ARGth difference region from buffer C to B. |
| 1974 | ARG is a prefix argument. If nil, copy the current difference region." |
| 1975 | (interactive "P") |
| 1976 | (ediff-diff-to-diff arg "cb")) |
| 1977 | |
| 1978 | (defun ediff-copy-C-to-A (arg) |
| 1979 | "Copy ARGth difference region from buffer C to A. |
| 1980 | ARG is a prefix argument. If nil, copy the current difference region." |
| 1981 | (interactive "P") |
| 1982 | (ediff-diff-to-diff arg "ca")) |
| 1983 | |
| 1984 | |
| 1985 | |
| 1986 | ;; Copy diff N from FROM-BUF-TYPE \(given as A, B or C\) to TO-BUF-TYPE. |
| 1987 | ;; If optional DO-NOT-SAVE is non-nil, do not save the old value of the |
| 1988 | ;; target diff. This is used in merging, when constructing the merged |
| 1989 | ;; version. |
| 1990 | (defun ediff-copy-diff (n from-buf-type to-buf-type |
| 1991 | &optional batch-invocation reg-to-copy) |
| 1992 | (let* ((to-buf (ediff-get-buffer to-buf-type)) |
| 1993 | ;;(from-buf (if (not reg-to-copy) (ediff-get-buffer from-buf-type))) |
| 1994 | (ctrl-buf ediff-control-buffer) |
| 1995 | (saved-p t) |
| 1996 | (three-way ediff-3way-job) |
| 1997 | messg |
| 1998 | ediff-verbose-p |
| 1999 | reg-to-delete reg-to-delete-beg reg-to-delete-end) |
| 2000 | |
| 2001 | (setq reg-to-delete-beg |
| 2002 | (ediff-get-diff-posn to-buf-type 'beg n ctrl-buf)) |
| 2003 | (setq reg-to-delete-end |
| 2004 | (ediff-get-diff-posn to-buf-type 'end n ctrl-buf)) |
| 2005 | |
| 2006 | (if reg-to-copy |
| 2007 | (setq from-buf-type nil) |
| 2008 | (setq reg-to-copy (ediff-get-region-contents n from-buf-type ctrl-buf))) |
| 2009 | |
| 2010 | (setq reg-to-delete (ediff-get-region-contents |
| 2011 | n to-buf-type ctrl-buf |
| 2012 | reg-to-delete-beg reg-to-delete-end)) |
| 2013 | |
| 2014 | (if (string= reg-to-delete reg-to-copy) |
| 2015 | (setq saved-p nil) ; don't copy identical buffers |
| 2016 | ;; seems ok to copy |
| 2017 | (if (or batch-invocation (ediff-test-save-region n to-buf-type)) |
| 2018 | (condition-case conds |
| 2019 | (progn |
| 2020 | (ediff-with-current-buffer to-buf |
| 2021 | ;; to prevent flags from interfering if buffer is writable |
| 2022 | (let ((inhibit-read-only (null buffer-read-only))) |
| 2023 | |
| 2024 | (goto-char reg-to-delete-end) |
| 2025 | (insert reg-to-copy) |
| 2026 | |
| 2027 | (if (> reg-to-delete-end reg-to-delete-beg) |
| 2028 | (kill-region reg-to-delete-beg reg-to-delete-end)) |
| 2029 | )) |
| 2030 | (or batch-invocation |
| 2031 | (setq |
| 2032 | messg |
| 2033 | (ediff-save-diff-region n to-buf-type reg-to-delete)))) |
| 2034 | (error (message "ediff-copy-diff: %s %s" |
| 2035 | (car conds) |
| 2036 | (mapconcat 'prin1-to-string (cdr conds) " ")) |
| 2037 | (beep 1) |
| 2038 | (sit-for 2) ; let the user see the error msg |
| 2039 | (setq saved-p nil) |
| 2040 | ))) |
| 2041 | ) |
| 2042 | |
| 2043 | ;; adjust state of difference in case 3-way and diff was copied ok |
| 2044 | (if (and saved-p three-way) |
| 2045 | (ediff-set-state-of-diff-in-all-buffers n ctrl-buf)) |
| 2046 | |
| 2047 | (if batch-invocation |
| 2048 | (ediff-clear-fine-differences n) |
| 2049 | ;; If diff3 job, we should recompute fine diffs so we clear them |
| 2050 | ;; before reinserting flags (and thus before ediff-recenter). |
| 2051 | (if (and saved-p three-way) |
| 2052 | (ediff-clear-fine-differences n)) |
| 2053 | |
| 2054 | (ediff-refresh-mode-lines) |
| 2055 | |
| 2056 | ;; For diff2 jobs, don't recompute fine diffs, since we know there |
| 2057 | ;; aren't any. So we clear diffs after ediff-recenter. |
| 2058 | (if (and saved-p (not three-way)) |
| 2059 | (ediff-clear-fine-differences n)) |
| 2060 | ;; Make sure that the message about saving and how to restore is seen |
| 2061 | ;; by the user |
| 2062 | (message "%s" messg)) |
| 2063 | )) |
| 2064 | |
| 2065 | ;; Save Nth diff of buffer BUF-TYPE \(A, B, or C\). |
| 2066 | ;; That is to say, the Nth diff on the `ediff-killed-diffs-alist'. REG |
| 2067 | ;; is the region to save. It is redundant here, but is passed anyway, for |
| 2068 | ;; convenience. |
| 2069 | (defun ediff-save-diff-region (n buf-type reg) |
| 2070 | (let* ((n-th-diff-saved (assoc n ediff-killed-diffs-alist)) |
| 2071 | (buf (ediff-get-buffer buf-type)) |
| 2072 | (this-buf-n-th-diff-saved (assoc buf (cdr n-th-diff-saved)))) |
| 2073 | |
| 2074 | (if this-buf-n-th-diff-saved |
| 2075 | ;; either nothing saved for n-th diff and buffer or we OK'ed |
| 2076 | ;; overriding |
| 2077 | (setcdr this-buf-n-th-diff-saved reg) |
| 2078 | (if n-th-diff-saved ;; n-th diff saved, but for another buffer |
| 2079 | (nconc n-th-diff-saved (list (cons buf reg))) |
| 2080 | (setq ediff-killed-diffs-alist ;; create record for n-th diff |
| 2081 | (cons (list n (cons buf reg)) |
| 2082 | ediff-killed-diffs-alist)))) |
| 2083 | (message "Saving old diff region #%d of buffer %S. To recover, type `r%s'" |
| 2084 | (1+ n) buf-type |
| 2085 | (if ediff-merge-job |
| 2086 | "" (downcase (symbol-name buf-type)))) |
| 2087 | )) |
| 2088 | |
| 2089 | ;; Test if saving Nth difference region of buffer BUF-TYPE is possible. |
| 2090 | (defun ediff-test-save-region (n buf-type) |
| 2091 | (let* ((n-th-diff-saved (assoc n ediff-killed-diffs-alist)) |
| 2092 | (buf (ediff-get-buffer buf-type)) |
| 2093 | (this-buf-n-th-diff-saved (assoc buf (cdr n-th-diff-saved)))) |
| 2094 | |
| 2095 | (if this-buf-n-th-diff-saved |
| 2096 | (if (yes-or-no-p |
| 2097 | (format |
| 2098 | "You've previously copied diff region %d to buffer %S. Confirm? " |
| 2099 | (1+ n) buf-type)) |
| 2100 | t |
| 2101 | (error "Quit")) |
| 2102 | t))) |
| 2103 | |
| 2104 | (defun ediff-pop-diff (n buf-type) |
| 2105 | "Pop last killed Nth diff region from buffer BUF-TYPE." |
| 2106 | (let* ((n-th-record (assoc n ediff-killed-diffs-alist)) |
| 2107 | (buf (ediff-get-buffer buf-type)) |
| 2108 | (saved-rec (assoc buf (cdr n-th-record))) |
| 2109 | (three-way ediff-3way-job) |
| 2110 | (ctl-buf ediff-control-buffer) |
| 2111 | ediff-verbose-p |
| 2112 | saved-diff reg-beg reg-end recovered) |
| 2113 | |
| 2114 | (if (cdr saved-rec) |
| 2115 | (setq saved-diff (cdr saved-rec)) |
| 2116 | (if (> ediff-number-of-differences 0) |
| 2117 | (error "Nothing saved for diff %d in buffer %S" (1+ n) buf-type) |
| 2118 | (error ediff-NO-DIFFERENCES))) |
| 2119 | |
| 2120 | (setq reg-beg (ediff-get-diff-posn buf-type 'beg n ediff-control-buffer)) |
| 2121 | (setq reg-end (ediff-get-diff-posn buf-type 'end n ediff-control-buffer)) |
| 2122 | |
| 2123 | (condition-case conds |
| 2124 | (ediff-with-current-buffer buf |
| 2125 | (let ((inhibit-read-only (null buffer-read-only))) |
| 2126 | |
| 2127 | (goto-char reg-end) |
| 2128 | (insert saved-diff) |
| 2129 | |
| 2130 | (if (> reg-end reg-beg) |
| 2131 | (kill-region reg-beg reg-end)) |
| 2132 | |
| 2133 | (setq recovered t) |
| 2134 | )) |
| 2135 | (error (message "ediff-pop-diff: %s %s" |
| 2136 | (car conds) |
| 2137 | (mapconcat 'prin1-to-string (cdr conds) " ")) |
| 2138 | (beep 1))) |
| 2139 | |
| 2140 | ;; Clearing fine diffs is necessary for |
| 2141 | ;; ediff-unselect-and-select-difference to properly recompute them. We |
| 2142 | ;; can't rely on ediff-copy-diff to clear this vector, as the user might |
| 2143 | ;; have modified diff regions after copying and, thus, may have recomputed |
| 2144 | ;; fine diffs. |
| 2145 | (if recovered |
| 2146 | (ediff-clear-fine-differences n)) |
| 2147 | |
| 2148 | ;; adjust state of difference |
| 2149 | (if (and three-way recovered) |
| 2150 | (ediff-set-state-of-diff-in-all-buffers n ctl-buf)) |
| 2151 | |
| 2152 | (ediff-refresh-mode-lines) |
| 2153 | |
| 2154 | (if recovered |
| 2155 | (progn |
| 2156 | (setq n-th-record (delq saved-rec n-th-record)) |
| 2157 | (message "Diff region %d in buffer %S restored" (1+ n) buf-type) |
| 2158 | )) |
| 2159 | )) |
| 2160 | |
| 2161 | (defun ediff-restore-diff (arg &optional key) |
| 2162 | "Restore ARGth diff from `ediff-killed-diffs-alist'. |
| 2163 | ARG is a prefix argument. If ARG is nil, restore the current-difference. |
| 2164 | If the second optional argument, a character, is given, use it to |
| 2165 | determine the target buffer instead of (ediff-last-command-char)" |
| 2166 | (interactive "P") |
| 2167 | (ediff-barf-if-not-control-buffer) |
| 2168 | (if (numberp arg) |
| 2169 | (ediff-jump-to-difference arg)) |
| 2170 | (ediff-pop-diff ediff-current-difference |
| 2171 | (ediff-char-to-buftype (or key (ediff-last-command-char)))) |
| 2172 | ;; recenter with rehighlighting, but no messages |
| 2173 | (let (ediff-verbose-p) |
| 2174 | (ediff-recenter))) |
| 2175 | |
| 2176 | (defun ediff-restore-diff-in-merge-buffer (arg) |
| 2177 | "Restore ARGth diff in the merge buffer. |
| 2178 | ARG is a prefix argument. If nil, restore the current diff." |
| 2179 | (interactive "P") |
| 2180 | (ediff-restore-diff arg ?c)) |
| 2181 | |
| 2182 | |
| 2183 | (defun ediff-toggle-regexp-match () |
| 2184 | "Toggle between focusing and hiding of difference regions that match |
| 2185 | a regular expression typed in by the user." |
| 2186 | (interactive) |
| 2187 | (ediff-barf-if-not-control-buffer) |
| 2188 | (let ((regexp-A "") |
| 2189 | (regexp-B "") |
| 2190 | (regexp-C "") |
| 2191 | msg-connective alt-msg-connective alt-connective) |
| 2192 | (cond |
| 2193 | ((or (and (eq ediff-skip-diff-region-function |
| 2194 | ediff-focus-on-regexp-matches-function) |
| 2195 | (eq (ediff-last-command-char) ?f)) |
| 2196 | (and (eq ediff-skip-diff-region-function |
| 2197 | ediff-hide-regexp-matches-function) |
| 2198 | (eq (ediff-last-command-char) ?h))) |
| 2199 | (message "Selective browsing by regexp turned off") |
| 2200 | (setq ediff-skip-diff-region-function 'ediff-show-all-diffs)) |
| 2201 | ((eq (ediff-last-command-char) ?h) |
| 2202 | (setq ediff-skip-diff-region-function ediff-hide-regexp-matches-function |
| 2203 | regexp-A |
| 2204 | (read-string |
| 2205 | (format |
| 2206 | "Ignore A-regions matching this regexp (default %s): " |
| 2207 | ediff-regexp-hide-A)) |
| 2208 | regexp-B |
| 2209 | (read-string |
| 2210 | (format |
| 2211 | "Ignore B-regions matching this regexp (default %s): " |
| 2212 | ediff-regexp-hide-B))) |
| 2213 | (if ediff-3way-comparison-job |
| 2214 | (setq regexp-C |
| 2215 | (read-string |
| 2216 | (format |
| 2217 | "Ignore C-regions matching this regexp (default %s): " |
| 2218 | ediff-regexp-hide-C)))) |
| 2219 | (if (eq ediff-hide-regexp-connective 'and) |
| 2220 | (setq msg-connective "BOTH" |
| 2221 | alt-msg-connective "ONE OF" |
| 2222 | alt-connective 'or) |
| 2223 | (setq msg-connective "ONE OF" |
| 2224 | alt-msg-connective "BOTH" |
| 2225 | alt-connective 'and)) |
| 2226 | (if (y-or-n-p |
| 2227 | (format |
| 2228 | "Ignore regions that match %s regexps, OK? " |
| 2229 | msg-connective)) |
| 2230 | (message "Will ignore regions that match %s regexps" msg-connective) |
| 2231 | (setq ediff-hide-regexp-connective alt-connective) |
| 2232 | (message "Will ignore regions that match %s regexps" |
| 2233 | alt-msg-connective)) |
| 2234 | |
| 2235 | (or (string= regexp-A "") (setq ediff-regexp-hide-A regexp-A)) |
| 2236 | (or (string= regexp-B "") (setq ediff-regexp-hide-B regexp-B)) |
| 2237 | (or (string= regexp-C "") (setq ediff-regexp-hide-C regexp-C))) |
| 2238 | |
| 2239 | ((eq (ediff-last-command-char) ?f) |
| 2240 | (setq ediff-skip-diff-region-function |
| 2241 | ediff-focus-on-regexp-matches-function |
| 2242 | regexp-A |
| 2243 | (read-string |
| 2244 | (format |
| 2245 | "Focus on A-regions matching this regexp (default %s): " |
| 2246 | ediff-regexp-focus-A)) |
| 2247 | regexp-B |
| 2248 | (read-string |
| 2249 | (format |
| 2250 | "Focus on B-regions matching this regexp (default %s): " |
| 2251 | ediff-regexp-focus-B))) |
| 2252 | (if ediff-3way-comparison-job |
| 2253 | (setq regexp-C |
| 2254 | (read-string |
| 2255 | (format |
| 2256 | "Focus on C-regions matching this regexp (default %s): " |
| 2257 | ediff-regexp-focus-C)))) |
| 2258 | (if (eq ediff-focus-regexp-connective 'and) |
| 2259 | (setq msg-connective "BOTH" |
| 2260 | alt-msg-connective "ONE OF" |
| 2261 | alt-connective 'or) |
| 2262 | (setq msg-connective "ONE OF" |
| 2263 | alt-msg-connective "BOTH" |
| 2264 | alt-connective 'and)) |
| 2265 | (if (y-or-n-p |
| 2266 | (format |
| 2267 | "Focus on regions that match %s regexps, OK? " |
| 2268 | msg-connective)) |
| 2269 | (message "Will focus on regions that match %s regexps" |
| 2270 | msg-connective) |
| 2271 | (setq ediff-focus-regexp-connective alt-connective) |
| 2272 | (message "Will focus on regions that match %s regexps" |
| 2273 | alt-msg-connective)) |
| 2274 | |
| 2275 | (or (string= regexp-A "") (setq ediff-regexp-focus-A regexp-A)) |
| 2276 | (or (string= regexp-B "") (setq ediff-regexp-focus-B regexp-B)) |
| 2277 | (or (string= regexp-C "") (setq ediff-regexp-focus-C regexp-C)))))) |
| 2278 | |
| 2279 | (defun ediff-toggle-skip-similar () |
| 2280 | (interactive) |
| 2281 | (ediff-barf-if-not-control-buffer) |
| 2282 | (if (not (eq ediff-auto-refine 'on)) |
| 2283 | (error |
| 2284 | "Can't skip over whitespace regions: first turn auto-refining on")) |
| 2285 | (setq ediff-ignore-similar-regions (not ediff-ignore-similar-regions)) |
| 2286 | (if ediff-ignore-similar-regions |
| 2287 | (message |
| 2288 | "Skipping regions that differ only in white space & line breaks") |
| 2289 | (message "Skipping over white-space differences turned off"))) |
| 2290 | |
| 2291 | (defun ediff-focus-on-regexp-matches (n) |
| 2292 | "Focus on diffs that match regexp `ediff-regexp-focus-A/B'. |
| 2293 | Regions to be ignored according to this function are those where |
| 2294 | buf A region doesn't match `ediff-regexp-focus-A' and buf B region |
| 2295 | doesn't match `ediff-regexp-focus-B'. |
| 2296 | This function returns nil if the region number N (specified as |
| 2297 | an argument) is not to be ignored and t if region N is to be ignored. |
| 2298 | |
| 2299 | N is a region number used by Ediff internally. It is 1 less |
| 2300 | the number seen by the user." |
| 2301 | (if (ediff-valid-difference-p n) |
| 2302 | (let* ((ctl-buf ediff-control-buffer) |
| 2303 | (regex-A ediff-regexp-focus-A) |
| 2304 | (regex-B ediff-regexp-focus-B) |
| 2305 | (regex-C ediff-regexp-focus-C) |
| 2306 | (reg-A-match (ediff-with-current-buffer ediff-buffer-A |
| 2307 | (save-restriction |
| 2308 | (narrow-to-region |
| 2309 | (ediff-get-diff-posn 'A 'beg n ctl-buf) |
| 2310 | (ediff-get-diff-posn 'A 'end n ctl-buf)) |
| 2311 | (goto-char (point-min)) |
| 2312 | (re-search-forward regex-A nil t)))) |
| 2313 | (reg-B-match (ediff-with-current-buffer ediff-buffer-B |
| 2314 | (save-restriction |
| 2315 | (narrow-to-region |
| 2316 | (ediff-get-diff-posn 'B 'beg n ctl-buf) |
| 2317 | (ediff-get-diff-posn 'B 'end n ctl-buf)) |
| 2318 | (re-search-forward regex-B nil t)))) |
| 2319 | (reg-C-match (if ediff-3way-comparison-job |
| 2320 | (ediff-with-current-buffer ediff-buffer-C |
| 2321 | (save-restriction |
| 2322 | (narrow-to-region |
| 2323 | (ediff-get-diff-posn 'C 'beg n ctl-buf) |
| 2324 | (ediff-get-diff-posn 'C 'end n ctl-buf)) |
| 2325 | (re-search-forward regex-C nil t)))))) |
| 2326 | (not (eval (if ediff-3way-comparison-job |
| 2327 | (list ediff-focus-regexp-connective |
| 2328 | reg-A-match reg-B-match reg-C-match) |
| 2329 | (list ediff-focus-regexp-connective |
| 2330 | reg-A-match reg-B-match)))) |
| 2331 | ))) |
| 2332 | |
| 2333 | (defun ediff-hide-regexp-matches (n) |
| 2334 | "Hide diffs that match regexp `ediff-regexp-hide-A/B/C'. |
| 2335 | Regions to be ignored are those where buf A region matches |
| 2336 | `ediff-regexp-hide-A' and buf B region matches `ediff-regexp-hide-B'. |
| 2337 | This function returns nil if the region number N (specified as |
| 2338 | an argument) is not to be ignored and t if region N is to be ignored. |
| 2339 | |
| 2340 | N is a region number used by Ediff internally. It is 1 less |
| 2341 | the number seen by the user." |
| 2342 | (if (ediff-valid-difference-p n) |
| 2343 | (let* ((ctl-buf ediff-control-buffer) |
| 2344 | (regex-A ediff-regexp-hide-A) |
| 2345 | (regex-B ediff-regexp-hide-B) |
| 2346 | (regex-C ediff-regexp-hide-C) |
| 2347 | (reg-A-match (ediff-with-current-buffer ediff-buffer-A |
| 2348 | (save-restriction |
| 2349 | (narrow-to-region |
| 2350 | (ediff-get-diff-posn 'A 'beg n ctl-buf) |
| 2351 | (ediff-get-diff-posn 'A 'end n ctl-buf)) |
| 2352 | (goto-char (point-min)) |
| 2353 | (re-search-forward regex-A nil t)))) |
| 2354 | (reg-B-match (ediff-with-current-buffer ediff-buffer-B |
| 2355 | (save-restriction |
| 2356 | (narrow-to-region |
| 2357 | (ediff-get-diff-posn 'B 'beg n ctl-buf) |
| 2358 | (ediff-get-diff-posn 'B 'end n ctl-buf)) |
| 2359 | (goto-char (point-min)) |
| 2360 | (re-search-forward regex-B nil t)))) |
| 2361 | (reg-C-match (if ediff-3way-comparison-job |
| 2362 | (ediff-with-current-buffer ediff-buffer-C |
| 2363 | (save-restriction |
| 2364 | (narrow-to-region |
| 2365 | (ediff-get-diff-posn 'C 'beg n ctl-buf) |
| 2366 | (ediff-get-diff-posn 'C 'end n ctl-buf)) |
| 2367 | (goto-char (point-min)) |
| 2368 | (re-search-forward regex-C nil t)))))) |
| 2369 | (eval (if ediff-3way-comparison-job |
| 2370 | (list ediff-hide-regexp-connective |
| 2371 | reg-A-match reg-B-match reg-C-match) |
| 2372 | (list ediff-hide-regexp-connective reg-A-match reg-B-match))) |
| 2373 | ))) |
| 2374 | |
| 2375 | |
| 2376 | \f |
| 2377 | ;;; Quitting, suspending, etc. |
| 2378 | |
| 2379 | (defun ediff-quit (reverse-default-keep-variants) |
| 2380 | "Finish an Ediff session and exit Ediff. |
| 2381 | Unselects the selected difference, if any, restores the read-only and modified |
| 2382 | flags of the compared file buffers, kills Ediff buffers for this session |
| 2383 | \(but not buffers A, B, C\). |
| 2384 | |
| 2385 | If `ediff-keep-variants' is nil, the user will be asked whether the buffers |
| 2386 | containing the variants should be removed \(if they haven't been modified\). |
| 2387 | If it is t, they will be preserved unconditionally. A prefix argument, |
| 2388 | temporarily reverses the meaning of this variable." |
| 2389 | (interactive "P") |
| 2390 | (ediff-barf-if-not-control-buffer) |
| 2391 | (let ((ctl-buf (current-buffer)) |
| 2392 | (ctl-frm (selected-frame)) |
| 2393 | (minibuffer-auto-raise t)) |
| 2394 | (if (y-or-n-p (format "Quit this Ediff session%s? " |
| 2395 | (if (ediff-buffer-live-p ediff-meta-buffer) |
| 2396 | " & show containing session group" ""))) |
| 2397 | (progn |
| 2398 | (message "") |
| 2399 | (set-buffer ctl-buf) |
| 2400 | (ediff-really-quit reverse-default-keep-variants)) |
| 2401 | (select-frame ctl-frm) |
| 2402 | (raise-frame ctl-frm) |
| 2403 | (message "")))) |
| 2404 | |
| 2405 | |
| 2406 | ;; Perform the quit operations. |
| 2407 | (defun ediff-really-quit (reverse-default-keep-variants) |
| 2408 | (ediff-unhighlight-diffs-totally) |
| 2409 | (ediff-clear-diff-vector 'ediff-difference-vector-A 'fine-diffs-also) |
| 2410 | (ediff-clear-diff-vector 'ediff-difference-vector-B 'fine-diffs-also) |
| 2411 | (ediff-clear-diff-vector 'ediff-difference-vector-C 'fine-diffs-also) |
| 2412 | (ediff-clear-diff-vector 'ediff-difference-vector-Ancestor 'fine-diffs-also) |
| 2413 | |
| 2414 | (ediff-delete-temp-files) |
| 2415 | |
| 2416 | ;; Restore the visibility range. This affects only ediff-*-regions/windows. |
| 2417 | ;; Since for other job names ediff-visible-region sets |
| 2418 | ;; ediff-visible-bounds to ediff-wide-bounds, the settings below are |
| 2419 | ;; ignored for such jobs. |
| 2420 | (if ediff-quit-widened |
| 2421 | (setq ediff-visible-bounds ediff-wide-bounds) |
| 2422 | (setq ediff-visible-bounds ediff-narrow-bounds)) |
| 2423 | |
| 2424 | ;; Apply selective display to narrow or widen |
| 2425 | (ediff-visible-region) |
| 2426 | (mapc (lambda (overl) |
| 2427 | (if (ediff-overlayp overl) |
| 2428 | (ediff-delete-overlay overl))) |
| 2429 | ediff-wide-bounds) |
| 2430 | (mapc (lambda (overl) |
| 2431 | (if (ediff-overlayp overl) |
| 2432 | (ediff-delete-overlay overl))) |
| 2433 | ediff-narrow-bounds) |
| 2434 | |
| 2435 | ;; restore buffer mode line id's in buffer-A/B/C |
| 2436 | (let ((control-buffer ediff-control-buffer) |
| 2437 | (meta-buffer ediff-meta-buffer) |
| 2438 | (after-quit-hook-internal ediff-after-quit-hook-internal) |
| 2439 | (session-number ediff-meta-session-number) |
| 2440 | ;; suitable working frame |
| 2441 | (warp-frame (if (and (ediff-window-display-p) (eq ediff-grab-mouse t)) |
| 2442 | (cond ((window-live-p ediff-window-A) |
| 2443 | (window-frame ediff-window-A)) |
| 2444 | ((window-live-p ediff-window-B) |
| 2445 | (window-frame ediff-window-B)) |
| 2446 | (t (next-frame)))))) |
| 2447 | (condition-case nil |
| 2448 | (ediff-with-current-buffer ediff-buffer-A |
| 2449 | (setq ediff-this-buffer-ediff-sessions |
| 2450 | (delq control-buffer ediff-this-buffer-ediff-sessions)) |
| 2451 | (kill-local-variable 'mode-line-buffer-identification) |
| 2452 | (kill-local-variable 'mode-line-format) |
| 2453 | ) |
| 2454 | (error)) |
| 2455 | |
| 2456 | (condition-case nil |
| 2457 | (ediff-with-current-buffer ediff-buffer-B |
| 2458 | (setq ediff-this-buffer-ediff-sessions |
| 2459 | (delq control-buffer ediff-this-buffer-ediff-sessions)) |
| 2460 | (kill-local-variable 'mode-line-buffer-identification) |
| 2461 | (kill-local-variable 'mode-line-format) |
| 2462 | ) |
| 2463 | (error)) |
| 2464 | |
| 2465 | (condition-case nil |
| 2466 | (ediff-with-current-buffer ediff-buffer-C |
| 2467 | (setq ediff-this-buffer-ediff-sessions |
| 2468 | (delq control-buffer ediff-this-buffer-ediff-sessions)) |
| 2469 | (kill-local-variable 'mode-line-buffer-identification) |
| 2470 | (kill-local-variable 'mode-line-format) |
| 2471 | ) |
| 2472 | (error)) |
| 2473 | |
| 2474 | (condition-case nil |
| 2475 | (ediff-with-current-buffer ediff-ancestor-buffer |
| 2476 | (setq ediff-this-buffer-ediff-sessions |
| 2477 | (delq control-buffer ediff-this-buffer-ediff-sessions)) |
| 2478 | (kill-local-variable 'mode-line-buffer-identification) |
| 2479 | (kill-local-variable 'mode-line-format) |
| 2480 | ) |
| 2481 | (error)) |
| 2482 | |
| 2483 | (setq ediff-session-registry |
| 2484 | (delq ediff-control-buffer ediff-session-registry)) |
| 2485 | (ediff-update-registry) |
| 2486 | ;; restore state of buffers to what it was before ediff |
| 2487 | (ediff-restore-protected-variables) |
| 2488 | |
| 2489 | ;; If the user interrupts (canceling saving the merge buffer), continue |
| 2490 | ;; normally. |
| 2491 | (condition-case nil |
| 2492 | (if (ediff-merge-job) |
| 2493 | (run-hooks 'ediff-quit-merge-hook)) |
| 2494 | (quit)) |
| 2495 | |
| 2496 | (run-hooks 'ediff-cleanup-hook) |
| 2497 | |
| 2498 | (ediff-janitor |
| 2499 | 'ask |
| 2500 | ;; reverse-default-keep-variants is t if the user quits with a prefix arg |
| 2501 | (if reverse-default-keep-variants |
| 2502 | (not ediff-keep-variants) |
| 2503 | ediff-keep-variants)) |
| 2504 | |
| 2505 | ;; one hook here is ediff-cleanup-mess, which kills the control buffer and |
| 2506 | ;; other auxiliary buffers. we made it into a hook to let the users do their |
| 2507 | ;; own cleanup, if needed. |
| 2508 | (run-hooks 'ediff-quit-hook) |
| 2509 | (ediff-update-meta-buffer meta-buffer nil session-number) |
| 2510 | |
| 2511 | ;; warp mouse into a working window |
| 2512 | (setq warp-frame ; if mouse is over a reasonable frame, use it |
| 2513 | (cond ((ediff-good-frame-under-mouse)) |
| 2514 | (t warp-frame))) |
| 2515 | (if (and (ediff-window-display-p) (frame-live-p warp-frame) ediff-grab-mouse) |
| 2516 | (set-mouse-position (if (featurep 'emacs) |
| 2517 | warp-frame |
| 2518 | (frame-selected-window warp-frame)) |
| 2519 | 2 1)) |
| 2520 | |
| 2521 | (run-hooks 'after-quit-hook-internal) |
| 2522 | )) |
| 2523 | |
| 2524 | ;; Returns frame under mouse, if this frame is not a minibuffer |
| 2525 | ;; frame. Otherwise: nil |
| 2526 | (defun ediff-good-frame-under-mouse () |
| 2527 | (let ((frame-or-win (car (mouse-position))) |
| 2528 | (buf-name "") |
| 2529 | frame obj-ok) |
| 2530 | (setq obj-ok |
| 2531 | (if (featurep 'emacs) |
| 2532 | (frame-live-p frame-or-win) |
| 2533 | (window-live-p frame-or-win))) |
| 2534 | (if obj-ok |
| 2535 | (setq frame (if (featurep 'emacs) frame-or-win (window-frame frame-or-win)) |
| 2536 | buf-name |
| 2537 | (buffer-name (window-buffer (frame-selected-window frame))))) |
| 2538 | (if (string-match "Minibuf" buf-name) |
| 2539 | nil |
| 2540 | frame))) |
| 2541 | |
| 2542 | |
| 2543 | (defun ediff-delete-temp-files () |
| 2544 | (if (and (stringp ediff-temp-file-A) (file-exists-p ediff-temp-file-A)) |
| 2545 | (delete-file ediff-temp-file-A)) |
| 2546 | (if (and (stringp ediff-temp-file-B) (file-exists-p ediff-temp-file-B)) |
| 2547 | (delete-file ediff-temp-file-B)) |
| 2548 | (if (and (stringp ediff-temp-file-C) (file-exists-p ediff-temp-file-C)) |
| 2549 | (delete-file ediff-temp-file-C))) |
| 2550 | |
| 2551 | |
| 2552 | ;; Kill control buffer, other auxiliary Ediff buffers. |
| 2553 | ;; Leave one of the frames split between buffers A/B/C |
| 2554 | (defun ediff-cleanup-mess () |
| 2555 | (let* ((buff-A ediff-buffer-A) |
| 2556 | (buff-B ediff-buffer-B) |
| 2557 | (buff-C ediff-buffer-C) |
| 2558 | (ctl-buf ediff-control-buffer) |
| 2559 | (ctl-wind (ediff-get-visible-buffer-window ctl-buf)) |
| 2560 | (ctl-frame ediff-control-frame) |
| 2561 | (three-way-job ediff-3way-job) |
| 2562 | (main-frame (cond ((window-live-p ediff-window-A) |
| 2563 | (window-frame ediff-window-A)) |
| 2564 | ((window-live-p ediff-window-B) |
| 2565 | (window-frame ediff-window-B))))) |
| 2566 | |
| 2567 | (ediff-kill-buffer-carefully ediff-diff-buffer) |
| 2568 | (ediff-kill-buffer-carefully ediff-custom-diff-buffer) |
| 2569 | (ediff-kill-buffer-carefully ediff-fine-diff-buffer) |
| 2570 | (ediff-kill-buffer-carefully ediff-tmp-buffer) |
| 2571 | (ediff-kill-buffer-carefully ediff-error-buffer) |
| 2572 | (ediff-kill-buffer-carefully ediff-msg-buffer) |
| 2573 | (ediff-kill-buffer-carefully ediff-debug-buffer) |
| 2574 | (if (boundp 'ediff-patch-diagnostics) |
| 2575 | (ediff-kill-buffer-carefully ediff-patch-diagnostics)) |
| 2576 | |
| 2577 | ;; delete control frame or window |
| 2578 | (cond ((and (ediff-window-display-p) (frame-live-p ctl-frame)) |
| 2579 | (delete-frame ctl-frame)) |
| 2580 | ((window-live-p ctl-wind) |
| 2581 | (delete-window ctl-wind))) |
| 2582 | |
| 2583 | ;; Hide bottom toolbar. --marcpa |
| 2584 | (if (not (ediff-multiframe-setup-p)) |
| 2585 | (ediff-kill-bottom-toolbar)) |
| 2586 | |
| 2587 | (ediff-kill-buffer-carefully ctl-buf) |
| 2588 | |
| 2589 | (if (frame-live-p main-frame) |
| 2590 | (select-frame main-frame)) |
| 2591 | |
| 2592 | ;; display only if not visible |
| 2593 | (condition-case nil |
| 2594 | (or (ediff-get-visible-buffer-window buff-B) |
| 2595 | (switch-to-buffer buff-B)) |
| 2596 | (error)) |
| 2597 | (condition-case nil |
| 2598 | (or (ediff-get-visible-buffer-window buff-A) |
| 2599 | (progn |
| 2600 | (if (and (ediff-get-visible-buffer-window buff-B) |
| 2601 | (ediff-buffer-live-p buff-A)) |
| 2602 | (funcall ediff-split-window-function)) |
| 2603 | (switch-to-buffer buff-A))) |
| 2604 | (error)) |
| 2605 | (if three-way-job |
| 2606 | (condition-case nil |
| 2607 | (or (ediff-get-visible-buffer-window buff-C) |
| 2608 | (progn |
| 2609 | (if (and (or (ediff-get-visible-buffer-window buff-A) |
| 2610 | (ediff-get-visible-buffer-window buff-B)) |
| 2611 | (ediff-buffer-live-p buff-C)) |
| 2612 | (funcall ediff-split-window-function)) |
| 2613 | (switch-to-buffer buff-C))) |
| 2614 | (error))) |
| 2615 | (balance-windows) |
| 2616 | (message "") |
| 2617 | )) |
| 2618 | |
| 2619 | (defun ediff-janitor (ask keep-variants) |
| 2620 | "Kill buffers A, B, and, possibly, C, if these buffers aren't modified. |
| 2621 | In merge jobs, buffer C is not deleted here, but rather according to |
| 2622 | ediff-quit-merge-hook. |
| 2623 | A side effect of cleaning up may be that you should be careful when comparing |
| 2624 | the same buffer in two separate Ediff sessions: quitting one of them might |
| 2625 | delete this buffer in another session as well." |
| 2626 | (ediff-dispose-of-variant-according-to-user |
| 2627 | ediff-buffer-A 'A ask keep-variants) |
| 2628 | (ediff-dispose-of-variant-according-to-user |
| 2629 | ediff-buffer-B 'B ask keep-variants) |
| 2630 | (if ediff-merge-job ; don't del buf C if merging--del ancestor buf instead |
| 2631 | (ediff-dispose-of-variant-according-to-user |
| 2632 | ediff-ancestor-buffer 'Ancestor ask keep-variants) |
| 2633 | (ediff-dispose-of-variant-according-to-user |
| 2634 | ediff-buffer-C 'C ask keep-variants) |
| 2635 | )) |
| 2636 | |
| 2637 | ;; Kill the variant buffer, according to user directives (ask, kill |
| 2638 | ;; unconditionaly, keep) |
| 2639 | ;; BUFF is the buffer, BUFF-TYPE is either 'A, or 'B, 'C, 'Ancestor |
| 2640 | (defun ediff-dispose-of-variant-according-to-user (buff bufftype ask keep-variants) |
| 2641 | ;; if this is indirect buffer, kill it and substitute with direct buf |
| 2642 | (if (and (ediff-buffer-live-p buff) |
| 2643 | (ediff-with-current-buffer buff ediff-temp-indirect-buffer)) |
| 2644 | (let ((wind (ediff-get-visible-buffer-window buff)) |
| 2645 | (base (buffer-base-buffer buff)) |
| 2646 | (modified-p (buffer-modified-p buff))) |
| 2647 | (if (and (window-live-p wind) (ediff-buffer-live-p base)) |
| 2648 | (set-window-buffer wind base)) |
| 2649 | ;; Kill indirect buffer even if it is modified, because the base buffer |
| 2650 | ;; is still there. Note that if the base buffer is dead then so will be |
| 2651 | ;; the indirect buffer |
| 2652 | (ediff-with-current-buffer buff |
| 2653 | (set-buffer-modified-p nil)) |
| 2654 | (ediff-kill-buffer-carefully buff) |
| 2655 | (ediff-with-current-buffer base |
| 2656 | (set-buffer-modified-p modified-p))) |
| 2657 | ;; otherwise, ask or use the value of keep-variants |
| 2658 | (or (not (ediff-buffer-live-p buff)) |
| 2659 | keep-variants |
| 2660 | (buffer-modified-p buff) |
| 2661 | (and ask |
| 2662 | (not (y-or-n-p (format "Kill buffer %S [%s]? " |
| 2663 | bufftype (buffer-name buff))))) |
| 2664 | (ediff-kill-buffer-carefully buff)) |
| 2665 | )) |
| 2666 | |
| 2667 | (defun ediff-maybe-save-and-delete-merge (&optional save-and-continue) |
| 2668 | "Default hook to run on quitting a merge job. |
| 2669 | This can also be used to save merge buffer in the middle of an Ediff session. |
| 2670 | |
| 2671 | If the optional SAVE-AND-CONTINUE argument is non-nil, save merge buffer and |
| 2672 | continue. Otherwise: |
| 2673 | If `ediff-autostore-merges' is nil, this does nothing. |
| 2674 | If it is t, it saves the merge buffer in the file `ediff-merge-store-file' |
| 2675 | or asks the user, if the latter is nil. It then asks the user whether to |
| 2676 | delete the merge buffer. |
| 2677 | If `ediff-autostore-merges' is neither nil nor t, the merge buffer is saved |
| 2678 | only if this merge job is part of a group, i.e., was invoked from within |
| 2679 | `ediff-merge-directories', `ediff-merge-directory-revisions', and such." |
| 2680 | (let ((merge-store-file ediff-merge-store-file) |
| 2681 | (ediff-autostore-merges ; fake ediff-autostore-merges, if necessary |
| 2682 | (if save-and-continue t ediff-autostore-merges))) |
| 2683 | (if ediff-autostore-merges |
| 2684 | (cond ((stringp merge-store-file) |
| 2685 | ;; store, ask to delete |
| 2686 | (ediff-write-merge-buffer-and-maybe-kill |
| 2687 | ediff-buffer-C merge-store-file 'show-file save-and-continue)) |
| 2688 | ((eq ediff-autostore-merges t) |
| 2689 | ;; ask for file name |
| 2690 | (setq merge-store-file |
| 2691 | (read-file-name "Save the result of the merge in file: ")) |
| 2692 | (ediff-write-merge-buffer-and-maybe-kill |
| 2693 | ediff-buffer-C merge-store-file nil save-and-continue)) |
| 2694 | ((and (ediff-buffer-live-p ediff-meta-buffer) |
| 2695 | (ediff-with-current-buffer ediff-meta-buffer |
| 2696 | (ediff-merge-metajob))) |
| 2697 | ;; The parent metajob passed nil as the autostore file. |
| 2698 | nil))) |
| 2699 | )) |
| 2700 | |
| 2701 | ;; write merge buffer. If the optional argument save-and-continue is non-nil, |
| 2702 | ;; then don't kill the merge buffer |
| 2703 | (defun ediff-write-merge-buffer-and-maybe-kill (buf file |
| 2704 | &optional |
| 2705 | show-file save-and-continue) |
| 2706 | (if (not (eq (find-buffer-visiting file) buf)) |
| 2707 | (let ((warn-message |
| 2708 | (format "Another buffer is visiting file %s. Too dangerous to save the merge buffer" |
| 2709 | file))) |
| 2710 | (beep) |
| 2711 | (message "%s" warn-message) |
| 2712 | (with-output-to-temp-buffer ediff-msg-buffer |
| 2713 | (princ "\n\n") |
| 2714 | (princ warn-message) |
| 2715 | (princ "\n\n") |
| 2716 | ) |
| 2717 | (sit-for 2)) |
| 2718 | (ediff-with-current-buffer buf |
| 2719 | (if (or (not (file-exists-p file)) |
| 2720 | (y-or-n-p (format "File %s exists, overwrite? " file))) |
| 2721 | (progn |
| 2722 | ;;(write-region nil nil file) |
| 2723 | (ediff-with-current-buffer buf |
| 2724 | (set-visited-file-name file) |
| 2725 | (save-buffer)) |
| 2726 | (if show-file |
| 2727 | (progn |
| 2728 | (message "Merge buffer saved in: %s" file) |
| 2729 | (set-buffer-modified-p nil) |
| 2730 | (sit-for 3))) |
| 2731 | (if (and |
| 2732 | (not save-and-continue) |
| 2733 | (y-or-n-p "Merge buffer saved. Now kill the buffer? ")) |
| 2734 | (ediff-kill-buffer-carefully buf))))) |
| 2735 | )) |
| 2736 | |
| 2737 | ;; The default way of suspending Ediff. |
| 2738 | ;; Buries Ediff buffers, kills all windows. |
| 2739 | (defun ediff-default-suspend-function () |
| 2740 | (let* ((buf-A ediff-buffer-A) |
| 2741 | (buf-B ediff-buffer-B) |
| 2742 | (buf-C ediff-buffer-C) |
| 2743 | (buf-A-wind (ediff-get-visible-buffer-window buf-A)) |
| 2744 | (buf-B-wind (ediff-get-visible-buffer-window buf-B)) |
| 2745 | (buf-C-wind (ediff-get-visible-buffer-window buf-C)) |
| 2746 | (buf-patch (if (boundp 'ediff-patchbufer) ediff-patchbufer nil)) |
| 2747 | (buf-patch-diag (if (boundp 'ediff-patch-diagnostics) |
| 2748 | ediff-patch-diagnostics nil)) |
| 2749 | (buf-err ediff-error-buffer) |
| 2750 | (buf-diff ediff-diff-buffer) |
| 2751 | (buf-custom-diff ediff-custom-diff-buffer) |
| 2752 | (buf-fine-diff ediff-fine-diff-buffer)) |
| 2753 | |
| 2754 | ;; hide the control panel |
| 2755 | (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame)) |
| 2756 | (iconify-frame ediff-control-frame) |
| 2757 | (bury-buffer)) |
| 2758 | (if buf-err (bury-buffer buf-err)) |
| 2759 | (if buf-diff (bury-buffer buf-diff)) |
| 2760 | (if buf-custom-diff (bury-buffer buf-custom-diff)) |
| 2761 | (if buf-fine-diff (bury-buffer buf-fine-diff)) |
| 2762 | (if buf-patch (bury-buffer buf-patch)) |
| 2763 | (if buf-patch-diag (bury-buffer buf-patch-diag)) |
| 2764 | (if (window-live-p buf-A-wind) |
| 2765 | (progn |
| 2766 | (select-window buf-A-wind) |
| 2767 | (delete-other-windows) |
| 2768 | (bury-buffer)) |
| 2769 | (if (ediff-buffer-live-p buf-A) |
| 2770 | (progn |
| 2771 | (set-buffer buf-A) |
| 2772 | (bury-buffer)))) |
| 2773 | (if (window-live-p buf-B-wind) |
| 2774 | (progn |
| 2775 | (select-window buf-B-wind) |
| 2776 | (delete-other-windows) |
| 2777 | (bury-buffer)) |
| 2778 | (if (ediff-buffer-live-p buf-B) |
| 2779 | (progn |
| 2780 | (set-buffer buf-B) |
| 2781 | (bury-buffer)))) |
| 2782 | (if (window-live-p buf-C-wind) |
| 2783 | (progn |
| 2784 | (select-window buf-C-wind) |
| 2785 | (delete-other-windows) |
| 2786 | (bury-buffer)) |
| 2787 | (if (ediff-buffer-live-p buf-C) |
| 2788 | (progn |
| 2789 | (set-buffer buf-C) |
| 2790 | (bury-buffer)))) |
| 2791 | )) |
| 2792 | |
| 2793 | |
| 2794 | (defun ediff-suspend () |
| 2795 | "Suspend Ediff. |
| 2796 | To resume, switch to the appropriate `Ediff Control Panel' |
| 2797 | buffer and then type \\[ediff-recenter]. Ediff will automatically set |
| 2798 | up an appropriate window config." |
| 2799 | (interactive) |
| 2800 | (ediff-barf-if-not-control-buffer) |
| 2801 | (run-hooks 'ediff-suspend-hook) |
| 2802 | (message |
| 2803 | "To resume, type M-x eregistry and select the desired Ediff session")) |
| 2804 | |
| 2805 | ;; ediff-barf-if-not-control-buffer ensures only called from ediff. |
| 2806 | (declare-function ediff-version "ediff" ()) |
| 2807 | |
| 2808 | (defun ediff-status-info () |
| 2809 | "Show the names of the buffers or files being operated on by Ediff. |
| 2810 | Hit \\[ediff-recenter] to reset the windows afterward." |
| 2811 | (interactive) |
| 2812 | (ediff-barf-if-not-control-buffer) |
| 2813 | (save-excursion |
| 2814 | (ediff-skip-unsuitable-frames)) |
| 2815 | (with-output-to-temp-buffer ediff-msg-buffer |
| 2816 | (ediff-with-current-buffer standard-output |
| 2817 | (fundamental-mode)) |
| 2818 | (raise-frame (selected-frame)) |
| 2819 | (princ (ediff-version)) |
| 2820 | (princ "\n\n") |
| 2821 | (ediff-with-current-buffer ediff-buffer-A |
| 2822 | (if buffer-file-name |
| 2823 | (princ |
| 2824 | (format "File A = %S\n" buffer-file-name)) |
| 2825 | (princ |
| 2826 | (format "Buffer A = %S\n" (buffer-name))))) |
| 2827 | (ediff-with-current-buffer ediff-buffer-B |
| 2828 | (if buffer-file-name |
| 2829 | (princ |
| 2830 | (format "File B = %S\n" buffer-file-name)) |
| 2831 | (princ |
| 2832 | (format "Buffer B = %S\n" (buffer-name))))) |
| 2833 | (if ediff-3way-job |
| 2834 | (ediff-with-current-buffer ediff-buffer-C |
| 2835 | (if buffer-file-name |
| 2836 | (princ |
| 2837 | (format "File C = %S\n" buffer-file-name)) |
| 2838 | (princ |
| 2839 | (format "Buffer C = %S\n" (buffer-name)))))) |
| 2840 | (princ (format "Customized diff output %s\n" |
| 2841 | (if (ediff-buffer-live-p ediff-custom-diff-buffer) |
| 2842 | (concat "\tin buffer " |
| 2843 | (buffer-name ediff-custom-diff-buffer)) |
| 2844 | " is not available"))) |
| 2845 | (princ (format "Plain diff output %s\n" |
| 2846 | (if (ediff-buffer-live-p ediff-diff-buffer) |
| 2847 | (concat "\tin buffer " |
| 2848 | (buffer-name ediff-diff-buffer)) |
| 2849 | " is not available"))) |
| 2850 | |
| 2851 | (let* ((A-line (ediff-with-current-buffer ediff-buffer-A |
| 2852 | (1+ (count-lines (point-min) (point))))) |
| 2853 | (B-line (ediff-with-current-buffer ediff-buffer-B |
| 2854 | (1+ (count-lines (point-min) (point))))) |
| 2855 | C-line) |
| 2856 | (princ (format "\Buffer A's point is on line %d\n" A-line)) |
| 2857 | (princ (format "Buffer B's point is on line %d\n" B-line)) |
| 2858 | (if ediff-3way-job |
| 2859 | (progn |
| 2860 | (setq C-line (ediff-with-current-buffer ediff-buffer-C |
| 2861 | (1+ (count-lines (point-min) (point))))) |
| 2862 | (princ (format "Buffer C's point is on line %d\n" C-line))))) |
| 2863 | |
| 2864 | (princ (format "\nCurrent difference number = %S\n" |
| 2865 | (cond ((< ediff-current-difference 0) 'start) |
| 2866 | ((>= ediff-current-difference |
| 2867 | ediff-number-of-differences) 'end) |
| 2868 | (t (1+ ediff-current-difference))))) |
| 2869 | |
| 2870 | (princ |
| 2871 | (format "\n%s regions that differ in white space & line breaks only" |
| 2872 | (if ediff-ignore-similar-regions |
| 2873 | "Ignoring" "Showing"))) |
| 2874 | (if (and ediff-merge-job ediff-show-clashes-only) |
| 2875 | (princ |
| 2876 | "\nFocusing on regions where both buffers differ from the ancestor")) |
| 2877 | (if (and ediff-skip-merge-regions-that-differ-from-default ediff-merge-job) |
| 2878 | (princ |
| 2879 | "\nSkipping merge regions that differ from default setting")) |
| 2880 | |
| 2881 | (cond ((eq ediff-skip-diff-region-function 'ediff-show-all-diffs) |
| 2882 | (princ "\nSelective browsing by regexp is off\n")) |
| 2883 | ((eq ediff-skip-diff-region-function |
| 2884 | ediff-hide-regexp-matches-function) |
| 2885 | (princ |
| 2886 | "\nIgnoring regions that match") |
| 2887 | (princ |
| 2888 | (format |
| 2889 | "\n\t regexp `%s' in buffer A %S\n\t regexp `%s' in buffer B\n" |
| 2890 | ediff-regexp-hide-A ediff-hide-regexp-connective |
| 2891 | ediff-regexp-hide-B))) |
| 2892 | ((eq ediff-skip-diff-region-function |
| 2893 | ediff-focus-on-regexp-matches-function) |
| 2894 | (princ |
| 2895 | "\nFocusing on regions that match") |
| 2896 | (princ |
| 2897 | (format |
| 2898 | "\n\t regexp `%s' in buffer A %S\n\t regexp `%s' in buffer B\n" |
| 2899 | ediff-regexp-focus-A ediff-focus-regexp-connective |
| 2900 | ediff-regexp-focus-B))) |
| 2901 | (t (princ "\nSelective browsing via a user-defined method.\n"))) |
| 2902 | |
| 2903 | (princ |
| 2904 | (format "\nBugs/suggestions: type `%s' while in Ediff Control Panel." |
| 2905 | (substitute-command-keys "\\[ediff-submit-report]"))) |
| 2906 | ) ; with output |
| 2907 | (if (frame-live-p ediff-control-frame) |
| 2908 | (ediff-reset-mouse ediff-control-frame)) |
| 2909 | (if (window-live-p ediff-control-window) |
| 2910 | (select-window ediff-control-window))) |
| 2911 | |
| 2912 | |
| 2913 | |
| 2914 | \f |
| 2915 | ;;; Support routines |
| 2916 | |
| 2917 | ;; Select a difference by placing the ASCII flags around the appropriate |
| 2918 | ;; group of lines in the A, B buffers |
| 2919 | ;; This may have to be modified for buffer C, when it will be supported. |
| 2920 | (defun ediff-select-difference (n) |
| 2921 | (if (and (ediff-buffer-live-p ediff-buffer-A) |
| 2922 | (ediff-buffer-live-p ediff-buffer-B) |
| 2923 | (ediff-valid-difference-p n)) |
| 2924 | (progn |
| 2925 | (cond |
| 2926 | ((and (ediff-has-face-support-p) ediff-use-faces) |
| 2927 | (ediff-highlight-diff n)) |
| 2928 | ((eq ediff-highlighting-style 'ascii) |
| 2929 | (ediff-place-flags-in-buffer |
| 2930 | 'A ediff-buffer-A ediff-control-buffer n) |
| 2931 | (ediff-place-flags-in-buffer |
| 2932 | 'B ediff-buffer-B ediff-control-buffer n) |
| 2933 | (if ediff-3way-job |
| 2934 | (ediff-place-flags-in-buffer |
| 2935 | 'C ediff-buffer-C ediff-control-buffer n)) |
| 2936 | (if (ediff-buffer-live-p ediff-ancestor-buffer) |
| 2937 | (ediff-place-flags-in-buffer |
| 2938 | 'Ancestor ediff-ancestor-buffer |
| 2939 | ediff-control-buffer n)) |
| 2940 | )) |
| 2941 | |
| 2942 | (ediff-install-fine-diff-if-necessary n) |
| 2943 | ;; set current difference here so the hook will be able to refer to it |
| 2944 | (setq ediff-current-difference n) |
| 2945 | (run-hooks 'ediff-select-hook)))) |
| 2946 | |
| 2947 | |
| 2948 | ;; Unselect a difference by removing the ASCII flags in the buffers. |
| 2949 | ;; This may have to be modified for buffer C, when it will be supported. |
| 2950 | (defun ediff-unselect-difference (n) |
| 2951 | (if (ediff-valid-difference-p n) |
| 2952 | (progn |
| 2953 | (cond ((and (ediff-has-face-support-p) ediff-use-faces) |
| 2954 | (ediff-unhighlight-diff)) |
| 2955 | ((eq ediff-highlighting-style 'ascii) |
| 2956 | (ediff-remove-flags-from-buffer |
| 2957 | ediff-buffer-A |
| 2958 | (ediff-get-diff-overlay n 'A)) |
| 2959 | (ediff-remove-flags-from-buffer |
| 2960 | ediff-buffer-B |
| 2961 | (ediff-get-diff-overlay n 'B)) |
| 2962 | (if ediff-3way-job |
| 2963 | (ediff-remove-flags-from-buffer |
| 2964 | ediff-buffer-C |
| 2965 | (ediff-get-diff-overlay n 'C))) |
| 2966 | (if (ediff-buffer-live-p ediff-ancestor-buffer) |
| 2967 | (ediff-remove-flags-from-buffer |
| 2968 | ediff-ancestor-buffer |
| 2969 | (ediff-get-diff-overlay n 'Ancestor))) |
| 2970 | )) |
| 2971 | |
| 2972 | ;; unhighlight fine diffs |
| 2973 | (ediff-set-fine-diff-properties ediff-current-difference 'default) |
| 2974 | (run-hooks 'ediff-unselect-hook)))) |
| 2975 | |
| 2976 | |
| 2977 | ;; Unselects prev diff and selects a new one, if FLAG has value other than |
| 2978 | ;; 'select-only or 'unselect-only. If FLAG is 'select-only, the |
| 2979 | ;; next difference is selected, but the current selection is not |
| 2980 | ;; unselected. If FLAG is 'unselect-only then the current selection is |
| 2981 | ;; unselected, but the next one is not selected. If NO-RECENTER is non-nil, |
| 2982 | ;; don't recenter buffers after selecting/unselecting. |
| 2983 | (defun ediff-unselect-and-select-difference (n &optional flag no-recenter) |
| 2984 | (let ((ediff-current-difference n)) |
| 2985 | (or no-recenter |
| 2986 | (ediff-recenter 'no-rehighlight))) |
| 2987 | |
| 2988 | (let ((control-buf ediff-control-buffer)) |
| 2989 | (unwind-protect |
| 2990 | (progn |
| 2991 | (or (eq flag 'select-only) |
| 2992 | (ediff-unselect-difference ediff-current-difference)) |
| 2993 | |
| 2994 | (or (eq flag 'unselect-only) |
| 2995 | (ediff-select-difference n)) |
| 2996 | ;; need to set current diff here even though it is also set in |
| 2997 | ;; ediff-select-difference because ediff-select-difference might not |
| 2998 | ;; be called if unselect-only is specified |
| 2999 | (setq ediff-current-difference n) |
| 3000 | ) ; end protected section |
| 3001 | |
| 3002 | (ediff-with-current-buffer control-buf (ediff-refresh-mode-lines))) |
| 3003 | )) |
| 3004 | |
| 3005 | |
| 3006 | |
| 3007 | (defun ediff-highlight-diff-in-one-buffer (n buf-type) |
| 3008 | (if (ediff-buffer-live-p (ediff-get-buffer buf-type)) |
| 3009 | (let* ((buff (ediff-get-buffer buf-type)) |
| 3010 | (last (ediff-with-current-buffer buff (point-max))) |
| 3011 | (begin (ediff-get-diff-posn buf-type 'beg n)) |
| 3012 | (end (ediff-get-diff-posn buf-type 'end n)) |
| 3013 | (xtra (if (equal begin end) 1 0)) |
| 3014 | (end-hilit (min last (+ end xtra))) |
| 3015 | (current-diff-overlay |
| 3016 | (symbol-value |
| 3017 | (ediff-get-symbol-from-alist |
| 3018 | buf-type ediff-current-diff-overlay-alist)))) |
| 3019 | |
| 3020 | (if (featurep 'xemacs) |
| 3021 | (ediff-move-overlay current-diff-overlay begin end-hilit) |
| 3022 | (ediff-move-overlay current-diff-overlay begin end-hilit buff)) |
| 3023 | (ediff-overlay-put current-diff-overlay 'priority |
| 3024 | (ediff-highest-priority begin end-hilit buff)) |
| 3025 | (ediff-overlay-put current-diff-overlay 'ediff-diff-num n) |
| 3026 | |
| 3027 | ;; unhighlight the background overlay for diff n so it won't |
| 3028 | ;; interfere with the current diff overlay |
| 3029 | (ediff-set-overlay-face (ediff-get-diff-overlay n buf-type) nil) |
| 3030 | ))) |
| 3031 | |
| 3032 | |
| 3033 | (defun ediff-unhighlight-diff-in-one-buffer (buf-type) |
| 3034 | (if (ediff-buffer-live-p (ediff-get-buffer buf-type)) |
| 3035 | (let ((current-diff-overlay |
| 3036 | (symbol-value |
| 3037 | (ediff-get-symbol-from-alist |
| 3038 | buf-type ediff-current-diff-overlay-alist))) |
| 3039 | (overlay |
| 3040 | (ediff-get-diff-overlay ediff-current-difference buf-type)) |
| 3041 | ) |
| 3042 | |
| 3043 | (ediff-move-overlay current-diff-overlay 1 1) |
| 3044 | |
| 3045 | ;; rehighlight the overlay in the background of the |
| 3046 | ;; current difference region |
| 3047 | (ediff-set-overlay-face |
| 3048 | overlay |
| 3049 | (if (and (ediff-has-face-support-p) |
| 3050 | ediff-use-faces ediff-highlight-all-diffs) |
| 3051 | (ediff-background-face buf-type ediff-current-difference))) |
| 3052 | ))) |
| 3053 | |
| 3054 | (defun ediff-unhighlight-diffs-totally-in-one-buffer (buf-type) |
| 3055 | (ediff-unselect-and-select-difference -1) |
| 3056 | (if (and (ediff-has-face-support-p) ediff-use-faces) |
| 3057 | (let* ((inhibit-quit t) |
| 3058 | (current-diff-overlay-var |
| 3059 | (ediff-get-symbol-from-alist |
| 3060 | buf-type ediff-current-diff-overlay-alist)) |
| 3061 | (current-diff-overlay (symbol-value current-diff-overlay-var))) |
| 3062 | (ediff-paint-background-regions 'unhighlight) |
| 3063 | (if (ediff-overlayp current-diff-overlay) |
| 3064 | (ediff-delete-overlay current-diff-overlay)) |
| 3065 | (set current-diff-overlay-var nil) |
| 3066 | ))) |
| 3067 | |
| 3068 | |
| 3069 | (defun ediff-highlight-diff (n) |
| 3070 | "Put face on diff N. Invoked for X displays only." |
| 3071 | (ediff-highlight-diff-in-one-buffer n 'A) |
| 3072 | (ediff-highlight-diff-in-one-buffer n 'B) |
| 3073 | (ediff-highlight-diff-in-one-buffer n 'C) |
| 3074 | (ediff-highlight-diff-in-one-buffer n 'Ancestor) |
| 3075 | ) |
| 3076 | |
| 3077 | |
| 3078 | (defun ediff-unhighlight-diff () |
| 3079 | "Remove overlays from buffers A, B, and C." |
| 3080 | (ediff-unhighlight-diff-in-one-buffer 'A) |
| 3081 | (ediff-unhighlight-diff-in-one-buffer 'B) |
| 3082 | (ediff-unhighlight-diff-in-one-buffer 'C) |
| 3083 | (ediff-unhighlight-diff-in-one-buffer 'Ancestor) |
| 3084 | ) |
| 3085 | |
| 3086 | ;; delete highlighting overlays, restore faces to their original form |
| 3087 | (defun ediff-unhighlight-diffs-totally () |
| 3088 | (ediff-unhighlight-diffs-totally-in-one-buffer 'A) |
| 3089 | (ediff-unhighlight-diffs-totally-in-one-buffer 'B) |
| 3090 | (ediff-unhighlight-diffs-totally-in-one-buffer 'C) |
| 3091 | (ediff-unhighlight-diffs-totally-in-one-buffer 'Ancestor) |
| 3092 | ) |
| 3093 | |
| 3094 | |
| 3095 | ;; for compatibility |
| 3096 | (defmacro ediff-minibuffer-with-setup-hook (fun &rest body) |
| 3097 | `(if (fboundp 'minibuffer-with-setup-hook) |
| 3098 | (minibuffer-with-setup-hook ,fun ,@body) |
| 3099 | ,@body)) |
| 3100 | |
| 3101 | ;; This is adapted from a similar function in `emerge.el'. |
| 3102 | ;; PROMPT should not have a trailing ': ', so that it can be modified |
| 3103 | ;; according to context. |
| 3104 | ;; If DEFAULT-FILE is set, it should be used as the default value. |
| 3105 | ;; If DEFAULT-DIR is non-nil, use it as the default directory. |
| 3106 | ;; Otherwise, use the value of Emacs' variable `default-directory.' |
| 3107 | (defun ediff-read-file-name (prompt default-dir default-file &optional no-dirs) |
| 3108 | ;; hack default-dir if it is not set |
| 3109 | (setq default-dir |
| 3110 | (file-name-as-directory |
| 3111 | (ediff-abbreviate-file-name |
| 3112 | (expand-file-name (or default-dir |
| 3113 | (and default-file |
| 3114 | (file-name-directory default-file)) |
| 3115 | default-directory))))) |
| 3116 | |
| 3117 | ;; strip the directory from default-file |
| 3118 | (if default-file |
| 3119 | (setq default-file (file-name-nondirectory default-file))) |
| 3120 | (if (string= default-file "") |
| 3121 | (setq default-file nil)) |
| 3122 | |
| 3123 | (let ((defaults (and (fboundp 'dired-dwim-target-defaults) |
| 3124 | (dired-dwim-target-defaults |
| 3125 | (and default-file (list default-file)) |
| 3126 | default-dir))) |
| 3127 | f) |
| 3128 | (setq f (ediff-minibuffer-with-setup-hook |
| 3129 | (lambda () (when defaults |
| 3130 | (setq minibuffer-default defaults))) |
| 3131 | (read-file-name |
| 3132 | (format "%s%s " |
| 3133 | prompt |
| 3134 | (cond (default-file |
| 3135 | (concat " (default " default-file "):")) |
| 3136 | (t (concat " (default " default-dir "):")))) |
| 3137 | default-dir |
| 3138 | (or default-file default-dir) |
| 3139 | t ; must match, no-confirm |
| 3140 | (if default-file (file-name-directory default-file))))) |
| 3141 | (setq f (expand-file-name f default-dir)) |
| 3142 | ;; If user entered a directory name, expand the default file in that |
| 3143 | ;; directory. This allows the user to enter a directory name for the |
| 3144 | ;; B-file and diff against the default-file in that directory instead |
| 3145 | ;; of a DIRED listing! |
| 3146 | (if (and (file-directory-p f) default-file) |
| 3147 | (setq f (expand-file-name |
| 3148 | (file-name-nondirectory default-file) f))) |
| 3149 | (if (and no-dirs (file-directory-p f)) |
| 3150 | (error "File %s is a directory" f)) |
| 3151 | f)) |
| 3152 | |
| 3153 | ;; If PREFIX is given, then it is used as a prefix for the temp file |
| 3154 | ;; name. Otherwise, `ediff' is used. If FILE is given, use this |
| 3155 | ;; file and don't create a new one. |
| 3156 | ;; In MS-DOS, make sure the prefix isn't too long, or else |
| 3157 | ;; `make-temp-name' isn't guaranteed to return a unique filename. |
| 3158 | ;; Also, save buffer from START to END in the file. |
| 3159 | ;; START defaults to (point-min), END to (point-max) |
| 3160 | (defun ediff-make-temp-file (buff &optional prefix given-file start end) |
| 3161 | (let* ((p (ediff-convert-standard-filename (or prefix "ediff"))) |
| 3162 | (short-p p) |
| 3163 | (coding-system-for-write ediff-coding-system-for-write) |
| 3164 | f short-f) |
| 3165 | (if (and (fboundp 'msdos-long-file-names) |
| 3166 | (not (msdos-long-file-names)) |
| 3167 | (> (length p) 2)) |
| 3168 | (setq short-p (substring p 0 2))) |
| 3169 | |
| 3170 | (setq f (concat ediff-temp-file-prefix p) |
| 3171 | short-f (concat ediff-temp-file-prefix short-p) |
| 3172 | f (cond (given-file) |
| 3173 | ((find-file-name-handler f 'insert-file-contents) |
| 3174 | ;; to thwart file handlers in write-region, e.g., if file |
| 3175 | ;; name ends with .Z or .gz |
| 3176 | ;; This is needed so that patches produced by ediff will |
| 3177 | ;; have more meaningful names |
| 3178 | (ediff-make-empty-tmp-file short-f)) |
| 3179 | (prefix |
| 3180 | ;; Prefix is most often the same as the file name for the |
| 3181 | ;; variant. Here we are trying to use the original file |
| 3182 | ;; name but in the temp directory. |
| 3183 | (ediff-make-empty-tmp-file f 'keep-name)) |
| 3184 | (t |
| 3185 | ;; If don't care about name, add some random stuff |
| 3186 | ;; to proposed file name. |
| 3187 | (ediff-make-empty-tmp-file short-f)))) |
| 3188 | |
| 3189 | ;; create the file |
| 3190 | (ediff-with-current-buffer buff |
| 3191 | (write-region (if start start (point-min)) |
| 3192 | (if end end (point-max)) |
| 3193 | f |
| 3194 | nil ; don't append---erase |
| 3195 | 'no-message) |
| 3196 | (set-file-modes f ediff-temp-file-mode) |
| 3197 | (expand-file-name f)))) |
| 3198 | |
| 3199 | ;; Create a temporary file. |
| 3200 | ;; The returned file name (created by appending some random characters at the |
| 3201 | ;; end of PROPOSED-NAME is guaranteed to point to a newly created empty file. |
| 3202 | ;; This is a replacement for make-temp-name, which eliminates a security hole. |
| 3203 | ;; If KEEP-PROPOSED-NAME isn't nil, try to keep PROPOSED-NAME, unless such file |
| 3204 | ;; already exists. |
| 3205 | ;; It is a modified version of make-temp-file in emacs 20.5 |
| 3206 | (defun ediff-make-empty-tmp-file (proposed-name &optional keep-proposed-name) |
| 3207 | (let ((file proposed-name)) |
| 3208 | (while (condition-case () |
| 3209 | (progn |
| 3210 | (if (or (file-exists-p file) (not keep-proposed-name)) |
| 3211 | (setq file (make-temp-name proposed-name))) |
| 3212 | ;; the with-temp-buffer thing is a workaround for an XEmacs |
| 3213 | ;; bug: write-region complains that we are trying to visit a |
| 3214 | ;; file in an indirect buffer, failing to notice that the |
| 3215 | ;; VISIT flag is unset and that we are actually writing from a |
| 3216 | ;; string and not from any buffer. |
| 3217 | (with-temp-buffer |
| 3218 | (write-region "" nil file nil 'silent nil 'excl)) |
| 3219 | nil) |
| 3220 | (file-already-exists t)) |
| 3221 | ;; the file was somehow created by someone else between |
| 3222 | ;; `make-temp-name' and `write-region', let's try again. |
| 3223 | nil) |
| 3224 | file)) |
| 3225 | |
| 3226 | |
| 3227 | ;; Quote metacharacters (using \) when executing diff in Unix, but not in |
| 3228 | ;; EMX OS/2 |
| 3229 | ;;(defun ediff-protect-metachars (str) |
| 3230 | ;; (or (memq system-type '(emx)) |
| 3231 | ;; (let ((limit 0)) |
| 3232 | ;; (while (string-match ediff-metachars str limit) |
| 3233 | ;; (setq str (concat (substring str 0 (match-beginning 0)) |
| 3234 | ;; "\\" |
| 3235 | ;; (substring str (match-beginning 0)))) |
| 3236 | ;; (setq limit (1+ (match-end 0)))))) |
| 3237 | ;; str) |
| 3238 | |
| 3239 | ;; Make sure the current buffer (for a file) has the same contents as the |
| 3240 | ;; file on disk, and attempt to remedy the situation if not. |
| 3241 | ;; Signal an error if we can't make them the same, or the user doesn't want |
| 3242 | ;; to do what is necessary to make them the same. |
| 3243 | ;; Also, Ediff always offers to revert obsolete buffers, whether they |
| 3244 | ;; are modified or not. |
| 3245 | (defun ediff-verify-file-buffer (&optional file-magic) |
| 3246 | ;; First check if the file has been modified since the buffer visited it. |
| 3247 | (if (verify-visited-file-modtime (current-buffer)) |
| 3248 | (if (buffer-modified-p) |
| 3249 | ;; If buffer is not obsolete and is modified, offer to save |
| 3250 | (if (yes-or-no-p |
| 3251 | (format "Buffer %s has been modified. Save it in file %s? " |
| 3252 | (buffer-name) |
| 3253 | buffer-file-name)) |
| 3254 | (condition-case nil |
| 3255 | (save-buffer) |
| 3256 | (error |
| 3257 | (beep) |
| 3258 | (message "Couldn't save %s" buffer-file-name))) |
| 3259 | (error "Buffer is out of sync for file %s" buffer-file-name)) |
| 3260 | ;; If buffer is not obsolete and is not modified, do nothing |
| 3261 | nil) |
| 3262 | ;; If buffer is obsolete, offer to revert |
| 3263 | (if (yes-or-no-p |
| 3264 | (format "File %s was modified since visited by buffer %s. REVERT file %s? " |
| 3265 | buffer-file-name |
| 3266 | (buffer-name) |
| 3267 | buffer-file-name)) |
| 3268 | (progn |
| 3269 | (if file-magic |
| 3270 | (erase-buffer)) |
| 3271 | (revert-buffer t t)) |
| 3272 | (error "Buffer out of sync for file %s" buffer-file-name)))) |
| 3273 | |
| 3274 | ;; if there is another buffer visiting the file of the merge buffer, offer to |
| 3275 | ;; save and delete the buffer; else bark |
| 3276 | (defun ediff-verify-file-merge-buffer (file) |
| 3277 | (let ((buff (if (stringp file) (find-buffer-visiting file))) |
| 3278 | warn-message) |
| 3279 | (or (null buff) |
| 3280 | (progn |
| 3281 | (setq warn-message |
| 3282 | (format "Buffer %s is visiting %s. Save and kill the buffer? " |
| 3283 | (buffer-name buff) file)) |
| 3284 | (with-output-to-temp-buffer ediff-msg-buffer |
| 3285 | (princ "\n\n") |
| 3286 | (princ warn-message) |
| 3287 | (princ "\n\n")) |
| 3288 | (if (y-or-n-p |
| 3289 | (message "%s" warn-message)) |
| 3290 | (with-current-buffer buff |
| 3291 | (save-buffer) |
| 3292 | (kill-buffer (current-buffer))) |
| 3293 | (error "Too dangerous to merge versions of a file visited by another buffer")))) |
| 3294 | )) |
| 3295 | |
| 3296 | |
| 3297 | |
| 3298 | (defun ediff-filename-magic-p (file) |
| 3299 | (or (ediff-file-compressed-p file) |
| 3300 | (ediff-file-remote-p file))) |
| 3301 | |
| 3302 | |
| 3303 | (defun ediff-save-buffer (arg) |
| 3304 | "Safe way of saving buffers A, B, C, and the diff output. |
| 3305 | `wa' saves buffer A, `wb' saves buffer B, `wc' saves buffer C, |
| 3306 | and `wd' saves the diff output. |
| 3307 | |
| 3308 | With prefix argument, `wd' saves plain diff output. |
| 3309 | Without an argument, it saves customized diff argument, if available |
| 3310 | \(and plain output, if customized output was not generated\)." |
| 3311 | (interactive "P") |
| 3312 | (ediff-barf-if-not-control-buffer) |
| 3313 | (ediff-compute-custom-diffs-maybe) |
| 3314 | (ediff-with-current-buffer |
| 3315 | (cond ((memq (ediff-last-command-char) '(?a ?b ?c)) |
| 3316 | (ediff-get-buffer |
| 3317 | (ediff-char-to-buftype (ediff-last-command-char)))) |
| 3318 | ((eq (ediff-last-command-char) ?d) |
| 3319 | (message "Saving diff output ...") |
| 3320 | (sit-for 1) ; let the user see the message |
| 3321 | (cond ((and arg (ediff-buffer-live-p ediff-diff-buffer)) |
| 3322 | ediff-diff-buffer) |
| 3323 | ((ediff-buffer-live-p ediff-custom-diff-buffer) |
| 3324 | ediff-custom-diff-buffer) |
| 3325 | ((ediff-buffer-live-p ediff-diff-buffer) |
| 3326 | ediff-diff-buffer) |
| 3327 | (t (error "Output from `diff' not found")))) |
| 3328 | ) |
| 3329 | (let ((window-min-height 2)) |
| 3330 | (save-buffer)))) |
| 3331 | |
| 3332 | |
| 3333 | ;; idea suggested by Hannu Koivisto <azure@iki.fi> |
| 3334 | (defun ediff-clone-buffer-for-region-comparison (buff region-name) |
| 3335 | (let ((cloned-buff (ediff-make-cloned-buffer buff region-name)) |
| 3336 | (pop-up-windows t) |
| 3337 | wind |
| 3338 | other-wind |
| 3339 | msg-buf) |
| 3340 | (ediff-with-current-buffer cloned-buff |
| 3341 | (setq ediff-temp-indirect-buffer t)) |
| 3342 | (pop-to-buffer cloned-buff) |
| 3343 | (setq wind (ediff-get-visible-buffer-window cloned-buff)) |
| 3344 | (select-window wind) |
| 3345 | (delete-other-windows) |
| 3346 | (ediff-activate-mark) |
| 3347 | (split-window-vertically) |
| 3348 | (ediff-select-lowest-window) |
| 3349 | (setq other-wind (selected-window)) |
| 3350 | (with-temp-buffer |
| 3351 | (erase-buffer) |
| 3352 | (insert |
| 3353 | (format "\n ******* Mark a region in buffer %s (or confirm the existing one) *******\n" |
| 3354 | (buffer-name cloned-buff))) |
| 3355 | (insert |
| 3356 | (ediff-with-current-buffer buff |
| 3357 | (format "\n\t When done, type %s Use %s to abort\n " |
| 3358 | (ediff-format-bindings-of 'exit-recursive-edit) |
| 3359 | (ediff-format-bindings-of 'abort-recursive-edit)))) |
| 3360 | (goto-char (point-min)) |
| 3361 | (setq msg-buf (current-buffer)) |
| 3362 | (set-window-buffer other-wind msg-buf) |
| 3363 | (shrink-window-if-larger-than-buffer) |
| 3364 | (if (window-live-p wind) |
| 3365 | (select-window wind)) |
| 3366 | (condition-case nil |
| 3367 | (recursive-edit) |
| 3368 | (quit |
| 3369 | (ediff-kill-buffer-carefully cloned-buff))) |
| 3370 | ) |
| 3371 | cloned-buff)) |
| 3372 | |
| 3373 | |
| 3374 | (defun ediff-clone-buffer-for-window-comparison (buff wind region-name) |
| 3375 | (let ((cloned-buff (ediff-make-cloned-buffer buff region-name))) |
| 3376 | (ediff-with-current-buffer cloned-buff |
| 3377 | (setq ediff-temp-indirect-buffer t)) |
| 3378 | (set-window-buffer wind cloned-buff) |
| 3379 | cloned-buff)) |
| 3380 | |
| 3381 | (defun ediff-clone-buffer-for-current-diff-comparison (buff buf-type reg-name) |
| 3382 | (let ((cloned-buff (ediff-make-cloned-buffer buff reg-name)) |
| 3383 | (reg-start (ediff-get-diff-posn buf-type 'beg)) |
| 3384 | (reg-end (ediff-get-diff-posn buf-type 'end))) |
| 3385 | (ediff-with-current-buffer cloned-buff |
| 3386 | ;; set region to be the current diff region |
| 3387 | (goto-char reg-start) |
| 3388 | (set-mark reg-end) |
| 3389 | (setq ediff-temp-indirect-buffer t)) |
| 3390 | cloned-buff)) |
| 3391 | |
| 3392 | |
| 3393 | |
| 3394 | (defun ediff-make-cloned-buffer (buff region-name) |
| 3395 | (ediff-make-indirect-buffer |
| 3396 | buff (generate-new-buffer-name |
| 3397 | (concat (if (stringp buff) buff (buffer-name buff)) region-name)))) |
| 3398 | |
| 3399 | |
| 3400 | (defun ediff-make-indirect-buffer (base-buf indirect-buf-name) |
| 3401 | (if (featurep 'xemacs) |
| 3402 | (make-indirect-buffer base-buf indirect-buf-name) |
| 3403 | (make-indirect-buffer base-buf indirect-buf-name 'clone))) |
| 3404 | |
| 3405 | |
| 3406 | ;; This function operates only from an ediff control buffer |
| 3407 | (defun ediff-compute-custom-diffs-maybe () |
| 3408 | (let ((buf-A-file-name (buffer-file-name ediff-buffer-A)) |
| 3409 | (buf-B-file-name (buffer-file-name ediff-buffer-B)) |
| 3410 | file-A file-B) |
| 3411 | (unless (and buf-A-file-name |
| 3412 | (file-exists-p buf-A-file-name) |
| 3413 | (not (ediff-file-remote-p buf-A-file-name))) |
| 3414 | (setq file-A (ediff-make-temp-file ediff-buffer-A))) |
| 3415 | (unless (and buf-B-file-name |
| 3416 | (file-exists-p buf-B-file-name) |
| 3417 | (not (ediff-file-remote-p buf-B-file-name))) |
| 3418 | (setq file-B (ediff-make-temp-file ediff-buffer-B))) |
| 3419 | (or (ediff-buffer-live-p ediff-custom-diff-buffer) |
| 3420 | (setq ediff-custom-diff-buffer |
| 3421 | (get-buffer-create |
| 3422 | (ediff-unique-buffer-name "*ediff-custom-diff" "*")))) |
| 3423 | (ediff-with-current-buffer ediff-custom-diff-buffer |
| 3424 | (setq buffer-read-only nil) |
| 3425 | (erase-buffer)) |
| 3426 | (ediff-exec-process |
| 3427 | ediff-custom-diff-program ediff-custom-diff-buffer 'synchronize |
| 3428 | ediff-custom-diff-options |
| 3429 | (or file-A buf-A-file-name) |
| 3430 | (or file-B buf-B-file-name)) |
| 3431 | ;; put the diff file in diff-mode, if it is available |
| 3432 | (if (fboundp 'diff-mode) |
| 3433 | (with-current-buffer ediff-custom-diff-buffer |
| 3434 | (diff-mode))) |
| 3435 | (and file-A (file-exists-p file-A) (delete-file file-A)) |
| 3436 | (and file-B (file-exists-p file-B) (delete-file file-B)) |
| 3437 | )) |
| 3438 | |
| 3439 | (defun ediff-show-diff-output (arg) |
| 3440 | (interactive "P") |
| 3441 | (ediff-barf-if-not-control-buffer) |
| 3442 | (ediff-compute-custom-diffs-maybe) |
| 3443 | (save-excursion |
| 3444 | (ediff-skip-unsuitable-frames ' ok-unsplittable)) |
| 3445 | (let ((buf (cond ((and arg (ediff-buffer-live-p ediff-diff-buffer)) |
| 3446 | ediff-diff-buffer) |
| 3447 | ((ediff-buffer-live-p ediff-custom-diff-buffer) |
| 3448 | ediff-custom-diff-buffer) |
| 3449 | ((ediff-buffer-live-p ediff-diff-buffer) |
| 3450 | ediff-diff-buffer) |
| 3451 | (t |
| 3452 | (beep) |
| 3453 | (message "Output from `diff' not found") |
| 3454 | nil)))) |
| 3455 | (if buf |
| 3456 | (progn |
| 3457 | (ediff-with-current-buffer buf |
| 3458 | (goto-char (point-min))) |
| 3459 | (switch-to-buffer buf) |
| 3460 | (raise-frame (selected-frame))))) |
| 3461 | (if (frame-live-p ediff-control-frame) |
| 3462 | (ediff-reset-mouse ediff-control-frame)) |
| 3463 | (if (window-live-p ediff-control-window) |
| 3464 | (select-window ediff-control-window))) |
| 3465 | |
| 3466 | |
| 3467 | (defun ediff-inferior-compare-regions () |
| 3468 | "Compare regions in an active Ediff session. |
| 3469 | Like ediff-regions-linewise but is called from under an active Ediff session on |
| 3470 | the files that belong to that session. |
| 3471 | |
| 3472 | After quitting the session invoked via this function, type C-l to the parent |
| 3473 | Ediff Control Panel to restore highlighting." |
| 3474 | (interactive) |
| 3475 | (let ((answer "") |
| 3476 | (possibilities (list ?A ?B ?C)) |
| 3477 | (zmacs-regions t) |
| 3478 | use-current-diff-p |
| 3479 | begA begB endA endB bufA bufB) |
| 3480 | |
| 3481 | (if (ediff-valid-difference-p ediff-current-difference) |
| 3482 | (progn |
| 3483 | (ediff-set-fine-diff-properties ediff-current-difference 'default) |
| 3484 | (ediff-unhighlight-diff))) |
| 3485 | (ediff-paint-background-regions 'unhighlight) |
| 3486 | |
| 3487 | (cond ((ediff-merge-job) |
| 3488 | (setq bufB ediff-buffer-C) |
| 3489 | ;; ask which buffer to compare to the merge buffer |
| 3490 | (while (cond ((eq answer ?A) |
| 3491 | (setq bufA ediff-buffer-A |
| 3492 | possibilities '(?B)) |
| 3493 | nil) |
| 3494 | ((eq answer ?B) |
| 3495 | (setq bufA ediff-buffer-B |
| 3496 | possibilities '(?A)) |
| 3497 | nil) |
| 3498 | ((equal answer "")) |
| 3499 | (t (beep 1) |
| 3500 | (message "Valid values are A or B") |
| 3501 | (sit-for 2) |
| 3502 | t)) |
| 3503 | (let ((cursor-in-echo-area t)) |
| 3504 | (message |
| 3505 | "Which buffer to compare to the merge buffer (A or B)? ") |
| 3506 | (setq answer (capitalize (read-char-exclusive)))))) |
| 3507 | |
| 3508 | ((ediff-3way-comparison-job) |
| 3509 | ;; ask which two buffers to compare |
| 3510 | (while (cond ((memq answer possibilities) |
| 3511 | (setq possibilities (delq answer possibilities)) |
| 3512 | (setq bufA |
| 3513 | (eval |
| 3514 | (ediff-get-symbol-from-alist |
| 3515 | answer ediff-buffer-alist))) |
| 3516 | nil) |
| 3517 | ((equal answer "")) |
| 3518 | (t (beep 1) |
| 3519 | (message |
| 3520 | "Valid values are %s" |
| 3521 | (mapconcat 'char-to-string possibilities " or ")) |
| 3522 | (sit-for 2) |
| 3523 | t)) |
| 3524 | (let ((cursor-in-echo-area t)) |
| 3525 | (message "Enter the 1st buffer you want to compare (%s): " |
| 3526 | (mapconcat 'char-to-string possibilities " or ")) |
| 3527 | (setq answer (capitalize (read-char-exclusive))))) |
| 3528 | (setq answer "") ; silence error msg |
| 3529 | (while (cond ((memq answer possibilities) |
| 3530 | (setq possibilities (delq answer possibilities)) |
| 3531 | (setq bufB |
| 3532 | (eval |
| 3533 | (ediff-get-symbol-from-alist |
| 3534 | answer ediff-buffer-alist))) |
| 3535 | nil) |
| 3536 | ((equal answer "")) |
| 3537 | (t (beep 1) |
| 3538 | (message |
| 3539 | "Valid values are %s" |
| 3540 | (mapconcat 'char-to-string possibilities " or ")) |
| 3541 | (sit-for 2) |
| 3542 | t)) |
| 3543 | (let ((cursor-in-echo-area t)) |
| 3544 | (message "Enter the 2nd buffer you want to compare (%s): " |
| 3545 | (mapconcat 'char-to-string possibilities "/")) |
| 3546 | (setq answer (capitalize (read-char-exclusive)))))) |
| 3547 | (t ; 2way comparison |
| 3548 | (setq bufA ediff-buffer-A |
| 3549 | bufB ediff-buffer-B |
| 3550 | possibilities nil))) |
| 3551 | |
| 3552 | (if (and (ediff-valid-difference-p ediff-current-difference) |
| 3553 | (y-or-n-p "Compare currently highlighted difference regions? ")) |
| 3554 | (setq use-current-diff-p t)) |
| 3555 | |
| 3556 | (setq bufA (if use-current-diff-p |
| 3557 | (ediff-clone-buffer-for-current-diff-comparison |
| 3558 | bufA 'A "-Region.A-") |
| 3559 | (ediff-clone-buffer-for-region-comparison bufA "-Region.A-"))) |
| 3560 | (ediff-with-current-buffer bufA |
| 3561 | (setq begA (region-beginning) |
| 3562 | endA (region-end)) |
| 3563 | (goto-char begA) |
| 3564 | (beginning-of-line) |
| 3565 | (setq begA (point)) |
| 3566 | (goto-char endA) |
| 3567 | (end-of-line) |
| 3568 | (or (eobp) (forward-char)) ; include the newline char |
| 3569 | (setq endA (point))) |
| 3570 | |
| 3571 | (setq bufB (if use-current-diff-p |
| 3572 | (ediff-clone-buffer-for-current-diff-comparison |
| 3573 | bufB 'B "-Region.B-") |
| 3574 | (ediff-clone-buffer-for-region-comparison bufB "-Region.B-"))) |
| 3575 | (ediff-with-current-buffer bufB |
| 3576 | (setq begB (region-beginning) |
| 3577 | endB (region-end)) |
| 3578 | (goto-char begB) |
| 3579 | (beginning-of-line) |
| 3580 | (setq begB (point)) |
| 3581 | (goto-char endB) |
| 3582 | (end-of-line) |
| 3583 | (or (eobp) (forward-char)) ; include the newline char |
| 3584 | (setq endB (point))) |
| 3585 | |
| 3586 | |
| 3587 | (ediff-regions-internal |
| 3588 | bufA begA endA bufB begB endB |
| 3589 | nil ; setup-hook |
| 3590 | (if use-current-diff-p ; job name |
| 3591 | 'ediff-regions-wordwise |
| 3592 | 'ediff-regions-linewise) |
| 3593 | (if use-current-diff-p ; word mode, if diffing current diff |
| 3594 | t nil) |
| 3595 | ;; setup param to pass to ediff-setup |
| 3596 | (list (cons 'ediff-split-window-function ediff-split-window-function))) |
| 3597 | )) |
| 3598 | |
| 3599 | |
| 3600 | |
| 3601 | (defun ediff-remove-flags-from-buffer (buffer overlay) |
| 3602 | (ediff-with-current-buffer buffer |
| 3603 | (let ((inhibit-read-only t)) |
| 3604 | (if (featurep 'xemacs) |
| 3605 | (ediff-overlay-put overlay 'begin-glyph nil) |
| 3606 | (ediff-overlay-put overlay 'before-string nil)) |
| 3607 | |
| 3608 | (if (featurep 'xemacs) |
| 3609 | (ediff-overlay-put overlay 'end-glyph nil) |
| 3610 | (ediff-overlay-put overlay 'after-string nil)) |
| 3611 | ))) |
| 3612 | |
| 3613 | |
| 3614 | |
| 3615 | (defun ediff-place-flags-in-buffer (buf-type buffer ctl-buffer diff) |
| 3616 | (ediff-with-current-buffer buffer |
| 3617 | (ediff-place-flags-in-buffer1 buf-type ctl-buffer diff))) |
| 3618 | |
| 3619 | |
| 3620 | (defun ediff-place-flags-in-buffer1 (buf-type ctl-buffer diff-no) |
| 3621 | (let* ((curr-overl (ediff-with-current-buffer ctl-buffer |
| 3622 | (ediff-get-diff-overlay diff-no buf-type))) |
| 3623 | (before (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer)) |
| 3624 | after beg-of-line flag) |
| 3625 | |
| 3626 | ;; insert flag before the difference |
| 3627 | (goto-char before) |
| 3628 | (setq beg-of-line (bolp)) |
| 3629 | |
| 3630 | (setq flag (ediff-with-current-buffer ctl-buffer |
| 3631 | (if (eq ediff-highlighting-style 'ascii) |
| 3632 | (if beg-of-line |
| 3633 | ediff-before-flag-bol ediff-before-flag-mol)))) |
| 3634 | |
| 3635 | ;; insert the flag itself |
| 3636 | (if (featurep 'xemacs) |
| 3637 | (ediff-overlay-put curr-overl 'begin-glyph flag) |
| 3638 | (ediff-overlay-put curr-overl 'before-string flag)) |
| 3639 | |
| 3640 | ;; insert the flag after the difference |
| 3641 | ;; `after' must be set here, after the before-flag was inserted |
| 3642 | (setq after (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer)) |
| 3643 | (goto-char after) |
| 3644 | (setq beg-of-line (bolp)) |
| 3645 | |
| 3646 | (setq flag (ediff-with-current-buffer ctl-buffer |
| 3647 | (if (eq ediff-highlighting-style 'ascii) |
| 3648 | (if beg-of-line |
| 3649 | ediff-after-flag-eol ediff-after-flag-mol)))) |
| 3650 | |
| 3651 | ;; insert the flag itself |
| 3652 | (if (featurep 'xemacs) |
| 3653 | (ediff-overlay-put curr-overl 'end-glyph flag) |
| 3654 | (ediff-overlay-put curr-overl 'after-string flag)) |
| 3655 | )) |
| 3656 | |
| 3657 | |
| 3658 | ;;; Some diff region tests |
| 3659 | |
| 3660 | ;; t if diff region is empty. |
| 3661 | ;; In case of buffer C, t also if it is not a 3way |
| 3662 | ;; comparison job (merging jobs return t as well). |
| 3663 | (defun ediff-empty-diff-region-p (n buf-type) |
| 3664 | (if (eq buf-type 'C) |
| 3665 | (or (not ediff-3way-comparison-job) |
| 3666 | (= (ediff-get-diff-posn 'C 'beg n) |
| 3667 | (ediff-get-diff-posn 'C 'end n))) |
| 3668 | (= (ediff-get-diff-posn buf-type 'beg n) |
| 3669 | (ediff-get-diff-posn buf-type 'end n)))) |
| 3670 | |
| 3671 | ;; Test if diff region is white space only. |
| 3672 | ;; If 2-way job and buf-type = C, then returns t. |
| 3673 | (defun ediff-whitespace-diff-region-p (n buf-type) |
| 3674 | (or (and (eq buf-type 'C) (not ediff-3way-job)) |
| 3675 | (ediff-empty-diff-region-p n buf-type) |
| 3676 | (let ((beg (ediff-get-diff-posn buf-type 'beg n)) |
| 3677 | (end (ediff-get-diff-posn buf-type 'end n))) |
| 3678 | (ediff-with-current-buffer (ediff-get-buffer buf-type) |
| 3679 | (save-excursion |
| 3680 | (goto-char beg) |
| 3681 | (skip-chars-forward ediff-whitespace) |
| 3682 | (>= (point) end)))))) |
| 3683 | |
| 3684 | |
| 3685 | (defun ediff-get-region-contents (n buf-type ctrl-buf &optional start end) |
| 3686 | (ediff-with-current-buffer |
| 3687 | (ediff-with-current-buffer ctrl-buf (ediff-get-buffer buf-type)) |
| 3688 | (buffer-substring |
| 3689 | (or start (ediff-get-diff-posn buf-type 'beg n ctrl-buf)) |
| 3690 | (or end (ediff-get-diff-posn buf-type 'end n ctrl-buf))))) |
| 3691 | |
| 3692 | ;; Returns positions of difference sectors in the BUF-TYPE buffer. |
| 3693 | ;; BUF-TYPE should be a symbol -- `A', `B', or `C'. |
| 3694 | ;; POS is either `beg' or `end'--it specifies whether you want the position at |
| 3695 | ;; the beginning of a difference or at the end. |
| 3696 | ;; |
| 3697 | ;; The optional argument N says which difference (default: |
| 3698 | ;; `ediff-current-difference'). N is the internal difference number (1- what |
| 3699 | ;; the user sees). The optional argument CONTROL-BUF says |
| 3700 | ;; which control buffer is in effect in case it is not the current |
| 3701 | ;; buffer. |
| 3702 | (defun ediff-get-diff-posn (buf-type pos &optional n control-buf) |
| 3703 | (let (diff-overlay) |
| 3704 | (or control-buf |
| 3705 | (setq control-buf (current-buffer))) |
| 3706 | |
| 3707 | (ediff-with-current-buffer control-buf |
| 3708 | (or n (setq n ediff-current-difference)) |
| 3709 | (if (or (< n 0) (>= n ediff-number-of-differences)) |
| 3710 | (if (> ediff-number-of-differences 0) |
| 3711 | (error ediff-BAD-DIFF-NUMBER |
| 3712 | this-command (1+ n) ediff-number-of-differences) |
| 3713 | (error ediff-NO-DIFFERENCES))) |
| 3714 | (setq diff-overlay (ediff-get-diff-overlay n buf-type))) |
| 3715 | (if (not (ediff-buffer-live-p (ediff-overlay-buffer diff-overlay))) |
| 3716 | (error ediff-KILLED-VITAL-BUFFER)) |
| 3717 | (if (eq pos 'beg) |
| 3718 | (ediff-overlay-start diff-overlay) |
| 3719 | (ediff-overlay-end diff-overlay)) |
| 3720 | )) |
| 3721 | |
| 3722 | |
| 3723 | ;; Restore highlighting to what it should be according to ediff-use-faces, |
| 3724 | ;; ediff-highlighting-style, and ediff-highlight-all-diffs variables. |
| 3725 | (defun ediff-restore-highlighting (&optional ctl-buf) |
| 3726 | (ediff-with-current-buffer (or ctl-buf (current-buffer)) |
| 3727 | (if (and (ediff-has-face-support-p) |
| 3728 | ediff-use-faces |
| 3729 | ediff-highlight-all-diffs) |
| 3730 | (ediff-paint-background-regions)) |
| 3731 | (ediff-select-difference ediff-current-difference))) |
| 3732 | |
| 3733 | |
| 3734 | |
| 3735 | ;; null out difference overlays so they won't slow down future |
| 3736 | ;; editing operations |
| 3737 | ;; VEC is either a difference vector or a fine-diff vector |
| 3738 | (defun ediff-clear-diff-vector (vec-var &optional fine-diffs-also) |
| 3739 | (if (vectorp (symbol-value vec-var)) |
| 3740 | (mapc (lambda (elt) |
| 3741 | (ediff-delete-overlay |
| 3742 | (ediff-get-diff-overlay-from-diff-record elt)) |
| 3743 | (if fine-diffs-also |
| 3744 | (ediff-clear-fine-diff-vector elt)) |
| 3745 | ) |
| 3746 | (symbol-value vec-var))) |
| 3747 | ;; allow them to be garbage collected |
| 3748 | (set vec-var nil)) |
| 3749 | |
| 3750 | |
| 3751 | \f |
| 3752 | ;;; Misc |
| 3753 | |
| 3754 | ;; In Emacs, this just makes overlay. In the future, when Emacs will start |
| 3755 | ;; supporting sticky overlays, this function will make a sticky overlay. |
| 3756 | ;; BEG and END are expressions telling where overlay starts. |
| 3757 | ;; If they are numbers or buffers, then all is well. Otherwise, they must |
| 3758 | ;; be expressions to be evaluated in buffer BUF in order to get the overlay |
| 3759 | ;; bounds. |
| 3760 | ;; If BUFF is not a live buffer, then return nil; otherwise, return the |
| 3761 | ;; newly created overlay. |
| 3762 | (defun ediff-make-bullet-proof-overlay (beg end buff) |
| 3763 | (if (ediff-buffer-live-p buff) |
| 3764 | (let (overl) |
| 3765 | (ediff-with-current-buffer buff |
| 3766 | (or (number-or-marker-p beg) |
| 3767 | (setq beg (eval beg))) |
| 3768 | (or (number-or-marker-p end) |
| 3769 | (setq end (eval end))) |
| 3770 | (setq overl |
| 3771 | (if (featurep 'xemacs) |
| 3772 | (make-extent beg end buff) |
| 3773 | ;; advance front and rear of the overlay |
| 3774 | (make-overlay beg end buff nil 'rear-advance))) |
| 3775 | |
| 3776 | ;; never detach |
| 3777 | (ediff-overlay-put |
| 3778 | overl (if (featurep 'emacs) 'evaporate 'detachable) nil) |
| 3779 | ;; make overlay open-ended |
| 3780 | ;; In emacs, it is made open ended at creation time |
| 3781 | (when (featurep 'xemacs) |
| 3782 | (ediff-overlay-put overl 'start-open nil) |
| 3783 | (ediff-overlay-put overl 'end-open nil)) |
| 3784 | (ediff-overlay-put overl 'ediff-diff-num 0) |
| 3785 | overl)))) |
| 3786 | |
| 3787 | |
| 3788 | (defun ediff-make-current-diff-overlay (type) |
| 3789 | (if (ediff-has-face-support-p) |
| 3790 | (let ((overlay (ediff-get-symbol-from-alist |
| 3791 | type ediff-current-diff-overlay-alist)) |
| 3792 | (buffer (ediff-get-buffer type)) |
| 3793 | (face (ediff-get-symbol-from-alist |
| 3794 | type ediff-current-diff-face-alist))) |
| 3795 | (set overlay |
| 3796 | (ediff-make-bullet-proof-overlay (point-max) (point-max) buffer)) |
| 3797 | (ediff-set-overlay-face (symbol-value overlay) face) |
| 3798 | (ediff-overlay-put (symbol-value overlay) 'ediff ediff-control-buffer)) |
| 3799 | )) |
| 3800 | |
| 3801 | |
| 3802 | ;; Like other-buffer, but prefers visible buffers and ignores temporary or |
| 3803 | ;; other insignificant buffers (those beginning with "^[ *]"). |
| 3804 | ;; Gets one arg--buffer name or a list of buffer names (it won't return |
| 3805 | ;; these buffers). |
| 3806 | ;; EXCL-BUFF-LIST is an exclusion list. |
| 3807 | (defun ediff-other-buffer (excl-buff-lst) |
| 3808 | (or (listp excl-buff-lst) (setq excl-buff-lst (list excl-buff-lst))) |
| 3809 | (let* ((all-buffers (nconc (ediff-get-selected-buffers) (buffer-list))) |
| 3810 | ;; we compute this the second time because we need to do memq on it |
| 3811 | ;; later, and nconc above will break it. Either this or use slow |
| 3812 | ;; append instead of nconc |
| 3813 | (selected-buffers (ediff-get-selected-buffers)) |
| 3814 | (prefered-buffer (car all-buffers)) |
| 3815 | visible-dired-buffers |
| 3816 | (excl-buff-name-list |
| 3817 | (mapcar |
| 3818 | (lambda (b) (cond ((stringp b) b) |
| 3819 | ((bufferp b) (buffer-name b)))) |
| 3820 | excl-buff-lst)) |
| 3821 | ;; if at least one buffer on the exclusion list is dired, then force |
| 3822 | ;; all others to be dired. This is because this means that the user |
| 3823 | ;; has already chosen a dired buffer before |
| 3824 | (use-dired-major-mode |
| 3825 | (cond ((null (ediff-buffer-live-p (car excl-buff-lst))) 'unknown) |
| 3826 | ((eq (ediff-with-current-buffer (car excl-buff-lst) major-mode) |
| 3827 | 'dired-mode) |
| 3828 | 'yes) |
| 3829 | (t 'no))) |
| 3830 | ;; significant-buffers must be visible and not belong |
| 3831 | ;; to the exclusion list `buff-list' |
| 3832 | ;; We also exclude temporary buffers, but keep mail and gnus buffers |
| 3833 | ;; Furthermore, we exclude dired buffers, unless they are the only |
| 3834 | ;; ones visible (and there are at least two of them). |
| 3835 | ;; Also, any visible window not on the exclusion list that is first in |
| 3836 | ;; the buffer list is chosen regardless. (This is because the user |
| 3837 | ;; clicked on it or did something to distinguish it). |
| 3838 | (significant-buffers |
| 3839 | (mapcar |
| 3840 | (lambda (x) |
| 3841 | (cond ((member (buffer-name x) excl-buff-name-list) nil) |
| 3842 | ((memq x selected-buffers) x) |
| 3843 | ((not (ediff-get-visible-buffer-window x)) nil) |
| 3844 | ((eq x prefered-buffer) x) |
| 3845 | ;; if prev selected buffer is dired, look only at |
| 3846 | ;; dired. |
| 3847 | ((eq use-dired-major-mode 'yes) |
| 3848 | (if (eq (ediff-with-current-buffer x major-mode) |
| 3849 | 'dired-mode) |
| 3850 | x nil)) |
| 3851 | ((eq (ediff-with-current-buffer x major-mode) |
| 3852 | 'dired-mode) |
| 3853 | (if (null use-dired-major-mode) |
| 3854 | ;; don't know if we must enforce dired. |
| 3855 | ;; Remember this buffer in case |
| 3856 | ;; dired buffs are the only ones visible. |
| 3857 | (setq visible-dired-buffers |
| 3858 | (cons x visible-dired-buffers))) |
| 3859 | ;; skip, if dired is not forced |
| 3860 | nil) |
| 3861 | ((memq (ediff-with-current-buffer x major-mode) |
| 3862 | '(rmail-mode |
| 3863 | vm-mode |
| 3864 | gnus-article-mode |
| 3865 | mh-show-mode)) |
| 3866 | x) |
| 3867 | ((string-match "^[ *]" (buffer-name x)) nil) |
| 3868 | ((string= "*scratch*" (buffer-name x)) nil) |
| 3869 | (t x))) |
| 3870 | all-buffers)) |
| 3871 | (clean-significant-buffers (delq nil significant-buffers)) |
| 3872 | less-significant-buffers) |
| 3873 | |
| 3874 | (if (and (null clean-significant-buffers) |
| 3875 | (> (length visible-dired-buffers) 0)) |
| 3876 | (setq clean-significant-buffers visible-dired-buffers)) |
| 3877 | |
| 3878 | (cond (clean-significant-buffers (car clean-significant-buffers)) |
| 3879 | ;; try also buffers that are not displayed in windows |
| 3880 | ((setq less-significant-buffers |
| 3881 | (delq nil |
| 3882 | (mapcar |
| 3883 | (lambda (x) |
| 3884 | (cond ((member (buffer-name x) excl-buff-name-list) |
| 3885 | nil) |
| 3886 | ((eq use-dired-major-mode 'yes) |
| 3887 | (if (eq (ediff-with-current-buffer |
| 3888 | x major-mode) |
| 3889 | 'dired-mode) |
| 3890 | x nil)) |
| 3891 | ((eq (ediff-with-current-buffer x major-mode) |
| 3892 | 'dired-mode) |
| 3893 | nil) |
| 3894 | ((string-match "^[ *]" (buffer-name x)) nil) |
| 3895 | ((string= "*scratch*" (buffer-name x)) nil) |
| 3896 | (t x))) |
| 3897 | all-buffers))) |
| 3898 | (car less-significant-buffers)) |
| 3899 | (t "*scratch*")) |
| 3900 | )) |
| 3901 | |
| 3902 | |
| 3903 | ;; If current buffer is a Buffer-menu buffer, then take the selected buffers |
| 3904 | ;; and append the buffer at the cursor to the end. |
| 3905 | ;; This list would be the preferred list. |
| 3906 | (defun ediff-get-selected-buffers () |
| 3907 | (if (eq major-mode 'Buffer-menu-mode) |
| 3908 | (let ((lis (condition-case nil |
| 3909 | (list (Buffer-menu-buffer t)) |
| 3910 | (error)) |
| 3911 | )) |
| 3912 | (save-excursion |
| 3913 | (goto-char (point-max)) |
| 3914 | (while (search-backward "\n>" nil t) |
| 3915 | (forward-char 1) |
| 3916 | (setq lis (cons (Buffer-menu-buffer t) lis))) |
| 3917 | lis)) |
| 3918 | )) |
| 3919 | |
| 3920 | ;; Construct a unique buffer name. |
| 3921 | ;; The first one tried is prefixsuffix, then prefix<2>suffix, |
| 3922 | ;; prefix<3>suffix, etc. |
| 3923 | (defun ediff-unique-buffer-name (prefix suffix) |
| 3924 | (if (null (get-buffer (concat prefix suffix))) |
| 3925 | (concat prefix suffix) |
| 3926 | (let ((n 2)) |
| 3927 | (while (get-buffer (format "%s<%d>%s" prefix n suffix)) |
| 3928 | (setq n (1+ n))) |
| 3929 | (format "%s<%d>%s" prefix n suffix)))) |
| 3930 | |
| 3931 | |
| 3932 | (defun ediff-submit-report () |
| 3933 | "Submit bug report on Ediff." |
| 3934 | (interactive) |
| 3935 | (ediff-barf-if-not-control-buffer) |
| 3936 | (let ((reporter-prompt-for-summary-p t) |
| 3937 | (ctl-buf ediff-control-buffer) |
| 3938 | (ediff-device-type (ediff-device-type)) |
| 3939 | varlist salutation buffer-name) |
| 3940 | (setq varlist '(ediff-diff-program ediff-diff-options |
| 3941 | ediff-diff3-program ediff-diff3-options |
| 3942 | ediff-patch-program ediff-patch-options |
| 3943 | ediff-shell |
| 3944 | ediff-use-faces |
| 3945 | ediff-auto-refine ediff-highlighting-style |
| 3946 | ediff-buffer-A ediff-buffer-B ediff-control-buffer |
| 3947 | ediff-forward-word-function |
| 3948 | ediff-control-frame |
| 3949 | ediff-control-frame-parameters |
| 3950 | ediff-control-frame-position-function |
| 3951 | ediff-prefer-iconified-control-frame |
| 3952 | ediff-window-setup-function |
| 3953 | ediff-split-window-function |
| 3954 | ediff-job-name |
| 3955 | ediff-word-mode |
| 3956 | buffer-name |
| 3957 | ediff-device-type |
| 3958 | )) |
| 3959 | (setq salutation " |
| 3960 | Congratulations! You may have unearthed a bug in Ediff! |
| 3961 | |
| 3962 | Please make a concise and accurate summary of what happened |
| 3963 | and mail it to the address above. |
| 3964 | ----------------------------------------------------------- |
| 3965 | ") |
| 3966 | |
| 3967 | (ediff-skip-unsuitable-frames) |
| 3968 | (ediff-reset-mouse) |
| 3969 | |
| 3970 | (switch-to-buffer ediff-msg-buffer) |
| 3971 | (erase-buffer) |
| 3972 | (delete-other-windows) |
| 3973 | (insert " |
| 3974 | Please read this first: |
| 3975 | ---------------------- |
| 3976 | |
| 3977 | Some ``bugs'' may actually be no bugs at all. For instance, if you are |
| 3978 | reporting that certain difference regions are not matched as you think they |
| 3979 | should, this is most likely due to the way Unix diff program decides what |
| 3980 | constitutes a difference region. Ediff is an Emacs interface to diff, and |
| 3981 | it has nothing to do with those decisions---it only takes the output from |
| 3982 | diff and presents it in a way that is better suited for human browsing and |
| 3983 | manipulation. |
| 3984 | |
| 3985 | If Emacs happens to dump core, this is NOT an Ediff problem---it is |
| 3986 | an Emacs bug. Report this to Emacs maintainers. |
| 3987 | |
| 3988 | Another popular topic for reports is compilation messages. Because Ediff |
| 3989 | interfaces to several other packages and runs under Emacs and XEmacs, |
| 3990 | byte-compilation may produce output like this: |
| 3991 | |
| 3992 | While compiling toplevel forms in file ediff.el: |
| 3993 | ** reference to free variable pm-color-alist |
| 3994 | ........................ |
| 3995 | While compiling the end of the data: |
| 3996 | ** The following functions are not known to be defined: |
| 3997 | ediff-valid-color-p, ediff-set-face, |
| 3998 | ........................ |
| 3999 | |
| 4000 | These are NOT errors, but inevitable warnings, which ought to be ignored. |
| 4001 | |
| 4002 | Please do not report those and similar things. However, comments and |
| 4003 | suggestions are always welcome. |
| 4004 | |
| 4005 | Mail anyway? (y or n) ") |
| 4006 | |
| 4007 | (if (y-or-n-p "Mail anyway? ") |
| 4008 | (progn |
| 4009 | (if (ediff-buffer-live-p ctl-buf) |
| 4010 | (set-buffer ctl-buf)) |
| 4011 | (setq buffer-name (buffer-name)) |
| 4012 | (require 'reporter) |
| 4013 | (reporter-submit-bug-report "kifer@cs.stonybrook.edu" |
| 4014 | (ediff-version) |
| 4015 | varlist |
| 4016 | nil |
| 4017 | 'delete-other-windows |
| 4018 | salutation)) |
| 4019 | (bury-buffer) |
| 4020 | (beep 1)(message "Bug report aborted") |
| 4021 | (if (ediff-buffer-live-p ctl-buf) |
| 4022 | (ediff-with-current-buffer ctl-buf |
| 4023 | (ediff-recenter 'no-rehighlight)))) |
| 4024 | )) |
| 4025 | |
| 4026 | |
| 4027 | ;; Find an appropriate syntax table for everyone to use |
| 4028 | ;; If buffer B is not fundamental or text mode, use its syntax table |
| 4029 | ;; Otherwise, use buffer B's. |
| 4030 | ;; The syntax mode is used in ediff-forward-word-function |
| 4031 | ;; The important thing is that every buffer should use the same syntax table |
| 4032 | ;; during the refinement operation |
| 4033 | (defun ediff-choose-syntax-table () |
| 4034 | (setq ediff-syntax-table |
| 4035 | (ediff-with-current-buffer ediff-buffer-A |
| 4036 | (if (not (memq major-mode |
| 4037 | '(fundamental-mode text-mode indented-text-mode))) |
| 4038 | (syntax-table)))) |
| 4039 | (if (not ediff-syntax-table) |
| 4040 | (setq ediff-syntax-table |
| 4041 | (ediff-with-current-buffer ediff-buffer-B |
| 4042 | (syntax-table)))) |
| 4043 | ) |
| 4044 | |
| 4045 | |
| 4046 | (defun ediff-deactivate-mark () |
| 4047 | (if (featurep 'xemacs) |
| 4048 | (zmacs-deactivate-region) |
| 4049 | (deactivate-mark))) |
| 4050 | |
| 4051 | (defun ediff-activate-mark () |
| 4052 | (if (featurep 'xemacs) |
| 4053 | (zmacs-activate-region) |
| 4054 | (make-local-variable 'transient-mark-mode) |
| 4055 | (setq mark-active t transient-mark-mode t))) |
| 4056 | |
| 4057 | (defun ediff-nuke-selective-display () |
| 4058 | (if (featurep 'xemacs) |
| 4059 | (nuke-selective-display) |
| 4060 | (save-excursion |
| 4061 | (save-restriction |
| 4062 | (widen) |
| 4063 | (goto-char (point-min)) |
| 4064 | (let ((mod-p (buffer-modified-p)) |
| 4065 | buffer-read-only end) |
| 4066 | (and (eq t selective-display) |
| 4067 | (while (search-forward "\^M" nil t) |
| 4068 | (end-of-line) |
| 4069 | (setq end (point)) |
| 4070 | (beginning-of-line) |
| 4071 | (while (search-forward "\^M" end t) |
| 4072 | (delete-char -1) |
| 4073 | (insert "\^J")))) |
| 4074 | (set-buffer-modified-p mod-p) |
| 4075 | (setq selective-display nil)))))) |
| 4076 | |
| 4077 | |
| 4078 | ;; The next two are modified versions from emerge.el. |
| 4079 | ;; VARS must be a list of symbols |
| 4080 | ;; ediff-save-variables returns an association list: ((var . val) ...) |
| 4081 | (defsubst ediff-save-variables (vars) |
| 4082 | (mapcar (lambda (v) (cons v (symbol-value v))) |
| 4083 | vars)) |
| 4084 | ;; VARS is a list of variable symbols. |
| 4085 | (defun ediff-restore-variables (vars assoc-list) |
| 4086 | (while vars |
| 4087 | (set (car vars) (cdr (assoc (car vars) assoc-list))) |
| 4088 | (setq vars (cdr vars)))) |
| 4089 | |
| 4090 | (defun ediff-change-saved-variable (var value buf-type) |
| 4091 | (let* ((assoc-list |
| 4092 | (symbol-value (ediff-get-symbol-from-alist |
| 4093 | buf-type |
| 4094 | ediff-buffer-values-orig-alist))) |
| 4095 | (assoc-elt (assoc var assoc-list))) |
| 4096 | (if assoc-elt |
| 4097 | (setcdr assoc-elt value)))) |
| 4098 | |
| 4099 | |
| 4100 | ;; must execute in control buf |
| 4101 | (defun ediff-save-protected-variables () |
| 4102 | (setq ediff-buffer-values-orig-A |
| 4103 | (ediff-with-current-buffer ediff-buffer-A |
| 4104 | (ediff-save-variables ediff-protected-variables))) |
| 4105 | (setq ediff-buffer-values-orig-B |
| 4106 | (ediff-with-current-buffer ediff-buffer-B |
| 4107 | (ediff-save-variables ediff-protected-variables))) |
| 4108 | (if ediff-3way-comparison-job |
| 4109 | (setq ediff-buffer-values-orig-C |
| 4110 | (ediff-with-current-buffer ediff-buffer-C |
| 4111 | (ediff-save-variables ediff-protected-variables)))) |
| 4112 | (if (ediff-buffer-live-p ediff-ancestor-buffer) |
| 4113 | (setq ediff-buffer-values-orig-Ancestor |
| 4114 | (ediff-with-current-buffer ediff-ancestor-buffer |
| 4115 | (ediff-save-variables ediff-protected-variables))))) |
| 4116 | |
| 4117 | ;; must execute in control buf |
| 4118 | (defun ediff-restore-protected-variables () |
| 4119 | (let ((values-A ediff-buffer-values-orig-A) |
| 4120 | (values-B ediff-buffer-values-orig-B) |
| 4121 | (values-C ediff-buffer-values-orig-C) |
| 4122 | (values-Ancestor ediff-buffer-values-orig-Ancestor)) |
| 4123 | (ediff-with-current-buffer ediff-buffer-A |
| 4124 | (ediff-restore-variables ediff-protected-variables values-A)) |
| 4125 | (ediff-with-current-buffer ediff-buffer-B |
| 4126 | (ediff-restore-variables ediff-protected-variables values-B)) |
| 4127 | (if ediff-3way-comparison-job |
| 4128 | (ediff-with-current-buffer ediff-buffer-C |
| 4129 | (ediff-restore-variables ediff-protected-variables values-C))) |
| 4130 | (if (ediff-buffer-live-p ediff-ancestor-buffer) |
| 4131 | (ediff-with-current-buffer ediff-ancestor-buffer |
| 4132 | (ediff-restore-variables ediff-protected-variables values-Ancestor))) |
| 4133 | )) |
| 4134 | |
| 4135 | ;; save BUFFER in FILE. used in hooks. |
| 4136 | (defun ediff-save-buffer-in-file (buffer file) |
| 4137 | (ediff-with-current-buffer buffer |
| 4138 | (write-file file))) |
| 4139 | |
| 4140 | |
| 4141 | ;;; Debug |
| 4142 | |
| 4143 | (ediff-defvar-local ediff-command-begin-time '(0 0 0) "") |
| 4144 | |
| 4145 | ;; calculate time used by command |
| 4146 | (defun ediff-calc-command-time () |
| 4147 | (let ((end (current-time)) |
| 4148 | micro sec) |
| 4149 | (setq micro |
| 4150 | (if (>= (nth 2 end) (nth 2 ediff-command-begin-time)) |
| 4151 | (- (nth 2 end) (nth 2 ediff-command-begin-time)) |
| 4152 | (+ (nth 2 end) (- 1000000 (nth 2 ediff-command-begin-time))))) |
| 4153 | (setq sec (- (nth 1 end) (nth 1 ediff-command-begin-time))) |
| 4154 | (or (equal ediff-command-begin-time '(0 0 0)) |
| 4155 | (message "Elapsed time: %d second(s) + %d microsecond(s)" sec micro)))) |
| 4156 | |
| 4157 | (defsubst ediff-save-time () |
| 4158 | (setq ediff-command-begin-time (current-time))) |
| 4159 | |
| 4160 | (defun ediff-profile () |
| 4161 | "Toggle profiling Ediff commands." |
| 4162 | (interactive) |
| 4163 | (ediff-barf-if-not-control-buffer) |
| 4164 | |
| 4165 | (if (featurep 'xemacs) |
| 4166 | (make-local-hook 'post-command-hook)) |
| 4167 | |
| 4168 | (let ((pre-hook 'pre-command-hook) |
| 4169 | (post-hook 'post-command-hook)) |
| 4170 | (if (not (equal ediff-command-begin-time '(0 0 0))) |
| 4171 | (progn (remove-hook pre-hook 'ediff-save-time) |
| 4172 | (remove-hook post-hook 'ediff-calc-command-time) |
| 4173 | (setq ediff-command-begin-time '(0 0 0)) |
| 4174 | (message "Ediff profiling disabled")) |
| 4175 | (add-hook pre-hook 'ediff-save-time t 'local) |
| 4176 | (add-hook post-hook 'ediff-calc-command-time nil 'local) |
| 4177 | (message "Ediff profiling enabled")))) |
| 4178 | |
| 4179 | (defun ediff-print-diff-vector (diff-vector-var) |
| 4180 | (princ (format "\n*** %S ***\n" diff-vector-var)) |
| 4181 | (mapcar (lambda (overl-vec) |
| 4182 | (princ |
| 4183 | (format |
| 4184 | "Diff %d: \tOverlay: %S |
| 4185 | \t\tFine diffs: %s |
| 4186 | \t\tNo-fine-diff-flag: %S |
| 4187 | \t\tState-of-diff:\t %S |
| 4188 | \t\tState-of-merge:\t %S |
| 4189 | " |
| 4190 | (1+ (ediff-overlay-get (aref overl-vec 0) 'ediff-diff-num)) |
| 4191 | (aref overl-vec 0) |
| 4192 | ;; fine-diff-vector |
| 4193 | (if (= (length (aref overl-vec 1)) 0) |
| 4194 | "none\n" |
| 4195 | (mapconcat 'prin1-to-string |
| 4196 | (aref overl-vec 1) "\n\t\t\t ")) |
| 4197 | (aref overl-vec 2) ; no fine diff flag |
| 4198 | (aref overl-vec 3) ; state-of-diff |
| 4199 | (aref overl-vec 4) ; state-of-merge |
| 4200 | ))) |
| 4201 | (eval diff-vector-var))) |
| 4202 | |
| 4203 | |
| 4204 | |
| 4205 | (defun ediff-debug-info () |
| 4206 | (interactive) |
| 4207 | (ediff-barf-if-not-control-buffer) |
| 4208 | (with-output-to-temp-buffer ediff-debug-buffer |
| 4209 | (ediff-with-current-buffer standard-output |
| 4210 | (fundamental-mode)) |
| 4211 | (princ (format "\nCtl buffer: %S\n" ediff-control-buffer)) |
| 4212 | (ediff-print-diff-vector (intern "ediff-difference-vector-A")) |
| 4213 | (ediff-print-diff-vector (intern "ediff-difference-vector-B")) |
| 4214 | (ediff-print-diff-vector (intern "ediff-difference-vector-C")) |
| 4215 | (ediff-print-diff-vector (intern "ediff-difference-vector-Ancestor")) |
| 4216 | )) |
| 4217 | |
| 4218 | |
| 4219 | ;;; General utilities |
| 4220 | |
| 4221 | ;; this uses comparison-func to decide who is a member |
| 4222 | (defun ediff-member (elt lis comparison-func) |
| 4223 | (while (and lis (not (funcall comparison-func (car lis) elt))) |
| 4224 | (setq lis (cdr lis))) |
| 4225 | lis) |
| 4226 | |
| 4227 | ;; Make a readable representation of the invocation sequence for FUNC-DEF. |
| 4228 | ;; It would either be a key or M-x something. |
| 4229 | (defun ediff-format-bindings-of (func-def) |
| 4230 | (let ((desc (car (where-is-internal func-def |
| 4231 | overriding-local-map |
| 4232 | nil nil)))) |
| 4233 | (if desc |
| 4234 | (key-description desc) |
| 4235 | (format "M-x %s" func-def)))) |
| 4236 | |
| 4237 | ;; this uses comparison-func to decide who is a member, and this determines how |
| 4238 | ;; intersection looks like |
| 4239 | (defun ediff-intersection (lis1 lis2 comparison-func) |
| 4240 | (let ((result (list 'a))) |
| 4241 | (while lis1 |
| 4242 | (if (ediff-member (car lis1) lis2 comparison-func) |
| 4243 | (nconc result (list (car lis1)))) |
| 4244 | (setq lis1 (cdr lis1))) |
| 4245 | (cdr result))) |
| 4246 | |
| 4247 | |
| 4248 | ;; eliminates duplicates using comparison-func |
| 4249 | (defun ediff-union (lis1 lis2 comparison-func) |
| 4250 | (let ((result (list 'a))) |
| 4251 | (while lis1 |
| 4252 | (or (ediff-member (car lis1) (cdr result) comparison-func) |
| 4253 | (nconc result (list (car lis1)))) |
| 4254 | (setq lis1 (cdr lis1))) |
| 4255 | (while lis2 |
| 4256 | (or (ediff-member (car lis2) (cdr result) comparison-func) |
| 4257 | (nconc result (list (car lis2)))) |
| 4258 | (setq lis2 (cdr lis2))) |
| 4259 | (cdr result))) |
| 4260 | |
| 4261 | ;; eliminates duplicates using comparison-func |
| 4262 | (defun ediff-set-difference (lis1 lis2 comparison-func) |
| 4263 | (let ((result (list 'a))) |
| 4264 | (while lis1 |
| 4265 | (or (ediff-member (car lis1) (cdr result) comparison-func) |
| 4266 | (ediff-member (car lis1) lis2 comparison-func) |
| 4267 | (nconc result (list (car lis1)))) |
| 4268 | (setq lis1 (cdr lis1))) |
| 4269 | (cdr result))) |
| 4270 | |
| 4271 | (defun ediff-add-to-history (history-var newelt) |
| 4272 | (if (fboundp 'add-to-history) |
| 4273 | (add-to-history history-var newelt) |
| 4274 | (set history-var (cons newelt (symbol-value history-var))))) |
| 4275 | |
| 4276 | (defalias 'ediff-copy-list 'copy-sequence) |
| 4277 | |
| 4278 | |
| 4279 | ;; don't report error if version control package wasn't found |
| 4280 | ;;(ediff-load-version-control 'silent) |
| 4281 | |
| 4282 | (run-hooks 'ediff-load-hook) |
| 4283 | |
| 4284 | |
| 4285 | ;; Local Variables: |
| 4286 | ;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) |
| 4287 | ;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1) |
| 4288 | ;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body)) |
| 4289 | ;; End: |
| 4290 | |
| 4291 | ;; arch-tag: f51099b6-ef4b-470f-88a1-3a0e0b03a879 |
| 4292 | ;;; ediff-util.el ends here |