1 ;;; emerge.el --- merge diffs inder Emacs control (version 4)
6 ;; emerge|Dale R. Worley|drw@math.mit.edu
7 ;; |File merge documentation
8 ;; |91-12-13|version 4|~/packages/emerge.doc.Z
10 ; - Changes from version 3 to version 4
12 ; More configuration variables are marked as user options.
14 ; Code is included for an improved version of make-auto-save-file-name
15 ; which eliminates many problems with the default version. See the
16 ; documentation of emerge-make-auto-save-file-name to see how to
19 ; Emerge now works with Gnu diff3, which can produce the groups of lines
20 ; from the various files in the order 1, 2, 3 or 1, 3, 2.
22 ; Added x f command to show what files or buffers are being operated on.
24 ; The merge buffer now starts read-only, which being in fast mode it
27 ; When merging buffers, Emerge writes their contents into temporary
28 ; files in the directory $TMPDIR (if it is defined), or /tmp by default.
30 ; Added x j command to join two differences.
32 ; Added x s command to split a difference into two differences.
34 ; Added emerge-version variable and function to report the version of Emerge
37 ; Added x t command to trim unchanged lines off top and bottom of
40 ; Added x d, x a, and x b commands to locate the differences at or near
41 ; a given location in one of the buffers.
43 ; Emerge no longer tries to copy the minor modes from the A buffer to
44 ; the merge buffer, only the major mode.
46 ; The programs executed to find the differences between versions of the file
47 ; are no longer controlled by emerge-diff/diff3-command, but rather by:
49 ; Variable: *Name of the program which compares two files.
50 ; emerge-diff3-program
51 ; Variable: *Name of the program which compares an ancestor file
52 ; (first argument) and two variant files (second and third arguments).
54 ; Variable: *Options to be passed to emerge-diff/diff3-program.
56 ; The names of the files are expanded (see expand-file-name) before being
57 ; passed to emerge-diff/diff3-program, so diff need not invoked under a shell
58 ; that understands '~', for instance.
60 ; If the diff/diff3 program reports errors, the user is notified and the
61 ; errors are displayed.
63 ; The command "0j" can be used to suppress the flags from showing in the buffers.
65 ; A discussion of the effect of the merge flags on indentation of code
66 ; has been added to the documentation.
68 ; If kill-fix.el is loaded, Emerge control variables new have their
69 ; 'preserved' property set, so setting the major mode in the merge
70 ; buffer doesn't destroy Emerge's state.
72 ; Added x c, x C, and x x commands to allow the A and B versions to be
73 ; combined into #ifdef - #endif forms.
75 ; Replaced calls of "ding" to calls of "error" where appropriate.
77 ; Added x m command to allow major mode of merge buffer to be changed.
79 ; Added x 1 command to shrink the merge window to one line.
81 ; Added emerge-startup-hooks to allow customization.
83 ; Fixed a bug that is activated when a remote merge request is made when
84 ; the minibuffer window is selected.
86 ; - Changes from version 2 to version 3
88 ; The directory into which temporary files are written is now controlled
89 ; by a user option (emerge-temp-file-prefix).
91 ; The A and B versions of the difference can be loaded into the kill
92 ; ring with the "c a" and "c b" commands.
94 ; The A and B versions of the difference can be inserted into the merge
95 ; buffer with the "i a" and "i b" commands.
97 ; The difference region of the merge buffer can be surrounded by the
98 ; point and mark with the "m" command.
100 ; The three windows can be scrolled together with the "^", "v", "<",
101 ; ">", and "|" commands.
103 ; The "s s" and "s a" commands report the state of the option in the
104 ; echo area. Similarly, the "f" and "e" commands report what they do in
107 ; The "q" command has been revamped, and its behavior is now controlled
108 ; by the manner in which Emerge is started. In particular, if you wish
109 ; to write the merge buffer into a file upon exiting, invoke
110 ; emerge-files[-with-ancestor] with a prefix argument, and it will
111 ; prompt you for the file name. Then exiting will write the merge
112 ; buffer to the file, unless "q" is given a prefix argument.
114 ; The "i a" and "i b" commands now work in fast mode.
116 ; The modifications that Emerge makes to save-buffer and write-file are
119 ; Emerge now handles merging narrowed buffers correctly.
121 ; Emerge now isn't fooled when the buffer visiting a file is not the
122 ; same as the file on disk.
126 ; To start Emerge, you must run one of four commands:
129 ; emerge-files-with-ancestor
131 ; emerge-buffers-with-ancestor
133 ; The "files" versions prompt you for two file names (the "A" and "B"
134 ; files), the "buffers" versions prompt you for two buffer names (the
135 ; "A" and "B" buffers). Emerge then runs a "diff" of the two entities
136 ; (emerge-buffers writes the buffers into temporary files for input to
137 ; diff) and digests the output to form a list of the differences between
138 ; the two files. Then three buffers are set up: two containing the
139 ; entities (emerge-files does a find-file (C-x C-f) on the files to get
140 ; them into buffers), and one, the "merge buffer", which contains the
141 ; working copy of the merged file that you are constructing. The three
142 ; buffers are put up in a nice three-window display, showing the A and B
143 ; buffers in the upper half and the merge buffer in the lower half.
145 ; The versions of the command that say "with-ancestor" ask for a third
146 ; name, that of an entity which is a common ancestor from which the
147 ; versions being merged were derived. These commands use "diff3" to
148 ; compare all three versions. If one version of a difference agrees
149 ; with the ancestor, then it is presumed that the other version is the
150 ; "correct" version, and is said to be "preferred".
152 ; (Note that if you use emerge-files, Emerge attempts to make sure that
153 ; file on disk and the file in the buffer are the same. If the file on
154 ; disk has been changed, Emerge offers to revert the buffer. If the
155 ; buffer has been modified, Emerge offers to save the buffer. If the
156 ; user declines the offer, or if the file on disk and the buffer have
157 ; both been modified, Emerge aborts with an error message. Emerge is
158 ; careful to widen the buffers containing the files if they have been
159 ; narrowed. If you use emerge-buffers, the buffers are not widened --
160 ; only the visible portion is used.)
162 ; During the merge, the A and B buffers are read-only, so you don't
163 ; damage them. (This is because the A and B versions of the differences
164 ; are extracted from these buffers.) When you quit the merge, the
165 ; read-only/read-write status and modified flag on the A and B buffers
166 ; are restored. In addition, auto-saving of the A and B buffers is
167 ; suppressed during the merge. This is because Emerge modifies the A
168 ; and B buffers to point out the text of the differences, and it would
169 ; be useless to save these changes. (Just before suppressing
170 ; auto-saving, Emerge forces an auto-save.)
172 ; If you give a prefix argument to emerge-files or
173 ; emerge-files-with-ancestor, it prompts you for another file name,
174 ; which is the file into which the merged file is to be written when you
175 ; exit Emerge. The output file name defaults to the A file name. If
176 ; you successfully quit Emerge, the merge buffer will be written to the
177 ; output file, and the buffers for the A, B, and ancestor buffers will
178 ; be deleted (if they exist and are not modified). If you abort Emerge,
179 ; the merge buffer will not be written and the buffers will not be
182 ; You can have any number of merges going at once -- just don't use any
183 ; one buffer as input to more than one merge at once, since that will
184 ; cause the read-only/modified/auto-save status save-and-restore to
187 ; Beware that when Emerge starts up, it does a diff or diff3 of the
188 ; files, which can take many minutes for long files with many
189 ; differences. Emacs can't do anything else until diff finishes.
191 ; If diff or diff3 produces error messages, Emerge will beep and display
192 ; the error messages instead of the merge buffer. There will be a
193 ; message in the echo area giving the name of the merge buffer. Note
194 ; that this is really just an informational message -- you still have
195 ; switch to the merge buffer and abort the merge to restore the
196 ; conditions before you ran Emerge. (Emerge considers any output line
197 ; that does not match the regexp emerge-diff/diff3-ok-lines to be an
200 ; After the merge has been set up, Emerge runs the hooks in
201 ; emerge-startup-hooks.
205 ; Once you have started the merge, you manipulate the merge buffer with
206 ; special commands issued in the merge buffer. You may also edit the
207 ; buffer with ordinary Emacs commands. Emerge keeps track of each
208 ; difference between the A and B buffers and the corresponding section
209 ; of the merge buffer. Initially, all differences show the A version,
210 ; except those for which B is preferred (because A agrees with the
211 ; ancestor), which show the B version. Emerge always has its attention
212 ; focused on one particular difference, which is marked off in the three
213 ; buffers by "vvvvvvvvvvvvvvvvvvvv" above and "^^^^^^^^^^^^^^^^^^^^"
214 ; below. The number of the difference is shown in the mode line.
216 ; A merge buffer can be in two modes: "fast" mode and "edit" mode. In
217 ; fast mode, emerge commands are single characters, and ordinary Emacs
218 ; commands are disabled. This makes Emerge operations fast, but
219 ; prevents you from doing more than selecing the A or the B version of
220 ; differences. In edit mode, all emerge commands must be prefixed with
221 ; C-c, and all (non-conflicting) Emacs commands are available. This
222 ; allows editing the merge buffer, but slows down Emerge operations.
223 ; Edit and fast modes are indicated by "F" and "E" in the minor modes in
226 ; The Emerge commands are:
228 ; p go to the previous difference
229 ; n go to the next difference
230 ; a select the A version of this difference
231 ; b select the B version of this difference
232 ; j go to a particular difference (prefix argument
233 ; specifies which difference) (0j suppresses display of
235 ; q quit - finish the merge*
236 ; f go into fast mode
237 ; e go into edit mode
238 ; s a set/clear auto-advance mode*
239 ; s s set/clear skip-prefers mode*
240 ; l recenter (C-l) all three windows*
242 ; prefix numeric arguments
243 ; d a select the A version as the default from here down in
245 ; d b select the B version as the default from here down in
247 ; c a copy the A version of the difference into the kill
249 ; c b copy the B version of the difference into the kill
251 ; i a insert the A version of the difference at the point
252 ; i b insert the B version of the difference at the point
253 ; m put the point and mark around the difference region
254 ; ^ scroll-down (like M-v) the three windows*
255 ; v scroll-up (like C-v) the three windows*
256 ; < scroll-left (like C-x <) the three windows*
257 ; > scroll-right (like C-x >) the three windows*
258 ; | reset horizontal scroll on the three windows*
259 ; x 1 shrink the merge window to one line (use C-u l to restore it
261 ; x a find the difference containing a location in the A buffer*
262 ; x b find the difference containing a location in the B buffer*
263 ; x c combine the two versions of this difference*
264 ; x C combine the two versions of this difference, using a
265 ; register's value as the template*
266 ; x d find the difference containing a location in the merge buffer*
267 ; x f show the files/buffers Emerge is operating on in Help window
268 ; (use C-u l to restore windows)
269 ; x j join this difference with the following one
270 ; (C-u x j joins this difference with the previous one)
271 ; x l show line numbers of points in A, B, and merge buffers
272 ; x m change major mode of merge buffer*
273 ; x s split this difference into two differences
274 ; (first position the point in all three buffers to the places
275 ; to split the difference)
276 ; x t trim identical lines off top and bottom of difference
277 ; (such lines occur when the A and B versions are
278 ; identical but differ from the ancestor version)
279 ; x x set the template for the x c command*
281 ; * - more details on these commands are given below
283 ; emerge-version is a variable giving the version number of Emerge. It
284 ; is also a function which displays emerge-version (when called
285 ; interactively) or returns it (when called from a program).
287 ; - Differences and their states
289 ; A difference can have one of seven states:
291 ; A: the difference is showing the A version.
293 ; B: the difference is showing the B version.
295 ; default-A and default-B: the difference is showing the A or B state,
296 ; but has never been selected by the user. All differences start in the
297 ; default-A state (and thus the merge buffer is a copy of the A buffer),
298 ; except those for which one buffer or another is preferred. When the
299 ; user selects the difference, it changes to the A or B state.
301 ; prefer-A and prefer-B: the difference is showing the A or B state. In
302 ; addition, the other buffer (that is, for prefer-A, the B buffer; for
303 ; prefer-B, the A buffer) agrees with the ancestor buffer. Thus,
304 ; presumably, the displayed version is the correct one. The "a" and "b"
305 ; commands override these states, and turn them into the A and B states.
307 ; combined: the difference is showing a combination of the A and B
308 ; states that was constructed by the "x c" or "x C" commands. Since
309 ; this state is neither the A or B states, the "a" and "b" commands
310 ; won't alter the difference unless they are given a prefix argument.
312 ; The state of the currently selected difference is shown in the mode
313 ; line of the merge window:
323 ; - Select default commands (d a and d b)
325 ; The d a and d b commands change all default-A's to default-B's (or
326 ; vice-versa) from the selected difference on down to the end of the
327 ; file to default-A or default-B, respectively. (Since a difference
328 ; that has been selected can not have state default-A or default-B, it
329 ; will never be affected by d a or d b. This leads to the unexpected
330 ; result that d a or d b never affects the difference selected at the
331 ; moment, but prevents differences that you have already looked at from
332 ; changing unexpectedly.)
334 ; If you work your way down from the top of the file, using d a and d b
335 ; at judicious points, you can effectivly make the A version the default
336 ; for some sections of the merge buffer and the B version the default
341 ; The quit command finishes the merge session by restoring the state of
342 ; the A and B buffers and removing the markers around the currently
343 ; selected difference. It also disables the Emerge commands in the
344 ; merge buffer, since executing them later could damage the contents of
345 ; the various buffers.
347 ; The action of "q" depends on how Emerge was started and whether "q"
348 ; was given a prefix argument. If there was no prefix argument, it is
349 ; considered a "successful" finish. If there was a prefix argument, it
350 ; is considered an "unsuccessful" finish. In either case, you are asked
351 ; to cofirm the exit, and the confirmation message tells which sort of
352 ; exit you are confirming.
354 ; If Emerge was started by some other process, success/failure is
355 ; reported to the caller.
357 ; If Emerge was started with emerge-files or emerge-files-with-ancestor,
358 ; if a prefix argument was given to that command, then you specified a
359 ; file into which the merge is to be written. A successful exit writes
360 ; the merge into the output file and then kills the A, B, and ancestor
361 ; buffers (so they aren't lying around to confuse you, since they
362 ; probably all have similar names).
364 ; - Auto-advance mode (s a)
366 ; If auto-advance mode is set, the "a" and "b" commands perform an "n"
367 ; (select next difference) afterward. When auto-advance mode is set,
368 ; it is indicated by "A" in the minor modes in the mode line.
369 ; "s a" with a positive argument sets auto-advance, with a non-positive
370 ; argument clears it, and with no argument toggles it.
372 ; - Skip-prefers mode (s s)
374 ; If skip-prefers mode is set, the "n" and "p" commands skip over
375 ; differences with states prefer-A and prefer-B. Thus you will only see
376 ; differences for which one version isn't presumed "correct". When
377 ; skip-prefers mode is set, it is indicated by "S" in the minor modes in
378 ; the mode line. "s s" with a positive argument sets auto-advance, with
379 ; a non-positive argument clears it, and with no argument toggles it.
383 ; The Emerge "l" command causes the selected difference to be brought
384 ; into view in the three windows, or at least, whichever of the three
385 ; merge buffers are visible at the moment. If a prefix argument is
386 ; given, then the original three-window display is set up before the
387 ; difference texts are shown.
389 ; - Scrolling the text (^, v, <, >, and |)
391 ; Emerge has several commands which scroll all three windows by the same
392 ; amount, thus allowing you to easily compare the versions of the text.
393 ; The commands are "^" (scroll-up), "v" (scroll-down), "<"
394 ; (scroll-left), ">" (scroll-right), and "|" (reset horizontal
395 ; scrolling). (Remember that Emacs names scrolling commands by the
396 ; motion of the text with respect to the window, so C-v is called
399 ; If these commands (except "|") are given an argument, that is the
400 ; number of lines or characters by which the windows are scrolled.
401 ; Otherwise, the amount of motion is computed based on the dimensions of
402 ; the merge buffer window -- the height of the merge buffer window
403 ; (minus next-frame-context-lines), or half the width of the merge
404 ; buffer window. (The A and B version windows are assumed to be as high
405 ; as the merge window, but half as wide.) If the argument is just `C-u
406 ; -', then the scrolling is half the default amount.
408 ; - Finding the difference at or near a location (x d, x a, and x b)
410 ; The "x d" command selects the difference containing the current point
411 ; in the merge buffer. If there is no difference containing the point,
412 ; an error is given. An argument can be given to the command to change
413 ; this behavior: if the argument is positive (e.g., C-u), the next
414 ; following difference is selected; if the argument is negative (e.g.,
415 ; C-u -), the previous difference is selected.
417 ; The "x a" and "x b" commands select the difference containing the
418 ; current point in the A and B buffers, respectively. Otherwise, they
419 ; act like the "x d" command. Note that although the point used in the
420 ; commands is not the merge buffer point, the commands can only be
421 ; issued in the merge buffer, because it is the only buffer with the
424 ; - Combining the two versions (x c, x C, and x x)
426 ; Sometimes one wants to combine the two versions of a difference. For
427 ; instance, when merging two versions of a program, one wants to make
428 ; something like this:
431 ; ...new version of code...
433 ; ...old version of code...
436 ; The "x c" command will make such a combined version. (Note that any
437 ; combined version is not the same as either the A or B versions, and so
438 ; the "a" and "b" commands will refuse to alter it unless they are given
439 ; a prefix argument.) The combination is made under control of a
440 ; template, which is a character string with the following
443 ; %a the A version of the difference
444 ; %b the B version of the difference
445 ; %% the character '%'
447 ; Thus, the template used above is
449 ; #ifdef NEW\n%b#else /* NEW */\n%a#endif /* NEW */\n
451 ; (using \n here to represent newlines). The template is stored in the
452 ; variable emerge-combine-versions-template, and its initial value is
453 ; the one given above. The template can be set (from the current
454 ; region) by the "x x" command. (Be careful to get the newlines in the
455 ; template in the right places!) ("x x" was chosen by analogy with "C-x
456 ; x".) ("x x" is only available in the merge buffer, of course.
457 ; Elsewhere, M-x emerge-set-combine-versions-template can be used.) If
458 ; "x x" is given a prefix argument, emerge-combine-versions-template is
459 ; localized in the merge buffer before its value is set, so the "x x"
460 ; command's effect (and the effect of any later "x x" command in the
461 ; merge buffer) is only on the merge buffer.
463 ; The "x C" command is like "x c", but it prompts for a character
464 ; which is the register whose value is to be used as the template.
465 ; This allows one to use multiple templates conveniently.
467 ; - Changing the major mode of the edit buffer (x m)
469 ; The "x m" command prompts for the name of a major-mode-setting command
470 ; and executes it. Ordinarily, major-mode-setting commands change the
471 ; mode line and local keymap, so the "x m" command then resets the
472 ; Emerge mode line and the fast or edit mode local keymap, as
475 ; If you have already changed the major mode of the merge buffer and
476 ; lost the Emerge keymap, you can use M-x emerge-set-merge-mode to
477 ; execute this command.
479 ; Beware that "x m" accepts any command name, not just
480 ; major-mode-setting commands.
482 ; - Writing the merge buffer manually
484 ; Emerge places a wrapper (emerge-query-and-call) on the key bindings of
485 ; save-buffer (usually "C-x C-s") and write-file (usually "C-x C-w"), in
486 ; order to protect the user from writing out the merge before it is
487 ; finished. Emerge-query-and-call asks the user if he is sure he wants
488 ; to write out the incomplete merge. If he answers yes, the buffer is
489 ; written out. The flags are suppressed while the write is being done.
490 ; As a result of this, the displayed portions of the buffers are
491 ; recentered (equivalent to "l").
493 ; - Running Emerge standalone
495 ; If you invoke emacs with the following arguments, you can execute
496 ; Emerge as a standalone program:
498 ; emacs -l emerge -f emerge-files-command file-a file-b file-out
500 ; emacs -l emerge -f emerge-files-with-ancestor-command
501 ; file-a file-b file-ancestor file-out
503 ; When the user gives the "q" (quit) command, Emerge will write out the
504 ; merge buffer in file-out and terminate Emacs. If a prefix argument is
505 ; given, Emacs will terminate with an unsuccessful return code (1), if
506 ; not, it will terminate with a successful return code (0).
508 ; - Invoking Emerge remotely
510 ; If you use the Emacs client/server code that supports remote
511 ; execution, then you can invoke Emerge remotely by executing one of the
514 ; (emerge-files-remote "file A" "file B" "output file")
516 ; (emerge-files-with-ancestor-remote "file A" "file B"
517 ; "ancestor file" "output file")
519 ; Returning a successful/unsuccessful return code is not yet supported
520 ; by the Emacs client/server code.
522 ; Beware that in systems of networked workstations, even though all user
523 ; directories are shared between all the workstations, the /tmp
524 ; directory on each workstation is not shared, so writing files into
525 ; /tmp and then remotely invoking Emerge is not likely to work.
527 ; - Effect of merge flags on indenting code
529 ; The presence of the flags confuses the indentation code of C and
530 ; Emacs-Lisp modes. Starting the flag strings
531 ; (emerge-{before,after}-flag) with '#' (for C) or ';' (for Lisp)
532 ; prevents the indentation code from noticing the flags. Remember to
533 ; change the flag strings before loading Emerge, or to execute
534 ; emerge-new-flags after changing them. But never change the flag
535 ; strings while a merge is being performed.
539 ; The following autoloads will make all top-level Emerge files
540 ; autoloading. Make sure that "emerge" is in a directory on load-path.
542 ; (autoload 'emerge-files "emerge"
543 ; "Run Emerge on two files."
545 ; (autoload 'emerge-files-with-ancestor "emerge"
546 ; "Run Emerge on two files, giving another file as the ancestor."
548 ; (autoload 'emerge-buffers "emerge"
549 ; "Run Emerge on two buffers."
551 ; (autoload 'emerge-buffers-with-ancestor "emerge"
552 ; "Run Emerge on two buffers, giving another buffer as the ancestor."
554 ; (autoload 'emerge-files-command "emerge")
555 ; (autoload 'emerge-files-with-ancestor-command "emerge")
556 ; (autoload 'emerge-files-remote "emerge")
557 ; (autoload 'emerge-files-with-ancestor-remote "emerge")
559 ; ================================================================
561 ;; Declare that we've got the subsystem loaded
562 ;; LCD Archive Entry:
563 ;; emerge|Dale R. Worley|drw@math.mit.edu
565 ;; |91-12-13|version 4|~/packages/emerge.el.Z
569 (defmacro emerge-eval-in-buffer
(buffer &rest forms
)
570 "Macro to switch to BUFFER, evaluate FORMS, returns to original buffer.
571 Differs from save-excursion in that it doesn't save the point and mark."
572 (` (let ((StartBuffer (current-buffer)))
575 (set-buffer (, buffer
))
577 (set-buffer StartBuffer
)))))
579 (defmacro emerge-defvar-local
(var value doc
)
580 "Defines SYMBOL as an advertised variable. Performs a defvar, then
581 executes make-variable-buffer-local on the variable. Also sets the
582 'preserved' property, so that kill-all-local-variables (called by major-mode
583 setting commands) won't destroy Emerge control variables."
585 (defvar (, var
) (, value
) (, doc
))
586 (make-variable-buffer-local '(, var
))
587 (put '(, var
) 'preserved t
))))
589 ;; Add entries to minor-mode-alist so that emerge modes show correctly
590 (setq emerge-minor-modes-list
'((emerge-mode " Emerge")
591 (emerge-fast-mode " F")
592 (emerge-edit-mode " E")
593 (emerge-auto-advance " A")
594 (emerge-skip-prefers " S")))
595 (if (not (assq 'emerge-mode minor-mode-alist
))
596 (setq minor-mode-alist
(append emerge-minor-modes-list
599 ;; We need to define this function so describe-mode can describe Emerge mode.
600 (defun emerge-mode ()
601 "Emerge mode is used by the Emerge file-merging package. It is entered only
602 through one of the functions:
604 emerge-files-with-ancestor
606 emerge-buffers-with-ancestor
608 emerge-files-with-ancestor-command
610 emerge-files-with-ancestor-remote
613 \\{emerge-basic-keymap}
614 Commands must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode, but can be invoked directly
617 (defvar emerge-version
"4"
618 "The version of Emerge.")
620 (defun emerge-version ()
621 "Return string describing the version of Emerge. When called interactively,
622 displays the version."
625 (message "Emerge version %s" (emerge-version))
628 ;;; Emerge configuration variables
630 ;; Commands that produce difference files
631 ;; All that can be configured is the name of the programs to execute
632 ;; (emerge-diff-program and emerge-diff3-program) and the options
633 ;; to be provided (emerge-diff-options). The order in which the file names
634 ;; are given is fixed.
635 ;; The file names are always expanded (see expand-file-name) before being
636 ;; passed to diff, thus they need not be invoked under a shell that
638 ;; The code which processes the diff/diff3 output depends on all the
639 ;; finicky details of their output, including the somewhat strange
640 ;; way they number lines of a file.
641 (defvar emerge-diff-program
"diff"
642 "*Name of the program which compares two files.")
643 (defvar emerge-diff3-program
"diff3"
644 "*Name of the program which compares an ancestor file (first argument)
645 and two variant files (second and third arguments).")
646 (defvar emerge-diff-options
""
647 "*Options to be passed to emerge-diff/diff3-program.")
648 (defvar emerge-match-diff-line
(let ((x "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)"))
649 (concat "^" x
"\\([acd]\\)" x
"$"))
650 "*Pattern to match lines produced by diff that describe differences (as
651 opposed to lines from the source files).")
652 (defvar emerge-diff-ok-lines
653 "^\\([0-9,]+[acd][0-9,]+$\\|[<>] \\|---\\)"
654 "*Regexp that matches normal output lines from emerge-diff-program .
655 Lines that do not match are assumed to be error output.")
656 (defvar emerge-diff3-ok-lines
657 "^\\([1-3]:\\|====\\| \\)"
658 "*Regexp that matches normal output lines from emerge-diff3-program .
659 Lines that do not match are assumed to be error output.")
661 ;; The flags used to mark differences in the buffers.
663 ;; These function definitions need to be up here, because they are used
665 (defun emerge-new-flags ()
666 "Function to be called after emerge-{before,after}-flag are changed to
667 compute values that depend on the flags."
668 (setq emerge-before-flag-length
(length emerge-before-flag
))
669 (setq emerge-before-flag-lines
670 (count-matches-string emerge-before-flag
"\n"))
671 (setq emerge-before-flag-match
(regexp-quote emerge-before-flag
))
672 (setq emerge-after-flag-length
(length emerge-after-flag
))
673 (setq emerge-after-flag-lines
674 (count-matches-string emerge-after-flag
"\n"))
675 (setq emerge-after-flag-match
(regexp-quote emerge-after-flag
)))
676 (defun count-matches-string (string regexp
)
677 "Return the number of matches in STRING for REGEXP."
680 (while (string-match regexp string i
)
681 (setq count
(1+ count
))
682 (setq i
(match-end 0)))
685 (defvar emerge-before-flag
"vvvvvvvvvvvvvvvvvvvv\n"
686 "*Flag placed above the highlighted block of code. Must end with newline.
687 Must be set before Emerge is loaded, or emerge-new-flags must be run
689 (defvar emerge-after-flag
"^^^^^^^^^^^^^^^^^^^^\n"
690 "*Flag placed below the highlighted block of code. Must end with newline.
691 Must be set before Emerge is loaded, or emerge-new-flags must be run
694 ;; Calculate dependent variables
697 (defvar emerge-min-visible-lines
3
698 "*Number of lines that we want to show above and below the flags when we are
699 displaying a difference.")
701 (defvar emerge-temp-file-prefix
702 (let ((env (getenv "TMPDIR"))
704 (setq d
(if (and env
(> (length env
) 0))
707 (if (= (aref d
(1- (length d
))) ?
/)
708 (setq d
(substring d
0 -
1)))
709 (concat d
"/emerge"))
710 "*Prefix to put on Emerge temporary file names.
711 Do not start with '~/' or '~user-name/'.")
713 (defvar emerge-temp-file-mode
384 ; u=rw only
714 "*Mode for Emerge temporary files.")
716 (defvar emerge-combine-versions-template
717 "#ifdef NEW\n%b#else /* NEW */\n%a#endif /* NEW */\n"
718 "*Template for emerge-combine-versions to combine the two versions.
719 The template is inserted as a string, with the following interpolations:
720 %a the A version of the difference
721 %b the B version of the difference
723 Don't forget to end the template with a newline.
724 Note that this variable can be made local to a particular merge buffer by
725 giving a prefix argument to emerge-set-combine-versions-template .")
729 (defvar emerge-basic-keymap nil
730 "Keymap of Emerge commands.
731 Directly available in 'fast' mode;
732 must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode.")
734 (defvar emerge-fast-keymap nil
735 "Local keymap used in Emerge 'fast' mode.
736 Makes Emerge commands directly available.")
738 (defvar emerge-command-prefix
"\C-c"
739 "*Command prefix for Emerge commands in 'edit' mode.
740 Must be set before Emerge is loaded.")
742 ;; This function sets up the fixed keymaps. It is executed when the first
743 ;; Emerge is done to allow the user maximum time to set up the global keymap.
744 (defun emerge-setup-fixed-keymaps ()
745 ;; Set up the basic keymap
746 (setq emerge-basic-keymap
(make-keymap))
747 (suppress-keymap emerge-basic-keymap
) ; this sets 0..9 to digit-argument and
748 ; - to negative-argument
749 (define-key emerge-basic-keymap
"p" 'emerge-previous-difference
)
750 (define-key emerge-basic-keymap
"n" 'emerge-next-difference
)
751 (define-key emerge-basic-keymap
"a" 'emerge-select-A
)
752 (define-key emerge-basic-keymap
"b" 'emerge-select-B
)
753 (define-key emerge-basic-keymap
"j" 'emerge-jump-to-difference
)
754 (define-key emerge-basic-keymap
"q" 'emerge-quit
)
755 (define-key emerge-basic-keymap
"f" 'emerge-fast-mode
)
756 (define-key emerge-basic-keymap
"e" 'emerge-edit-mode
)
757 (define-key emerge-basic-keymap
"s" nil
)
758 (define-key emerge-basic-keymap
"sa" 'emerge-auto-advance
)
759 (define-key emerge-basic-keymap
"ss" 'emerge-skip-prefers
)
760 (define-key emerge-basic-keymap
"l" 'emerge-recenter
)
761 (define-key emerge-basic-keymap
"d" nil
)
762 (define-key emerge-basic-keymap
"da" 'emerge-default-A
)
763 (define-key emerge-basic-keymap
"db" 'emerge-default-B
)
764 (define-key emerge-basic-keymap
"c" nil
)
765 (define-key emerge-basic-keymap
"ca" 'emerge-copy-as-kill-A
)
766 (define-key emerge-basic-keymap
"cb" 'emerge-copy-as-kill-B
)
767 (define-key emerge-basic-keymap
"i" nil
)
768 (define-key emerge-basic-keymap
"ia" 'emerge-insert-A
)
769 (define-key emerge-basic-keymap
"ib" 'emerge-insert-B
)
770 (define-key emerge-basic-keymap
"m" 'emerge-mark-difference
)
771 (define-key emerge-basic-keymap
"v" 'emerge-scroll-up
)
772 (define-key emerge-basic-keymap
"^" 'emerge-scroll-down
)
773 (define-key emerge-basic-keymap
"<" 'emerge-scroll-left
)
774 (define-key emerge-basic-keymap
">" 'emerge-scroll-right
)
775 (define-key emerge-basic-keymap
"|" 'emerge-scroll-reset
)
776 (define-key emerge-basic-keymap
"x" nil
)
777 (define-key emerge-basic-keymap
"x1" 'emerge-one-line-window
)
778 (define-key emerge-basic-keymap
"xa" 'emerge-find-difference-A
)
779 (define-key emerge-basic-keymap
"xb" 'emerge-find-difference-B
)
780 (define-key emerge-basic-keymap
"xc" 'emerge-combine-versions
)
781 (define-key emerge-basic-keymap
"xC" 'emerge-combine-versions-register
)
782 (define-key emerge-basic-keymap
"xd" 'emerge-find-difference
)
783 (define-key emerge-basic-keymap
"xf" 'emerge-file-names
)
784 (define-key emerge-basic-keymap
"xj" 'emerge-join-differences
)
785 (define-key emerge-basic-keymap
"xl" 'emerge-line-numbers
)
786 (define-key emerge-basic-keymap
"xm" 'emerge-set-merge-mode
)
787 (define-key emerge-basic-keymap
"xs" 'emerge-split-difference
)
788 (define-key emerge-basic-keymap
"xt" 'emerge-trim-difference
)
789 (define-key emerge-basic-keymap
"xx" 'emerge-set-combine-versions-template
)
790 ;; Allow emerge-basic-keymap to be referenced indirectly
791 (fset 'emerge-basic-keymap emerge-basic-keymap
)
792 ;; Set up the fast mode keymap
793 (setq emerge-fast-keymap
(copy-keymap emerge-basic-keymap
))
794 ;; Allow prefixed commands to work in fast mode
795 (define-key emerge-fast-keymap emerge-command-prefix
'emerge-basic-keymap
)
796 ;; Allow emerge-fast-keymap to be referenced indirectly
797 (fset 'emerge-fast-keymap emerge-fast-keymap
)
798 ;; Suppress write-file and save-buffer
799 (emerge-shadow-key-definition 'write-file
'emerge-query-write-file
800 (current-global-map) emerge-fast-keymap
)
801 (emerge-shadow-key-definition 'save-buffer
'emerge-query-save-buffer
802 (current-global-map) emerge-fast-keymap
))
804 ;; Variables which control each merge. They are local to the merge buffer.
807 (emerge-defvar-local emerge-mode nil
808 "Indicator for emerge-mode.")
809 (emerge-defvar-local emerge-fast-mode nil
810 "Indicator for emerge-mode fast submode.")
811 (emerge-defvar-local emerge-edit-mode nil
812 "Indicator for emerge-mode edit submode.")
813 (emerge-defvar-local emerge-A-buffer nil
814 "The buffer in which the A variant is stored.")
815 (emerge-defvar-local emerge-B-buffer nil
816 "The buffer in which the B variant is stored.")
817 (emerge-defvar-local emerge-merge-buffer nil
818 "The buffer in which the merged file is manipulated.")
819 (emerge-defvar-local emerge-ancestor-buffer nil
820 "The buffer in which the ancestor variant is stored,
821 or nil if there is none.")
823 (defconst emerge-saved-variables
824 '((buffer-modified-p set-buffer-modified-p
)
826 buffer-auto-save-file-name
)
827 "Variables and properties of a buffer which are saved, modified and restored
829 (defconst emerge-merging-values
'(nil t nil
)
830 "Values to be assigned to emerge-saved-variables during a merge.")
832 (emerge-defvar-local emerge-A-buffer-values nil
833 "Remembers emerge-saved-variables for emerge-A-buffer.")
834 (emerge-defvar-local emerge-B-buffer-values nil
835 "Remembers emerge-saved-variables for emerge-B-buffer.")
837 (emerge-defvar-local emerge-difference-list nil
838 "Vector of differences between the variants, and markers in the buffers to
839 show where they are. Each difference is represented by a vector of seven
840 elements. The first two are markers to the beginning and end of the difference
841 section in the A buffer, the second two are markers for the B buffer, the third
842 two are markers for the merge buffer, and the last element is the \"state\" of
843 that difference in the merge buffer.
844 A section of a buffer is described by two markers, one to the beginning of
845 the first line of the section, and one to the beginning of the first line
846 after the section. (If the section is empty, both markers point to the same
847 point.) If the section is part of the selected difference, then the markers
848 are moved into the flags, so the user can edit the section without disturbing
851 A the merge buffer currently contains the A variant
852 B the merge buffer currently contains the B variant
853 default-A the merge buffer contains the A variant by default,
854 but this difference hasn't been selected yet, so
855 change-default commands can alter it
856 default-B the merge buffer contains the B variant by default,
857 but this difference hasn't been selected yet, so
858 change-default commands can alter it
859 prefer-A in a three-file merge, the A variant is the prefered
861 prefer-B in a three-file merge, the B variant is the prefered
863 (emerge-defvar-local emerge-current-difference -
1
864 "The difference that is currently selected.")
865 (emerge-defvar-local emerge-number-of-differences nil
866 "Number of differences found.")
867 (emerge-defvar-local emerge-edit-keymap nil
868 "The local keymap for the merge buffer, with the emerge commands defined in
869 it. Used to save the local keymap during fast mode, when the local keymap is
870 replaced by emerge-fast-keymap.")
871 (emerge-defvar-local emerge-old-keymap nil
872 "The original local keymap for the merge buffer.")
873 (emerge-defvar-local emerge-auto-advance nil
874 "*If non-nil, emerge-select-A and emerge-select-B automatically advance to
875 the next difference.")
876 (emerge-defvar-local emerge-skip-prefers nil
877 "*If non-nil, differences for which there is a preference are automatically
879 (emerge-defvar-local emerge-startup-hooks nil
880 "*Hooks to run in the merge buffer after the merge has been set up.")
881 (emerge-defvar-local emerge-quit-hooks nil
882 "Hooks to run in the merge buffer after the merge has been finished.
883 emerge-prefix-argument will be bound to the prefix argument of the emerge-quit
885 This is not a user option, since Emerge uses it for its own processing.")
886 (emerge-defvar-local emerge-output-description nil
887 "Describes output destination of the merge, for the use of
890 ;;; Setup functions for two-file mode.
892 (defun emerge-files-internal (file-A file-B
&optional startup-hooks quit-hooks
894 (let ((buffer-A (find-file-noselect file-A
))
895 (buffer-B (find-file-noselect file-B
)))
896 ;; Make sure the entire files are seen, and they reflect what is on disk
897 (emerge-eval-in-buffer buffer-A
899 (emerge-verify-file-buffer))
900 (emerge-eval-in-buffer buffer-B
902 (emerge-verify-file-buffer))
903 (emerge-setup buffer-A file-A buffer-B file-B startup-hooks quit-hooks
906 ;; Start up Emerge on two files
907 (defun emerge-setup (buffer-A file-A buffer-B file-B startup-hooks quit-hooks
909 (setq file-A
(expand-file-name file-A
))
910 (setq file-B
(expand-file-name file-B
))
911 (setq output-file
(and output-file
(expand-file-name output-file
)))
912 (let* ((merge-buffer-name (emerge-unique-buffer-name "*merge" "*"))
913 ;; create the merge buffer from buffer A, so it inherits buffer A's
914 ;; default directory, etc.
915 (merge-buffer (emerge-eval-in-buffer
917 (get-buffer-create merge-buffer-name
))))
918 (emerge-eval-in-buffer
920 (emerge-copy-modes buffer-A
)
921 (setq buffer-read-only nil
)
924 (setq emerge-A-buffer buffer-A
)
925 (setq emerge-B-buffer buffer-B
)
926 (setq emerge-ancestor-buffer nil
)
927 (setq emerge-merge-buffer merge-buffer
)
928 (setq emerge-output-description
930 (concat "Output to file: " output-file
)
931 (concat "Output to buffer: " (buffer-name merge-buffer
))))
932 (insert-buffer emerge-A-buffer
)
934 (setq emerge-difference-list
(emerge-make-diff-list file-A file-B
))
935 (setq emerge-number-of-differences
(length emerge-difference-list
))
936 (setq emerge-current-difference -
1)
937 (setq emerge-quit-hooks quit-hooks
)
938 (emerge-remember-buffer-characteristics))
939 (emerge-setup-windows buffer-A buffer-B merge-buffer t
)
940 (emerge-eval-in-buffer merge-buffer
941 (run-hooks 'startup-hooks
'emerge-startup-hooks
)
942 (setq buffer-read-only t
))))
944 ;; Generate the Emerge difference list between two files
945 (defun emerge-make-diff-list (file-A file-B
)
946 (setq emerge-diff-buffer
(get-buffer-create "*emerge-diff*"))
947 (emerge-eval-in-buffer
951 (format "%s %s %s %s"
952 emerge-diff-program emerge-diff-options file-A file-B
)
954 (emerge-prepare-error-list emerge-diff-ok-lines
)
955 (emerge-convert-diffs-to-markers
956 emerge-A-buffer emerge-B-buffer emerge-merge-buffer
957 (emerge-extract-diffs emerge-diff-buffer
)))
959 (defun emerge-extract-diffs (diff-buffer)
961 (emerge-eval-in-buffer
963 (goto-char (point-min))
964 (while (re-search-forward emerge-match-diff-line nil t
)
965 (let* ((a-begin (string-to-int (buffer-substring (match-beginning 1)
967 (a-end (let ((b (match-beginning 3))
970 (string-to-int (buffer-substring b e
))
972 (diff-type (buffer-substring (match-beginning 4) (match-end 4)))
973 (b-begin (string-to-int (buffer-substring (match-beginning 5)
975 (b-end (let ((b (match-beginning 7))
978 (string-to-int (buffer-substring b e
))
980 ;; fix the beginning and end numbers, because diff is somewhat
981 ;; strange about how it numbers lines
982 (if (string-equal diff-type
"a")
984 (setq b-end
(1+ b-end
))
985 (setq a-begin
(1+ a-begin
))
986 (setq a-end a-begin
))
987 (if (string-equal diff-type
"d")
989 (setq a-end
(1+ a-end
))
990 (setq b-begin
(1+ b-begin
))
991 (setq b-end b-begin
))
992 ;; (string-equal diff-type "c")
994 (setq a-end
(1+ a-end
))
995 (setq b-end
(1+ b-end
)))))
996 (setq list
(cons (vector a-begin a-end
1002 ;; Set up buffer of diff/diff3 error messages.
1003 (defun emerge-prepare-error-list (ok-regexp)
1004 (setq emerge-diff-error-buffer
(get-buffer-create "*emerge-diff-errors*"))
1005 (emerge-eval-in-buffer
1006 emerge-diff-error-buffer
1008 (insert-buffer emerge-diff-buffer
)
1009 (delete-matching-lines ok-regexp
)))
1011 ;;; Top-level and setup functions for three-file mode.
1013 (defun emerge-files-with-ancestor-internal (file-A file-B file-ancestor
1014 &optional startup-hooks quit-hooks
1016 (let ((buffer-A (find-file-noselect file-A
))
1017 (buffer-B (find-file-noselect file-B
))
1018 (buffer-ancestor (find-file-noselect file-ancestor
)))
1019 ;; Make sure the entire files are seen, and they reflect what is on disk
1020 (emerge-eval-in-buffer buffer-A
1022 (emerge-verify-file-buffer))
1023 (emerge-eval-in-buffer buffer-B
1025 (emerge-verify-file-buffer))
1026 (emerge-eval-in-buffer buffer-ancestor
1028 (emerge-verify-file-buffer))
1029 (emerge-setup-with-ancestor buffer-A file-A buffer-B file-B
1030 buffer-ancestor file-ancestor
1031 startup-hooks quit-hooks output-file
)))
1033 ;; Start up Emerge on two files with an ancestor
1034 (defun emerge-setup-with-ancestor (buffer-A file-A buffer-B file-B
1035 buffer-ancestor file-ancestor
1036 &optional startup-hooks quit-hooks
1038 (setq file-A
(expand-file-name file-A
))
1039 (setq file-B
(expand-file-name file-B
))
1040 (setq file-ancestor
(expand-file-name file-ancestor
))
1041 (setq output-file
(and output-file
(expand-file-name output-file
)))
1042 (let* ((merge-buffer-name (emerge-unique-buffer-name "*merge" "*"))
1043 ;; create the merge buffer from buffer A, so it inherits buffer A's
1044 ;; default directory, etc.
1045 (merge-buffer (emerge-eval-in-buffer
1047 (get-buffer-create merge-buffer-name
))))
1048 (emerge-eval-in-buffer
1050 (emerge-copy-modes buffer-A
)
1051 (setq buffer-read-only nil
)
1053 (setq emerge-mode t
)
1054 (setq emerge-A-buffer buffer-A
)
1055 (setq emerge-B-buffer buffer-B
)
1056 (setq emerge-ancestor-buffer buffer-ancestor
)
1057 (setq emerge-merge-buffer merge-buffer
)
1058 (setq emerge-output-description
1060 (concat "Output to file: " output-file
)
1061 (concat "Output to buffer: " (buffer-name merge-buffer
))))
1062 (insert-buffer emerge-A-buffer
)
1064 (setq emerge-difference-list
1065 (emerge-make-diff3-list file-A file-B file-ancestor
))
1066 (setq emerge-number-of-differences
(length emerge-difference-list
))
1067 (setq emerge-current-difference -
1)
1068 (setq emerge-quit-hooks quit-hooks
)
1069 (emerge-remember-buffer-characteristics)
1070 (emerge-select-prefer-Bs))
1071 (emerge-setup-windows buffer-A buffer-B merge-buffer t
)
1072 (emerge-eval-in-buffer merge-buffer
1073 (run-hooks 'startup-hooks
'emerge-startup-hooks
)
1074 (setq buffer-read-only t
))))
1076 ;; Generate the Emerge difference list between two files with an ancestor
1077 (defun emerge-make-diff3-list (file-A file-B file-ancestor
)
1078 (setq emerge-diff-buffer
(get-buffer-create "*emerge-diff*"))
1079 (emerge-eval-in-buffer
1083 (format "%s %s %s %s %s"
1084 emerge-diff3-program emerge-diff-options
1085 file-ancestor file-A file-B
)
1087 (emerge-prepare-error-list emerge-diff3-ok-lines
)
1088 (emerge-convert-diffs-to-markers
1089 emerge-A-buffer emerge-B-buffer emerge-merge-buffer
1090 (emerge-extract-diffs3 emerge-diff-buffer
)))
1092 (defun emerge-extract-diffs3 (diff-buffer)
1094 (emerge-eval-in-buffer
1096 (while (re-search-forward "^====\\(.?\\)$" nil t
)
1097 ;; leave point after matched line
1098 (beginning-of-line 2)
1099 (let ((agreement (buffer-substring (match-beginning 1) (match-end 1))))
1100 ;; if the A and B files are the same, ignore the difference
1101 (if (not (string-equal agreement
"1"))
1104 (let ((group-2 (emerge-get-diff3-group "2"))
1105 (group-3 (emerge-get-diff3-group "3")))
1106 (vector (car group-2
) (car (cdr group-2
))
1107 (car group-3
) (car (cdr group-3
))
1108 (cond ((string-equal agreement
"2") 'prefer-A
)
1109 ((string-equal agreement
"3") 'prefer-B
)
1114 (defun emerge-get-diff3-group (file)
1115 ;; This save-excursion allows emerge-get-diff3-group to be called for the
1116 ;; various groups of lines (1, 2, 3) in any order, and for the lines to
1117 ;; appear in any order. The reason this is necessary is that Gnu diff3
1118 ;; can produce the groups in the order 1, 2, 3 or 1, 3, 2.
1121 (concat "^" file
":\\([0-9]+\\)\\(,\\([0-9]+\\)\\)?\\([ac]\\)$"))
1122 (beginning-of-line 2)
1123 ;; treatment depends on whether it is an "a" group or a "c" group
1124 (if (string-equal (buffer-substring (match-beginning 4) (match-end 4)) "c")
1125 ;; it is a "c" group
1126 (if (match-beginning 2)
1127 ;; it has two numbers
1128 (list (string-to-int
1129 (buffer-substring (match-beginning 1) (match-end 1)))
1131 (buffer-substring (match-beginning 3) (match-end 3)))))
1132 ;; it has one number
1133 (let ((x (string-to-int
1134 (buffer-substring (match-beginning 1) (match-end 1)))))
1136 ;; it is an "a" group
1137 (let ((x (1+ (string-to-int
1138 (buffer-substring (match-beginning 1) (match-end 1))))))
1141 ;;; Functions to start Emerge on files
1144 (defun emerge-files (arg file-A file-B file-out
&optional startup-hooks
1146 "Run Emerge on two files."
1149 (list current-prefix-arg
1150 (setq f
(read-file-name "File A to merge: " nil nil
'confirm
))
1151 (read-file-name "File B to merge: " nil nil
'confirm
)
1152 (and current-prefix-arg
1154 (format "Output file: (default %s) " f
)
1156 (emerge-files-internal
1157 file-A file-B startup-hooks
1159 (cons (` (lambda () (emerge-files-exit (, file-out
))))
1165 (defun emerge-files-with-ancestor (arg file-A file-B file-ancestor file-out
1166 &optional startup-hooks quit-hooks
)
1167 "Run Emerge on two files, giving another file as the ancestor."
1170 (list current-prefix-arg
1171 (setq f
(read-file-name "File A to merge: " nil nil
'confirm
))
1172 (read-file-name "File B to merge: " nil nil
'confirm
)
1173 (read-file-name "Ancestor file: " nil nil
'confirm
)
1174 (and current-prefix-arg
1176 (format "Output file: (default %s) " f
)
1178 (emerge-files-with-ancestor-internal
1179 file-A file-B file-ancestor startup-hooks
1181 (cons (` (lambda () (emerge-files-exit (, file-out
))))
1186 ;; Write the merge buffer out in place of the file the A buffer is visiting.
1187 (defun emerge-files-exit (file-out)
1188 ;; if merge was successful was given, save to disk
1189 (if (not emerge-prefix-argument
)
1190 (emerge-write-and-delete file-out
)))
1192 ;;; Functions to start Emerge on buffers
1195 (defun emerge-buffers (buffer-A buffer-B
&optional startup-hooks quit-hooks
)
1196 "Run Emerge on two buffers."
1197 (interactive "bBuffer A to merge: \nbBuffer B to merge: ")
1198 (let ((emerge-file-A (emerge-make-temp-file "A"))
1199 (emerge-file-B (emerge-make-temp-file "B")))
1200 (emerge-eval-in-buffer
1202 (write-region (point-min) (point-max) emerge-file-A nil
'no-message
))
1203 (emerge-eval-in-buffer
1205 (write-region (point-min) (point-max) emerge-file-B nil
'no-message
))
1206 (emerge-setup (get-buffer buffer-A
) emerge-file-A
1207 (get-buffer buffer-B
) emerge-file-B
1208 (cons (function (lambda ()
1209 (delete-file emerge-file-A
)
1210 (delete-file emerge-file-B
)))
1216 (defun emerge-buffers-with-ancestor (buffer-A buffer-B buffer-ancestor
1217 &optional startup-hooks
1219 "Run Emerge on two buffers, giving another buffer as the ancestor."
1221 "bBuffer A to merge: \nbBuffer B to merge: \nbAncestor buffer: ")
1222 (let ((emerge-file-A (emerge-make-temp-file "A"))
1223 (emerge-file-B (emerge-make-temp-file "B"))
1224 (emerge-file-ancestor (emerge-make-temp-file "anc")))
1225 (emerge-eval-in-buffer
1227 (write-region (point-min) (point-max) emerge-file-A nil
'no-message
))
1228 (emerge-eval-in-buffer
1230 (write-region (point-min) (point-max) emerge-file-B nil
'no-message
))
1231 (emerge-eval-in-buffer
1233 (write-region (point-min) (point-max) emerge-file-ancestor nil
1235 (emerge-setup-with-ancestor (get-buffer buffer-A
) emerge-file-A
1236 (get-buffer buffer-B
) emerge-file-B
1237 (get-buffer buffer-ancestor
)
1238 emerge-file-ancestor
1239 (cons (function (lambda ()
1240 (delete-file emerge-file-A
)
1241 (delete-file emerge-file-B
)
1243 emerge-file-ancestor
)))
1248 ;;; Functions to start Emerge from the command line
1251 (defun emerge-files-command ()
1252 (let ((file-a (nth 0 command-line-args-left
))
1253 (file-b (nth 1 command-line-args-left
))
1254 (file-out (nth 2 command-line-args-left
)))
1255 (setq command-line-args-left
(nthcdr 3 command-line-args-left
))
1256 (emerge-files-internal
1258 (list (` (lambda () (emerge-command-exit (, file-out
))))))))
1261 (defun emerge-files-with-ancestor-command ()
1262 (let (file-a file-b file-anc file-out
)
1263 ;; check for a -a flag, for filemerge compatibility
1264 (if (string= (car command-line-args-left
) "-a")
1265 ;; arguments are "-a ancestor file-a file-b file-out"
1267 (setq file-a
(nth 2 command-line-args-left
))
1268 (setq file-b
(nth 3 command-line-args-left
))
1269 (setq file-anc
(nth 1 command-line-args-left
))
1270 (setq file-out
(nth 4 command-line-args-left
))
1271 (setq command-line-args-left
(nthcdr 5 command-line-args-left
)))
1272 ;; arguments are "file-a file-b ancestor file-out"
1273 (setq file-a
(nth 0 command-line-args-left
))
1274 (setq file-b
(nth 1 command-line-args-left
))
1275 (setq file-anc
(nth 2 command-line-args-left
))
1276 (setq file-out
(nth 3 command-line-args-left
))
1277 (setq command-line-args-left
(nthcdr 4 command-line-args-left
)))
1278 (emerge-files-with-ancestor-internal
1279 file-a file-b file-anc nil
1280 (list (` (lambda () (emerge-command-exit (, file-out
))))))))
1282 (defun emerge-command-exit (file-out)
1283 (emerge-write-and-delete file-out
)
1284 (kill-emacs (if emerge-prefix-argument
1 0)))
1286 ;;; Functions to start Emerge via remote request
1289 (defun emerge-files-remote (file-a file-b file-out
)
1290 (setq emerge-file-out file-out
)
1291 (emerge-files-internal
1293 (list (` (lambda () (emerge-remote-exit (, file-out
) '(, exit-func
)))))
1295 (throw 'client-wait nil
))
1298 (defun emerge-files-with-ancestor-remote (file-a file-b file-anc file-out
)
1299 (setq emerge-file-out file-out
)
1300 (emerge-files-with-ancestor-internal
1301 file-a file-b file-anc nil
1302 (list (` (lambda () (emerge-remote-exit (, file-out
) '(, exit-func
)))))
1304 (throw 'client-wait nil
))
1306 (defun emerge-remote-exit (file-out exit-func
)
1307 (emerge-write-and-delete file-out
)
1308 (kill-buffer emerge-merge-buffer
)
1309 (funcall exit-func
(if emerge-prefix-argument
1 0)))
1311 ;;; Common setup routines
1313 ;; Set up the window configuration. If POS is given, set the points to
1314 ;; the beginnings of the buffers.
1315 (defun emerge-setup-windows (buffer-A buffer-B merge-buffer
&optional pos
)
1316 ;; Make sure we are not in the minibuffer window when we try to delete
1317 ;; all other windows.
1318 (if (eq (selected-window) (minibuffer-window))
1320 (delete-other-windows)
1321 (switch-to-buffer merge-buffer
)
1322 (emerge-refresh-mode-line)
1323 (split-window-vertically)
1324 (split-window-horizontally)
1325 (switch-to-buffer buffer-A
)
1327 (goto-char (point-min)))
1329 (switch-to-buffer buffer-B
)
1331 (goto-char (point-min)))
1334 (goto-char (point-min)))
1335 ;; If diff/diff3 reports errors, display them rather than the merge buffer.
1336 (if (/= 0 (emerge-eval-in-buffer emerge-diff-error-buffer
(buffer-size)))
1339 (message "Errors found in diff/diff3 output. Merge buffer is %s."
1340 (buffer-name emerge-merge-buffer
))
1341 (switch-to-buffer emerge-diff-error-buffer
))))
1343 ;; Set up the keymap in the merge buffer
1344 (defun emerge-set-keys ()
1345 ;; Set up fixed keymaps if necessary
1346 (if (not emerge-basic-keymap
)
1347 (emerge-setup-fixed-keymaps))
1348 ;; Save the old local map
1349 (setq emerge-old-keymap
(current-local-map))
1350 ;; Construct the edit keymap
1351 (setq emerge-edit-keymap
(if emerge-old-keymap
1352 (copy-keymap emerge-old-keymap
)
1353 (make-sparse-keymap)))
1354 ;; Install the Emerge commands
1355 (emerge-force-define-key emerge-edit-keymap emerge-command-prefix
1356 'emerge-basic-keymap
)
1357 ;; Suppress write-file and save-buffer
1358 (emerge-recursively-substitute-key-definition 'write-file
1359 'emerge-query-write-file
1361 (emerge-recursively-substitute-key-definition 'save-buffer
1362 'emerge-query-save-buffer
1364 (emerge-shadow-key-definition 'write-file
'emerge-query-write-file
1365 (current-global-map) emerge-edit-keymap
)
1366 (emerge-shadow-key-definition 'save-buffer
'emerge-query-save-buffer
1367 (current-global-map) emerge-edit-keymap
)
1368 (use-local-map emerge-fast-keymap
)
1369 (setq emerge-edit-mode nil
)
1370 (setq emerge-fast-mode t
))
1372 (defun emerge-remember-buffer-characteristics ()
1373 "Must be called in the merge buffer. Remembers certain properties of the
1374 buffers being merged (read-only, modified, auto-save), and saves them in
1375 buffer local variables. Sets the buffers read-only and turns off auto-save.
1376 These characteristics are restored by emerge-restore-buffer-characteristics."
1377 ;; force auto-save, because we will turn off auto-saving in buffers for the
1380 ;; remember and alter buffer characteristics
1381 (setq emerge-A-buffer-values
1382 (emerge-eval-in-buffer
1385 (emerge-save-variables emerge-saved-variables
)
1386 (emerge-restore-variables emerge-saved-variables
1387 emerge-merging-values
))))
1388 (setq emerge-B-buffer-values
1389 (emerge-eval-in-buffer
1392 (emerge-save-variables emerge-saved-variables
)
1393 (emerge-restore-variables emerge-saved-variables
1394 emerge-merging-values
)))))
1396 (defun emerge-restore-buffer-characteristics ()
1397 "Restores the characteristics remembered by
1398 emerge-remember-buffer-characteristics."
1399 (let ((A-values emerge-A-buffer-values
)
1400 (B-values emerge-B-buffer-values
))
1401 (emerge-eval-in-buffer emerge-A-buffer
1402 (emerge-restore-variables emerge-saved-variables
1404 (emerge-eval-in-buffer emerge-B-buffer
1405 (emerge-restore-variables emerge-saved-variables
1408 (defun emerge-convert-diffs-to-markers (A-buffer
1413 (A-point-min (emerge-eval-in-buffer A-buffer
(point-min)))
1414 (offset (1- A-point-min
))
1415 (A-hidden-lines (emerge-eval-in-buffer
1419 (count-lines 1 A-point-min
))))
1420 (B-point-min (emerge-eval-in-buffer B-buffer
(point-min)))
1421 (B-hidden-lines (emerge-eval-in-buffer
1425 (count-lines 1 B-point-min
)))))
1427 (let* ((list-element (car lineno-list
))
1432 (a-begin (aref list-element
0))
1433 (a-end (aref list-element
1))
1434 (b-begin (aref list-element
2))
1435 (b-end (aref list-element
3))
1436 (state (aref list-element
4)))
1437 ;; place markers at the appropriate places in the buffers
1438 (emerge-eval-in-buffer
1440 (goto-line (+ a-begin A-hidden-lines
))
1441 (setq a-begin-marker
(point-marker))
1442 (goto-line (+ a-end A-hidden-lines
))
1443 (setq a-end-marker
(point-marker)))
1444 (emerge-eval-in-buffer
1446 (goto-line (+ b-begin B-hidden-lines
))
1447 (setq b-begin-marker
(point-marker))
1448 (goto-line (+ b-end B-hidden-lines
))
1449 (setq b-end-marker
(point-marker)))
1450 (setq merge-begin-marker
(set-marker
1452 (- (marker-position a-begin-marker
)
1455 (setq merge-end-marker
(set-marker
1457 (- (marker-position a-end-marker
)
1460 ;; record all the markers for this difference
1461 (setq marker-list
(cons (vector a-begin-marker a-end-marker
1462 b-begin-marker b-end-marker
1463 merge-begin-marker merge-end-marker
1466 (setq lineno-list
(cdr lineno-list
)))
1467 ;; convert the list of difference information into a vector for
1469 (setq emerge-difference-list
(apply 'vector
(nreverse marker-list
)))))
1471 ;; If we have an ancestor, select all B variants that we prefer
1472 (defun emerge-select-prefer-Bs ()
1474 (while (< n emerge-number-of-differences
)
1475 (if (eq (aref (aref emerge-difference-list n
) 6) 'prefer-B
)
1477 (emerge-unselect-and-select-difference n t
)
1479 (aset (aref emerge-difference-list n
) 6 'prefer-B
)))
1481 (emerge-unselect-and-select-difference -
1))
1483 ;;; Common exit routines
1485 (defun emerge-write-and-delete (file-out)
1486 ;; clear screen format
1487 (delete-other-windows)
1488 ;; delete A, B, and ancestor buffers, if they haven't been changed
1489 (if (not (buffer-modified-p emerge-A-buffer
))
1490 (kill-buffer emerge-A-buffer
))
1491 (if (not (buffer-modified-p emerge-B-buffer
))
1492 (kill-buffer emerge-B-buffer
))
1493 (if (and emerge-ancestor-buffer
1494 (not (buffer-modified-p emerge-ancestor-buffer
)))
1495 (kill-buffer emerge-ancestor-buffer
))
1496 ;; Write merge buffer to file
1497 (write-file file-out
))
1501 (defun emerge-recenter (&optional arg
)
1502 "Bring the highlighted region of all three merge buffers into view,
1503 if they are in windows. If an ARGUMENT is given, the default three-window
1504 display is reestablished."
1506 ;; If there is an argument, rebuild the window structure
1508 (emerge-setup-windows emerge-A-buffer emerge-B-buffer
1509 emerge-merge-buffer
))
1510 ;; Redisplay whatever buffers are showing, if there is a selected difference
1511 (if (and (>= emerge-current-difference
0)
1512 (< emerge-current-difference emerge-number-of-differences
))
1513 (let* ((merge-buffer emerge-merge-buffer
)
1514 (buffer-A emerge-A-buffer
)
1515 (buffer-B emerge-B-buffer
)
1516 (window-A (get-buffer-window buffer-A
))
1517 (window-B (get-buffer-window buffer-B
))
1518 (merge-window (get-buffer-window merge-buffer
))
1520 (aref emerge-difference-list emerge-current-difference
)))
1522 (select-window window-A
)
1523 (emerge-position-region
1524 (- (aref diff-vector
0)
1525 (1- emerge-before-flag-length
))
1526 (+ (aref diff-vector
1)
1527 (1- emerge-after-flag-length
))
1528 (1+ (aref diff-vector
0)))))
1530 (select-window window-B
)
1531 (emerge-position-region
1532 (- (aref diff-vector
2)
1533 (1- emerge-before-flag-length
))
1534 (+ (aref diff-vector
3)
1535 (1- emerge-after-flag-length
))
1536 (1+ (aref diff-vector
2)))))
1537 (if merge-window
(progn
1538 (select-window merge-window
)
1539 (emerge-position-region
1540 (- (aref diff-vector
4)
1541 (1- emerge-before-flag-length
))
1542 (+ (aref diff-vector
5)
1543 (1- emerge-after-flag-length
))
1544 (1+ (aref diff-vector
4))))))))
1546 ;;; Window scrolling operations
1547 ;; These operations are designed to scroll all three windows the same amount,
1548 ;; so as to keep the text in them aligned.
1550 ;; Perform some operation on all three windows (if they are showing).
1551 ;; Catches all errors on the operation in the A and B windows, but not
1552 ;; in the merge window. Usually, errors come from scrolling off the
1553 ;; beginning or end of the buffer, and this gives a nice error message:
1554 ;; End of buffer is reported in the merge buffer, but if the scroll was
1555 ;; possible in the A or B windows, it is performed there before the error
1557 (defun emerge-operate-on-windows (operation arg
)
1558 (let* ((merge-buffer emerge-merge-buffer
)
1559 (buffer-A emerge-A-buffer
)
1560 (buffer-B emerge-B-buffer
)
1561 (window-A (get-buffer-window buffer-A
))
1562 (window-B (get-buffer-window buffer-B
))
1563 (merge-window (get-buffer-window merge-buffer
)))
1565 (select-window window-A
)
1567 (funcall operation arg
)
1570 (select-window window-B
)
1572 (funcall operation arg
)
1574 (if merge-window
(progn
1575 (select-window merge-window
)
1576 (funcall operation arg
)))))
1578 (defun emerge-scroll-up (&optional arg
)
1579 "Scroll up all three merge buffers, if they are in windows.
1580 If an ARGUMENT is given, that is how many lines are scrolled, else nearly
1581 the size of the merge window. `C-u -' alone as argument scrolls half the
1582 size of the merge window."
1584 (emerge-operate-on-windows
1586 ;; calculate argument to scroll-up
1587 ;; if there is an explicit argument
1588 (if (and arg
(not (equal arg
'-
)))
1590 (prefix-numeric-value arg
)
1591 ;; if not, see if we can determine a default amount (the window height)
1592 (let ((merge-window (get-buffer-window emerge-merge-buffer
)))
1593 (if (null merge-window
)
1594 ;; no window, use nil
1596 (let ((default-amount
1597 (- (window-height merge-window
) 1 next-screen-context-lines
)))
1598 ;; the window was found
1600 ;; C-u as argument means half of default amount
1601 (/ default-amount
2)
1602 ;; no argument means default amount
1603 default-amount
)))))))
1605 (defun emerge-scroll-down (&optional arg
)
1606 "Scroll down all three merge buffers, if they are in windows.
1607 If an ARGUMENT is given, that is how many lines are scrolled, else nearly
1608 the size of the merge window. `C-u -' alone as argument scrolls half the
1609 size of the merge window."
1611 (emerge-operate-on-windows
1613 ;; calculate argument to scroll-down
1614 ;; if there is an explicit argument
1615 (if (and arg
(not (equal arg
'-
)))
1617 (prefix-numeric-value arg
)
1618 ;; if not, see if we can determine a default amount (the window height)
1619 (let ((merge-window (get-buffer-window emerge-merge-buffer
)))
1620 (if (null merge-window
)
1621 ;; no window, use nil
1623 (let ((default-amount
1624 (- (window-height merge-window
) 1 next-screen-context-lines
)))
1625 ;; the window was found
1627 ;; C-u as argument means half of default amount
1628 (/ default-amount
2)
1629 ;; no argument means default amount
1630 default-amount
)))))))
1632 (defun emerge-scroll-left (&optional arg
)
1633 "Scroll left all three merge buffers, if they are in windows.
1634 If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1635 the width of the A and B windows. `C-u -' alone as argument scrolls half the
1636 width of the A and B windows."
1638 (emerge-operate-on-windows
1640 ;; calculate argument to scroll-left
1641 ;; if there is an explicit argument
1642 (if (and arg
(not (equal arg
'-
)))
1644 (prefix-numeric-value arg
)
1645 ;; if not, see if we can determine a default amount
1646 ;; (half the window width)
1647 (let ((merge-window (get-buffer-window emerge-merge-buffer
)))
1648 (if (null merge-window
)
1649 ;; no window, use nil
1651 (let ((default-amount
1652 (- (/ (window-width merge-window
) 2) 3)))
1653 ;; the window was found
1655 ;; C-u as argument means half of default amount
1656 (/ default-amount
2)
1657 ;; no argument means default amount
1658 default-amount
)))))))
1660 (defun emerge-scroll-right (&optional arg
)
1661 "Scroll right all three merge buffers, if they are in windows.
1662 If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1663 the width of the A and B windows. `C-u -' alone as argument scrolls half the
1664 width of the A and B windows."
1666 (emerge-operate-on-windows
1668 ;; calculate argument to scroll-right
1669 ;; if there is an explicit argument
1670 (if (and arg
(not (equal arg
'-
)))
1672 (prefix-numeric-value arg
)
1673 ;; if not, see if we can determine a default amount
1674 ;; (half the window width)
1675 (let ((merge-window (get-buffer-window emerge-merge-buffer
)))
1676 (if (null merge-window
)
1677 ;; no window, use nil
1679 (let ((default-amount
1680 (- (/ (window-width merge-window
) 2) 3)))
1681 ;; the window was found
1683 ;; C-u as argument means half of default amount
1684 (/ default-amount
2)
1685 ;; no argument means default amount
1686 default-amount
)))))))
1688 (defun emerge-scroll-reset ()
1689 "Reset horizontal scrolling of all three merge buffers to the left margin,
1690 if they are in windows."
1692 (emerge-operate-on-windows
1693 (function (lambda (x) (set-window-hscroll (selected-window) 0)))
1696 ;; Attempt to show the region nicely.
1697 ;; If there are min-lines lines above and below the region, then don't do
1699 ;; If not, recenter the region to make it so.
1700 ;; If that isn't possible, remove context lines balancedly from top and botton
1701 ;; so the entire region shows.
1702 ;; If that isn't possible, show the top of the region.
1703 ;; BEG must be at the beginning of a line.
1704 (defun emerge-position-region (beg end pos
)
1705 ;; First test whether the entire region is visible with
1706 ;; emerge-min-visible-lines above and below it
1707 (if (not (and (<= (progn
1708 (move-to-window-line emerge-min-visible-lines
)
1712 (move-to-window-line
1713 (- (1+ emerge-min-visible-lines
)))
1715 ;; We failed that test, see if it fits at all
1716 ;; Meanwhile positioning it correctly in case it doesn't fit
1718 (set-window-start (selected-window) beg
)
1719 (setq fits
(pos-visible-in-window-p end
))
1721 ;; Determine the number of lines that the region occupies
1723 (while (> end
(progn
1724 (move-to-window-line lines
)
1726 (setq lines
(1+ lines
)))
1727 ;; And position the beginning on the right line
1729 (recenter (/ (1+ (- (1- (window-height (selected-window)))
1734 (defun emerge-next-difference ()
1735 "Advance to the next difference."
1737 (if (< emerge-current-difference emerge-number-of-differences
)
1738 (let ((n (1+ emerge-current-difference
)))
1739 (while (and emerge-skip-prefers
1740 (< n emerge-number-of-differences
)
1741 (memq (aref (aref emerge-difference-list n
) 6)
1742 '(prefer-A prefer-B
)))
1744 (let ((buffer-read-only nil
))
1745 (emerge-unselect-and-select-difference n
)))
1748 (defun emerge-previous-difference ()
1749 "Go to the previous difference."
1751 (if (> emerge-current-difference -
1)
1752 (let ((n (1- emerge-current-difference
)))
1753 (while (and emerge-skip-prefers
1755 (memq (aref (aref emerge-difference-list n
) 6)
1756 '(prefer-A prefer-B
)))
1758 (let ((buffer-read-only nil
))
1759 (emerge-unselect-and-select-difference n
)))
1760 (error "At beginning")))
1762 (defun emerge-jump-to-difference (difference-number)
1763 "Go to the N-th difference."
1765 (let ((buffer-read-only nil
))
1766 (setq difference-number
(1- difference-number
))
1767 (if (and (>= difference-number -
1)
1768 (< difference-number
(1+ emerge-number-of-differences
)))
1769 (emerge-unselect-and-select-difference difference-number
)
1770 (error "Bad difference number"))))
1772 (defun emerge-quit (arg)
1773 "Finish an Emerge session. Prefix ARGUMENT means to abort rather than
1774 successfully finish. The difference depends on how the merge was started,
1775 but usually means to not write over one of the original files, or to signal
1776 to some process which invoked Emerge a failure code.
1778 Unselects the selected difference, if any, restores the read-only and modified
1779 flags of the merged file buffers, restores the local keymap of the merge
1780 buffer, and sets off various emerge flags. Using Emerge commands in this
1781 buffer after this will cause serious problems."
1786 "Do you really want to successfully finish this merge? "
1787 "Do you really want to abort this merge? "))
1789 (emerge-really-quit arg
)))
1791 ;; Perform the quit operations.
1792 (defun emerge-really-quit (arg)
1793 (setq buffer-read-only nil
)
1794 (emerge-unselect-and-select-difference -
1)
1795 (emerge-restore-buffer-characteristics)
1796 ;; null out the difference markers so they don't slow down future editing
1798 (mapcar (function (lambda (d)
1799 (set-marker (aref d
0) nil
)
1800 (set-marker (aref d
1) nil
)
1801 (set-marker (aref d
2) nil
)
1802 (set-marker (aref d
3) nil
)
1803 (set-marker (aref d
4) nil
)
1804 (set-marker (aref d
5) nil
)))
1805 emerge-difference-list
)
1806 ;; allow them to be garbage collected
1807 (setq emerge-difference-list nil
)
1808 ;; restore the local map
1809 (use-local-map emerge-old-keymap
)
1810 ;; turn off all the emerge modes
1811 (setq emerge-mode nil
)
1812 (setq emerge-fast-mode nil
)
1813 (setq emerge-edit-mode nil
)
1814 (setq emerge-auto-advance nil
)
1815 (setq emerge-skip-prefers nil
)
1816 ;; restore mode line
1817 (kill-local-variable 'mode-line-buffer-identification
)
1818 (let ((emerge-prefix-argument arg
))
1819 (run-hooks 'emerge-quit-hooks
)))
1821 (defun emerge-select-A (&optional force
)
1822 "Select the A variant of this difference. Refuses to function if this
1823 difference has been edited, i.e., if it is neither the A nor the B variant.
1824 An ARGUMENT forces the variant to be selected even if the difference has
1828 (function (lambda ()
1829 (emerge-select-A-edit merge-begin merge-end A-begin A-end
)
1830 (if emerge-auto-advance
1831 (emerge-next-difference)))))
1833 (function (lambda ()
1834 (if emerge-auto-advance
1835 (emerge-next-difference))))))
1836 (emerge-select-version force operate-no-change operate operate
)))
1838 ;; Actually select the A variant
1839 (defun emerge-select-A-edit (merge-begin merge-end A-begin A-end
)
1840 (emerge-eval-in-buffer
1842 (delete-region merge-begin merge-end
)
1843 (goto-char merge-begin
)
1844 (insert-buffer-substring emerge-A-buffer A-begin A-end
)
1845 (goto-char merge-begin
)
1846 (aset diff-vector
6 'A
)
1847 (emerge-refresh-mode-line)))
1849 (defun emerge-select-B (&optional force
)
1850 "Select the B variant of this difference. Refuses to function if this
1851 difference has been edited, i.e., if it is neither the A nor the B variant.
1852 An ARGUMENT forces the variant to be selected even if the difference has
1856 (function (lambda ()
1857 (emerge-select-B-edit merge-begin merge-end B-begin B-end
)
1858 (if emerge-auto-advance
1859 (emerge-next-difference)))))
1861 (function (lambda ()
1862 (if emerge-auto-advance
1863 (emerge-next-difference))))))
1864 (emerge-select-version force operate operate-no-change operate
)))
1866 ;; Actually select the B variant
1867 (defun emerge-select-B-edit (merge-begin merge-end B-begin B-end
)
1868 (emerge-eval-in-buffer
1870 (delete-region merge-begin merge-end
)
1871 (goto-char merge-begin
)
1872 (insert-buffer-substring emerge-B-buffer B-begin B-end
)
1873 (goto-char merge-begin
)
1874 (aset diff-vector
6 'B
)
1875 (emerge-refresh-mode-line)))
1877 (defun emerge-default-A ()
1878 "Selects the A variant for all differences from here down in the buffer
1879 which are still defaulted, i.e., which the user has not selected and for
1880 which there is no preference."
1882 (let ((buffer-read-only nil
))
1883 (let ((selected-difference emerge-current-difference
)
1884 (n (max emerge-current-difference
0)))
1885 (while (< n emerge-number-of-differences
)
1886 (let ((diff-vector (aref emerge-difference-list n
)))
1887 (if (eq (aref diff-vector
6) 'default-B
)
1889 (emerge-unselect-and-select-difference n t
)
1891 (aset diff-vector
6 'default-A
))))
1893 (if (= (* (/ n
10) 10) n
)
1894 (message "Setting default to A...%d" n
)))
1895 (emerge-unselect-and-select-difference selected-difference
)))
1896 (message "Default A set"))
1898 (defun emerge-default-B ()
1899 "Selects the B variant for all differences from here down in the buffer
1900 which are still defaulted, i.e., which the user has not selected and for
1901 which there is no preference."
1903 (let ((buffer-read-only nil
))
1904 (let ((selected-difference emerge-current-difference
)
1905 (n (max emerge-current-difference
0)))
1906 (while (< n emerge-number-of-differences
)
1907 (let ((diff-vector (aref emerge-difference-list n
)))
1908 (if (eq (aref diff-vector
6) 'default-A
)
1910 (emerge-unselect-and-select-difference n t
)
1912 (aset diff-vector
6 'default-B
))))
1914 (if (= (* (/ n
10) 10) n
)
1915 (message "Setting default to B...%d" n
)))
1916 (emerge-unselect-and-select-difference selected-difference
)))
1917 (message "Default B set"))
1919 (defun emerge-fast-mode ()
1920 "Set fast mode, in which ordinary Emacs commands are disabled, and Emerge
1921 commands are need not be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1923 (setq buffer-read-only t
)
1924 (use-local-map emerge-fast-keymap
)
1925 (setq emerge-mode t
)
1926 (setq emerge-fast-mode t
)
1927 (setq emerge-edit-mode nil
)
1928 (message "Fast mode set")
1929 ;; force mode line redisplay
1930 (set-buffer-modified-p (buffer-modified-p)))
1932 (defun emerge-edit-mode ()
1933 "Set edit mode, in which ordinary Emacs commands are available, and Emerge
1934 commands must be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1936 (setq buffer-read-only nil
)
1937 (use-local-map emerge-edit-keymap
)
1938 (setq emerge-mode t
)
1939 (setq emerge-fast-mode nil
)
1940 (setq emerge-edit-mode t
)
1941 (message "Edit mode set")
1942 ;; force mode line redisplay
1943 (set-buffer-modified-p (buffer-modified-p)))
1945 (defun emerge-auto-advance (arg)
1946 "Toggle auto-advance mode, which causes emerge-select-A and
1947 emerge-select-B to automatically advance to the next difference. (See
1948 emerge-auto-advance.)
1949 If a positive ARGUMENT is given, it turns on auto-advance mode.
1950 If a negative ARGUMENT is given, it turns off auto-advance mode."
1952 (setq emerge-auto-advance
(if (null arg
)
1953 (not emerge-auto-advance
)
1954 (> (prefix-numeric-value arg
) 0)))
1955 (message (if emerge-skip-prefers
1957 "Auto-advance cleared"))
1958 ;; force mode line redisplay
1959 (set-buffer-modified-p (buffer-modified-p)))
1961 (defun emerge-skip-prefers (arg)
1962 "Toggle skip-prefers mode, which causes emerge-next-difference and
1963 emerge-previous-difference to automatically skip over differences for which
1964 there is a preference. (See emerge-skip-prefers.)
1965 If a positive ARGUMENT is given, it turns on skip-prefers mode.
1966 If a negative ARGUMENT is given, it turns off skip-prefers mode."
1968 (setq emerge-skip-prefers
(if (null arg
)
1969 (not emerge-skip-prefers
)
1970 (> (prefix-numeric-value arg
) 0)))
1971 (message (if emerge-skip-prefers
1973 "Skip-prefers cleared"))
1974 ;; force mode line redisplay
1975 (set-buffer-modified-p (buffer-modified-p)))
1977 (defun emerge-copy-as-kill-A ()
1978 "Put the A variant of this difference in the kill ring."
1980 (emerge-validate-difference)
1982 (aref emerge-difference-list emerge-current-difference
))
1983 (A-begin (1+ (aref diff-vector
0)))
1984 (A-end (1- (aref diff-vector
1)))
1985 ;; so further kills don't append
1988 (set-buffer emerge-A-buffer
)
1989 (copy-region-as-kill A-begin A-end
))))
1991 (defun emerge-copy-as-kill-B ()
1992 "Put the B variant of this difference in the kill ring."
1994 (emerge-validate-difference)
1996 (aref emerge-difference-list emerge-current-difference
))
1997 (B-begin (1+ (aref diff-vector
2)))
1998 (B-end (1- (aref diff-vector
3)))
1999 ;; so further kills don't append
2002 (set-buffer emerge-B-buffer
)
2003 (copy-region-as-kill B-begin B-end
))))
2005 (defun emerge-insert-A (arg)
2006 "Insert the A variant of this difference at the point.
2007 Leaves point after text, mark before.
2008 With prefix argument, puts point before, mark after."
2010 (emerge-validate-difference)
2012 (aref emerge-difference-list emerge-current-difference
))
2013 (A-begin (1+ (aref diff-vector
0)))
2014 (A-end (1- (aref diff-vector
1)))
2016 (buffer-read-only nil
))
2017 (insert-buffer-substring emerge-A-buffer A-begin A-end
)
2021 (goto-char opoint
))))
2023 (defun emerge-insert-B (arg)
2024 "Insert the B variant of this difference at the point.
2025 Leaves point after text, mark before.
2026 With prefix argument, puts point before, mark after."
2028 (emerge-validate-difference)
2030 (aref emerge-difference-list emerge-current-difference
))
2031 (B-begin (1+ (aref diff-vector
2)))
2032 (B-end (1- (aref diff-vector
3)))
2034 (buffer-read-only nil
))
2035 (insert-buffer-substring emerge-B-buffer B-begin B-end
)
2039 (goto-char opoint
))))
2041 (defun emerge-mark-difference (arg)
2042 "Leaves the point before this difference and the mark after it.
2043 With prefix argument, puts mark before, point after."
2045 (emerge-validate-difference)
2047 (aref emerge-difference-list emerge-current-difference
))
2048 (merge-begin (1+ (aref diff-vector
4)))
2049 (merge-end (1- (aref diff-vector
5))))
2052 (goto-char merge-begin
)
2053 (set-mark merge-end
))
2054 (goto-char merge-end
)
2055 (set-mark merge-begin
))))
2057 (defun emerge-file-names ()
2058 "Show the names of the buffers or files being operated on by Emerge.
2059 Use ^U L to reset the windows afterward."
2061 (delete-other-windows)
2062 (let ((temp-buffer-show-hook
2063 (function (lambda (buf)
2064 (split-window-vertically)
2065 (switch-to-buffer buf
)
2066 (other-window 1)))))
2067 (with-output-to-temp-buffer "*Help*"
2068 (emerge-eval-in-buffer emerge-A-buffer
2069 (if buffer-file-name
2071 (princ "File A is: ")
2072 (princ buffer-file-name
))
2074 (princ "Buffer A is: ")
2075 (princ (buffer-name))))
2077 (emerge-eval-in-buffer emerge-B-buffer
2078 (if buffer-file-name
2080 (princ "File B is: ")
2081 (princ buffer-file-name
))
2083 (princ "Buffer B is: ")
2084 (princ (buffer-name))))
2086 (if emerge-ancestor-buffer
2087 (emerge-eval-in-buffer emerge-ancestor-buffer
2088 (if buffer-file-name
2090 (princ "Ancestor file is: ")
2091 (princ buffer-file-name
))
2093 (princ "Ancestor buffer is: ")
2094 (princ (buffer-name))))
2096 (princ emerge-output-description
))))
2098 (defun emerge-join-differences (arg)
2099 "Join the selected difference with the following one. With a prefix
2100 argument, join with the preceeding one."
2102 (let ((n emerge-current-difference
))
2103 ;; adjust n to be first difference to join
2106 ;; n and n+1 are the differences to join
2107 ;; check that they are both differences
2108 (if (or (< n
0) (>= n
(1- emerge-number-of-differences
)))
2109 (error "Incorrect differences to join"))
2111 (emerge-unselect-difference emerge-current-difference
)
2112 ;; decrement total number of differences
2113 (setq emerge-number-of-differences
(1- emerge-number-of-differences
))
2114 ;; build new differences vector
2116 (new-differences (make-vector emerge-number-of-differences nil
)))
2117 (while (< i emerge-number-of-differences
)
2118 (aset new-differences i
2120 ((< i n
) (aref emerge-difference-list i
))
2121 ((> i n
) (aref emerge-difference-list
(1+ i
)))
2122 (t (let ((prev (aref emerge-difference-list i
))
2123 (next (aref emerge-difference-list
(1+ i
))))
2124 (vector (aref prev
0)
2130 (let ((ps (aref prev
6))
2135 ((and (or (eq ps
'B
) (eq ps
'prefer-B
))
2136 (or (eq ns
'B
) (eq ns
'prefer-B
)))
2140 (setq emerge-difference-list new-differences
))
2141 ;; set the current difference correctly
2142 (setq emerge-current-difference n
)
2143 ;; fix the mode line
2144 (emerge-refresh-mode-line)
2145 ;; reinsert the flags
2146 (emerge-select-difference emerge-current-difference
)
2149 (defun emerge-split-difference ()
2150 "Split the current difference where the points are in the three windows."
2152 (let ((n emerge-current-difference
))
2153 ;; check that this is a valid difference
2154 (emerge-validate-difference)
2155 ;; get the point values and old difference
2156 (let ((A-point (emerge-eval-in-buffer emerge-A-buffer
2158 (B-point (emerge-eval-in-buffer emerge-B-buffer
2160 (merge-point (point-marker))
2161 (old-diff (aref emerge-difference-list n
)))
2162 ;; check location of the points, give error if they aren't in the
2164 (if (or (< A-point
(aref old-diff
0))
2165 (> A-point
(aref old-diff
1)))
2166 (error "Point outside of difference in A buffer"))
2167 (if (or (< B-point
(aref old-diff
2))
2168 (> B-point
(aref old-diff
3)))
2169 (error "Point outside of difference in B buffer"))
2170 (if (or (< merge-point
(aref old-diff
4))
2171 (> merge-point
(aref old-diff
5)))
2172 (error "Point outside of difference in merge buffer"))
2174 (emerge-unselect-difference emerge-current-difference
)
2175 ;; increment total number of differences
2176 (setq emerge-number-of-differences
(1+ emerge-number-of-differences
))
2177 ;; build new differences vector
2179 (new-differences (make-vector emerge-number-of-differences nil
)))
2180 (while (< i emerge-number-of-differences
)
2181 (aset new-differences i
2184 (aref emerge-difference-list i
))
2186 (aref emerge-difference-list
(1- i
)))
2188 (vector (aref old-diff
0)
2196 (vector (copy-marker A-point
)
2198 (copy-marker B-point
)
2200 (copy-marker merge-point
)
2202 (aref old-diff
6)))))
2204 (setq emerge-difference-list new-differences
))
2205 ;; set the current difference correctly
2206 (setq emerge-current-difference n
)
2207 ;; fix the mode line
2208 (emerge-refresh-mode-line)
2209 ;; reinsert the flags
2210 (emerge-select-difference emerge-current-difference
)
2211 (emerge-recenter))))
2213 (defun emerge-trim-difference ()
2214 "Trim lines off the top and bottom of a difference that are the same in
2215 both the A and B versions. (This can happen when the A and B versions
2216 have common lines that the ancestor version does not share.)"
2218 ;; make sure we are in a real difference
2219 (emerge-validate-difference)
2221 (emerge-unselect-difference emerge-current-difference
)
2222 (let* ((diff (aref emerge-difference-list emerge-current-difference
))
2223 (top-a (marker-position (aref diff
0)))
2224 (bottom-a (marker-position (aref diff
1)))
2225 (top-b (marker-position (aref diff
2)))
2226 (bottom-b (marker-position (aref diff
3)))
2227 (top-m (marker-position (aref diff
4)))
2228 (bottom-m (marker-position (aref diff
5)))
2229 size success sa sb sm
)
2230 ;; move down the tops of the difference regions as much as possible
2231 ;; Try advancing comparing 1000 chars at a time.
2232 ;; When that fails, go 500 chars at a time, and so on.
2237 (setq size
(min size
(- bottom-a top-a
) (- bottom-b top-b
)
2238 (- bottom-m top-m
)))
2239 (setq sa
(emerge-eval-in-buffer emerge-A-buffer
2240 (buffer-substring top-a
2242 (setq sb
(emerge-eval-in-buffer emerge-B-buffer
2243 (buffer-substring top-b
2245 (setq sm
(buffer-substring top-m
(+ size top-m
)))
2246 (setq success
(and (> size
0) (equal sa sb
) (equal sb sm
)))
2248 (setq top-a
(+ top-a size
)
2249 top-b
(+ top-b size
)
2250 top-m
(+ top-m size
))))
2251 (setq size
(/ size
2)))
2252 ;; move up the bottoms of the difference regions as much as possible
2253 ;; Try advancing comparing 1000 chars at a time.
2254 ;; When that fails, go 500 chars at a time, and so on.
2259 (setq size
(min size
(- bottom-a top-a
) (- bottom-b top-b
)
2260 (- bottom-m top-m
)))
2261 (setq sa
(emerge-eval-in-buffer emerge-A-buffer
2262 (buffer-substring (- bottom-a size
)
2264 (setq sb
(emerge-eval-in-buffer emerge-B-buffer
2265 (buffer-substring (- bottom-b size
)
2267 (setq sm
(buffer-substring (- bottom-m size
) bottom-m
))
2268 (setq success
(and (> size
0) (equal sa sb
) (equal sb sm
)))
2270 (setq bottom-a
(- bottom-a size
)
2271 bottom-b
(- bottom-b size
)
2272 bottom-m
(- bottom-m size
))))
2273 (setq size
(/ size
2)))
2274 ;; {top,bottom}-{a,b,m} are now set at the new beginnings and ends
2275 ;; of the difference regions. Move them to the beginning of lines, as
2277 (emerge-eval-in-buffer emerge-A-buffer
2280 (aset diff
0 (point-marker))
2281 (goto-char bottom-a
)
2282 (beginning-of-line 2)
2283 (aset diff
1 (point-marker)))
2284 (emerge-eval-in-buffer emerge-B-buffer
2287 (aset diff
2 (point-marker))
2288 (goto-char bottom-b
)
2289 (beginning-of-line 2)
2290 (aset diff
3 (point-marker)))
2293 (aset diff
4 (point-marker))
2294 (goto-char bottom-m
)
2295 (beginning-of-line 2)
2296 (aset diff
5 (point-marker))
2297 ;; put the flags back in, recenter the display
2298 (emerge-select-difference emerge-current-difference
)
2301 (defun emerge-find-difference (arg)
2302 "Find the difference containing the current position of the point.
2303 If there is no containing difference and the prefix argument is positive,
2304 it finds the nearest following difference. A negative prefix argument finds
2305 the nearest previous difference."
2307 ;; search for the point in the merge buffer, using the markers
2308 ;; for the beginning and end of the differences in the merge buffer
2309 (emerge-find-difference1 arg
(point) 4 5))
2311 (defun emerge-find-difference-A (arg)
2312 "Find the difference containing the current position of the point in the
2313 A buffer. (Nonetheless, this command must be executed in the merge buffer.)
2314 If there is no containing difference and the prefix argument is positive,
2315 it finds the nearest following difference. A negative prefix argument finds
2316 the nearest previous difference."
2318 ;; search for the point in the A buffer, using the markers
2319 ;; for the beginning and end of the differences in the A buffer
2320 (emerge-find-difference1 arg
2321 (emerge-eval-in-buffer emerge-A-buffer
(point))
2324 (defun emerge-find-difference-B (arg)
2325 "Find the difference containing the current position of the point in the
2326 B buffer. (Nonetheless, this command must be executed in the merge buffer.)
2327 If there is no containing difference and the prefix argument is positive,
2328 it finds the nearest following difference. A negative prefix argument finds
2329 the nearest previous difference."
2331 ;; search for the point in the B buffer, using the markers
2332 ;; for the beginning and end of the differences in the B buffer
2333 (emerge-find-difference1 arg
2334 (emerge-eval-in-buffer emerge-B-buffer
(point))
2337 (defun emerge-find-difference1 (arg location begin end
)
2339 ;; find first difference containing or after the current position
2342 (while (< n emerge-number-of-differences
)
2343 (let ((diff-vector (aref emerge-difference-list n
)))
2344 (if (<= location
(marker-position (aref diff-vector end
)))
2347 emerge-number-of-differences
))
2349 ;; whether the found difference contains the current position
2350 (and (< index emerge-number-of-differences
)
2351 (<= (marker-position (aref (aref emerge-difference-list index
)
2355 ;; numeric value of prefix argument
2356 (prefix-numeric-value arg
)))
2357 (emerge-unselect-and-select-difference
2359 ;; if the point is in a difference, select it
2361 ;; if the arg is nil and the point is not in a difference, error
2362 ((null arg
) (error "No difference contains point"))
2363 ;; if the arg is positive, select the following difference
2365 (if (< index emerge-number-of-differences
)
2367 (error "No difference contains or follows point")))
2368 ;; if the arg is negative, select the preceeding difference
2372 (error "No difference contains or preceeds point")))))))
2374 (defun emerge-line-numbers ()
2375 "Display the current line numbers of the points in the A, B, and
2379 (and (>= emerge-current-difference
0)
2380 (< emerge-current-difference emerge-number-of-differences
)))
2381 (diff (and valid-diff
2382 (aref emerge-difference-list emerge-current-difference
)))
2383 (merge-line (emerge-line-number-in-buf 4 5))
2384 (A-line (emerge-eval-in-buffer emerge-A-buffer
2385 (emerge-line-number-in-buf 0 1)))
2386 (B-line (emerge-eval-in-buffer emerge-B-buffer
2387 (emerge-line-number-in-buf 2 3))))
2388 (message "At lines: merge = %d, A = %d, B = %d"
2389 merge-line A-line B-line
)))
2391 (defun emerge-line-number-in-buf (begin-marker end-marker
)
2393 (setq temp
(save-excursion
2395 (1+ (count-lines 1 (point)))))
2398 (if (> (point) (aref diff begin-marker
))
2399 (setq temp
(- temp emerge-before-flag-lines
)))
2400 (if (> (point) (aref diff end-marker
))
2401 (setq temp
(- temp emerge-after-flag-lines
)))))
2404 (defun emerge-set-combine-versions-template (start end
&optional localize
)
2405 "Copy region into emerge-combine-versions-template which controls how
2406 emerge-combine-versions will combine the two versions.
2407 With prefix argument, emerge-combine-versions is made local to this
2408 merge buffer. Localization is permanent for any particular merge buffer."
2409 (interactive "r\nP")
2411 (make-local-variable 'emerge-combine-versions-template
))
2412 (setq emerge-combine-versions-template
(buffer-substring start end
))
2414 (if (assq 'emerge-combine-versions-template
(buffer-local-variables))
2415 "emerge-set-combine-versions-template set locally."
2416 "emerge-set-combine-versions-template set.")))
2418 (defun emerge-combine-versions (&optional force
)
2419 "Combine the two versions using the template in
2420 emerge-combine-versions-template.
2421 Refuses to function if this difference has been edited, i.e., if it is
2422 neither the A nor the B variant.
2423 An ARGUMENT forces the variant to be selected even if the difference has
2426 (emerge-combine-versions-internal emerge-combine-versions-template force
))
2428 (defun emerge-combine-versions-register (char &optional force
)
2429 "Combine the two versions using the template in register REG.
2430 See documentation of the variable emerge-combine-versions-template
2431 for how the template is interpreted.
2432 Refuses to function if this difference has been edited, i.e., if it is
2433 neither the A nor the B variant.
2434 An ARGUMENT forces the variant to be selected even if the difference has
2436 (interactive "cRegister containing template: \nP")
2437 (let ((template (get-register char
)))
2438 (if (not (stringp template
))
2439 (error "Register does not contain text"))
2440 (emerge-combine-versions-internal template force
)))
2442 (defun emerge-combine-versions-internal (template force
)
2444 (function (lambda ()
2445 (emerge-combine-versions-edit merge-begin merge-end
2446 A-begin A-end B-begin B-end
)
2447 (if emerge-auto-advance
2448 (emerge-next-difference))))))
2449 (emerge-select-version force operate operate operate
)))
2451 (defun emerge-combine-versions-edit (merge-begin merge-end
2452 A-begin A-end B-begin B-end
)
2453 (emerge-eval-in-buffer
2455 (delete-region merge-begin merge-end
)
2456 (goto-char merge-begin
)
2458 (while (< i
(length template
))
2459 (let ((c (aref template i
)))
2468 (insert-buffer-substring emerge-A-buffer A-begin A-end
))
2470 (insert-buffer-substring emerge-B-buffer B-begin B-end
))
2477 (goto-char merge-begin
)
2478 (aset diff-vector
6 'combined
)
2479 (emerge-refresh-mode-line)))
2481 (defun emerge-set-merge-mode (mode)
2482 "Set the major mode in a merge buffer. Overrides any change that the mode
2483 might make to the mode line or local keymap. Leaves merge in fast mode."
2485 (list (intern (completing-read "New major mode for merge buffer: "
2486 obarray
'commandp t nil
))))
2488 (emerge-refresh-mode-line)
2489 (if emerge-fast-mode
2491 (emerge-edit-mode)))
2493 (defun emerge-one-line-window ()
2495 (let ((window-min-height 1))
2496 (shrink-window (- (window-height) 2))))
2498 ;;; Support routines
2500 ;; Select a difference by placing the visual flags around the appropriate
2501 ;; group of lines in the A, B, and merge buffers
2502 (defun emerge-select-difference (n)
2503 (let ((diff-vector (aref emerge-difference-list n
)))
2504 (emerge-place-flags-in-buffer emerge-A-buffer
2505 (aref diff-vector
0) (aref diff-vector
1))
2506 (emerge-place-flags-in-buffer emerge-B-buffer
2507 (aref diff-vector
2) (aref diff-vector
3))
2508 (emerge-place-flags-in-buffer emerge-merge-buffer
2509 (aref diff-vector
4) (aref diff-vector
5))))
2511 (defun emerge-place-flags-in-buffer (buffer before after
)
2512 (if (eq buffer emerge-merge-buffer
)
2513 (emerge-place-flags-in-buffer1 buffer before after
)
2514 (emerge-eval-in-buffer
2516 (emerge-place-flags-in-buffer1 buffer before after
))))
2518 (defun emerge-place-flags-in-buffer1 (buffer before after
)
2519 (let ((buffer-read-only nil
))
2522 (insert-before-markers emerge-before-flag
)
2524 (insert emerge-after-flag
)
2525 ;; put the markers into the flags, so alterations above or below won't move
2527 ;; before marker is one char before the end of the before flag
2528 ;; after marker is one char after the beginning of the after flag
2529 (set-marker before
(1- before
))
2530 (set-marker after
(1+ after
))))
2532 ;; Unselect a difference by removing the visual flags in the buffers.
2533 (defun emerge-unselect-difference (n)
2534 (let ((diff-vector (aref emerge-difference-list n
)))
2535 (emerge-remove-flags-in-buffer emerge-A-buffer
2536 (aref diff-vector
0) (aref diff-vector
1))
2537 (emerge-remove-flags-in-buffer emerge-B-buffer
2538 (aref diff-vector
2) (aref diff-vector
3))
2539 (emerge-remove-flags-in-buffer emerge-merge-buffer
2540 (aref diff-vector
4) (aref diff-vector
5))))
2542 (defun emerge-remove-flags-in-buffer (buffer before after
)
2543 (emerge-eval-in-buffer
2545 (let ((buffer-read-only nil
))
2546 ;; put the markers at the beginning of the flags
2547 (set-marker before
(- before
(1- emerge-before-flag-length
)))
2548 (set-marker after
(1- after
))
2551 (if (looking-at emerge-before-flag-match
)
2552 (delete-char emerge-before-flag-length
)
2553 ;; the flag isn't there
2555 (message "Trouble removing flag."))
2557 (if (looking-at emerge-after-flag-match
)
2558 (delete-char emerge-after-flag-length
)
2559 ;; the flag isn't there
2561 (message "Trouble removing flag.")))))
2563 ;; Select a difference, removing an flags that exist now.
2564 (defun emerge-unselect-and-select-difference (n &optional suppress-display
)
2565 (if (and (>= emerge-current-difference
0)
2566 (< emerge-current-difference emerge-number-of-differences
))
2567 (emerge-unselect-difference emerge-current-difference
))
2568 (if (and (>= n
0) (< n emerge-number-of-differences
))
2570 (emerge-select-difference n
)
2571 (let* ((diff-vector (aref emerge-difference-list n
))
2572 (selection-type (aref diff-vector
6)))
2573 (if (eq selection-type
'default-A
)
2574 (aset diff-vector
6 'A
)
2575 (if (eq selection-type
'default-B
)
2576 (aset diff-vector
6 'B
))))))
2577 (setq emerge-current-difference n
)
2578 (if (not suppress-display
)
2581 (emerge-refresh-mode-line))))
2583 ;; Perform tests to see whether user should be allowed to select a version
2584 ;; of this difference:
2585 ;; a valid difference has been selected; and
2586 ;; the difference text in the merge buffer is:
2587 ;; the A version (execute a-version), or
2588 ;; the B version (execute b-version), or
2589 ;; empty (execute neither-version), or
2590 ;; argument FORCE is true (execute neither-version)
2591 ;; Otherwise, signal an error.
2592 (defun emerge-select-version (force a-version b-version neither-version
)
2593 (emerge-validate-difference)
2594 (let ((buffer-read-only nil
))
2596 (aref emerge-difference-list emerge-current-difference
))
2597 (A-begin (1+ (aref diff-vector
0)))
2598 (A-end (1- (aref diff-vector
1)))
2599 (B-begin (1+ (aref diff-vector
2)))
2600 (B-end (1- (aref diff-vector
3)))
2601 (merge-begin (1+ (aref diff-vector
4)))
2602 (merge-end (1- (aref diff-vector
5))))
2603 (if (emerge-compare-buffers emerge-A-buffer A-begin A-end
2604 emerge-merge-buffer merge-begin
2607 (if (emerge-compare-buffers emerge-B-buffer B-begin B-end
2608 emerge-merge-buffer merge-begin
2611 (if (or force
(= merge-begin merge-end
))
2612 (funcall neither-version
)
2613 (error "This difference region has been edited.")))))))
2615 ;; Revise the mode line to display which difference we have selected
2617 (defun emerge-refresh-mode-line ()
2618 (setq mode-line-buffer-identification
2619 (list (format "Emerge: %%b diff %d of %d%s"
2620 (1+ emerge-current-difference
)
2621 emerge-number-of-differences
2622 (if (and (>= emerge-current-difference
0)
2623 (< emerge-current-difference
2624 emerge-number-of-differences
))
2625 (cdr (assq (aref (aref emerge-difference-list
2626 emerge-current-difference
)
2630 (prefer-A .
" - A*")
2631 (prefer-B .
" - B*")
2632 (combined .
" - comb"))))
2634 ;; Force mode-line redisplay
2635 (set-buffer-modified-p (buffer-modified-p)))
2637 ;; compare two regions in two buffers for containing the same text
2638 (defun emerge-compare-buffers (buffer-x x-begin x-end buffer-y y-begin y-end
)
2639 ;; first check that the two regions are the same length
2640 (if (not (and (= (- x-end x-begin
) (- y-end y-begin
))))
2643 (while (< x-begin x-end
)
2644 ;; bite off and compare no more than 1000 characters at a time
2645 (let* ((compare-length (min (- x-end x-begin
) 1000))
2646 (x-string (emerge-eval-in-buffer
2648 (buffer-substring x-begin
2649 (+ x-begin compare-length
))))
2650 (y-string (emerge-eval-in-buffer
2652 (buffer-substring y-begin
2653 (+ y-begin compare-length
)))))
2654 (if (not (string-equal x-string y-string
))
2656 (setq x-begin
(+ x-begin compare-length
))
2657 (setq y-begin
(+ y-begin compare-length
)))))
2660 ;; Construct a unique buffer name.
2661 ;; The first one tried is prefixsuffix, then prefix<2>suffix,
2662 ;; prefix<3>suffix, etc.
2663 (defun emerge-unique-buffer-name (prefix suffix
)
2664 (if (null (get-buffer (concat prefix suffix
)))
2665 (concat prefix suffix
)
2667 (while (get-buffer (format "%s<%d>%s" prefix n suffix
))
2669 (format "%s<%d>%s" prefix n suffix
))))
2671 ;; Verify that we have a difference selected.
2672 (defun emerge-validate-difference ()
2673 (if (not (and (>= emerge-current-difference
0)
2674 (< emerge-current-difference emerge-number-of-differences
)))
2675 (error "No difference selected")))
2677 ;;; Functions for saving and restoring a batch of variables
2679 ;; These functions save (get the values of) and restore (set the values of)
2680 ;; a list of variables. The argument is a list of symbols (the names of
2681 ;; the variables). A list element can also be a list of two functions,
2682 ;; the first of which (when called with no arguments) gets the value, and
2683 ;; the second (when called with a value as an argment) sets the value.
2684 ;; A "function" is anything that funcall can handle as an argument.
2686 (defun emerge-save-variables (vars)
2687 (mapcar (function (lambda (v) (if (symbolp v
)
2689 (funcall (car v
)))))
2692 (defun emerge-restore-variables (vars values
)
2694 (let ((var (car vars
))
2695 (value (car values
)))
2698 (funcall (car (cdr var
)) value
)))
2699 (setq vars
(cdr vars
))
2700 (setq values
(cdr values
))))
2702 ;; Make a temporary file that only we have access to.
2703 ;; PREFIX is appended to emerge-temp-file-prefix to make the filename prefix.
2704 (defun emerge-make-temp-file (prefix)
2705 (let ((f (make-temp-name (concat emerge-temp-file-prefix prefix
))))
2707 (write-region (point-min) (point-min) f nil
'no-message
)
2708 (set-file-modes f emerge-temp-file-mode
)
2711 ;;; Functions that query the user before he can write out the current buffer.
2713 (defun emerge-query-write-file ()
2714 "Query the user if he really wants to write out the incomplete merge.
2715 If he says yes, call write-file to do so. See emerge-query-and-call
2716 for details of the querying process."
2718 (emerge-query-and-call 'write-file
))
2720 (defun emerge-query-save-buffer ()
2721 "Query the user if he really wants to write out the incomplete merge.
2722 If he says yes, call save-buffer to do so. See emerge-query-and-call
2723 for details of the querying process."
2725 (emerge-query-and-call 'save-buffer
))
2727 (defun emerge-query-and-call (command)
2728 "Query the user if he really wants to write out the incomplete merge.
2729 If he says yes, call COMMAND interactively. During the call, the flags
2730 around the current difference are removed."
2731 (if (yes-or-no-p "Do you really write to write out this unfinished merge? ")
2732 ;; He really wants to do it -- unselect the difference for the duration
2734 (if (and (>= emerge-current-difference
0)
2735 (< emerge-current-difference emerge-number-of-differences
))
2736 (emerge-unselect-difference emerge-current-difference
))
2737 ;; call-interactively takes the value of current-prefix-arg as the
2738 ;; prefix argument value to be passed to the command. Thus, we have
2739 ;; to do nothing special to make sure the prefix argument is
2740 ;; transmitted to the command.
2741 (call-interactively command
)
2742 (if (and (>= emerge-current-difference
0)
2743 (< emerge-current-difference emerge-number-of-differences
))
2745 (emerge-select-difference emerge-current-difference
)
2746 (emerge-recenter))))
2747 ;; He's being smart and not doing it
2748 (message "Not written")))
2750 ;; Make sure the current buffer (for a file) has the same contents as the
2751 ;; file on disk, and attempt to remedy the situation if not.
2752 ;; Signal an error if we can't make them the same, or the user doesn't want
2753 ;; to do what is necessary to make them the same.
2754 (defun emerge-verify-file-buffer ()
2755 ;; First check if the file has been modified since the buffer visited it.
2756 (if (verify-visited-file-modtime (current-buffer))
2757 (if (buffer-modified-p)
2758 ;; If buffer is not obsolete and is modified, offer to save
2759 (if (yes-or-no-p (format "Save file %s? " buffer-file-name
))
2761 (error "Buffer out of sync for file %s" buffer-file-name
))
2762 ;; If buffer is not obsolete and is not modified, do nothing
2764 (if (buffer-modified-p)
2765 ;; If buffer is obsolete and is modified, give error
2766 (error "Buffer out of sync for file %s" buffer-file-name
)
2767 ;; If buffer is obsolete and is not modified, offer to revert
2768 (if (yes-or-no-p (format "Revert file %s? " buffer-file-name
))
2770 (error "Buffer out of sync for file %s" buffer-file-name
)))))
2772 ;; Utilities that might have value outside of Emerge.
2774 ;; Set up the mode in the current buffer to duplicate the mode in another
2776 (defun emerge-copy-modes (buffer)
2777 ;; Set the major mode
2778 (funcall (emerge-eval-in-buffer buffer major-mode
)))
2780 ;; Define a key, even if a prefix of it is defined
2781 (defun emerge-force-define-key (keymap key definition
)
2782 "Like define-key, but is not stopped if a prefix of KEY is a defined
2784 ;; Find out if a prefix of key is defined
2785 (let ((v (lookup-key keymap key
)))
2786 ;; If so, undefine it
2788 (define-key keymap
(substring key
0 v
) nil
)))
2789 ;; Now define the key
2790 (define-key keymap key definition
))
2792 ;;; Improvements to describe-mode, so that it describes minor modes as well
2793 ;;; as the major mode
2794 (defun describe-mode (&optional minor
)
2795 "Display documentation of current major mode.
2796 If optional MINOR is non-nil (or prefix argument is given if interactive),
2797 display documentation of acive minor modes as well.
2798 For this to work correctly for a minor mode, the mode's indicator variable
2799 (listed in minor-mode-alist) must also be a function whose documentation
2800 describes the minor mode."
2802 (with-output-to-temp-buffer "*Help*"
2805 (princ (documentation major-mode
))
2806 (let ((minor-modes minor-mode-alist
)
2807 (locals (buffer-local-variables)))
2809 (let* ((minor-mode (car (car minor-modes
)))
2810 (indicator (car (cdr (car minor-modes
))))
2811 (local-binding (assq minor-mode locals
)))
2812 ;; Document a minor mode if it is listed in minor-mode-alist,
2813 ;; bound locally in this buffer, non-nil, and has a function
2815 (if (and local-binding
2817 (fboundp minor-mode
))
2819 (princ (format "\n\n\n%s minor mode (indicator%s):\n"
2820 minor-mode indicator
))
2821 (princ (documentation minor-mode
)))))
2822 (setq minor-modes
(cdr minor-modes
))))
2823 (print-help-return-message)))
2825 ;; Adjust things so that keyboard macro definitions are documented correctly.
2826 (fset 'defining-kbd-macro
(symbol-function 'start-kbd-macro
))
2828 ;; Function to shadow a definition in a keymap with definitions in another.
2829 (defun emerge-shadow-key-definition (olddef newdef keymap shadowmap
)
2830 "Shadow OLDDEF with NEWDEF for any keys in KEYMAP with entries in SHADOWMAP.
2831 In other words, SHADOWMAP will now shadow all definitions of OLDDEF in KEYMAP
2832 with NEWDEF. Does not affect keys that are already defined in SHADOWMAP,
2833 including those whose definition is OLDDEF."
2834 ;; loop through all keymaps accessible from keymap
2835 (let ((maps (accessible-keymaps keymap
)))
2837 (let ((prefix (car (car maps
)))
2838 (map (cdr (car maps
))))
2842 (let ((len (length map
))
2845 (if (eq (aref map i
) olddef
)
2846 ;; set the shadowing definition
2847 (let ((key (concat prefix
(char-to-string i
))))
2848 (emerge-define-key-if-possible shadowmap key newdef
)))
2852 (if (eq (cdr-safe (car-safe map
)) olddef
)
2853 ;; set the shadowing definition
2855 (concat prefix
(char-to-string (car (car map
))))))
2856 (emerge-define-key-if-possible shadowmap key newdef
)))
2857 (setq map
(cdr map
)))))
2858 (setq maps
(cdr maps
)))))
2860 ;; Define a key if it (or a prefix) is not already defined in the map.
2861 (defun emerge-define-key-if-possible (keymap key definition
)
2862 ;; look up the present definition of the key
2863 (let ((present (lookup-key keymap key
)))
2864 (if (integerp present
)
2865 ;; if it is "too long", look up the valid prefix
2866 (if (not (lookup-key keymap
(substring key
0 present
)))
2867 ;; if the prefix isn't defined, define it
2868 (define-key keymap key definition
))
2869 ;; if there is no present definition, define it
2871 (define-key keymap key definition
)))))
2873 (defun emerge-recursively-substitute-key-definition (olddef newdef keymap
)
2874 "Like substitute-key-definition, but examines and substitutes in all
2875 keymaps accessible from KEYMAP. Make sure that subordinate keymaps aren't
2876 shared with other keymaps! (copy-keymap will suffice.)"
2877 ;; Loop through all keymaps accessible from keymap
2878 (let ((maps (accessible-keymaps keymap
)))
2880 ;; Substitute in this keymap
2881 (substitute-key-definition olddef newdef
(cdr (car maps
)))
2882 (setq maps
(cdr maps
)))))
2884 ;; Show the name of the file in the buffer.
2885 (defun emerge-show-file-name ()
2886 "Displays the name of the file loaded into the current buffer.
2887 If the name won't fit on one line, the minibuffer is expanded to hold it,
2888 and the command waits for a keystroke from the user. If the keystroke is
2889 SPC, it is ignored; if it is anything else, it is processed as a command."
2891 (let ((name (buffer-file-name)))
2893 (setq name
"Buffer has no file name."))
2894 (save-window-excursion
2895 (select-window (minibuffer-window))
2898 (if (not (pos-visible-in-window-p))
2899 (let ((echo-keystrokes 0))
2900 (while (and (not (pos-visible-in-window-p))
2901 (> (1- (frame-height)) (window-height)))
2903 (let ((c (read-char)))
2905 (setq unread-command-char c
))))))))
2907 ;; Improved auto-save file names.
2908 ;; This function fixes many problems with the standard auto-save file names:
2909 ;; Auto-save files for non-file buffers get put in the default directory
2910 ;; for the buffer, whether that makes sense or not.
2911 ;; Auto-save files for file buffers get put in the directory of the file,
2912 ;; regardless of whether we can write into it or not.
2913 ;; Auto-save files for non-file buffers don't use the process id, so if a
2914 ;; user runs more than on Emacs, they can make auto-save files that overwrite
2916 ;; To use this function, do:
2917 ;; (fset 'make-auto-save-file-name
2918 ;; (symbol-function 'emerge-make-auto-save-file-name))
2919 (defun emerge-make-auto-save-file-name ()
2920 "Return file name to use for auto-saves of current buffer.
2921 Does not consider auto-save-visited-file-name; that is checked
2922 before calling this function.
2923 You can redefine this for customization.
2924 See also auto-save-file-name-p."
2925 (if buffer-file-name
2926 ;; if buffer has a file, try the format <file directory>/#<file name>#
2927 (let ((f (concat (file-name-directory buffer-file-name
)
2929 (file-name-nondirectory buffer-file-name
)
2931 (if (file-writable-p f
)
2932 ;; the file is writable, so use it
2934 ;; the file isn't writable, so use the format
2935 ;; ~/#&<file name>&<hash of directory>#
2936 (concat (getenv "HOME")
2938 (file-name-nondirectory buffer-file-name
)
2940 (hash-string-into-string
2941 (file-name-directory buffer-file-name
))
2943 ;; if buffer has no file, use the format ~/#%<buffer name>%<process id>#
2944 (expand-file-name (concat (getenv "HOME")
2946 ;; quote / into \! and \ into \\
2947 (unslashify-name (buffer-name))
2952 ;; Hash a string into five characters more-or-less suitable for use in a file
2953 ;; name. (Allowed characters are ! through ~, except /.)
2954 (defun hash-string-into-string (s)
2955 (let ((bins (vector 0 0 0 0 0))
2957 (while (< i
(length s
))
2958 (aset bins
(% i
5) (%
(+ (* (aref bins
(% i
5)) 35)
2962 (mapconcat (function (lambda (b)
2963 (setq b
(+ (% b
93) ?
!))
2966 (char-to-string b
)))
2969 ;; Quote any /s in a string by replacing them with \!.
2970 ;; Also, replace any \s by \\, to make it one-to-one.
2971 (defun unslashify-name (s)
2973 (while (string-match "[/\\]" s limit
)
2974 (setq s
(concat (substring s
0 (match-beginning 0))
2975 (if (string= (substring s
(match-beginning 0)
2980 (substring s
(match-end 0))))
2981 (setq limit
(1+ (match-end 0)))))
2986 ;;; emerge.el ends here