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