Added or corrected documentation headers
[emacs.git] / lisp / emerge.el
blobc0efed3217533a3df710d3a0993be9f95c794add
1 ;;; emerge.el --- merge diffs under Emacs control
3 ;;; The author has placed this file in the public domain.
5 ;; Author: Dale R. Worley <drw@math.mit.edu>
6 ;; Version: 4
7 ;; Keywords: unix, tools
9 ;;; Commentary:
11 ;; This package assists you in reconciling differences between pair of files.
13 ; - Starting
15 ; To start Emerge, you must run one of four commands:
17 ; emerge-files
18 ; emerge-files-with-ancestor
19 ; emerge-buffers
20 ; emerge-buffers-with-ancestor
22 ; The "files" versions prompt you for two file names (the "A" and "B"
23 ; files), the "buffers" versions prompt you for two buffer names (the
24 ; "A" and "B" buffers). Emerge then runs a "diff" of the two entities
25 ; (emerge-buffers writes the buffers into temporary files for input to
26 ; diff) and digests the output to form a list of the differences between
27 ; the two files. Then three buffers are set up: two containing the
28 ; entities (emerge-files does a find-file (C-x C-f) on the files to get
29 ; them into buffers), and one, the "merge buffer", which contains the
30 ; working copy of the merged file that you are constructing. The three
31 ; buffers are put up in a nice three-window display, showing the A and B
32 ; buffers in the upper half and the merge buffer in the lower half.
34 ; The versions of the command that say "with-ancestor" ask for a third
35 ; name, that of an entity which is a common ancestor from which the
36 ; versions being merged were derived. These commands use "diff3" to
37 ; compare all three versions. If one version of a difference agrees
38 ; with the ancestor, then it is presumed that the other version is the
39 ; "correct" version, and is said to be "preferred".
41 ; (Note that if you use emerge-files, Emerge attempts to make sure that
42 ; file on disk and the file in the buffer are the same. If the file on
43 ; disk has been changed, Emerge offers to revert the buffer. If the
44 ; buffer has been modified, Emerge offers to save the buffer. If the
45 ; user declines the offer, or if the file on disk and the buffer have
46 ; both been modified, Emerge aborts with an error message. Emerge is
47 ; careful to widen the buffers containing the files if they have been
48 ; narrowed. If you use emerge-buffers, the buffers are not widened --
49 ; only the visible portion is used.)
51 ; During the merge, the A and B buffers are read-only, so you don't
52 ; damage them. (This is because the A and B versions of the differences
53 ; are extracted from these buffers.) When you quit the merge, the
54 ; read-only/read-write status and modified flag on the A and B buffers
55 ; are restored. In addition, auto-saving of the A and B buffers is
56 ; suppressed during the merge. This is because Emerge modifies the A
57 ; and B buffers to point out the text of the differences, and it would
58 ; be useless to save these changes. (Just before suppressing
59 ; auto-saving, Emerge forces an auto-save.)
61 ; If you give a prefix argument to emerge-files or
62 ; emerge-files-with-ancestor, it prompts you for another file name,
63 ; which is the file into which the merged file is to be written when you
64 ; exit Emerge. The output file name defaults to the A file name. If
65 ; you successfully quit Emerge, the merge buffer will be written to the
66 ; output file, and the buffers for the A, B, and ancestor buffers will
67 ; be deleted (if they exist and are not modified). If you abort Emerge,
68 ; the merge buffer will not be written and the buffers will not be
69 ; deleted.
71 ; You can have any number of merges going at once -- just don't use any
72 ; one buffer as input to more than one merge at once, since that will
73 ; cause the read-only/modified/auto-save status save-and-restore to
74 ; screw up.
76 ; Beware that when Emerge starts up, it does a diff or diff3 of the
77 ; files, which can take many minutes for long files with many
78 ; differences. Emacs can't do anything else until diff finishes.
80 ; If diff or diff3 produces error messages, Emerge will beep and display
81 ; the error messages instead of the merge buffer. There will be a
82 ; message in the echo area giving the name of the merge buffer. Note
83 ; that this is really just an informational message -- you still have
84 ; switch to the merge buffer and abort the merge to restore the
85 ; conditions before you ran Emerge. (Emerge considers any output line
86 ; that does not match the regexp emerge-diff/diff3-ok-lines to be an
87 ; error message.)
89 ; After the merge has been set up, Emerge runs the hooks in
90 ; emerge-startup-hook.
92 ; - Merging
94 ; Once you have started the merge, you manipulate the merge buffer with
95 ; special commands issued in the merge buffer. You may also edit the
96 ; buffer with ordinary Emacs commands. Emerge keeps track of each
97 ; difference between the A and B buffers and the corresponding section
98 ; of the merge buffer. Initially, all differences show the A version,
99 ; except those for which B is preferred (because A agrees with the
100 ; ancestor), which show the B version. Emerge always has its attention
101 ; focused on one particular difference, which is marked off in the three
102 ; buffers by "vvvvvvvvvvvvvvvvvvvv" above and "^^^^^^^^^^^^^^^^^^^^"
103 ; below. The number of the difference is shown in the mode line.
105 ; A merge buffer can be in two modes: "fast" mode and "edit" mode. In
106 ; fast mode, emerge commands are single characters, and ordinary Emacs
107 ; commands are disabled. This makes Emerge operations fast, but
108 ; prevents you from doing more than selecing the A or the B version of
109 ; differences. In edit mode, all emerge commands must be prefixed with
110 ; C-c, and all (non-conflicting) Emacs commands are available. This
111 ; allows editing the merge buffer, but slows down Emerge operations.
112 ; Edit and fast modes are indicated by "F" and "E" in the minor modes in
113 ; the mode line.
115 ; The Emerge commands are:
117 ; p go to the previous difference
118 ; n go to the next difference
119 ; a select the A version of this difference
120 ; b select the B version of this difference
121 ; j go to a particular difference (prefix argument
122 ; specifies which difference) (0j suppresses display of
123 ; the flags)
124 ; q quit - finish the merge*
125 ; f go into fast mode
126 ; e go into edit mode
127 ; s a set/clear auto-advance mode*
128 ; s s set/clear skip-prefers mode*
129 ; l recenter (C-l) all three windows*
130 ; - and 0 through 9
131 ; prefix numeric arguments
132 ; d a select the A version as the default from here down in
133 ; the merge buffer*
134 ; d b select the B version as the default from here down in
135 ; the merge buffer*
136 ; c a copy the A version of the difference into the kill
137 ; ring
138 ; c b copy the B version of the difference into the kill
139 ; ring
140 ; i a insert the A version of the difference at the point
141 ; i b insert the B version of the difference at the point
142 ; m put the point and mark around the difference region
143 ; ^ scroll-down (like M-v) the three windows*
144 ; v scroll-up (like C-v) the three windows*
145 ; < scroll-left (like C-x <) the three windows*
146 ; > scroll-right (like C-x >) the three windows*
147 ; | reset horizontal scroll on the three windows*
148 ; x 1 shrink the merge window to one line (use C-u l to restore it
149 ; to full size)
150 ; x a find the difference containing a location in the A buffer*
151 ; x b find the difference containing a location in the B buffer*
152 ; x c combine the two versions of this difference*
153 ; x C combine the two versions of this difference, using a
154 ; register's value as the template*
155 ; x d find the difference containing a location in the merge buffer*
156 ; x f show the files/buffers Emerge is operating on in Help window
157 ; (use C-u l to restore windows)
158 ; x j join this difference with the following one
159 ; (C-u x j joins this difference with the previous one)
160 ; x l show line numbers of points in A, B, and merge buffers
161 ; x m change major mode of merge buffer*
162 ; x s split this difference into two differences
163 ; (first position the point in all three buffers to the places
164 ; to split the difference)
165 ; x t trim identical lines off top and bottom of difference
166 ; (such lines occur when the A and B versions are
167 ; identical but differ from the ancestor version)
168 ; x x set the template for the x c command*
170 ; * - more details on these commands are given below
172 ; emerge-version is a variable giving the version number of Emerge. It
173 ; is also a function which displays emerge-version (when called
174 ; interactively) or returns it (when called from a program).
176 ; - Differences and their states
178 ; A difference can have one of seven states:
180 ; A: the difference is showing the A version.
182 ; B: the difference is showing the B version.
184 ; default-A and default-B: the difference is showing the A or B state,
185 ; but has never been selected by the user. All differences start in the
186 ; default-A state (and thus the merge buffer is a copy of the A buffer),
187 ; except those for which one buffer or another is preferred. When the
188 ; user selects the difference, it changes to the A or B state.
190 ; prefer-A and prefer-B: the difference is showing the A or B state. In
191 ; addition, the other buffer (that is, for prefer-A, the B buffer; for
192 ; prefer-B, the A buffer) agrees with the ancestor buffer. Thus,
193 ; presumably, the displayed version is the correct one. The "a" and "b"
194 ; commands override these states, and turn them into the A and B states.
196 ; combined: the difference is showing a combination of the A and B
197 ; states that was constructed by the "x c" or "x C" commands. Since
198 ; this state is neither the A or B states, the "a" and "b" commands
199 ; won't alter the difference unless they are given a prefix argument.
201 ; The state of the currently selected difference is shown in the mode
202 ; line of the merge window:
204 ; state display
206 ; A A
207 ; B B
208 ; prefer-A A*
209 ; prefer-B B*
210 ; combined comb
212 ; - Select default commands (d a and d b)
214 ; The d a and d b commands change all default-A's to default-B's (or
215 ; vice-versa) from the selected difference on down to the end of the
216 ; file to default-A or default-B, respectively. (Since a difference
217 ; that has been selected can not have state default-A or default-B, it
218 ; will never be affected by d a or d b. This leads to the unexpected
219 ; result that d a or d b never affects the difference selected at the
220 ; moment, but prevents differences that you have already looked at from
221 ; changing unexpectedly.)
223 ; If you work your way down from the top of the file, using d a and d b
224 ; at judicious points, you can effectivly make the A version the default
225 ; for some sections of the merge buffer and the B version the default
226 ; for others.
228 ; - Exiting (q)
230 ; The quit command finishes the merge session by restoring the state of
231 ; the A and B buffers and removing the markers around the currently
232 ; selected difference. It also disables the Emerge commands in the
233 ; merge buffer, since executing them later could damage the contents of
234 ; the various buffers.
236 ; The action of "q" depends on how Emerge was started and whether "q"
237 ; was given a prefix argument. If there was no prefix argument, it is
238 ; considered a "successful" finish. If there was a prefix argument, it
239 ; is considered an "unsuccessful" finish. In either case, you are asked
240 ; to cofirm the exit, and the confirmation message tells which sort of
241 ; exit you are confirming.
243 ; If Emerge was started by some other process, success/failure is
244 ; reported to the caller.
246 ; If Emerge was started with emerge-files or emerge-files-with-ancestor,
247 ; if a prefix argument was given to that command, then you specified a
248 ; file into which the merge is to be written. A successful exit writes
249 ; the merge into the output file and then kills the A, B, and ancestor
250 ; buffers (so they aren't lying around to confuse you, since they
251 ; probably all have similar names).
253 ; - Auto-advance mode (s a)
255 ; If auto-advance mode is set, the "a" and "b" commands perform an "n"
256 ; (select next difference) afterward. When auto-advance mode is set,
257 ; it is indicated by "A" in the minor modes in the mode line.
258 ; "s a" with a positive argument sets auto-advance, with a non-positive
259 ; argument clears it, and with no argument toggles it.
261 ; - Skip-prefers mode (s s)
263 ; If skip-prefers mode is set, the "n" and "p" commands skip over
264 ; differences with states prefer-A and prefer-B. Thus you will only see
265 ; differences for which one version isn't presumed "correct". When
266 ; skip-prefers mode is set, it is indicated by "S" in the minor modes in
267 ; the mode line. "s s" with a positive argument sets auto-advance, with
268 ; a non-positive argument clears it, and with no argument toggles it.
270 ; - Recenter (l)
272 ; The Emerge "l" command causes the selected difference to be brought
273 ; into view in the three windows, or at least, whichever of the three
274 ; merge buffers are visible at the moment. If a prefix argument is
275 ; given, then the original three-window display is set up before the
276 ; difference texts are shown.
278 ; - Scrolling the text (^, v, <, >, and |)
280 ; Emerge has several commands which scroll all three windows by the same
281 ; amount, thus allowing you to easily compare the versions of the text.
282 ; The commands are "^" (scroll-up), "v" (scroll-down), "<"
283 ; (scroll-left), ">" (scroll-right), and "|" (reset horizontal
284 ; scrolling). (Remember that Emacs names scrolling commands by the
285 ; motion of the text with respect to the window, so C-v is called
286 ; "scroll-up".)
288 ; If these commands (except "|") are given an argument, that is the
289 ; number of lines or characters by which the windows are scrolled.
290 ; Otherwise, the amount of motion is computed based on the dimensions of
291 ; the merge buffer window -- the height of the merge buffer window
292 ; (minus next-frame-context-lines), or half the width of the merge
293 ; buffer window. (The A and B version windows are assumed to be as high
294 ; as the merge window, but half as wide.) If the argument is just `C-u
295 ; -', then the scrolling is half the default amount.
297 ; - Finding the difference at or near a location (x d, x a, and x b)
299 ; The "x d" command selects the difference containing the current point
300 ; in the merge buffer. If there is no difference containing the point,
301 ; an error is given. An argument can be given to the command to change
302 ; this behavior: if the argument is positive (e.g., C-u), the next
303 ; following difference is selected; if the argument is negative (e.g.,
304 ; C-u -), the previous difference is selected.
306 ; The "x a" and "x b" commands select the difference containing the
307 ; current point in the A and B buffers, respectively. Otherwise, they
308 ; act like the "x d" command. Note that although the point used in the
309 ; commands is not the merge buffer point, the commands can only be
310 ; issued in the merge buffer, because it is the only buffer with the
311 ; Emerge keymap.
313 ; - Combining the two versions (x c, x C, and x x)
315 ; Sometimes one wants to combine the two versions of a difference. For
316 ; instance, when merging two versions of a program, one wants to make
317 ; something like this:
319 ; #ifdef NEW
320 ; ...new version of code...
321 ; #else /* NEW */
322 ; ...old version of code...
323 ; #endif /* NEW */
325 ; The "x c" command will make such a combined version. (Note that any
326 ; combined version is not the same as either the A or B versions, and so
327 ; the "a" and "b" commands will refuse to alter it unless they are given
328 ; a prefix argument.) The combination is made under control of a
329 ; template, which is a character string with the following
330 ; interpolations:
332 ; %a the A version of the difference
333 ; %b the B version of the difference
334 ; %% the character '%'
336 ; Thus, the template used above is
338 ; #ifdef NEW\n%b#else /* NEW */\n%a#endif /* NEW */\n
340 ; (using \n here to represent newlines). The template is stored in the
341 ; variable emerge-combine-versions-template, and its initial value is
342 ; the one given above. The template can be set (from the current
343 ; region) by the "x x" command. (Be careful to get the newlines in the
344 ; template in the right places!) ("x x" was chosen by analogy with "C-x
345 ; x".) ("x x" is only available in the merge buffer, of course.
346 ; Elsewhere, M-x emerge-set-combine-versions-template can be used.) If
347 ; "x x" is given a prefix argument, emerge-combine-versions-template is
348 ; localized in the merge buffer before its value is set, so the "x x"
349 ; command's effect (and the effect of any later "x x" command in the
350 ; merge buffer) is only on the merge buffer.
352 ; The "x C" command is like "x c", but it prompts for a character
353 ; which is the register whose value is to be used as the template.
354 ; This allows one to use multiple templates conveniently.
356 ; - Changing the major mode of the edit buffer (x m)
358 ; The "x m" command prompts for the name of a major-mode-setting command
359 ; and executes it. Ordinarily, major-mode-setting commands change the
360 ; mode line and local keymap, so the "x m" command then resets the
361 ; Emerge mode line and the fast or edit mode local keymap, as
362 ; appropriate.
364 ; If you have already changed the major mode of the merge buffer and
365 ; lost the Emerge keymap, you can use M-x emerge-set-merge-mode to
366 ; execute this command.
368 ; Beware that "x m" accepts any command name, not just
369 ; major-mode-setting commands.
371 ; - Writing the merge buffer manually
373 ; Emerge places a wrapper (emerge-query-and-call) on the key bindings of
374 ; save-buffer (usually "C-x C-s") and write-file (usually "C-x C-w"), in
375 ; order to protect the user from writing out the merge before it is
376 ; finished. Emerge-query-and-call asks the user if he is sure he wants
377 ; to write out the incomplete merge. If he answers yes, the buffer is
378 ; written out. The flags are suppressed while the write is being done.
379 ; As a result of this, the displayed portions of the buffers are
380 ; recentered (equivalent to "l").
382 ; - Running Emerge standalone
384 ; If you invoke emacs with the following arguments, you can execute
385 ; Emerge as a standalone program:
387 ; emacs -l emerge -f emerge-files-command file-a file-b file-out
389 ; emacs -l emerge -f emerge-files-with-ancestor-command
390 ; file-a file-b file-ancestor file-out
392 ; When the user gives the "q" (quit) command, Emerge will write out the
393 ; merge buffer in file-out and terminate Emacs. If a prefix argument is
394 ; given, Emacs will terminate with an unsuccessful return code (1), if
395 ; not, it will terminate with a successful return code (0).
397 ; - Invoking Emerge remotely
399 ; If you use the Emacs client/server code that supports remote
400 ; execution, then you can invoke Emerge remotely by executing one of the
401 ; Lisp calls:
403 ; (emerge-files-remote "file A" "file B" "output file")
405 ; (emerge-files-with-ancestor-remote "file A" "file B"
406 ; "ancestor file" "output file")
408 ; Returning a successful/unsuccessful return code is not yet supported
409 ; by the Emacs client/server code.
411 ; Beware that in systems of networked workstations, even though all user
412 ; directories are shared between all the workstations, the /tmp
413 ; directory on each workstation is not shared, so writing files into
414 ; /tmp and then remotely invoking Emerge is not likely to work.
416 ; - Effect of merge flags on indenting code
418 ; The presence of the flags confuses the indentation code of C and
419 ; Emacs-Lisp modes. Starting the flag strings
420 ; (emerge-{before,after}-flag) with '#' (for C) or ';' (for Lisp)
421 ; prevents the indentation code from noticing the flags. Remember to
422 ; change the flag strings before loading Emerge, or to execute
423 ; emerge-new-flags after changing them. But never change the flag
424 ; strings while a merge is being performed.
426 ; - Autoloading
428 ; The following autoloads will make all top-level Emerge files
429 ; autoloading. Make sure that "emerge" is in a directory on load-path.
431 ; (autoload 'emerge-files "emerge"
432 ; "Run Emerge on two files."
433 ; t)
434 ; (autoload 'emerge-files-with-ancestor "emerge"
435 ; "Run Emerge on two files, giving another file as the ancestor."
436 ; t)
437 ; (autoload 'emerge-buffers "emerge"
438 ; "Run Emerge on two buffers."
439 ; t)
440 ; (autoload 'emerge-buffers-with-ancestor "emerge"
441 ; "Run Emerge on two buffers, giving another buffer as the ancestor."
442 ; t)
443 ; (autoload 'emerge-files-command "emerge")
444 ; (autoload 'emerge-files-with-ancestor-command "emerge")
445 ; (autoload 'emerge-files-remote "emerge")
446 ; (autoload 'emerge-files-with-ancestor-remote "emerge")
448 ; ================================================================
450 ;;; Change Log:
452 ; - Changes from version 3 to version 4
454 ; More configuration variables are marked as user options.
456 ; Code is included for an improved version of make-auto-save-file-name
457 ; which eliminates many problems with the default version. See the
458 ; documentation of emerge-make-auto-save-file-name to see how to
459 ; activate it.
461 ; Emerge now works with Gnu diff3, which can produce the groups of lines
462 ; from the various files in the order 1, 2, 3 or 1, 3, 2.
464 ; Added x f command to show what files or buffers are being operated on.
466 ; The merge buffer now starts read-only, which being in fast mode it
467 ; should be.
469 ; When merging buffers, Emerge writes their contents into temporary
470 ; files in the directory $TMPDIR (if it is defined), or /tmp by default.
472 ; Added x j command to join two differences.
474 ; Added x s command to split a difference into two differences.
476 ; Added emerge-version variable and function to report the version of Emerge
477 ; being run.
479 ; Added x t command to trim unchanged lines off top and bottom of
480 ; difference region.
482 ; Added x d, x a, and x b commands to locate the differences at or near
483 ; a given location in one of the buffers.
485 ; Emerge no longer tries to copy the minor modes from the A buffer to
486 ; the merge buffer, only the major mode.
488 ; The programs executed to find the differences between versions of the file
489 ; are no longer controlled by emerge-diff/diff3-command, but rather by:
490 ; emerge-diff-program
491 ; Variable: *Name of the program which compares two files.
492 ; emerge-diff3-program
493 ; Variable: *Name of the program which compares an ancestor file
494 ; (first argument) and two variant files (second and third arguments).
495 ; emerge-diff-options
496 ; Variable: *Options to be passed to emerge-diff/diff3-program.
498 ; The names of the files are expanded (see expand-file-name) before being
499 ; passed to emerge-diff/diff3-program, so diff need not invoked under a shell
500 ; that understands '~', for instance.
502 ; If the diff/diff3 program reports errors, the user is notified and the
503 ; errors are displayed.
505 ; The command "0j" can be used to suppress the flags from showing in the buffers.
507 ; A discussion of the effect of the merge flags on indentation of code
508 ; has been added to the documentation.
510 ; If kill-fix.el is loaded, Emerge control variables new have their
511 ; 'preserved' property set, so setting the major mode in the merge
512 ; buffer doesn't destroy Emerge's state.
514 ; Added x c, x C, and x x commands to allow the A and B versions to be
515 ; combined into #ifdef - #endif forms.
517 ; Replaced calls of "ding" to calls of "error" where appropriate.
519 ; Added x m command to allow major mode of merge buffer to be changed.
521 ; Added x 1 command to shrink the merge window to one line.
523 ; Added emerge-startup-hook to allow customization.
525 ; Fixed a bug that is activated when a remote merge request is made when
526 ; the minibuffer window is selected.
528 ; - Changes from version 2 to version 3
530 ; The directory into which temporary files are written is now controlled
531 ; by a user option (emerge-temp-file-prefix).
533 ; The A and B versions of the difference can be loaded into the kill
534 ; ring with the "c a" and "c b" commands.
536 ; The A and B versions of the difference can be inserted into the merge
537 ; buffer with the "i a" and "i b" commands.
539 ; The difference region of the merge buffer can be surrounded by the
540 ; point and mark with the "m" command.
542 ; The three windows can be scrolled together with the "^", "v", "<",
543 ; ">", and "|" commands.
545 ; The "s s" and "s a" commands report the state of the option in the
546 ; echo area. Similarly, the "f" and "e" commands report what they do in
547 ; the echo area.
549 ; The "q" command has been revamped, and its behavior is now controlled
550 ; by the manner in which Emerge is started. In particular, if you wish
551 ; to write the merge buffer into a file upon exiting, invoke
552 ; emerge-files[-with-ancestor] with a prefix argument, and it will
553 ; prompt you for the file name. Then exiting will write the merge
554 ; buffer to the file, unless "q" is given a prefix argument.
556 ; The "i a" and "i b" commands now work in fast mode.
558 ; The modifications that Emerge makes to save-buffer and write-file are
559 ; described.
561 ; Emerge now handles merging narrowed buffers correctly.
563 ; Emerge now isn't fooled when the buffer visiting a file is not the
564 ; same as the file on disk.
566 ;;; Code:
568 ;;; Macros
570 (defmacro emerge-eval-in-buffer (buffer &rest forms)
571 "Macro to switch to BUFFER, evaluate FORMS, returns to original buffer.
572 Differs from `save-excursion' in that it doesn't save the point and mark."
573 (` (let ((StartBuffer (current-buffer)))
574 (unwind-protect
575 (progn
576 (set-buffer (, buffer))
577 (,@ forms))
578 (set-buffer StartBuffer)))))
580 (defmacro emerge-defvar-local (var value doc)
581 "Defines SYMBOL as an advertised variable.
582 Performs a defvar, then executes `make-variable-buffer-local' on
583 the variable. Also sets the 'preserved' property, so that
584 `kill-all-local-variables' (called by major-mode setting commands)
585 won't destroy Emerge control variables."
586 (` (progn
587 (defvar (, var) (, value) (, doc))
588 (make-variable-buffer-local '(, var))
589 (put '(, var) 'preserved t))))
591 ;; Add entries to minor-mode-alist so that emerge modes show correctly
592 (setq emerge-minor-modes-list '((emerge-mode " Emerge")
593 (emerge-fast-mode " F")
594 (emerge-edit-mode " E")
595 (emerge-auto-advance " A")
596 (emerge-skip-prefers " S")))
597 (if (not (assq 'emerge-mode minor-mode-alist))
598 (setq minor-mode-alist (append emerge-minor-modes-list
599 minor-mode-alist)))
601 ;; We need to define this function so describe-mode can describe Emerge mode.
602 (defun emerge-mode ()
603 "Emerge mode is used by the Emerge file-merging package.
604 It is entered only through one of the functions:
605 `emerge-files'
606 `emerge-files-with-ancestor'
607 `emerge-buffers'
608 `emerge-buffers-with-ancestor'
609 `emerge-files-command'
610 `emerge-files-with-ancestor-command'
611 `emerge-files-remote'
612 `emerge-files-with-ancestor-remote'
614 Commands:
615 \\{emerge-basic-keymap}
616 Commands must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode, but can be invoked directly
617 in 'fast' mode.")
619 (defvar emerge-version "4"
620 "The version of Emerge.")
622 (defun emerge-version ()
623 "Return string describing the version of Emerge.
624 When called interactively, displays the version."
625 (interactive)
626 (if (interactive-p)
627 (message "Emerge version %s" (emerge-version))
628 emerge-version))
630 ;;; Emerge configuration variables
632 ;; Commands that produce difference files
633 ;; All that can be configured is the name of the programs to execute
634 ;; (emerge-diff-program and emerge-diff3-program) and the options
635 ;; to be provided (emerge-diff-options). The order in which the file names
636 ;; are given is fixed.
637 ;; The file names are always expanded (see expand-file-name) before being
638 ;; passed to diff, thus they need not be invoked under a shell that
639 ;; understands '~'.
640 ;; The code which processes the diff/diff3 output depends on all the
641 ;; finicky details of their output, including the somewhat strange
642 ;; way they number lines of a file.
643 (defvar emerge-diff-program "diff"
644 "*Name of the program which compares two files.")
645 (defvar emerge-diff3-program "diff3"
646 "*Name of the program which compares an ancestor file (first argument)
647 and two variant files (second and third arguments).")
648 (defvar emerge-diff-options ""
649 "*Options to be passed to emerge-diff/diff3-program.")
650 (defvar emerge-match-diff-line (let ((x "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)"))
651 (concat "^" x "\\([acd]\\)" x "$"))
652 "*Pattern to match lines produced by diff that describe differences (as
653 opposed to lines from the source files).")
654 (defvar emerge-diff-ok-lines
655 "^\\([0-9,]+[acd][0-9,]+$\\|[<>] \\|---\\)"
656 "*Regexp that matches normal output lines from emerge-diff-program .
657 Lines that do not match are assumed to be error output.")
658 (defvar emerge-diff3-ok-lines
659 "^\\([1-3]:\\|====\\| \\)"
660 "*Regexp that matches normal output lines from emerge-diff3-program .
661 Lines that do not match are assumed to be error output.")
663 ;; The flags used to mark differences in the buffers.
665 ;; These function definitions need to be up here, because they are used
666 ;; during loading.
667 (defun emerge-new-flags ()
668 "Function to be called after `emerge-{before,after}-flag'.
669 This is called after these functions are changed to compute values that
670 depend on the flags."
671 (setq emerge-before-flag-length (length emerge-before-flag))
672 (setq emerge-before-flag-lines
673 (count-matches-string emerge-before-flag "\n"))
674 (setq emerge-before-flag-match (regexp-quote emerge-before-flag))
675 (setq emerge-after-flag-length (length emerge-after-flag))
676 (setq emerge-after-flag-lines
677 (count-matches-string emerge-after-flag "\n"))
678 (setq emerge-after-flag-match (regexp-quote emerge-after-flag)))
679 (defun count-matches-string (string regexp)
680 "Return the number of matches in STRING for REGEXP."
681 (let ((i 0)
682 (count 0))
683 (while (string-match regexp string i)
684 (setq count (1+ count))
685 (setq i (match-end 0)))
686 count))
688 (defvar emerge-before-flag "vvvvvvvvvvvvvvvvvvvv\n"
689 "*Flag placed above the highlighted block of code. Must end with newline.
690 Must be set before Emerge is loaded, or emerge-new-flags must be run
691 after setting.")
692 (defvar emerge-after-flag "^^^^^^^^^^^^^^^^^^^^\n"
693 "*Flag placed below the highlighted block of code. Must end with newline.
694 Must be set before Emerge is loaded, or emerge-new-flags must be run
695 after setting.")
697 ;; Calculate dependent variables
698 (emerge-new-flags)
700 (defvar emerge-min-visible-lines 3
701 "*Number of lines that we want to show above and below the flags when we are
702 displaying a difference.")
704 (defvar emerge-temp-file-prefix
705 (let ((env (getenv "TMPDIR"))
707 (setq d (if (and env (> (length env) 0))
709 "/tmp"))
710 (if (= (aref d (1- (length d))) ?/)
711 (setq d (substring d 0 -1)))
712 (concat d "/emerge"))
713 "*Prefix to put on Emerge temporary file names.
714 Do not start with '~/' or '~user-name/'.")
716 (defvar emerge-temp-file-mode 384 ; u=rw only
717 "*Mode for Emerge temporary files.")
719 (defvar emerge-combine-versions-template
720 "#ifdef NEW\n%b#else /* NEW */\n%a#endif /* NEW */\n"
721 "*Template for emerge-combine-versions to combine the two versions.
722 The template is inserted as a string, with the following interpolations:
723 %a the A version of the difference
724 %b the B version of the difference
725 %% the character '%'
726 Don't forget to end the template with a newline.
727 Note that this variable can be made local to a particular merge buffer by
728 giving a prefix argument to emerge-set-combine-versions-template .")
730 ;; Build keymaps
732 (defvar emerge-basic-keymap nil
733 "Keymap of Emerge commands.
734 Directly available in 'fast' mode;
735 must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode.")
737 (defvar emerge-fast-keymap nil
738 "Local keymap used in Emerge 'fast' mode.
739 Makes Emerge commands directly available.")
741 (defvar emerge-command-prefix "\C-c"
742 "*Command prefix for Emerge commands in 'edit' mode.
743 Must be set before Emerge is loaded.")
745 ;; This function sets up the fixed keymaps. It is executed when the first
746 ;; Emerge is done to allow the user maximum time to set up the global keymap.
747 (defun emerge-setup-fixed-keymaps ()
748 ;; Set up the basic keymap
749 (setq emerge-basic-keymap (make-keymap))
750 (suppress-keymap emerge-basic-keymap) ; this sets 0..9 to digit-argument and
751 ; - to negative-argument
752 (define-key emerge-basic-keymap "p" 'emerge-previous-difference)
753 (define-key emerge-basic-keymap "n" 'emerge-next-difference)
754 (define-key emerge-basic-keymap "a" 'emerge-select-A)
755 (define-key emerge-basic-keymap "b" 'emerge-select-B)
756 (define-key emerge-basic-keymap "j" 'emerge-jump-to-difference)
757 (define-key emerge-basic-keymap "q" 'emerge-quit)
758 (define-key emerge-basic-keymap "f" 'emerge-fast-mode)
759 (define-key emerge-basic-keymap "e" 'emerge-edit-mode)
760 (define-key emerge-basic-keymap "s" nil)
761 (define-key emerge-basic-keymap "sa" 'emerge-auto-advance)
762 (define-key emerge-basic-keymap "ss" 'emerge-skip-prefers)
763 (define-key emerge-basic-keymap "l" 'emerge-recenter)
764 (define-key emerge-basic-keymap "d" nil)
765 (define-key emerge-basic-keymap "da" 'emerge-default-A)
766 (define-key emerge-basic-keymap "db" 'emerge-default-B)
767 (define-key emerge-basic-keymap "c" nil)
768 (define-key emerge-basic-keymap "ca" 'emerge-copy-as-kill-A)
769 (define-key emerge-basic-keymap "cb" 'emerge-copy-as-kill-B)
770 (define-key emerge-basic-keymap "i" nil)
771 (define-key emerge-basic-keymap "ia" 'emerge-insert-A)
772 (define-key emerge-basic-keymap "ib" 'emerge-insert-B)
773 (define-key emerge-basic-keymap "m" 'emerge-mark-difference)
774 (define-key emerge-basic-keymap "v" 'emerge-scroll-up)
775 (define-key emerge-basic-keymap "^" 'emerge-scroll-down)
776 (define-key emerge-basic-keymap "<" 'emerge-scroll-left)
777 (define-key emerge-basic-keymap ">" 'emerge-scroll-right)
778 (define-key emerge-basic-keymap "|" 'emerge-scroll-reset)
779 (define-key emerge-basic-keymap "x" nil)
780 (define-key emerge-basic-keymap "x1" 'emerge-one-line-window)
781 (define-key emerge-basic-keymap "xa" 'emerge-find-difference-A)
782 (define-key emerge-basic-keymap "xb" 'emerge-find-difference-B)
783 (define-key emerge-basic-keymap "xc" 'emerge-combine-versions)
784 (define-key emerge-basic-keymap "xC" 'emerge-combine-versions-register)
785 (define-key emerge-basic-keymap "xd" 'emerge-find-difference)
786 (define-key emerge-basic-keymap "xf" 'emerge-file-names)
787 (define-key emerge-basic-keymap "xj" 'emerge-join-differences)
788 (define-key emerge-basic-keymap "xl" 'emerge-line-numbers)
789 (define-key emerge-basic-keymap "xm" 'emerge-set-merge-mode)
790 (define-key emerge-basic-keymap "xs" 'emerge-split-difference)
791 (define-key emerge-basic-keymap "xt" 'emerge-trim-difference)
792 (define-key emerge-basic-keymap "xx" 'emerge-set-combine-versions-template)
793 ;; Allow emerge-basic-keymap to be referenced indirectly
794 (fset 'emerge-basic-keymap emerge-basic-keymap)
795 ;; Set up the fast mode keymap
796 (setq emerge-fast-keymap (copy-keymap emerge-basic-keymap))
797 ;; Allow prefixed commands to work in fast mode
798 (define-key emerge-fast-keymap emerge-command-prefix 'emerge-basic-keymap)
799 ;; Allow emerge-fast-keymap to be referenced indirectly
800 (fset 'emerge-fast-keymap emerge-fast-keymap)
801 ;; Suppress write-file and save-buffer
802 (emerge-shadow-key-definition 'write-file 'emerge-query-write-file
803 (current-global-map) emerge-fast-keymap)
804 (emerge-shadow-key-definition 'save-buffer 'emerge-query-save-buffer
805 (current-global-map) emerge-fast-keymap))
807 ;; Variables which control each merge. They are local to the merge buffer.
809 ;; Mode variables
810 (emerge-defvar-local emerge-mode nil
811 "Indicator for emerge-mode.")
812 (emerge-defvar-local emerge-fast-mode nil
813 "Indicator for emerge-mode fast submode.")
814 (emerge-defvar-local emerge-edit-mode nil
815 "Indicator for emerge-mode edit submode.")
816 (emerge-defvar-local emerge-A-buffer nil
817 "The buffer in which the A variant is stored.")
818 (emerge-defvar-local emerge-B-buffer nil
819 "The buffer in which the B variant is stored.")
820 (emerge-defvar-local emerge-merge-buffer nil
821 "The buffer in which the merged file is manipulated.")
822 (emerge-defvar-local emerge-ancestor-buffer nil
823 "The buffer in which the ancestor variant is stored,
824 or nil if there is none.")
826 (defconst emerge-saved-variables
827 '((buffer-modified-p set-buffer-modified-p)
828 buffer-read-only
829 buffer-auto-save-file-name)
830 "Variables and properties of a buffer which are saved, modified and restored
831 during a merge.")
832 (defconst emerge-merging-values '(nil t nil)
833 "Values to be assigned to emerge-saved-variables during a merge.")
835 (emerge-defvar-local emerge-A-buffer-values nil
836 "Remembers emerge-saved-variables for emerge-A-buffer.")
837 (emerge-defvar-local emerge-B-buffer-values nil
838 "Remembers emerge-saved-variables for emerge-B-buffer.")
840 (emerge-defvar-local emerge-difference-list nil
841 "Vector of differences between the variants, and markers in the buffers to
842 show where they are. Each difference is represented by a vector of seven
843 elements. The first two are markers to the beginning and end of the difference
844 section in the A buffer, the second two are markers for the B buffer, the third
845 two are markers for the merge buffer, and the last element is the \"state\" of
846 that difference in the merge buffer.
847 A section of a buffer is described by two markers, one to the beginning of
848 the first line of the section, and one to the beginning of the first line
849 after the section. (If the section is empty, both markers point to the same
850 point.) If the section is part of the selected difference, then the markers
851 are moved into the flags, so the user can edit the section without disturbing
852 the markers.
853 The \"states\" are:
854 A the merge buffer currently contains the A variant
855 B the merge buffer currently contains the B variant
856 default-A the merge buffer contains the A variant by default,
857 but this difference hasn't been selected yet, so
858 change-default commands can alter it
859 default-B the merge buffer contains the B variant by default,
860 but this difference hasn't been selected yet, so
861 change-default commands can alter it
862 prefer-A in a three-file merge, the A variant is the prefered
863 choice
864 prefer-B in a three-file merge, the B variant is the prefered
865 choice")
866 (emerge-defvar-local emerge-current-difference -1
867 "The difference that is currently selected.")
868 (emerge-defvar-local emerge-number-of-differences nil
869 "Number of differences found.")
870 (emerge-defvar-local emerge-edit-keymap nil
871 "The local keymap for the merge buffer, with the emerge commands defined in
872 it. Used to save the local keymap during fast mode, when the local keymap is
873 replaced by emerge-fast-keymap.")
874 (emerge-defvar-local emerge-old-keymap nil
875 "The original local keymap for the merge buffer.")
876 (emerge-defvar-local emerge-auto-advance nil
877 "*If non-nil, emerge-select-A and emerge-select-B automatically advance to
878 the next difference.")
879 (emerge-defvar-local emerge-skip-prefers nil
880 "*If non-nil, differences for which there is a preference are automatically
881 skipped.")
882 (emerge-defvar-local emerge-startup-hook nil
883 "*Hooks to run in the merge buffer after the merge has been set up.")
884 (emerge-defvar-local emerge-quit-hook nil
885 "Hooks to run in the merge buffer after the merge has been finished.
886 emerge-prefix-argument will be bound to the prefix argument of the emerge-quit
887 command.
888 This is not a user option, since Emerge uses it for its own processing.")
889 (emerge-defvar-local emerge-output-description nil
890 "Describes output destination merge, for the use of `emerge-file-names'.")
892 ;;; Setup functions for two-file mode.
894 (defun emerge-files-internal (file-A file-B &optional startup-hooks quit-hooks
895 output-file)
896 (let ((buffer-A (find-file-noselect file-A))
897 (buffer-B (find-file-noselect file-B)))
898 ;; Make sure the entire files are seen, and they reflect what is on disk
899 (emerge-eval-in-buffer buffer-A
900 (widen)
901 (emerge-verify-file-buffer))
902 (emerge-eval-in-buffer buffer-B
903 (widen)
904 (emerge-verify-file-buffer))
905 (emerge-setup buffer-A file-A buffer-B file-B startup-hooks quit-hooks
906 output-file)))
908 ;; Start up Emerge on two files
909 (defun emerge-setup (buffer-A file-A buffer-B file-B startup-hooks quit-hooks
910 output-file)
911 (setq file-A (expand-file-name file-A))
912 (setq file-B (expand-file-name file-B))
913 (setq output-file (and output-file (expand-file-name output-file)))
914 (let* ((merge-buffer-name (emerge-unique-buffer-name "*merge" "*"))
915 ;; create the merge buffer from buffer A, so it inherits buffer A's
916 ;; default directory, etc.
917 (merge-buffer (emerge-eval-in-buffer
918 buffer-A
919 (get-buffer-create merge-buffer-name))))
920 (emerge-eval-in-buffer
921 merge-buffer
922 (emerge-copy-modes buffer-A)
923 (setq buffer-read-only nil)
924 (auto-save-mode 1)
925 (setq emerge-mode t)
926 (setq emerge-A-buffer buffer-A)
927 (setq emerge-B-buffer buffer-B)
928 (setq emerge-ancestor-buffer nil)
929 (setq emerge-merge-buffer merge-buffer)
930 (setq emerge-output-description
931 (if output-file
932 (concat "Output to file: " output-file)
933 (concat "Output to buffer: " (buffer-name merge-buffer))))
934 (insert-buffer emerge-A-buffer)
935 (emerge-set-keys)
936 (setq emerge-difference-list (emerge-make-diff-list file-A file-B))
937 (setq emerge-number-of-differences (length emerge-difference-list))
938 (setq emerge-current-difference -1)
939 (setq emerge-quit-hooks quit-hooks)
940 (emerge-remember-buffer-characteristics))
941 (emerge-setup-windows buffer-A buffer-B merge-buffer t)
942 (emerge-eval-in-buffer merge-buffer
943 (run-hooks 'startup-hooks 'emerge-startup-hook)
944 (setq buffer-read-only t))))
946 ;; Generate the Emerge difference list between two files
947 (defun emerge-make-diff-list (file-A file-B)
948 (setq emerge-diff-buffer (get-buffer-create "*emerge-diff*"))
949 (emerge-eval-in-buffer
950 emerge-diff-buffer
951 (erase-buffer)
952 (shell-command
953 (format "%s %s %s %s"
954 emerge-diff-program emerge-diff-options file-A file-B)
956 (emerge-prepare-error-list emerge-diff-ok-lines)
957 (emerge-convert-diffs-to-markers
958 emerge-A-buffer emerge-B-buffer emerge-merge-buffer
959 (emerge-extract-diffs emerge-diff-buffer)))
961 (defun emerge-extract-diffs (diff-buffer)
962 (let (list)
963 (emerge-eval-in-buffer
964 diff-buffer
965 (goto-char (point-min))
966 (while (re-search-forward emerge-match-diff-line nil t)
967 (let* ((a-begin (string-to-int (buffer-substring (match-beginning 1)
968 (match-end 1))))
969 (a-end (let ((b (match-beginning 3))
970 (e (match-end 3)))
971 (if b
972 (string-to-int (buffer-substring b e))
973 a-begin)))
974 (diff-type (buffer-substring (match-beginning 4) (match-end 4)))
975 (b-begin (string-to-int (buffer-substring (match-beginning 5)
976 (match-end 5))))
977 (b-end (let ((b (match-beginning 7))
978 (e (match-end 7)))
979 (if b
980 (string-to-int (buffer-substring b e))
981 b-begin))))
982 ;; fix the beginning and end numbers, because diff is somewhat
983 ;; strange about how it numbers lines
984 (if (string-equal diff-type "a")
985 (progn
986 (setq b-end (1+ b-end))
987 (setq a-begin (1+ a-begin))
988 (setq a-end a-begin))
989 (if (string-equal diff-type "d")
990 (progn
991 (setq a-end (1+ a-end))
992 (setq b-begin (1+ b-begin))
993 (setq b-end b-begin))
994 ;; (string-equal diff-type "c")
995 (progn
996 (setq a-end (1+ a-end))
997 (setq b-end (1+ b-end)))))
998 (setq list (cons (vector a-begin a-end
999 b-begin b-end
1000 'default-A)
1001 list)))))
1002 (nreverse list)))
1004 ;; Set up buffer of diff/diff3 error messages.
1005 (defun emerge-prepare-error-list (ok-regexp)
1006 (setq emerge-diff-error-buffer (get-buffer-create "*emerge-diff-errors*"))
1007 (emerge-eval-in-buffer
1008 emerge-diff-error-buffer
1009 (erase-buffer)
1010 (insert-buffer emerge-diff-buffer)
1011 (delete-matching-lines ok-regexp)))
1013 ;;; Top-level and setup functions for three-file mode.
1015 (defun emerge-files-with-ancestor-internal (file-A file-B file-ancestor
1016 &optional startup-hooks quit-hooks
1017 output-file)
1018 (let ((buffer-A (find-file-noselect file-A))
1019 (buffer-B (find-file-noselect file-B))
1020 (buffer-ancestor (find-file-noselect file-ancestor)))
1021 ;; Make sure the entire files are seen, and they reflect what is on disk
1022 (emerge-eval-in-buffer buffer-A
1023 (widen)
1024 (emerge-verify-file-buffer))
1025 (emerge-eval-in-buffer buffer-B
1026 (widen)
1027 (emerge-verify-file-buffer))
1028 (emerge-eval-in-buffer buffer-ancestor
1029 (widen)
1030 (emerge-verify-file-buffer))
1031 (emerge-setup-with-ancestor buffer-A file-A buffer-B file-B
1032 buffer-ancestor file-ancestor
1033 startup-hooks quit-hooks output-file)))
1035 ;; Start up Emerge on two files with an ancestor
1036 (defun emerge-setup-with-ancestor (buffer-A file-A buffer-B file-B
1037 buffer-ancestor file-ancestor
1038 &optional startup-hooks quit-hooks
1039 output-file)
1040 (setq file-A (expand-file-name file-A))
1041 (setq file-B (expand-file-name file-B))
1042 (setq file-ancestor (expand-file-name file-ancestor))
1043 (setq output-file (and output-file (expand-file-name output-file)))
1044 (let* ((merge-buffer-name (emerge-unique-buffer-name "*merge" "*"))
1045 ;; create the merge buffer from buffer A, so it inherits buffer A's
1046 ;; default directory, etc.
1047 (merge-buffer (emerge-eval-in-buffer
1048 buffer-A
1049 (get-buffer-create merge-buffer-name))))
1050 (emerge-eval-in-buffer
1051 merge-buffer
1052 (emerge-copy-modes buffer-A)
1053 (setq buffer-read-only nil)
1054 (auto-save-mode 1)
1055 (setq emerge-mode t)
1056 (setq emerge-A-buffer buffer-A)
1057 (setq emerge-B-buffer buffer-B)
1058 (setq emerge-ancestor-buffer buffer-ancestor)
1059 (setq emerge-merge-buffer merge-buffer)
1060 (setq emerge-output-description
1061 (if output-file
1062 (concat "Output to file: " output-file)
1063 (concat "Output to buffer: " (buffer-name merge-buffer))))
1064 (insert-buffer emerge-A-buffer)
1065 (emerge-set-keys)
1066 (setq emerge-difference-list
1067 (emerge-make-diff3-list file-A file-B file-ancestor))
1068 (setq emerge-number-of-differences (length emerge-difference-list))
1069 (setq emerge-current-difference -1)
1070 (setq emerge-quit-hook quit-hooks)
1071 (emerge-remember-buffer-characteristics)
1072 (emerge-select-prefer-Bs))
1073 (emerge-setup-windows buffer-A buffer-B merge-buffer t)
1074 (emerge-eval-in-buffer merge-buffer
1075 (run-hooks 'startup-hooks 'emerge-startup-hook)
1076 (setq buffer-read-only t))))
1078 ;; Generate the Emerge difference list between two files with an ancestor
1079 (defun emerge-make-diff3-list (file-A file-B file-ancestor)
1080 (setq emerge-diff-buffer (get-buffer-create "*emerge-diff*"))
1081 (emerge-eval-in-buffer
1082 emerge-diff-buffer
1083 (erase-buffer)
1084 (shell-command
1085 (format "%s %s %s %s %s"
1086 emerge-diff3-program emerge-diff-options
1087 file-ancestor file-A file-B)
1089 (emerge-prepare-error-list emerge-diff3-ok-lines)
1090 (emerge-convert-diffs-to-markers
1091 emerge-A-buffer emerge-B-buffer emerge-merge-buffer
1092 (emerge-extract-diffs3 emerge-diff-buffer)))
1094 (defun emerge-extract-diffs3 (diff-buffer)
1095 (let (list)
1096 (emerge-eval-in-buffer
1097 diff-buffer
1098 (while (re-search-forward "^====\\(.?\\)$" nil t)
1099 ;; leave point after matched line
1100 (beginning-of-line 2)
1101 (let ((agreement (buffer-substring (match-beginning 1) (match-end 1))))
1102 ;; if the A and B files are the same, ignore the difference
1103 (if (not (string-equal agreement "1"))
1104 (setq list
1105 (cons
1106 (let ((group-2 (emerge-get-diff3-group "2"))
1107 (group-3 (emerge-get-diff3-group "3")))
1108 (vector (car group-2) (car (cdr group-2))
1109 (car group-3) (car (cdr group-3))
1110 (cond ((string-equal agreement "2") 'prefer-A)
1111 ((string-equal agreement "3") 'prefer-B)
1112 (t 'default-A))))
1113 list))))))
1114 (nreverse list)))
1116 (defun emerge-get-diff3-group (file)
1117 ;; This save-excursion allows emerge-get-diff3-group to be called for the
1118 ;; various groups of lines (1, 2, 3) in any order, and for the lines to
1119 ;; appear in any order. The reason this is necessary is that Gnu diff3
1120 ;; can produce the groups in the order 1, 2, 3 or 1, 3, 2.
1121 (save-excursion
1122 (re-search-forward
1123 (concat "^" file ":\\([0-9]+\\)\\(,\\([0-9]+\\)\\)?\\([ac]\\)$"))
1124 (beginning-of-line 2)
1125 ;; treatment depends on whether it is an "a" group or a "c" group
1126 (if (string-equal (buffer-substring (match-beginning 4) (match-end 4)) "c")
1127 ;; it is a "c" group
1128 (if (match-beginning 2)
1129 ;; it has two numbers
1130 (list (string-to-int
1131 (buffer-substring (match-beginning 1) (match-end 1)))
1132 (1+ (string-to-int
1133 (buffer-substring (match-beginning 3) (match-end 3)))))
1134 ;; it has one number
1135 (let ((x (string-to-int
1136 (buffer-substring (match-beginning 1) (match-end 1)))))
1137 (list x (1+ x))))
1138 ;; it is an "a" group
1139 (let ((x (1+ (string-to-int
1140 (buffer-substring (match-beginning 1) (match-end 1))))))
1141 (list x x)))))
1143 ;;; Functions to start Emerge on files
1145 ;;;###autoload
1146 (defun emerge-files (arg file-A file-B file-out &optional startup-hooks
1147 quit-hooks)
1148 "Run Emerge on two files."
1149 (interactive
1150 (let (f)
1151 (list current-prefix-arg
1152 (setq f (read-file-name "File A to merge: " nil nil 'confirm))
1153 (read-file-name "File B to merge: " nil nil 'confirm)
1154 (and current-prefix-arg
1155 (read-file-name
1156 (format "Output file: (default %s) " f)
1157 nil f nil)))))
1158 (emerge-files-internal
1159 file-A file-B startup-hooks
1160 (if arg
1161 (cons (` (lambda () (emerge-files-exit (, file-out))))
1162 quit-hooks)
1163 quit-hooks)
1164 file-out))
1166 ;;;###autoload
1167 (defun emerge-files-with-ancestor (arg file-A file-B file-ancestor file-out
1168 &optional startup-hooks quit-hooks)
1169 "Run Emerge on two files, giving another file as the ancestor."
1170 (interactive
1171 (let (f)
1172 (list current-prefix-arg
1173 (setq f (read-file-name "File A to merge: " nil nil 'confirm))
1174 (read-file-name "File B to merge: " nil nil 'confirm)
1175 (read-file-name "Ancestor file: " nil nil 'confirm)
1176 (and current-prefix-arg
1177 (read-file-name
1178 (format "Output file: (default %s) " f)
1179 nil f nil)))))
1180 (emerge-files-with-ancestor-internal
1181 file-A file-B file-ancestor startup-hooks
1182 (if arg
1183 (cons (` (lambda () (emerge-files-exit (, file-out))))
1184 quit-hooks)
1185 quit-hooks)
1186 file-out))
1188 ;; Write the merge buffer out in place of the file the A buffer is visiting.
1189 (defun emerge-files-exit (file-out)
1190 ;; if merge was successful was given, save to disk
1191 (if (not emerge-prefix-argument)
1192 (emerge-write-and-delete file-out)))
1194 ;;; Functions to start Emerge on buffers
1196 ;;;###autoload
1197 (defun emerge-buffers (buffer-A buffer-B &optional startup-hooks quit-hooks)
1198 "Run Emerge on two buffers."
1199 (interactive "bBuffer A to merge: \nbBuffer B to merge: ")
1200 (let ((emerge-file-A (emerge-make-temp-file "A"))
1201 (emerge-file-B (emerge-make-temp-file "B")))
1202 (emerge-eval-in-buffer
1203 buffer-A
1204 (write-region (point-min) (point-max) emerge-file-A nil 'no-message))
1205 (emerge-eval-in-buffer
1206 buffer-B
1207 (write-region (point-min) (point-max) emerge-file-B nil 'no-message))
1208 (emerge-setup (get-buffer buffer-A) emerge-file-A
1209 (get-buffer buffer-B) emerge-file-B
1210 (cons (function (lambda ()
1211 (delete-file emerge-file-A)
1212 (delete-file emerge-file-B)))
1213 startup-hooks)
1214 quit-hooks
1215 nil)))
1217 ;;;###autoload
1218 (defun emerge-buffers-with-ancestor (buffer-A buffer-B buffer-ancestor
1219 &optional startup-hooks
1220 quit-hooks)
1221 "Run Emerge on two buffers, giving another buffer as the ancestor."
1222 (interactive
1223 "bBuffer A to merge: \nbBuffer B to merge: \nbAncestor buffer: ")
1224 (let ((emerge-file-A (emerge-make-temp-file "A"))
1225 (emerge-file-B (emerge-make-temp-file "B"))
1226 (emerge-file-ancestor (emerge-make-temp-file "anc")))
1227 (emerge-eval-in-buffer
1228 buffer-A
1229 (write-region (point-min) (point-max) emerge-file-A nil 'no-message))
1230 (emerge-eval-in-buffer
1231 buffer-B
1232 (write-region (point-min) (point-max) emerge-file-B nil 'no-message))
1233 (emerge-eval-in-buffer
1234 buffer-ancestor
1235 (write-region (point-min) (point-max) emerge-file-ancestor nil
1236 'no-message))
1237 (emerge-setup-with-ancestor (get-buffer buffer-A) emerge-file-A
1238 (get-buffer buffer-B) emerge-file-B
1239 (get-buffer buffer-ancestor)
1240 emerge-file-ancestor
1241 (cons (function (lambda ()
1242 (delete-file emerge-file-A)
1243 (delete-file emerge-file-B)
1244 (delete-file
1245 emerge-file-ancestor)))
1246 startup-hooks)
1247 quit-hooks
1248 nil)))
1250 ;;; Functions to start Emerge from the command line
1252 ;;;###autoload
1253 (defun emerge-files-command ()
1254 (let ((file-a (nth 0 command-line-args-left))
1255 (file-b (nth 1 command-line-args-left))
1256 (file-out (nth 2 command-line-args-left)))
1257 (setq command-line-args-left (nthcdr 3 command-line-args-left))
1258 (emerge-files-internal
1259 file-a file-b nil
1260 (list (` (lambda () (emerge-command-exit (, file-out))))))))
1262 ;;;###autoload
1263 (defun emerge-files-with-ancestor-command ()
1264 (let (file-a file-b file-anc file-out)
1265 ;; check for a -a flag, for filemerge compatibility
1266 (if (string= (car command-line-args-left) "-a")
1267 ;; arguments are "-a ancestor file-a file-b file-out"
1268 (progn
1269 (setq file-a (nth 2 command-line-args-left))
1270 (setq file-b (nth 3 command-line-args-left))
1271 (setq file-anc (nth 1 command-line-args-left))
1272 (setq file-out (nth 4 command-line-args-left))
1273 (setq command-line-args-left (nthcdr 5 command-line-args-left)))
1274 ;; arguments are "file-a file-b ancestor file-out"
1275 (setq file-a (nth 0 command-line-args-left))
1276 (setq file-b (nth 1 command-line-args-left))
1277 (setq file-anc (nth 2 command-line-args-left))
1278 (setq file-out (nth 3 command-line-args-left))
1279 (setq command-line-args-left (nthcdr 4 command-line-args-left)))
1280 (emerge-files-with-ancestor-internal
1281 file-a file-b file-anc nil
1282 (list (` (lambda () (emerge-command-exit (, file-out))))))))
1284 (defun emerge-command-exit (file-out)
1285 (emerge-write-and-delete file-out)
1286 (kill-emacs (if emerge-prefix-argument 1 0)))
1288 ;;; Functions to start Emerge via remote request
1290 ;;;###autoload
1291 (defun emerge-files-remote (file-a file-b file-out)
1292 (setq emerge-file-out file-out)
1293 (emerge-files-internal
1294 file-a file-b nil
1295 (list (` (lambda () (emerge-remote-exit (, file-out) '(, exit-func)))))
1296 file-out)
1297 (throw 'client-wait nil))
1299 ;;;###autoload
1300 (defun emerge-files-with-ancestor-remote (file-a file-b file-anc file-out)
1301 (setq emerge-file-out file-out)
1302 (emerge-files-with-ancestor-internal
1303 file-a file-b file-anc nil
1304 (list (` (lambda () (emerge-remote-exit (, file-out) '(, exit-func)))))
1305 file-out)
1306 (throw 'client-wait nil))
1308 (defun emerge-remote-exit (file-out exit-func)
1309 (emerge-write-and-delete file-out)
1310 (kill-buffer emerge-merge-buffer)
1311 (funcall exit-func (if emerge-prefix-argument 1 0)))
1313 ;;; Common setup routines
1315 ;; Set up the window configuration. If POS is given, set the points to
1316 ;; the beginnings of the buffers.
1317 (defun emerge-setup-windows (buffer-A buffer-B merge-buffer &optional pos)
1318 ;; Make sure we are not in the minibuffer window when we try to delete
1319 ;; all other windows.
1320 (if (eq (selected-window) (minibuffer-window))
1321 (other-window 1))
1322 (delete-other-windows)
1323 (switch-to-buffer merge-buffer)
1324 (emerge-refresh-mode-line)
1325 (split-window-vertically)
1326 (split-window-horizontally)
1327 (switch-to-buffer buffer-A)
1328 (if pos
1329 (goto-char (point-min)))
1330 (other-window 1)
1331 (switch-to-buffer buffer-B)
1332 (if pos
1333 (goto-char (point-min)))
1334 (other-window 1)
1335 (if pos
1336 (goto-char (point-min)))
1337 ;; If diff/diff3 reports errors, display them rather than the merge buffer.
1338 (if (/= 0 (emerge-eval-in-buffer emerge-diff-error-buffer (buffer-size)))
1339 (progn
1340 (ding)
1341 (message "Errors found in diff/diff3 output. Merge buffer is %s."
1342 (buffer-name emerge-merge-buffer))
1343 (switch-to-buffer emerge-diff-error-buffer))))
1345 ;; Set up the keymap in the merge buffer
1346 (defun emerge-set-keys ()
1347 ;; Set up fixed keymaps if necessary
1348 (if (not emerge-basic-keymap)
1349 (emerge-setup-fixed-keymaps))
1350 ;; Save the old local map
1351 (setq emerge-old-keymap (current-local-map))
1352 ;; Construct the edit keymap
1353 (setq emerge-edit-keymap (if emerge-old-keymap
1354 (copy-keymap emerge-old-keymap)
1355 (make-sparse-keymap)))
1356 ;; Install the Emerge commands
1357 (emerge-force-define-key emerge-edit-keymap emerge-command-prefix
1358 'emerge-basic-keymap)
1359 ;; Suppress write-file and save-buffer
1360 (emerge-recursively-substitute-key-definition 'write-file
1361 'emerge-query-write-file
1362 emerge-edit-keymap)
1363 (emerge-recursively-substitute-key-definition 'save-buffer
1364 'emerge-query-save-buffer
1365 emerge-edit-keymap)
1366 (emerge-shadow-key-definition 'write-file 'emerge-query-write-file
1367 (current-global-map) emerge-edit-keymap)
1368 (emerge-shadow-key-definition 'save-buffer 'emerge-query-save-buffer
1369 (current-global-map) emerge-edit-keymap)
1370 (use-local-map emerge-fast-keymap)
1371 (setq emerge-edit-mode nil)
1372 (setq emerge-fast-mode t))
1374 (defun emerge-remember-buffer-characteristics ()
1375 "Remembers certain properties of the buffers being merged.
1376 Must be called in the merge buffer. Remembers read-only, modified,
1377 auto-save, and saves them in buffer local variables. Sets the buffers
1378 read-only and turns off `auto-save-mode'.
1379 These characteristics are restored by emerge-restore-buffer-characteristics."
1380 ;; force auto-save, because we will turn off auto-saving in buffers for the
1381 ;; duration
1382 (do-auto-save)
1383 ;; remember and alter buffer characteristics
1384 (setq emerge-A-buffer-values
1385 (emerge-eval-in-buffer
1386 emerge-A-buffer
1387 (prog1
1388 (emerge-save-variables emerge-saved-variables)
1389 (emerge-restore-variables emerge-saved-variables
1390 emerge-merging-values))))
1391 (setq emerge-B-buffer-values
1392 (emerge-eval-in-buffer
1393 emerge-B-buffer
1394 (prog1
1395 (emerge-save-variables emerge-saved-variables)
1396 (emerge-restore-variables emerge-saved-variables
1397 emerge-merging-values)))))
1399 (defun emerge-restore-buffer-characteristics ()
1400 "Restores the characteristics remembered by
1401 emerge-remember-buffer-characteristics."
1402 (let ((A-values emerge-A-buffer-values)
1403 (B-values emerge-B-buffer-values))
1404 (emerge-eval-in-buffer emerge-A-buffer
1405 (emerge-restore-variables emerge-saved-variables
1406 A-values))
1407 (emerge-eval-in-buffer emerge-B-buffer
1408 (emerge-restore-variables emerge-saved-variables
1409 B-values))))
1411 (defun emerge-convert-diffs-to-markers (A-buffer
1412 B-buffer
1413 merge-buffer
1414 lineno-list)
1415 (let* (marker-list
1416 (A-point-min (emerge-eval-in-buffer A-buffer (point-min)))
1417 (offset (1- A-point-min))
1418 (A-hidden-lines (emerge-eval-in-buffer
1419 A-buffer
1420 (save-restriction
1421 (widen)
1422 (count-lines 1 A-point-min))))
1423 (B-point-min (emerge-eval-in-buffer B-buffer (point-min)))
1424 (B-hidden-lines (emerge-eval-in-buffer
1425 B-buffer
1426 (save-restriction
1427 (widen)
1428 (count-lines 1 B-point-min)))))
1429 (while lineno-list
1430 (let* ((list-element (car lineno-list))
1431 a-begin-marker
1432 a-end-marker
1433 b-begin-marker
1434 b-end-marker
1435 (a-begin (aref list-element 0))
1436 (a-end (aref list-element 1))
1437 (b-begin (aref list-element 2))
1438 (b-end (aref list-element 3))
1439 (state (aref list-element 4)))
1440 ;; place markers at the appropriate places in the buffers
1441 (emerge-eval-in-buffer
1442 A-buffer
1443 (goto-line (+ a-begin A-hidden-lines))
1444 (setq a-begin-marker (point-marker))
1445 (goto-line (+ a-end A-hidden-lines))
1446 (setq a-end-marker (point-marker)))
1447 (emerge-eval-in-buffer
1448 B-buffer
1449 (goto-line (+ b-begin B-hidden-lines))
1450 (setq b-begin-marker (point-marker))
1451 (goto-line (+ b-end B-hidden-lines))
1452 (setq b-end-marker (point-marker)))
1453 (setq merge-begin-marker (set-marker
1454 (make-marker)
1455 (- (marker-position a-begin-marker)
1456 offset)
1457 merge-buffer))
1458 (setq merge-end-marker (set-marker
1459 (make-marker)
1460 (- (marker-position a-end-marker)
1461 offset)
1462 merge-buffer))
1463 ;; record all the markers for this difference
1464 (setq marker-list (cons (vector a-begin-marker a-end-marker
1465 b-begin-marker b-end-marker
1466 merge-begin-marker merge-end-marker
1467 state)
1468 marker-list)))
1469 (setq lineno-list (cdr lineno-list)))
1470 ;; convert the list of difference information into a vector for
1471 ;; fast access
1472 (setq emerge-difference-list (apply 'vector (nreverse marker-list)))))
1474 ;; If we have an ancestor, select all B variants that we prefer
1475 (defun emerge-select-prefer-Bs ()
1476 (let ((n 0))
1477 (while (< n emerge-number-of-differences)
1478 (if (eq (aref (aref emerge-difference-list n) 6) 'prefer-B)
1479 (progn
1480 (emerge-unselect-and-select-difference n t)
1481 (emerge-select-B)
1482 (aset (aref emerge-difference-list n) 6 'prefer-B)))
1483 (setq n (1+ n))))
1484 (emerge-unselect-and-select-difference -1))
1486 ;;; Common exit routines
1488 (defun emerge-write-and-delete (file-out)
1489 ;; clear screen format
1490 (delete-other-windows)
1491 ;; delete A, B, and ancestor buffers, if they haven't been changed
1492 (if (not (buffer-modified-p emerge-A-buffer))
1493 (kill-buffer emerge-A-buffer))
1494 (if (not (buffer-modified-p emerge-B-buffer))
1495 (kill-buffer emerge-B-buffer))
1496 (if (and emerge-ancestor-buffer
1497 (not (buffer-modified-p emerge-ancestor-buffer)))
1498 (kill-buffer emerge-ancestor-buffer))
1499 ;; Write merge buffer to file
1500 (write-file file-out))
1502 ;;; Commands
1504 (defun emerge-recenter (&optional arg)
1505 "Bring the highlighted region of all three merge buffers into view.
1506 This brings the buffers into view if they are in windows.
1507 If an ARGUMENT is given, the default three-window display is reestablished."
1508 (interactive "P")
1509 ;; If there is an argument, rebuild the window structure
1510 (if arg
1511 (emerge-setup-windows emerge-A-buffer emerge-B-buffer
1512 emerge-merge-buffer))
1513 ;; Redisplay whatever buffers are showing, if there is a selected difference
1514 (if (and (>= emerge-current-difference 0)
1515 (< emerge-current-difference emerge-number-of-differences))
1516 (let* ((merge-buffer emerge-merge-buffer)
1517 (buffer-A emerge-A-buffer)
1518 (buffer-B emerge-B-buffer)
1519 (window-A (get-buffer-window buffer-A))
1520 (window-B (get-buffer-window buffer-B))
1521 (merge-window (get-buffer-window merge-buffer))
1522 (diff-vector
1523 (aref emerge-difference-list emerge-current-difference)))
1524 (if window-A (progn
1525 (select-window window-A)
1526 (emerge-position-region
1527 (- (aref diff-vector 0)
1528 (1- emerge-before-flag-length))
1529 (+ (aref diff-vector 1)
1530 (1- emerge-after-flag-length))
1531 (1+ (aref diff-vector 0)))))
1532 (if window-B (progn
1533 (select-window window-B)
1534 (emerge-position-region
1535 (- (aref diff-vector 2)
1536 (1- emerge-before-flag-length))
1537 (+ (aref diff-vector 3)
1538 (1- emerge-after-flag-length))
1539 (1+ (aref diff-vector 2)))))
1540 (if merge-window (progn
1541 (select-window merge-window)
1542 (emerge-position-region
1543 (- (aref diff-vector 4)
1544 (1- emerge-before-flag-length))
1545 (+ (aref diff-vector 5)
1546 (1- emerge-after-flag-length))
1547 (1+ (aref diff-vector 4))))))))
1549 ;;; Window scrolling operations
1550 ;; These operations are designed to scroll all three windows the same amount,
1551 ;; so as to keep the text in them aligned.
1553 ;; Perform some operation on all three windows (if they are showing).
1554 ;; Catches all errors on the operation in the A and B windows, but not
1555 ;; in the merge window. Usually, errors come from scrolling off the
1556 ;; beginning or end of the buffer, and this gives a nice error message:
1557 ;; End of buffer is reported in the merge buffer, but if the scroll was
1558 ;; possible in the A or B windows, it is performed there before the error
1559 ;; is reported.
1560 (defun emerge-operate-on-windows (operation arg)
1561 (let* ((merge-buffer emerge-merge-buffer)
1562 (buffer-A emerge-A-buffer)
1563 (buffer-B emerge-B-buffer)
1564 (window-A (get-buffer-window buffer-A))
1565 (window-B (get-buffer-window buffer-B))
1566 (merge-window (get-buffer-window merge-buffer)))
1567 (if window-A (progn
1568 (select-window window-A)
1569 (condition-case nil
1570 (funcall operation arg)
1571 (error))))
1572 (if window-B (progn
1573 (select-window window-B)
1574 (condition-case nil
1575 (funcall operation arg)
1576 (error))))
1577 (if merge-window (progn
1578 (select-window merge-window)
1579 (funcall operation arg)))))
1581 (defun emerge-scroll-up (&optional arg)
1582 "Scroll up all three merge buffers, if they are in windows.
1583 If an ARGUMENT is given, that is how many lines are scrolled, else nearly
1584 the size of the merge window. `C-u -' alone as argument scrolls half the
1585 size of the merge window."
1586 (interactive "P")
1587 (emerge-operate-on-windows
1588 'scroll-up
1589 ;; calculate argument to scroll-up
1590 ;; if there is an explicit argument
1591 (if (and arg (not (equal arg '-)))
1592 ;; use it
1593 (prefix-numeric-value arg)
1594 ;; if not, see if we can determine a default amount (the window height)
1595 (let ((merge-window (get-buffer-window emerge-merge-buffer)))
1596 (if (null merge-window)
1597 ;; no window, use nil
1599 (let ((default-amount
1600 (- (window-height merge-window) 1 next-screen-context-lines)))
1601 ;; the window was found
1602 (if arg
1603 ;; C-u as argument means half of default amount
1604 (/ default-amount 2)
1605 ;; no argument means default amount
1606 default-amount)))))))
1608 (defun emerge-scroll-down (&optional arg)
1609 "Scroll down all three merge buffers, if they are in windows.
1610 If an ARGUMENT is given, that is how many lines are scrolled, else nearly
1611 the size of the merge window. `C-u -' alone as argument scrolls half the
1612 size of the merge window."
1613 (interactive "P")
1614 (emerge-operate-on-windows
1615 'scroll-down
1616 ;; calculate argument to scroll-down
1617 ;; if there is an explicit argument
1618 (if (and arg (not (equal arg '-)))
1619 ;; use it
1620 (prefix-numeric-value arg)
1621 ;; if not, see if we can determine a default amount (the window height)
1622 (let ((merge-window (get-buffer-window emerge-merge-buffer)))
1623 (if (null merge-window)
1624 ;; no window, use nil
1626 (let ((default-amount
1627 (- (window-height merge-window) 1 next-screen-context-lines)))
1628 ;; the window was found
1629 (if arg
1630 ;; C-u as argument means half of default amount
1631 (/ default-amount 2)
1632 ;; no argument means default amount
1633 default-amount)))))))
1635 (defun emerge-scroll-left (&optional arg)
1636 "Scroll left all three merge buffers, if they are in windows.
1637 If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1638 the width of the A and B windows. C-u - alone as argument scrolls half the
1639 width of the A and B windows."
1640 (interactive "P")
1641 (emerge-operate-on-windows
1642 'scroll-left
1643 ;; calculate argument to scroll-left
1644 ;; if there is an explicit argument
1645 (if (and arg (not (equal arg '-)))
1646 ;; use it
1647 (prefix-numeric-value arg)
1648 ;; if not, see if we can determine a default amount
1649 ;; (half the window width)
1650 (let ((merge-window (get-buffer-window emerge-merge-buffer)))
1651 (if (null merge-window)
1652 ;; no window, use nil
1654 (let ((default-amount
1655 (- (/ (window-width merge-window) 2) 3)))
1656 ;; the window was found
1657 (if arg
1658 ;; C-u as argument means half of default amount
1659 (/ default-amount 2)
1660 ;; no argument means default amount
1661 default-amount)))))))
1663 (defun emerge-scroll-right (&optional arg)
1664 "Scroll right all three merge buffers, if they are in windows.
1665 If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1666 the width of the A and B windows. C-u - alone as argument scrolls half the
1667 width of the A and B windows."
1668 (interactive "P")
1669 (emerge-operate-on-windows
1670 'scroll-right
1671 ;; calculate argument to scroll-right
1672 ;; if there is an explicit argument
1673 (if (and arg (not (equal arg '-)))
1674 ;; use it
1675 (prefix-numeric-value arg)
1676 ;; if not, see if we can determine a default amount
1677 ;; (half the window width)
1678 (let ((merge-window (get-buffer-window emerge-merge-buffer)))
1679 (if (null merge-window)
1680 ;; no window, use nil
1682 (let ((default-amount
1683 (- (/ (window-width merge-window) 2) 3)))
1684 ;; the window was found
1685 (if arg
1686 ;; C-u as argument means half of default amount
1687 (/ default-amount 2)
1688 ;; no argument means default amount
1689 default-amount)))))))
1691 (defun emerge-scroll-reset ()
1692 "Reset horizontal scrolling.
1693 This resets the horizontal scrolling of all three merge buffers
1694 to the left margin, if they are in windows."
1695 (interactive)
1696 (emerge-operate-on-windows
1697 (function (lambda (x) (set-window-hscroll (selected-window) 0)))
1698 nil))
1700 ;; Attempt to show the region nicely.
1701 ;; If there are min-lines lines above and below the region, then don't do
1702 ;; anything.
1703 ;; If not, recenter the region to make it so.
1704 ;; If that isn't possible, remove context lines balancedly from top and botton
1705 ;; so the entire region shows.
1706 ;; If that isn't possible, show the top of the region.
1707 ;; BEG must be at the beginning of a line.
1708 (defun emerge-position-region (beg end pos)
1709 ;; First test whether the entire region is visible with
1710 ;; emerge-min-visible-lines above and below it
1711 (if (not (and (<= (progn
1712 (move-to-window-line emerge-min-visible-lines)
1713 (point))
1714 beg)
1715 (<= end (progn
1716 (move-to-window-line
1717 (- (1+ emerge-min-visible-lines)))
1718 (point)))))
1719 ;; We failed that test, see if it fits at all
1720 ;; Meanwhile positioning it correctly in case it doesn't fit
1721 (progn
1722 (set-window-start (selected-window) beg)
1723 (setq fits (pos-visible-in-window-p end))
1724 (if fits
1725 ;; Determine the number of lines that the region occupies
1726 (let ((lines 0))
1727 (while (> end (progn
1728 (move-to-window-line lines)
1729 (point)))
1730 (setq lines (1+ lines)))
1731 ;; And position the beginning on the right line
1732 (goto-char beg)
1733 (recenter (/ (1+ (- (1- (window-height (selected-window)))
1734 lines))
1735 2))))))
1736 (goto-char pos))
1738 (defun emerge-next-difference ()
1739 "Advance to the next difference."
1740 (interactive)
1741 (if (< emerge-current-difference emerge-number-of-differences)
1742 (let ((n (1+ emerge-current-difference)))
1743 (while (and emerge-skip-prefers
1744 (< n emerge-number-of-differences)
1745 (memq (aref (aref emerge-difference-list n) 6)
1746 '(prefer-A prefer-B)))
1747 (setq n (1+ n)))
1748 (let ((buffer-read-only nil))
1749 (emerge-unselect-and-select-difference n)))
1750 (error "At end")))
1752 (defun emerge-previous-difference ()
1753 "Go to the previous difference."
1754 (interactive)
1755 (if (> emerge-current-difference -1)
1756 (let ((n (1- emerge-current-difference)))
1757 (while (and emerge-skip-prefers
1758 (> n -1)
1759 (memq (aref (aref emerge-difference-list n) 6)
1760 '(prefer-A prefer-B)))
1761 (setq n (1- n)))
1762 (let ((buffer-read-only nil))
1763 (emerge-unselect-and-select-difference n)))
1764 (error "At beginning")))
1766 (defun emerge-jump-to-difference (difference-number)
1767 "Go to the N-th difference."
1768 (interactive "p")
1769 (let ((buffer-read-only nil))
1770 (setq difference-number (1- difference-number))
1771 (if (and (>= difference-number -1)
1772 (< difference-number (1+ emerge-number-of-differences)))
1773 (emerge-unselect-and-select-difference difference-number)
1774 (error "Bad difference number"))))
1776 (defun emerge-quit (arg)
1777 "Finish an Emerge session.
1778 Prefix argument means to abort rather than successfully finish.
1779 The difference depends on how the merge was started,
1780 but usually means to not write over one of the original files, or to signal
1781 to some process which invoked Emerge a failure code.
1783 Unselects the selected difference, if any, restores the read-only and modified
1784 flags of the merged file buffers, restores the local keymap of the merge
1785 buffer, and sets off various emerge flags. Using Emerge commands in this
1786 buffer after this will cause serious problems."
1787 (interactive "P")
1788 (if (prog1
1789 (y-or-n-p
1790 (if (not arg)
1791 "Do you really want to successfully finish this merge? "
1792 "Do you really want to abort this merge? "))
1793 (message ""))
1794 (emerge-really-quit arg)))
1796 ;; Perform the quit operations.
1797 (defun emerge-really-quit (arg)
1798 (setq buffer-read-only nil)
1799 (emerge-unselect-and-select-difference -1)
1800 (emerge-restore-buffer-characteristics)
1801 ;; null out the difference markers so they don't slow down future editing
1802 ;; operations
1803 (mapcar (function (lambda (d)
1804 (set-marker (aref d 0) nil)
1805 (set-marker (aref d 1) nil)
1806 (set-marker (aref d 2) nil)
1807 (set-marker (aref d 3) nil)
1808 (set-marker (aref d 4) nil)
1809 (set-marker (aref d 5) nil)))
1810 emerge-difference-list)
1811 ;; allow them to be garbage collected
1812 (setq emerge-difference-list nil)
1813 ;; restore the local map
1814 (use-local-map emerge-old-keymap)
1815 ;; turn off all the emerge modes
1816 (setq emerge-mode nil)
1817 (setq emerge-fast-mode nil)
1818 (setq emerge-edit-mode nil)
1819 (setq emerge-auto-advance nil)
1820 (setq emerge-skip-prefers nil)
1821 ;; restore mode line
1822 (kill-local-variable 'mode-line-buffer-identification)
1823 (let ((emerge-prefix-argument arg))
1824 (run-hooks 'emerge-quit-hook)))
1826 (defun emerge-select-A (&optional force)
1827 "Select the A variant of this difference.
1828 Refuses to function if this difference has been edited, i.e., if it
1829 is neither the A nor the B variant.
1830 An ARGUMENT forces the variant to be selected even if the difference has
1831 been edited."
1832 (interactive "P")
1833 (let ((operate
1834 (function (lambda ()
1835 (emerge-select-A-edit merge-begin merge-end A-begin A-end)
1836 (if emerge-auto-advance
1837 (emerge-next-difference)))))
1838 (operate-no-change
1839 (function (lambda ()
1840 (if emerge-auto-advance
1841 (emerge-next-difference))))))
1842 (emerge-select-version force operate-no-change operate operate)))
1844 ;; Actually select the A variant
1845 (defun emerge-select-A-edit (merge-begin merge-end A-begin A-end)
1846 (emerge-eval-in-buffer
1847 emerge-merge-buffer
1848 (delete-region merge-begin merge-end)
1849 (goto-char merge-begin)
1850 (insert-buffer-substring emerge-A-buffer A-begin A-end)
1851 (goto-char merge-begin)
1852 (aset diff-vector 6 'A)
1853 (emerge-refresh-mode-line)))
1855 (defun emerge-select-B (&optional force)
1856 "Select the B variant of this difference.
1857 Refuses to function if this difference has been edited, i.e., if it
1858 is neither the A nor the B variant. An ARGUMENT forces the variant to be selected even if the difference has
1859 been edited."
1860 (interactive "P")
1861 (let ((operate
1862 (function (lambda ()
1863 (emerge-select-B-edit merge-begin merge-end B-begin B-end)
1864 (if emerge-auto-advance
1865 (emerge-next-difference)))))
1866 (operate-no-change
1867 (function (lambda ()
1868 (if emerge-auto-advance
1869 (emerge-next-difference))))))
1870 (emerge-select-version force operate operate-no-change operate)))
1872 ;; Actually select the B variant
1873 (defun emerge-select-B-edit (merge-begin merge-end B-begin B-end)
1874 (emerge-eval-in-buffer
1875 emerge-merge-buffer
1876 (delete-region merge-begin merge-end)
1877 (goto-char merge-begin)
1878 (insert-buffer-substring emerge-B-buffer B-begin B-end)
1879 (goto-char merge-begin)
1880 (aset diff-vector 6 'B)
1881 (emerge-refresh-mode-line)))
1883 (defun emerge-default-A ()
1884 "Selects the A variant.
1885 This selects the A variant for all differences from here down in the buffer
1886 which are still defaulted, i.e., which the user has not selected and for
1887 which there is no preference."
1888 (interactive)
1889 (let ((buffer-read-only nil))
1890 (let ((selected-difference emerge-current-difference)
1891 (n (max emerge-current-difference 0)))
1892 (while (< n emerge-number-of-differences)
1893 (let ((diff-vector (aref emerge-difference-list n)))
1894 (if (eq (aref diff-vector 6) 'default-B)
1895 (progn
1896 (emerge-unselect-and-select-difference n t)
1897 (emerge-select-A)
1898 (aset diff-vector 6 'default-A))))
1899 (setq n (1+ n))
1900 (if (= (* (/ n 10) 10) n)
1901 (message "Setting default to A...%d" n)))
1902 (emerge-unselect-and-select-difference selected-difference)))
1903 (message "Default A set"))
1905 (defun emerge-default-B ()
1906 "Selects the B variant.
1907 This selects the B variant for all differences from here down in the buffer
1908 which are still defaulted, i.e., which the user has not selected and for
1909 which there is no preference."
1910 (interactive)
1911 (let ((buffer-read-only nil))
1912 (let ((selected-difference emerge-current-difference)
1913 (n (max emerge-current-difference 0)))
1914 (while (< n emerge-number-of-differences)
1915 (let ((diff-vector (aref emerge-difference-list n)))
1916 (if (eq (aref diff-vector 6) 'default-A)
1917 (progn
1918 (emerge-unselect-and-select-difference n t)
1919 (emerge-select-B)
1920 (aset diff-vector 6 'default-B))))
1921 (setq n (1+ n))
1922 (if (= (* (/ n 10) 10) n)
1923 (message "Setting default to B...%d" n)))
1924 (emerge-unselect-and-select-difference selected-difference)))
1925 (message "Default B set"))
1927 (defun emerge-fast-mode ()
1928 "Set fast mode.
1929 In this mode ordinary Emacs commands are disabled, and Emerge commands
1930 are need not be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1931 (interactive)
1932 (setq buffer-read-only t)
1933 (use-local-map emerge-fast-keymap)
1934 (setq emerge-mode t)
1935 (setq emerge-fast-mode t)
1936 (setq emerge-edit-mode nil)
1937 (message "Fast mode set")
1938 ;; force mode line redisplay
1939 (set-buffer-modified-p (buffer-modified-p)))
1941 (defun emerge-edit-mode ()
1942 "Set edit mode.
1943 In this mode ordinary Emacs commands are available, and Emerge commands
1944 must be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1945 (interactive)
1946 (setq buffer-read-only nil)
1947 (use-local-map emerge-edit-keymap)
1948 (setq emerge-mode t)
1949 (setq emerge-fast-mode nil)
1950 (setq emerge-edit-mode t)
1951 (message "Edit mode set")
1952 ;; force mode line redisplay
1953 (set-buffer-modified-p (buffer-modified-p)))
1955 (defun emerge-auto-advance (arg)
1956 "Toggle auto-advance mode.
1957 This mode causes `emerge-select-A' and `emerge-select-B' to automatically
1958 advance to the next difference. (See `emerge-auto-advance'.)
1959 If a positive ARGUMENT is given, it turns on `auto-advance-mode'.
1960 If a negative ARGUMENT is given, it turns off `auto-advance-mode'."
1961 (interactive "P")
1962 (setq emerge-auto-advance (if (null arg)
1963 (not emerge-auto-advance)
1964 (> (prefix-numeric-value arg) 0)))
1965 (message (if emerge-skip-prefers
1966 "Auto-advance set"
1967 "Auto-advance cleared"))
1968 ;; force mode line redisplay
1969 (set-buffer-modified-p (buffer-modified-p)))
1971 (defun emerge-skip-prefers (arg)
1972 "Toggle skip-prefers mode.
1973 This mode causes `emerge-next-difference' and `emerge-previous-difference'
1974 to automatically skip over differences for which there is a preference.
1975 (See `emerge-skip-prefers'.) If a positive ARG is given, it turns on
1976 `skip-prefers' mode.
1977 If a negative ARG is given, it turns off `skip-prefers' mode."
1978 (interactive "P")
1979 (setq emerge-skip-prefers (if (null arg)
1980 (not emerge-skip-prefers)
1981 (> (prefix-numeric-value arg) 0)))
1982 (message (if emerge-skip-prefers
1983 "Skip-prefers set"
1984 "Skip-prefers cleared"))
1985 ;; force mode line redisplay
1986 (set-buffer-modified-p (buffer-modified-p)))
1988 (defun emerge-copy-as-kill-A ()
1989 "Put the A variant of this difference in the kill ring."
1990 (interactive)
1991 (emerge-validate-difference)
1992 (let* ((diff-vector
1993 (aref emerge-difference-list emerge-current-difference))
1994 (A-begin (1+ (aref diff-vector 0)))
1995 (A-end (1- (aref diff-vector 1)))
1996 ;; so further kills don't append
1997 this-command)
1998 (save-excursion
1999 (set-buffer emerge-A-buffer)
2000 (copy-region-as-kill A-begin A-end))))
2002 (defun emerge-copy-as-kill-B ()
2003 "Put the B variant of this difference in the kill ring."
2004 (interactive)
2005 (emerge-validate-difference)
2006 (let* ((diff-vector
2007 (aref emerge-difference-list emerge-current-difference))
2008 (B-begin (1+ (aref diff-vector 2)))
2009 (B-end (1- (aref diff-vector 3)))
2010 ;; so further kills don't append
2011 this-command)
2012 (save-excursion
2013 (set-buffer emerge-B-buffer)
2014 (copy-region-as-kill B-begin B-end))))
2016 (defun emerge-insert-A (arg)
2017 "Insert the A variant of this difference at the point.
2018 Leaves point after text, mark before.
2019 With prefix argument, puts point before, mark after."
2020 (interactive "P")
2021 (emerge-validate-difference)
2022 (let* ((diff-vector
2023 (aref emerge-difference-list emerge-current-difference))
2024 (A-begin (1+ (aref diff-vector 0)))
2025 (A-end (1- (aref diff-vector 1)))
2026 (opoint (point))
2027 (buffer-read-only nil))
2028 (insert-buffer-substring emerge-A-buffer A-begin A-end)
2029 (if (not arg)
2030 (set-mark opoint)
2031 (set-mark (point))
2032 (goto-char opoint))))
2034 (defun emerge-insert-B (arg)
2035 "Insert the B variant of this difference at the point.
2036 Leaves point after text, mark before.
2037 With prefix argument, puts point before, mark after."
2038 (interactive "P")
2039 (emerge-validate-difference)
2040 (let* ((diff-vector
2041 (aref emerge-difference-list emerge-current-difference))
2042 (B-begin (1+ (aref diff-vector 2)))
2043 (B-end (1- (aref diff-vector 3)))
2044 (opoint (point))
2045 (buffer-read-only nil))
2046 (insert-buffer-substring emerge-B-buffer B-begin B-end)
2047 (if (not arg)
2048 (set-mark opoint)
2049 (set-mark (point))
2050 (goto-char opoint))))
2052 (defun emerge-mark-difference (arg)
2053 "Leaves the point before this difference and the mark after it.
2054 With prefix argument, puts mark before, point after."
2055 (interactive "P")
2056 (emerge-validate-difference)
2057 (let* ((diff-vector
2058 (aref emerge-difference-list emerge-current-difference))
2059 (merge-begin (1+ (aref diff-vector 4)))
2060 (merge-end (1- (aref diff-vector 5))))
2061 (if (not arg)
2062 (progn
2063 (goto-char merge-begin)
2064 (set-mark merge-end))
2065 (goto-char merge-end)
2066 (set-mark merge-begin))))
2068 (defun emerge-file-names ()
2069 "Show the names of the buffers or files being operated on by Emerge.
2070 Use C-u l to reset the windows afterward."
2071 (interactive)
2072 (delete-other-windows)
2073 (let ((temp-buffer-show-function
2074 (function (lambda (buf)
2075 (split-window-vertically)
2076 (switch-to-buffer buf)
2077 (other-window 1)))))
2078 (with-output-to-temp-buffer "*Help*"
2079 (emerge-eval-in-buffer emerge-A-buffer
2080 (if buffer-file-name
2081 (progn
2082 (princ "File A is: ")
2083 (princ buffer-file-name))
2084 (progn
2085 (princ "Buffer A is: ")
2086 (princ (buffer-name))))
2087 (princ "\n"))
2088 (emerge-eval-in-buffer emerge-B-buffer
2089 (if buffer-file-name
2090 (progn
2091 (princ "File B is: ")
2092 (princ buffer-file-name))
2093 (progn
2094 (princ "Buffer B is: ")
2095 (princ (buffer-name))))
2096 (princ "\n"))
2097 (if emerge-ancestor-buffer
2098 (emerge-eval-in-buffer emerge-ancestor-buffer
2099 (if buffer-file-name
2100 (progn
2101 (princ "Ancestor file is: ")
2102 (princ buffer-file-name))
2103 (progn
2104 (princ "Ancestor buffer is: ")
2105 (princ (buffer-name))))
2106 (princ "\n")))
2107 (princ emerge-output-description))))
2109 (defun emerge-join-differences (arg)
2110 "Join the selected difference with the following one.
2111 With a prefix argument, join with the preceeding one."
2112 (interactive "P")
2113 (let ((n emerge-current-difference))
2114 ;; adjust n to be first difference to join
2115 (if arg
2116 (setq n (1- n)))
2117 ;; n and n+1 are the differences to join
2118 ;; check that they are both differences
2119 (if (or (< n 0) (>= n (1- emerge-number-of-differences)))
2120 (error "Incorrect differences to join"))
2121 ;; remove the flags
2122 (emerge-unselect-difference emerge-current-difference)
2123 ;; decrement total number of differences
2124 (setq emerge-number-of-differences (1- emerge-number-of-differences))
2125 ;; build new differences vector
2126 (let ((i 0)
2127 (new-differences (make-vector emerge-number-of-differences nil)))
2128 (while (< i emerge-number-of-differences)
2129 (aset new-differences i
2130 (cond
2131 ((< i n) (aref emerge-difference-list i))
2132 ((> i n) (aref emerge-difference-list (1+ i)))
2133 (t (let ((prev (aref emerge-difference-list i))
2134 (next (aref emerge-difference-list (1+ i))))
2135 (vector (aref prev 0)
2136 (aref next 1)
2137 (aref prev 2)
2138 (aref next 3)
2139 (aref prev 4)
2140 (aref next 5)
2141 (let ((ps (aref prev 6))
2142 (ns (aref next 6)))
2143 (cond
2144 ((eq ps ns)
2146 ((and (or (eq ps 'B) (eq ps 'prefer-B))
2147 (or (eq ns 'B) (eq ns 'prefer-B)))
2149 (t 'A))))))))
2150 (setq i (1+ i)))
2151 (setq emerge-difference-list new-differences))
2152 ;; set the current difference correctly
2153 (setq emerge-current-difference n)
2154 ;; fix the mode line
2155 (emerge-refresh-mode-line)
2156 ;; reinsert the flags
2157 (emerge-select-difference emerge-current-difference)
2158 (emerge-recenter)))
2160 (defun emerge-split-difference ()
2161 "Split the current difference where the points are in the three windows."
2162 (interactive)
2163 (let ((n emerge-current-difference))
2164 ;; check that this is a valid difference
2165 (emerge-validate-difference)
2166 ;; get the point values and old difference
2167 (let ((A-point (emerge-eval-in-buffer emerge-A-buffer
2168 (point-marker)))
2169 (B-point (emerge-eval-in-buffer emerge-B-buffer
2170 (point-marker)))
2171 (merge-point (point-marker))
2172 (old-diff (aref emerge-difference-list n)))
2173 ;; check location of the points, give error if they aren't in the
2174 ;; differences
2175 (if (or (< A-point (aref old-diff 0))
2176 (> A-point (aref old-diff 1)))
2177 (error "Point outside of difference in A buffer"))
2178 (if (or (< B-point (aref old-diff 2))
2179 (> B-point (aref old-diff 3)))
2180 (error "Point outside of difference in B buffer"))
2181 (if (or (< merge-point (aref old-diff 4))
2182 (> merge-point (aref old-diff 5)))
2183 (error "Point outside of difference in merge buffer"))
2184 ;; remove the flags
2185 (emerge-unselect-difference emerge-current-difference)
2186 ;; increment total number of differences
2187 (setq emerge-number-of-differences (1+ emerge-number-of-differences))
2188 ;; build new differences vector
2189 (let ((i 0)
2190 (new-differences (make-vector emerge-number-of-differences nil)))
2191 (while (< i emerge-number-of-differences)
2192 (aset new-differences i
2193 (cond
2194 ((< i n)
2195 (aref emerge-difference-list i))
2196 ((> i (1+ n))
2197 (aref emerge-difference-list (1- i)))
2198 ((= i n)
2199 (vector (aref old-diff 0)
2200 A-point
2201 (aref old-diff 2)
2202 B-point
2203 (aref old-diff 4)
2204 merge-point
2205 (aref old-diff 6)))
2207 (vector (copy-marker A-point)
2208 (aref old-diff 1)
2209 (copy-marker B-point)
2210 (aref old-diff 3)
2211 (copy-marker merge-point)
2212 (aref old-diff 5)
2213 (aref old-diff 6)))))
2214 (setq i (1+ i)))
2215 (setq emerge-difference-list new-differences))
2216 ;; set the current difference correctly
2217 (setq emerge-current-difference n)
2218 ;; fix the mode line
2219 (emerge-refresh-mode-line)
2220 ;; reinsert the flags
2221 (emerge-select-difference emerge-current-difference)
2222 (emerge-recenter))))
2224 (defun emerge-trim-difference ()
2225 "Trim lines off top and bottom of difference that are the same.
2226 If lines are the same in both the A and the B versions, strip them off.
2227 (This can happen when the A and B versions have common lines that the
2228 ancestor version does not share.)"
2229 (interactive)
2230 ;; make sure we are in a real difference
2231 (emerge-validate-difference)
2232 ;; remove the flags
2233 (emerge-unselect-difference emerge-current-difference)
2234 (let* ((diff (aref emerge-difference-list emerge-current-difference))
2235 (top-a (marker-position (aref diff 0)))
2236 (bottom-a (marker-position (aref diff 1)))
2237 (top-b (marker-position (aref diff 2)))
2238 (bottom-b (marker-position (aref diff 3)))
2239 (top-m (marker-position (aref diff 4)))
2240 (bottom-m (marker-position (aref diff 5)))
2241 size success sa sb sm)
2242 ;; move down the tops of the difference regions as much as possible
2243 ;; Try advancing comparing 1000 chars at a time.
2244 ;; When that fails, go 500 chars at a time, and so on.
2245 (setq size 1000)
2246 (while (> size 0)
2247 (setq success t)
2248 (while success
2249 (setq size (min size (- bottom-a top-a) (- bottom-b top-b)
2250 (- bottom-m top-m)))
2251 (setq sa (emerge-eval-in-buffer emerge-A-buffer
2252 (buffer-substring top-a
2253 (+ size top-a))))
2254 (setq sb (emerge-eval-in-buffer emerge-B-buffer
2255 (buffer-substring top-b
2256 (+ size top-b))))
2257 (setq sm (buffer-substring top-m (+ size top-m)))
2258 (setq success (and (> size 0) (equal sa sb) (equal sb sm)))
2259 (if success
2260 (setq top-a (+ top-a size)
2261 top-b (+ top-b size)
2262 top-m (+ top-m size))))
2263 (setq size (/ size 2)))
2264 ;; move up the bottoms of the difference regions as much as possible
2265 ;; Try advancing comparing 1000 chars at a time.
2266 ;; When that fails, go 500 chars at a time, and so on.
2267 (setq size 1000)
2268 (while (> size 0)
2269 (setq success t)
2270 (while success
2271 (setq size (min size (- bottom-a top-a) (- bottom-b top-b)
2272 (- bottom-m top-m)))
2273 (setq sa (emerge-eval-in-buffer emerge-A-buffer
2274 (buffer-substring (- bottom-a size)
2275 bottom-a)))
2276 (setq sb (emerge-eval-in-buffer emerge-B-buffer
2277 (buffer-substring (- bottom-b size)
2278 bottom-b)))
2279 (setq sm (buffer-substring (- bottom-m size) bottom-m))
2280 (setq success (and (> size 0) (equal sa sb) (equal sb sm)))
2281 (if success
2282 (setq bottom-a (- bottom-a size)
2283 bottom-b (- bottom-b size)
2284 bottom-m (- bottom-m size))))
2285 (setq size (/ size 2)))
2286 ;; {top,bottom}-{a,b,m} are now set at the new beginnings and ends
2287 ;; of the difference regions. Move them to the beginning of lines, as
2288 ;; appropriate.
2289 (emerge-eval-in-buffer emerge-A-buffer
2290 (goto-char top-a)
2291 (beginning-of-line)
2292 (aset diff 0 (point-marker))
2293 (goto-char bottom-a)
2294 (beginning-of-line 2)
2295 (aset diff 1 (point-marker)))
2296 (emerge-eval-in-buffer emerge-B-buffer
2297 (goto-char top-b)
2298 (beginning-of-line)
2299 (aset diff 2 (point-marker))
2300 (goto-char bottom-b)
2301 (beginning-of-line 2)
2302 (aset diff 3 (point-marker)))
2303 (goto-char top-m)
2304 (beginning-of-line)
2305 (aset diff 4 (point-marker))
2306 (goto-char bottom-m)
2307 (beginning-of-line 2)
2308 (aset diff 5 (point-marker))
2309 ;; put the flags back in, recenter the display
2310 (emerge-select-difference emerge-current-difference)
2311 (emerge-recenter)))
2313 (defun emerge-find-difference (arg)
2314 "Find the difference containing the current position of the point.
2315 If there is no containing difference and the prefix argument is positive,
2316 it finds the nearest following difference. A negative prefix argument finds
2317 the nearest previous difference."
2318 (interactive "P")
2319 ;; search for the point in the merge buffer, using the markers
2320 ;; for the beginning and end of the differences in the merge buffer
2321 (emerge-find-difference1 arg (point) 4 5))
2323 (defun emerge-find-difference-A (arg)
2324 "Find the difference containing the position of the point in the A buffer.
2325 This command must be executed in the merge buffer.
2326 If there is no containing difference and the prefix argument is positive,
2327 it finds the nearest following difference. A negative prefix argument finds
2328 the nearest previous difference."
2329 (interactive "P")
2330 ;; search for the point in the A buffer, using the markers
2331 ;; for the beginning and end of the differences in the A buffer
2332 (emerge-find-difference1 arg
2333 (emerge-eval-in-buffer emerge-A-buffer (point))
2334 0 1))
2336 (defun emerge-find-difference-B (arg)
2337 "Find the difference containing the position of the point in the B buffer.
2338 This command must be executed in the merge buffer.
2339 If there is no containing difference and the prefix argument is positive,
2340 it finds the nearest following difference. A negative prefix argument finds
2341 the nearest previous difference."
2342 (interactive "P")
2343 ;; search for the point in the B buffer, using the markers
2344 ;; for the beginning and end of the differences in the B buffer
2345 (emerge-find-difference1 arg
2346 (emerge-eval-in-buffer emerge-B-buffer (point))
2347 2 3))
2349 (defun emerge-find-difference1 (arg location begin end)
2350 (let* ((index
2351 ;; find first difference containing or after the current position
2352 (catch 'search
2353 (let ((n 0))
2354 (while (< n emerge-number-of-differences)
2355 (let ((diff-vector (aref emerge-difference-list n)))
2356 (if (<= location (marker-position (aref diff-vector end)))
2357 (throw 'search n)))
2358 (setq n (1+ n))))
2359 emerge-number-of-differences))
2360 (contains
2361 ;; whether the found difference contains the current position
2362 (and (< index emerge-number-of-differences)
2363 (<= (marker-position (aref (aref emerge-difference-list index)
2364 begin))
2365 location)))
2366 (arg-value
2367 ;; numeric value of prefix argument
2368 (prefix-numeric-value arg)))
2369 (emerge-unselect-and-select-difference
2370 (cond
2371 ;; if the point is in a difference, select it
2372 (contains index)
2373 ;; if the arg is nil and the point is not in a difference, error
2374 ((null arg) (error "No difference contains point"))
2375 ;; if the arg is positive, select the following difference
2376 ((> arg-value 0)
2377 (if (< index emerge-number-of-differences)
2378 index
2379 (error "No difference contains or follows point")))
2380 ;; if the arg is negative, select the preceeding difference
2382 (if (> index 0)
2383 (1- index)
2384 (error "No difference contains or preceeds point")))))))
2386 (defun emerge-line-numbers ()
2387 "Display the current line numbers.
2388 This function displays the line numbers of the points in the A, B, and
2389 merge buffers."
2390 (interactive)
2391 (let* ((valid-diff
2392 (and (>= emerge-current-difference 0)
2393 (< emerge-current-difference emerge-number-of-differences)))
2394 (diff (and valid-diff
2395 (aref emerge-difference-list emerge-current-difference)))
2396 (merge-line (emerge-line-number-in-buf 4 5))
2397 (A-line (emerge-eval-in-buffer emerge-A-buffer
2398 (emerge-line-number-in-buf 0 1)))
2399 (B-line (emerge-eval-in-buffer emerge-B-buffer
2400 (emerge-line-number-in-buf 2 3))))
2401 (message "At lines: merge = %d, A = %d, B = %d"
2402 merge-line A-line B-line)))
2404 (defun emerge-line-number-in-buf (begin-marker end-marker)
2405 (let (temp)
2406 (setq temp (save-excursion
2407 (beginning-of-line)
2408 (1+ (count-lines 1 (point)))))
2409 (if valid-diff
2410 (progn
2411 (if (> (point) (aref diff begin-marker))
2412 (setq temp (- temp emerge-before-flag-lines)))
2413 (if (> (point) (aref diff end-marker))
2414 (setq temp (- temp emerge-after-flag-lines)))))
2415 temp))
2417 (defun emerge-set-combine-versions-template (start end &optional localize)
2418 "Copy region into `emerge-combine-versions-template'.
2419 This controls how `emerge-combine-versions' will combine the two versions.
2420 With prefix argument, `emerge-combine-versions' is made local to this
2421 merge buffer. Localization is permanent for any particular merge buffer."
2422 (interactive "r\nP")
2423 (if localize
2424 (make-local-variable 'emerge-combine-versions-template))
2425 (setq emerge-combine-versions-template (buffer-substring start end))
2426 (message
2427 (if (assq 'emerge-combine-versions-template (buffer-local-variables))
2428 "emerge-set-combine-versions-template set locally."
2429 "emerge-set-combine-versions-template set.")))
2431 (defun emerge-combine-versions (&optional force)
2432 "Combine versions using the template in `emerge-combine-versions-template'.
2433 Refuses to function if this difference has been edited, i.e., if it is
2434 neither the A nor the B variant.
2435 An argument forces the variant to be selected even if the difference has
2436 been edited."
2437 (interactive "P")
2438 (emerge-combine-versions-internal emerge-combine-versions-template force))
2440 (defun emerge-combine-versions-register (char &optional force)
2441 "Combine the two versions using the template in register REG.
2442 See documentation of the variable `emerge-combine-versions-template'
2443 for how the template is interpreted.
2444 Refuses to function if this difference has been edited, i.e., if it is
2445 neither the A nor the B variant.
2446 An argument forces the variant to be selected even if the difference has
2447 been edited."
2448 (interactive "cRegister containing template: \nP")
2449 (let ((template (get-register char)))
2450 (if (not (stringp template))
2451 (error "Register does not contain text"))
2452 (emerge-combine-versions-internal template force)))
2454 (defun emerge-combine-versions-internal (template force)
2455 (let ((operate
2456 (function (lambda ()
2457 (emerge-combine-versions-edit merge-begin merge-end
2458 A-begin A-end B-begin B-end)
2459 (if emerge-auto-advance
2460 (emerge-next-difference))))))
2461 (emerge-select-version force operate operate operate)))
2463 (defun emerge-combine-versions-edit (merge-begin merge-end
2464 A-begin A-end B-begin B-end)
2465 (emerge-eval-in-buffer
2466 emerge-merge-buffer
2467 (delete-region merge-begin merge-end)
2468 (goto-char merge-begin)
2469 (let ((i 0))
2470 (while (< i (length template))
2471 (let ((c (aref template i)))
2472 (if (= c ?%)
2473 (progn
2474 (setq i (1+ i))
2475 (setq c
2476 (condition-case nil
2477 (aref template i)
2478 (error ?%)))
2479 (cond ((= c ?a)
2480 (insert-buffer-substring emerge-A-buffer A-begin A-end))
2481 ((= c ?b)
2482 (insert-buffer-substring emerge-B-buffer B-begin B-end))
2483 ((= c ?%)
2484 (insert ?%))
2486 (insert c))))
2487 (insert c)))
2488 (setq i (1+ i))))
2489 (goto-char merge-begin)
2490 (aset diff-vector 6 'combined)
2491 (emerge-refresh-mode-line)))
2493 (defun emerge-set-merge-mode (mode)
2494 "Set the major mode in a merge buffer.
2495 Overrides any change that the mode might make to the mode line or local
2496 keymap. Leaves merge in fast mode."
2497 (interactive
2498 (list (intern (completing-read "New major mode for merge buffer: "
2499 obarray 'commandp t nil))))
2500 (funcall mode)
2501 (emerge-refresh-mode-line)
2502 (if emerge-fast-mode
2503 (emerge-fast-mode)
2504 (emerge-edit-mode)))
2506 (defun emerge-one-line-window ()
2507 (interactive)
2508 (let ((window-min-height 1))
2509 (shrink-window (- (window-height) 2))))
2511 ;;; Support routines
2513 ;; Select a difference by placing the visual flags around the appropriate
2514 ;; group of lines in the A, B, and merge buffers
2515 (defun emerge-select-difference (n)
2516 (let ((diff-vector (aref emerge-difference-list n)))
2517 (emerge-place-flags-in-buffer emerge-A-buffer
2518 (aref diff-vector 0) (aref diff-vector 1))
2519 (emerge-place-flags-in-buffer emerge-B-buffer
2520 (aref diff-vector 2) (aref diff-vector 3))
2521 (emerge-place-flags-in-buffer emerge-merge-buffer
2522 (aref diff-vector 4) (aref diff-vector 5))))
2524 (defun emerge-place-flags-in-buffer (buffer before after)
2525 (if (eq buffer emerge-merge-buffer)
2526 (emerge-place-flags-in-buffer1 buffer before after)
2527 (emerge-eval-in-buffer
2528 buffer
2529 (emerge-place-flags-in-buffer1 buffer before after))))
2531 (defun emerge-place-flags-in-buffer1 (buffer before after)
2532 (let ((buffer-read-only nil))
2533 ;; insert the flags
2534 (goto-char before)
2535 (insert-before-markers emerge-before-flag)
2536 (goto-char after)
2537 (insert emerge-after-flag)
2538 ;; put the markers into the flags, so alterations above or below won't move
2539 ;; them
2540 ;; before marker is one char before the end of the before flag
2541 ;; after marker is one char after the beginning of the after flag
2542 (set-marker before (1- before))
2543 (set-marker after (1+ after))))
2545 ;; Unselect a difference by removing the visual flags in the buffers.
2546 (defun emerge-unselect-difference (n)
2547 (let ((diff-vector (aref emerge-difference-list n)))
2548 (emerge-remove-flags-in-buffer emerge-A-buffer
2549 (aref diff-vector 0) (aref diff-vector 1))
2550 (emerge-remove-flags-in-buffer emerge-B-buffer
2551 (aref diff-vector 2) (aref diff-vector 3))
2552 (emerge-remove-flags-in-buffer emerge-merge-buffer
2553 (aref diff-vector 4) (aref diff-vector 5))))
2555 (defun emerge-remove-flags-in-buffer (buffer before after)
2556 (emerge-eval-in-buffer
2557 buffer
2558 (let ((buffer-read-only nil))
2559 ;; put the markers at the beginning of the flags
2560 (set-marker before (- before (1- emerge-before-flag-length)))
2561 (set-marker after (1- after))
2562 ;; remove the flags
2563 (goto-char before)
2564 (if (looking-at emerge-before-flag-match)
2565 (delete-char emerge-before-flag-length)
2566 ;; the flag isn't there
2567 (ding)
2568 (message "Trouble removing flag."))
2569 (goto-char after)
2570 (if (looking-at emerge-after-flag-match)
2571 (delete-char emerge-after-flag-length)
2572 ;; the flag isn't there
2573 (ding)
2574 (message "Trouble removing flag.")))))
2576 ;; Select a difference, removing an flags that exist now.
2577 (defun emerge-unselect-and-select-difference (n &optional suppress-display)
2578 (if (and (>= emerge-current-difference 0)
2579 (< emerge-current-difference emerge-number-of-differences))
2580 (emerge-unselect-difference emerge-current-difference))
2581 (if (and (>= n 0) (< n emerge-number-of-differences))
2582 (progn
2583 (emerge-select-difference n)
2584 (let* ((diff-vector (aref emerge-difference-list n))
2585 (selection-type (aref diff-vector 6)))
2586 (if (eq selection-type 'default-A)
2587 (aset diff-vector 6 'A)
2588 (if (eq selection-type 'default-B)
2589 (aset diff-vector 6 'B))))))
2590 (setq emerge-current-difference n)
2591 (if (not suppress-display)
2592 (progn
2593 (emerge-recenter)
2594 (emerge-refresh-mode-line))))
2596 ;; Perform tests to see whether user should be allowed to select a version
2597 ;; of this difference:
2598 ;; a valid difference has been selected; and
2599 ;; the difference text in the merge buffer is:
2600 ;; the A version (execute a-version), or
2601 ;; the B version (execute b-version), or
2602 ;; empty (execute neither-version), or
2603 ;; argument FORCE is true (execute neither-version)
2604 ;; Otherwise, signal an error.
2605 (defun emerge-select-version (force a-version b-version neither-version)
2606 (emerge-validate-difference)
2607 (let ((buffer-read-only nil))
2608 (let* ((diff-vector
2609 (aref emerge-difference-list emerge-current-difference))
2610 (A-begin (1+ (aref diff-vector 0)))
2611 (A-end (1- (aref diff-vector 1)))
2612 (B-begin (1+ (aref diff-vector 2)))
2613 (B-end (1- (aref diff-vector 3)))
2614 (merge-begin (1+ (aref diff-vector 4)))
2615 (merge-end (1- (aref diff-vector 5))))
2616 (if (emerge-compare-buffers emerge-A-buffer A-begin A-end
2617 emerge-merge-buffer merge-begin
2618 merge-end)
2619 (funcall a-version)
2620 (if (emerge-compare-buffers emerge-B-buffer B-begin B-end
2621 emerge-merge-buffer merge-begin
2622 merge-end)
2623 (funcall b-version)
2624 (if (or force (= merge-begin merge-end))
2625 (funcall neither-version)
2626 (error "This difference region has been edited.")))))))
2628 ;; Revise the mode line to display which difference we have selected
2630 (defun emerge-refresh-mode-line ()
2631 (setq mode-line-buffer-identification
2632 (list (format "Emerge: %%b diff %d of %d%s"
2633 (1+ emerge-current-difference)
2634 emerge-number-of-differences
2635 (if (and (>= emerge-current-difference 0)
2636 (< emerge-current-difference
2637 emerge-number-of-differences))
2638 (cdr (assq (aref (aref emerge-difference-list
2639 emerge-current-difference)
2641 '((A . " - A")
2642 (B . " - B")
2643 (prefer-A . " - A*")
2644 (prefer-B . " - B*")
2645 (combined . " - comb"))))
2646 ""))))
2647 ;; Force mode-line redisplay
2648 (set-buffer-modified-p (buffer-modified-p)))
2650 ;; compare two regions in two buffers for containing the same text
2651 (defun emerge-compare-buffers (buffer-x x-begin x-end buffer-y y-begin y-end)
2652 ;; first check that the two regions are the same length
2653 (if (not (and (= (- x-end x-begin) (- y-end y-begin))))
2655 (catch 'exit
2656 (while (< x-begin x-end)
2657 ;; bite off and compare no more than 1000 characters at a time
2658 (let* ((compare-length (min (- x-end x-begin) 1000))
2659 (x-string (emerge-eval-in-buffer
2660 buffer-x
2661 (buffer-substring x-begin
2662 (+ x-begin compare-length))))
2663 (y-string (emerge-eval-in-buffer
2664 buffer-y
2665 (buffer-substring y-begin
2666 (+ y-begin compare-length)))))
2667 (if (not (string-equal x-string y-string))
2668 (throw 'exit nil)
2669 (setq x-begin (+ x-begin compare-length))
2670 (setq y-begin (+ y-begin compare-length)))))
2671 t)))
2673 ;; Construct a unique buffer name.
2674 ;; The first one tried is prefixsuffix, then prefix<2>suffix,
2675 ;; prefix<3>suffix, etc.
2676 (defun emerge-unique-buffer-name (prefix suffix)
2677 (if (null (get-buffer (concat prefix suffix)))
2678 (concat prefix suffix)
2679 (let ((n 2))
2680 (while (get-buffer (format "%s<%d>%s" prefix n suffix))
2681 (setq n (1+ n)))
2682 (format "%s<%d>%s" prefix n suffix))))
2684 ;; Verify that we have a difference selected.
2685 (defun emerge-validate-difference ()
2686 (if (not (and (>= emerge-current-difference 0)
2687 (< emerge-current-difference emerge-number-of-differences)))
2688 (error "No difference selected")))
2690 ;;; Functions for saving and restoring a batch of variables
2692 ;; These functions save (get the values of) and restore (set the values of)
2693 ;; a list of variables. The argument is a list of symbols (the names of
2694 ;; the variables). A list element can also be a list of two functions,
2695 ;; the first of which (when called with no arguments) gets the value, and
2696 ;; the second (when called with a value as an argment) sets the value.
2697 ;; A "function" is anything that funcall can handle as an argument.
2699 (defun emerge-save-variables (vars)
2700 (mapcar (function (lambda (v) (if (symbolp v)
2701 (symbol-value v)
2702 (funcall (car v)))))
2703 vars))
2705 (defun emerge-restore-variables (vars values)
2706 (while vars
2707 (let ((var (car vars))
2708 (value (car values)))
2709 (if (symbolp var)
2710 (set var value)
2711 (funcall (car (cdr var)) value)))
2712 (setq vars (cdr vars))
2713 (setq values (cdr values))))
2715 ;; Make a temporary file that only we have access to.
2716 ;; PREFIX is appended to emerge-temp-file-prefix to make the filename prefix.
2717 (defun emerge-make-temp-file (prefix)
2718 (let ((f (make-temp-name (concat emerge-temp-file-prefix prefix))))
2719 ;; create the file
2720 (write-region (point-min) (point-min) f nil 'no-message)
2721 (set-file-modes f emerge-temp-file-mode)
2724 ;;; Functions that query the user before he can write out the current buffer.
2726 (defun emerge-query-write-file ()
2727 "Query the user if he really wants to write out the incomplete merge.
2728 If he says yes, call `write-file' to do so. See `emerge-query-and-call'
2729 for details of the querying process."
2730 (interactive)
2731 (emerge-query-and-call 'write-file))
2733 (defun emerge-query-save-buffer ()
2734 "Query the user if he really wants to write out the incomplete merge.
2735 If he says yes, call `save-buffer' to do so. See `emerge-query-and-call'
2736 for details of the querying process."
2737 (interactive)
2738 (emerge-query-and-call 'save-buffer))
2740 (defun emerge-query-and-call (command)
2741 "Query the user if he really wants to write out the incomplete merge.
2742 If he says yes, call COMMAND interactively. During the call, the flags
2743 around the current difference are removed."
2744 (if (yes-or-no-p "Do you really write to write out this unfinished merge? ")
2745 ;; He really wants to do it -- unselect the difference for the duration
2746 (progn
2747 (if (and (>= emerge-current-difference 0)
2748 (< emerge-current-difference emerge-number-of-differences))
2749 (emerge-unselect-difference emerge-current-difference))
2750 ;; call-interactively takes the value of current-prefix-arg as the
2751 ;; prefix argument value to be passed to the command. Thus, we have
2752 ;; to do nothing special to make sure the prefix argument is
2753 ;; transmitted to the command.
2754 (call-interactively command)
2755 (if (and (>= emerge-current-difference 0)
2756 (< emerge-current-difference emerge-number-of-differences))
2757 (progn
2758 (emerge-select-difference emerge-current-difference)
2759 (emerge-recenter))))
2760 ;; He's being smart and not doing it
2761 (message "Not written")))
2763 ;; Make sure the current buffer (for a file) has the same contents as the
2764 ;; file on disk, and attempt to remedy the situation if not.
2765 ;; Signal an error if we can't make them the same, or the user doesn't want
2766 ;; to do what is necessary to make them the same.
2767 (defun emerge-verify-file-buffer ()
2768 ;; First check if the file has been modified since the buffer visited it.
2769 (if (verify-visited-file-modtime (current-buffer))
2770 (if (buffer-modified-p)
2771 ;; If buffer is not obsolete and is modified, offer to save
2772 (if (yes-or-no-p (format "Save file %s? " buffer-file-name))
2773 (save-buffer)
2774 (error "Buffer out of sync for file %s" buffer-file-name))
2775 ;; If buffer is not obsolete and is not modified, do nothing
2776 nil)
2777 (if (buffer-modified-p)
2778 ;; If buffer is obsolete and is modified, give error
2779 (error "Buffer out of sync for file %s" buffer-file-name)
2780 ;; If buffer is obsolete and is not modified, offer to revert
2781 (if (yes-or-no-p (format "Revert file %s? " buffer-file-name))
2782 (revert-buffer t t)
2783 (error "Buffer out of sync for file %s" buffer-file-name)))))
2785 ;; Utilities that might have value outside of Emerge.
2787 ;; Set up the mode in the current buffer to duplicate the mode in another
2788 ;; buffer.
2789 (defun emerge-copy-modes (buffer)
2790 ;; Set the major mode
2791 (funcall (emerge-eval-in-buffer buffer major-mode)))
2793 ;; Define a key, even if a prefix of it is defined
2794 (defun emerge-force-define-key (keymap key definition)
2795 "Like `define-key', but isn't stopped if a prefix of KEY is a defined
2796 command."
2797 ;; Find out if a prefix of key is defined
2798 (let ((v (lookup-key keymap key)))
2799 ;; If so, undefine it
2800 (if (integerp v)
2801 (define-key keymap (substring key 0 v) nil)))
2802 ;; Now define the key
2803 (define-key keymap key definition))
2805 ;;; Improvements to describe-mode, so that it describes minor modes as well
2806 ;;; as the major mode
2807 (defun describe-mode (&optional minor)
2808 "Display documentation of current major mode.
2809 If optional MINOR is non-nil (or prefix argument is given if interactive),
2810 display documentation of acive minor modes as well.
2811 For this to work correctly for a minor mode, the mode's indicator variable
2812 (listed in `minor-mode-alist') must also be a function whose documentation
2813 describes the minor mode."
2814 (interactive)
2815 (with-output-to-temp-buffer "*Help*"
2816 (princ mode-name)
2817 (princ " Mode:\n")
2818 (princ (documentation major-mode))
2819 (let ((minor-modes minor-mode-alist)
2820 (locals (buffer-local-variables)))
2821 (while minor-modes
2822 (let* ((minor-mode (car (car minor-modes)))
2823 (indicator (car (cdr (car minor-modes))))
2824 (local-binding (assq minor-mode locals)))
2825 ;; Document a minor mode if it is listed in minor-mode-alist,
2826 ;; bound locally in this buffer, non-nil, and has a function
2827 ;; definition.
2828 (if (and local-binding
2829 (cdr local-binding)
2830 (fboundp minor-mode))
2831 (progn
2832 (princ (format "\n\n\n%s minor mode (indicator%s):\n"
2833 minor-mode indicator))
2834 (princ (documentation minor-mode)))))
2835 (setq minor-modes (cdr minor-modes))))
2836 (print-help-return-message)))
2838 ;; Adjust things so that keyboard macro definitions are documented correctly.
2839 (fset 'defining-kbd-macro (symbol-function 'start-kbd-macro))
2841 ;; Function to shadow a definition in a keymap with definitions in another.
2842 (defun emerge-shadow-key-definition (olddef newdef keymap shadowmap)
2843 "Shadow OLDDEF with NEWDEF for any keys in KEYMAP with entries in SHADOWMAP.
2844 In other words, SHADOWMAP will now shadow all definitions of OLDDEF in KEYMAP
2845 with NEWDEF. Does not affect keys that are already defined in SHADOWMAP,
2846 including those whose definition is OLDDEF."
2847 ;; loop through all keymaps accessible from keymap
2848 (let ((maps (accessible-keymaps keymap)))
2849 (while maps
2850 (let ((prefix (car (car maps)))
2851 (map (cdr (car maps))))
2852 ;; examine a keymap
2853 (if (arrayp map)
2854 ;; array keymap
2855 (let ((len (length map))
2856 (i 0))
2857 (while (< i len)
2858 (if (eq (aref map i) olddef)
2859 ;; set the shadowing definition
2860 (let ((key (concat prefix (char-to-string i))))
2861 (emerge-define-key-if-possible shadowmap key newdef)))
2862 (setq i (1+ i))))
2863 ;; sparse keymap
2864 (while map
2865 (if (eq (cdr-safe (car-safe map)) olddef)
2866 ;; set the shadowing definition
2867 (let ((key
2868 (concat prefix (char-to-string (car (car map))))))
2869 (emerge-define-key-if-possible shadowmap key newdef)))
2870 (setq map (cdr map)))))
2871 (setq maps (cdr maps)))))
2873 ;; Define a key if it (or a prefix) is not already defined in the map.
2874 (defun emerge-define-key-if-possible (keymap key definition)
2875 ;; look up the present definition of the key
2876 (let ((present (lookup-key keymap key)))
2877 (if (integerp present)
2878 ;; if it is "too long", look up the valid prefix
2879 (if (not (lookup-key keymap (substring key 0 present)))
2880 ;; if the prefix isn't defined, define it
2881 (define-key keymap key definition))
2882 ;; if there is no present definition, define it
2883 (if (not present)
2884 (define-key keymap key definition)))))
2886 (defun emerge-recursively-substitute-key-definition (olddef newdef keymap)
2887 "Like `substitute-key-definition', but examines and substitutes in all
2888 keymaps accessible from KEYMAP. Make sure that subordinate keymaps aren't
2889 shared with other keymaps! (`copy-keymap' will suffice.)"
2890 ;; Loop through all keymaps accessible from keymap
2891 (let ((maps (accessible-keymaps keymap)))
2892 (while maps
2893 ;; Substitute in this keymap
2894 (substitute-key-definition olddef newdef (cdr (car maps)))
2895 (setq maps (cdr maps)))))
2897 ;; Show the name of the file in the buffer.
2898 (defun emerge-show-file-name ()
2899 "Displays the name of the file loaded into the current buffer.
2900 If the name won't fit on one line, the minibuffer is expanded to hold it,
2901 and the command waits for a keystroke from the user. If the keystroke is
2902 SPC, it is ignored; if it is anything else, it is processed as a command."
2903 (interactive)
2904 (let ((name (buffer-file-name)))
2905 (or name
2906 (setq name "Buffer has no file name."))
2907 (save-window-excursion
2908 (select-window (minibuffer-window))
2909 (erase-buffer)
2910 (insert name)
2911 (if (not (pos-visible-in-window-p))
2912 (let ((echo-keystrokes 0))
2913 (while (and (not (pos-visible-in-window-p))
2914 (> (1- (frame-height)) (window-height)))
2915 (enlarge-window 1))
2916 (let ((c (read-event)))
2917 (if (not (eq c 32))
2918 (setq unread-command-events (list c)))))))))
2920 ;; Improved auto-save file names.
2921 ;; This function fixes many problems with the standard auto-save file names:
2922 ;; Auto-save files for non-file buffers get put in the default directory
2923 ;; for the buffer, whether that makes sense or not.
2924 ;; Auto-save files for file buffers get put in the directory of the file,
2925 ;; regardless of whether we can write into it or not.
2926 ;; Auto-save files for non-file buffers don't use the process id, so if a
2927 ;; user runs more than on Emacs, they can make auto-save files that overwrite
2928 ;; each other.
2929 ;; To use this function, do:
2930 ;; (fset 'make-auto-save-file-name
2931 ;; (symbol-function 'emerge-make-auto-save-file-name))
2932 (defun emerge-make-auto-save-file-name ()
2933 "Return file name to use for auto-saves of current buffer.
2934 Does not consider auto-save-visited-file-name; that is checked
2935 before calling this function.
2936 You can redefine this for customization.
2937 See also auto-save-file-name-p."
2938 (if buffer-file-name
2939 ;; if buffer has a file, try the format <file directory>/#<file name>#
2940 (let ((f (concat (file-name-directory buffer-file-name)
2942 (file-name-nondirectory buffer-file-name)
2943 "#")))
2944 (if (file-writable-p f)
2945 ;; the file is writable, so use it
2947 ;; the file isn't writable, so use the format
2948 ;; ~/#&<file name>&<hash of directory>#
2949 (concat (getenv "HOME")
2950 "/#&"
2951 (file-name-nondirectory buffer-file-name)
2953 (hash-string-into-string
2954 (file-name-directory buffer-file-name))
2955 "#")))
2956 ;; if buffer has no file, use the format ~/#%<buffer name>%<process id>#
2957 (expand-file-name (concat (getenv "HOME")
2958 "/#%"
2959 ;; quote / into \! and \ into \\
2960 (unslashify-name (buffer-name))
2962 (make-temp-name "")
2963 "#"))))
2965 ;; Hash a string into five characters more-or-less suitable for use in a file
2966 ;; name. (Allowed characters are ! through ~, except /.)
2967 (defun hash-string-into-string (s)
2968 (let ((bins (vector 0 0 0 0 0))
2969 (i 0))
2970 (while (< i (length s))
2971 (aset bins (% i 5) (% (+ (* (aref bins (% i 5)) 35)
2972 (aref s i))
2973 65536))
2974 (setq i (1+ i)))
2975 (mapconcat (function (lambda (b)
2976 (setq b (+ (% b 93) ?!))
2977 (if (>= b ?/)
2978 (setq b (1+ b)))
2979 (char-to-string b)))
2980 bins "")))
2982 ;; Quote any /s in a string by replacing them with \!.
2983 ;; Also, replace any \s by \\, to make it one-to-one.
2984 (defun unslashify-name (s)
2985 (let ((limit 0))
2986 (while (string-match "[/\\]" s limit)
2987 (setq s (concat (substring s 0 (match-beginning 0))
2988 (if (string= (substring s (match-beginning 0)
2989 (match-end 0))
2990 "/")
2991 "\\!"
2992 "\\\\")
2993 (substring s (match-end 0))))
2994 (setq limit (1+ (match-end 0)))))
2997 (provide 'emerge)
2999 ;;; emerge.el ends here