comparison lisp/emerge.el @ 2770:6574a888b539

Install DRW's version 5.
author Richard M. Stallman <rms@gnu.org>
date Thu, 13 May 1993 19:24:38 +0000
parents 9364da723c1e
children 2d2b77186415
comparison
equal deleted inserted replaced
2769:209f745babd1 2770:6574a888b539
1 ;;; emerge.el --- merge diffs under Emacs control 1 ;;; Emacs subsystem to merge two files, version 5 beta
2 2 ;;; Written by Dale R. Worley <drw@math.mit.edu>.
3 ;;; The author has placed this file in the public domain. 3
4 4 ;; WARRANTY DISCLAIMER
5 ;; Author: Dale R. Worley <drw@math.mit.edu> 5
6 ;; Version: 4.1 6 ;; This software was created by Dale R. Worley and is
7 ;; Keywords: unix, tools 7 ;; distributed free of charge. It is placed in the public domain and
8 8 ;; permission is granted to anyone to use, duplicate, modify and redistribute
9 ;;; Commentary: 9 ;; it provided that this notice is attached.
10 10
11 ;; This package assists you in reconciling differences between pair of files. 11 ;; Dale R. Worley provides absolutely NO WARRANTY OF ANY KIND
12 12 ;; with respect to this software. The entire risk as to the quality and
13 ; - Starting 13 ;; performance of this software is with the user. IN NO EVENT WILL DALE
14 ; 14 ;; R. WORLEY BE LIABLE TO ANYONE FOR ANY DAMAGES ARISING OUT THE
15 ; To start Emerge, you must run one of four commands: 15 ;; USE OF THIS SOFTWARE, INCLUDING, WITHOUT LIMITATION, DAMAGES RESULTING FROM
16 ; 16 ;; LOST DATA OR LOST PROFITS, OR FOR ANY SPECIAL, INCIDENTAL OR CONSEQUENTIAL
17 ; emerge-files 17 ;; DAMAGES.
18 ; emerge-files-with-ancestor 18
19 ; emerge-buffers 19 ;; Declare that we've got the subsystem loaded
20 ; emerge-buffers-with-ancestor 20 (provide 'emerge)
21 ; 21
22 ; The "files" versions prompt you for two file names (the "A" and "B" 22 ;; LCD Archive Entry:
23 ; files), the "buffers" versions prompt you for two buffer names (the 23 ;; emerge|Dale R. Worley|drw@math.mit.edu
24 ; "A" and "B" buffers). Emerge then runs a "diff" of the two entities 24 ;; |File merge
25 ; (emerge-buffers writes the buffers into temporary files for input to 25 ;; |92-11-20|version 5 beta|~/packages/emerge.el.Z
26 ; diff) and digests the output to form a list of the differences between
27 ; the two files. Then three buffers are set up: two containing the
28 ; entities (emerge-files does a find-file (C-x C-f) on the files to get
29 ; them into buffers), and one, the "merge buffer", which contains the
30 ; working copy of the merged file that you are constructing. The three
31 ; buffers are put up in a nice three-window display, showing the A and B
32 ; buffers in the upper half and the merge buffer in the lower half.
33 ;
34 ; The versions of the command that say "with-ancestor" ask for a third
35 ; name, that of an entity which is a common ancestor from which the
36 ; versions being merged were derived. These commands use "diff3" to
37 ; compare all three versions. If one version of a difference agrees
38 ; with the ancestor, then it is presumed that the other version is the
39 ; "correct" version, and is said to be "preferred".
40 ;
41 ; (Note that if you use emerge-files, Emerge attempts to make sure that
42 ; file on disk and the file in the buffer are the same. If the file on
43 ; disk has been changed, Emerge offers to revert the buffer. If the
44 ; buffer has been modified, Emerge offers to save the buffer. If the
45 ; user declines the offer, or if the file on disk and the buffer have
46 ; both been modified, Emerge aborts with an error message. Emerge is
47 ; careful to widen the buffers containing the files if they have been
48 ; narrowed. If you use emerge-buffers, the buffers are not widened --
49 ; only the visible portion is used.)
50 ;
51 ; During the merge, the A and B buffers are read-only, so you don't
52 ; damage them. (This is because the A and B versions of the differences
53 ; are extracted from these buffers.) When you quit the merge, the
54 ; read-only/read-write status and modified flag on the A and B buffers
55 ; are restored. In addition, auto-saving of the A and B buffers is
56 ; suppressed during the merge. This is because Emerge modifies the A
57 ; and B buffers to point out the text of the differences, and it would
58 ; be useless to save these changes. (Just before suppressing
59 ; auto-saving, Emerge forces an auto-save.)
60 ;
61 ; If you give a prefix argument to emerge-files or
62 ; emerge-files-with-ancestor, it prompts you for another file name,
63 ; which is the file into which the merged file is to be written when you
64 ; exit Emerge. The output file name defaults to the A file name. If
65 ; you successfully quit Emerge, the merge buffer will be written to the
66 ; output file, and the buffers for the A, B, and ancestor buffers will
67 ; be deleted (if they exist and are not modified). If you abort Emerge,
68 ; the merge buffer will not be written and the buffers will not be
69 ; deleted.
70 ;
71 ; You can have any number of merges going at once -- just don't use any
72 ; one buffer as input to more than one merge at once, since that will
73 ; cause the read-only/modified/auto-save status save-and-restore to
74 ; screw up.
75 ;
76 ; Beware that when Emerge starts up, it does a diff or diff3 of the
77 ; files, which can take many minutes for long files with many
78 ; differences. Emacs can't do anything else until diff finishes.
79 ;
80 ; If diff or diff3 produces error messages, Emerge will beep and display
81 ; the error messages instead of the merge buffer. There will be a
82 ; message in the echo area giving the name of the merge buffer. Note
83 ; that this is really just an informational message -- you still have
84 ; switch to the merge buffer and abort the merge to restore the
85 ; conditions before you ran Emerge. (Emerge considers any output line
86 ; that does not match the regexp emerge-diff/diff3-ok-lines to be an
87 ; error message.)
88 ;
89 ; After the merge has been set up, Emerge runs the hooks in
90 ; emerge-startup-hook.
91 ;
92 ; - Merging
93 ;
94 ; Once you have started the merge, you manipulate the merge buffer with
95 ; special commands issued in the merge buffer. You may also edit the
96 ; buffer with ordinary Emacs commands. Emerge keeps track of each
97 ; difference between the A and B buffers and the corresponding section
98 ; of the merge buffer. Initially, all differences show the A version,
99 ; except those for which B is preferred (because A agrees with the
100 ; ancestor), which show the B version. Emerge always has its attention
101 ; focused on one particular difference, which is marked off in the three
102 ; buffers by "vvvvvvvvvvvvvvvvvvvv" above and "^^^^^^^^^^^^^^^^^^^^"
103 ; below. The number of the difference is shown in the mode line.
104 ;
105 ; A merge buffer can be in two modes: "fast" mode and "edit" mode. In
106 ; fast mode, emerge commands are single characters, and ordinary Emacs
107 ; commands are disabled. This makes Emerge operations fast, but
108 ; prevents you from doing more than selecing the A or the B version of
109 ; differences. In edit mode, all emerge commands must be prefixed with
110 ; C-c, and all (non-conflicting) Emacs commands are available. This
111 ; allows editing the merge buffer, but slows down Emerge operations.
112 ; Edit and fast modes are indicated by "F" and "E" in the minor modes in
113 ; the mode line.
114 ;
115 ; The Emerge commands are:
116 ;
117 ; p go to the previous difference
118 ; n go to the next difference
119 ; a select the A version of this difference
120 ; b select the B version of this difference
121 ; j go to a particular difference (prefix argument
122 ; specifies which difference) (0j suppresses display of
123 ; the flags)
124 ; q quit - finish the merge*
125 ; f go into fast mode
126 ; e go into edit mode
127 ; s a set/clear auto-advance mode*
128 ; s s set/clear skip-prefers mode*
129 ; l recenter (C-l) all three windows*
130 ; - and 0 through 9
131 ; prefix numeric arguments
132 ; d a select the A version as the default from here down in
133 ; the merge buffer*
134 ; d b select the B version as the default from here down in
135 ; the merge buffer*
136 ; c a copy the A version of the difference into the kill
137 ; ring
138 ; c b copy the B version of the difference into the kill
139 ; ring
140 ; i a insert the A version of the difference at the point
141 ; i b insert the B version of the difference at the point
142 ; m put the point and mark around the difference region
143 ; ^ scroll-down (like M-v) the three windows*
144 ; v scroll-up (like C-v) the three windows*
145 ; < scroll-left (like C-x <) the three windows*
146 ; > scroll-right (like C-x >) the three windows*
147 ; | reset horizontal scroll on the three windows*
148 ; x 1 shrink the merge window to one line (use C-u l to restore it
149 ; to full size)
150 ; x a find the difference containing a location in the A buffer*
151 ; x b find the difference containing a location in the B buffer*
152 ; x c combine the two versions of this difference*
153 ; x C combine the two versions of this difference, using a
154 ; register's value as the template*
155 ; x d find the difference containing a location in the merge buffer*
156 ; x f show the files/buffers Emerge is operating on in Help window
157 ; (use C-u l to restore windows)
158 ; x j join this difference with the following one
159 ; (C-u x j joins this difference with the previous one)
160 ; x l show line numbers of points in A, B, and merge buffers
161 ; x m change major mode of merge buffer*
162 ; x s split this difference into two differences
163 ; (first position the point in all three buffers to the places
164 ; to split the difference)
165 ; x t trim identical lines off top and bottom of difference
166 ; (such lines occur when the A and B versions are
167 ; identical but differ from the ancestor version)
168 ; x x set the template for the x c command*
169 ;
170 ; * - more details on these commands are given below
171 ;
172 ; emerge-version is a variable giving the version number of Emerge. It
173 ; is also a function which displays emerge-version (when called
174 ; interactively) or returns it (when called from a program).
175 ;
176 ; - Differences and their states
177 ;
178 ; A difference can have one of seven states:
179 ;
180 ; A: the difference is showing the A version.
181 ;
182 ; B: the difference is showing the B version.
183 ;
184 ; default-A and default-B: the difference is showing the A or B state,
185 ; but has never been selected by the user. All differences start in the
186 ; default-A state (and thus the merge buffer is a copy of the A buffer),
187 ; except those for which one buffer or another is preferred. When the
188 ; user selects the difference, it changes to the A or B state.
189 ;
190 ; prefer-A and prefer-B: the difference is showing the A or B state. In
191 ; addition, the other buffer (that is, for prefer-A, the B buffer; for
192 ; prefer-B, the A buffer) agrees with the ancestor buffer. Thus,
193 ; presumably, the displayed version is the correct one. The "a" and "b"
194 ; commands override these states, and turn them into the A and B states.
195 ;
196 ; combined: the difference is showing a combination of the A and B
197 ; states that was constructed by the "x c" or "x C" commands. Since
198 ; this state is neither the A or B states, the "a" and "b" commands
199 ; won't alter the difference unless they are given a prefix argument.
200 ;
201 ; The state of the currently selected difference is shown in the mode
202 ; line of the merge window:
203 ;
204 ; state display
205 ;
206 ; A A
207 ; B B
208 ; prefer-A A*
209 ; prefer-B B*
210 ; combined comb
211 ;
212 ; - Select default commands (d a and d b)
213 ;
214 ; The d a and d b commands change all default-A's to default-B's (or
215 ; vice-versa) from the selected difference on down to the end of the
216 ; file to default-A or default-B, respectively. (Since a difference
217 ; that has been selected can not have state default-A or default-B, it
218 ; will never be affected by d a or d b. This leads to the unexpected
219 ; result that d a or d b never affects the difference selected at the
220 ; moment, but prevents differences that you have already looked at from
221 ; changing unexpectedly.)
222 ;
223 ; If you work your way down from the top of the file, using d a and d b
224 ; at judicious points, you can effectivly make the A version the default
225 ; for some sections of the merge buffer and the B version the default
226 ; for others.
227 ;
228 ; - Exiting (q)
229 ;
230 ; The quit command finishes the merge session by restoring the state of
231 ; the A and B buffers and removing the markers around the currently
232 ; selected difference. It also disables the Emerge commands in the
233 ; merge buffer, since executing them later could damage the contents of
234 ; the various buffers.
235 ;
236 ; The action of "q" depends on how Emerge was started and whether "q"
237 ; was given a prefix argument. If there was no prefix argument, it is
238 ; considered a "successful" finish. If there was a prefix argument, it
239 ; is considered an "unsuccessful" finish. In either case, you are asked
240 ; to cofirm the exit, and the confirmation message tells which sort of
241 ; exit you are confirming.
242 ;
243 ; If Emerge was started by some other process, success/failure is
244 ; reported to the caller.
245 ;
246 ; If Emerge was started with emerge-files or emerge-files-with-ancestor,
247 ; if a prefix argument was given to that command, then you specified a
248 ; file into which the merge is to be written. A successful exit writes
249 ; the merge into the output file and then kills the A, B, and ancestor
250 ; buffers (so they aren't lying around to confuse you, since they
251 ; probably all have similar names).
252 ;
253 ; - Auto-advance mode (s a)
254 ;
255 ; If auto-advance mode is set, the "a" and "b" commands perform an "n"
256 ; (select next difference) afterward. When auto-advance mode is set,
257 ; it is indicated by "A" in the minor modes in the mode line.
258 ; "s a" with a positive argument sets auto-advance, with a non-positive
259 ; argument clears it, and with no argument toggles it.
260 ;
261 ; - Skip-prefers mode (s s)
262 ;
263 ; If skip-prefers mode is set, the "n" and "p" commands skip over
264 ; differences with states prefer-A and prefer-B. Thus you will only see
265 ; differences for which one version isn't presumed "correct". When
266 ; skip-prefers mode is set, it is indicated by "S" in the minor modes in
267 ; the mode line. "s s" with a positive argument sets auto-advance, with
268 ; a non-positive argument clears it, and with no argument toggles it.
269 ;
270 ; - Recenter (l)
271 ;
272 ; The Emerge "l" command causes the selected difference to be brought
273 ; into view in the three windows, or at least, whichever of the three
274 ; merge buffers are visible at the moment. If a prefix argument is
275 ; given, then the original three-window display is set up before the
276 ; difference texts are shown.
277 ;
278 ; - Scrolling the text (^, v, <, >, and |)
279 ;
280 ; Emerge has several commands which scroll all three windows by the same
281 ; amount, thus allowing you to easily compare the versions of the text.
282 ; The commands are "^" (scroll-up), "v" (scroll-down), "<"
283 ; (scroll-left), ">" (scroll-right), and "|" (reset horizontal
284 ; scrolling). (Remember that Emacs names scrolling commands by the
285 ; motion of the text with respect to the window, so C-v is called
286 ; "scroll-up".)
287 ;
288 ; If these commands (except "|") are given an argument, that is the
289 ; number of lines or characters by which the windows are scrolled.
290 ; Otherwise, the amount of motion is computed based on the dimensions of
291 ; the merge buffer window -- the height of the merge buffer window
292 ; (minus next-frame-context-lines), or half the width of the merge
293 ; buffer window. (The A and B version windows are assumed to be as high
294 ; as the merge window, but half as wide.) If the argument is just `C-u
295 ; -', then the scrolling is half the default amount.
296 ;
297 ; - Finding the difference at or near a location (x d, x a, and x b)
298 ;
299 ; The "x d" command selects the difference containing the current point
300 ; in the merge buffer. If there is no difference containing the point,
301 ; an error is given. An argument can be given to the command to change
302 ; this behavior: if the argument is positive (e.g., C-u), the next
303 ; following difference is selected; if the argument is negative (e.g.,
304 ; C-u -), the previous difference is selected.
305 ;
306 ; The "x a" and "x b" commands select the difference containing the
307 ; current point in the A and B buffers, respectively. Otherwise, they
308 ; act like the "x d" command. Note that although the point used in the
309 ; commands is not the merge buffer point, the commands can only be
310 ; issued in the merge buffer, because it is the only buffer with the
311 ; Emerge keymap.
312 ;
313 ; - Combining the two versions (x c, x C, and x x)
314 ;
315 ; Sometimes one wants to combine the two versions of a difference. For
316 ; instance, when merging two versions of a program, one wants to make
317 ; something like this:
318 ;
319 ; #ifdef NEW
320 ; ...new version of code...
321 ; #else /* NEW */
322 ; ...old version of code...
323 ; #endif /* NEW */
324 ;
325 ; The "x c" command will make such a combined version. (Note that any
326 ; combined version is not the same as either the A or B versions, and so
327 ; the "a" and "b" commands will refuse to alter it unless they are given
328 ; a prefix argument.) The combination is made under control of a
329 ; template, which is a character string with the following
330 ; interpolations:
331 ;
332 ; %a the A version of the difference
333 ; %b the B version of the difference
334 ; %% the character '%'
335 ;
336 ; Thus, the template used above is
337 ;
338 ; #ifdef NEW\n%b#else /* NEW */\n%a#endif /* NEW */\n
339 ;
340 ; (using \n here to represent newlines). The template is stored in the
341 ; variable emerge-combine-versions-template, and its initial value is
342 ; the one given above. The template can be set (from the current
343 ; region) by the "x x" command. (Be careful to get the newlines in the
344 ; template in the right places!) ("x x" was chosen by analogy with "C-x
345 ; x".) ("x x" is only available in the merge buffer, of course.
346 ; Elsewhere, M-x emerge-set-combine-versions-template can be used.) If
347 ; "x x" is given a prefix argument, emerge-combine-versions-template is
348 ; localized in the merge buffer before its value is set, so the "x x"
349 ; command's effect (and the effect of any later "x x" command in the
350 ; merge buffer) is only on the merge buffer.
351 ;
352 ; The "x C" command is like "x c", but it prompts for a character
353 ; which is the register whose value is to be used as the template.
354 ; This allows one to use multiple templates conveniently.
355 ;
356 ; - Changing the major mode of the edit buffer (x m)
357 ;
358 ; The "x m" command prompts for the name of a major-mode-setting command
359 ; and executes it. Ordinarily, major-mode-setting commands change the
360 ; mode line and local keymap, so the "x m" command then resets the
361 ; Emerge mode line and the fast or edit mode local keymap, as
362 ; appropriate.
363 ;
364 ; If you have already changed the major mode of the merge buffer and
365 ; lost the Emerge keymap, you can use M-x emerge-set-merge-mode to
366 ; execute this command.
367 ;
368 ; Beware that "x m" accepts any command name, not just
369 ; major-mode-setting commands.
370 ;
371 ; - Writing the merge buffer manually
372 ;
373 ; Emerge places a wrapper (emerge-query-and-call) on the key bindings of
374 ; save-buffer (usually "C-x C-s") and write-file (usually "C-x C-w"), in
375 ; order to protect the user from writing out the merge before it is
376 ; finished. Emerge-query-and-call asks the user if he is sure he wants
377 ; to write out the incomplete merge. If he answers yes, the buffer is
378 ; written out. The flags are suppressed while the write is being done.
379 ; As a result of this, the displayed portions of the buffers are
380 ; recentered (equivalent to "l").
381 ;
382 ; - Running Emerge standalone
383 ;
384 ; If you invoke emacs with the following arguments, you can execute
385 ; Emerge as a standalone program:
386 ;
387 ; emacs -l emerge -f emerge-files-command file-a file-b file-out
388 ;
389 ; emacs -l emerge -f emerge-files-with-ancestor-command
390 ; file-a file-b file-ancestor file-out
391 ;
392 ; When the user gives the "q" (quit) command, Emerge will write out the
393 ; merge buffer in file-out and terminate Emacs. If a prefix argument is
394 ; given, Emacs will terminate with an unsuccessful return code (1), if
395 ; not, it will terminate with a successful return code (0).
396 ;
397 ; - Invoking Emerge remotely
398 ;
399 ; If you use the Emacs client/server code that supports remote
400 ; execution, then you can invoke Emerge remotely by executing one of the
401 ; Lisp calls:
402 ;
403 ; (emerge-files-remote "file A" "file B" "output file")
404 ;
405 ; (emerge-files-with-ancestor-remote "file A" "file B"
406 ; "ancestor file" "output file")
407 ;
408 ; Returning a successful/unsuccessful return code is not yet supported
409 ; by the Emacs client/server code.
410 ;
411 ; Beware that in systems of networked workstations, even though all user
412 ; directories are shared between all the workstations, the /tmp
413 ; directory on each workstation is not shared, so writing files into
414 ; /tmp and then remotely invoking Emerge is not likely to work.
415 ;
416 ; - Effect of merge flags on indenting code
417 ;
418 ; The presence of the flags confuses the indentation code of C and
419 ; Emacs-Lisp modes. Starting the flag strings
420 ; (emerge-{before,after}-flag) with '#' (for C) or ';' (for Lisp)
421 ; prevents the indentation code from noticing the flags. Remember to
422 ; change the flag strings before loading Emerge, or to execute
423 ; emerge-new-flags after changing them. But never change the flag
424 ; strings while a merge is being performed.
425 ;
426 ; - Autoloading
427 ;
428 ; The following autoloads will make all top-level Emerge files
429 ; autoloading. Make sure that "emerge" is in a directory on load-path.
430 ;
431 ; (autoload 'emerge-files "emerge"
432 ; "Run Emerge on two files."
433 ; t)
434 ; (autoload 'emerge-files-with-ancestor "emerge"
435 ; "Run Emerge on two files, giving another file as the ancestor."
436 ; t)
437 ; (autoload 'emerge-buffers "emerge"
438 ; "Run Emerge on two buffers."
439 ; t)
440 ; (autoload 'emerge-buffers-with-ancestor "emerge"
441 ; "Run Emerge on two buffers, giving another buffer as the ancestor."
442 ; t)
443 ; (autoload 'emerge-files-command "emerge")
444 ; (autoload 'emerge-files-with-ancestor-command "emerge")
445 ; (autoload 'emerge-files-remote "emerge")
446 ; (autoload 'emerge-files-with-ancestor-remote "emerge")
447 ;
448 ; ================================================================
449
450 ;;; Change Log:
451
452 ; - Changes from version 3 to version 4
453 ;
454 ; More configuration variables are marked as user options.
455 ;
456 ; Code is included for an improved version of make-auto-save-file-name
457 ; which eliminates many problems with the default version. See the
458 ; documentation of emerge-make-auto-save-file-name to see how to
459 ; activate it.
460 ;
461 ; Emerge now works with Gnu diff3, which can produce the groups of lines
462 ; from the various files in the order 1, 2, 3 or 1, 3, 2.
463 ;
464 ; Added x f command to show what files or buffers are being operated on.
465 ;
466 ; The merge buffer now starts read-only, which being in fast mode it
467 ; should be.
468 ;
469 ; When merging buffers, Emerge writes their contents into temporary
470 ; files in the directory $TMPDIR (if it is defined), or /tmp by default.
471 ;
472 ; Added x j command to join two differences.
473 ;
474 ; Added x s command to split a difference into two differences.
475 ;
476 ; Added emerge-version variable and function to report the version of Emerge
477 ; being run.
478 ;
479 ; Added x t command to trim unchanged lines off top and bottom of
480 ; difference region.
481 ;
482 ; Added x d, x a, and x b commands to locate the differences at or near
483 ; a given location in one of the buffers.
484 ;
485 ; Emerge no longer tries to copy the minor modes from the A buffer to
486 ; the merge buffer, only the major mode.
487 ;
488 ; The programs executed to find the differences between versions of the file
489 ; are no longer controlled by emerge-diff/diff3-command, but rather by:
490 ; emerge-diff-program
491 ; Variable: *Name of the program which compares two files.
492 ; emerge-diff3-program
493 ; Variable: *Name of the program which compares an ancestor file
494 ; (first argument) and two variant files (second and third arguments).
495 ; emerge-diff-options
496 ; Variable: *Options to be passed to emerge-diff/diff3-program.
497 ;
498 ; The names of the files are expanded (see expand-file-name) before being
499 ; passed to emerge-diff/diff3-program, so diff need not invoked under a shell
500 ; that understands '~', for instance.
501 ;
502 ; If the diff/diff3 program reports errors, the user is notified and the
503 ; errors are displayed.
504 ;
505 ; The command "0j" can be used to suppress the flags from showing in the buffers.
506 ;
507 ; A discussion of the effect of the merge flags on indentation of code
508 ; has been added to the documentation.
509 ;
510 ; If kill-fix.el is loaded, Emerge control variables new have their
511 ; 'preserved' property set, so setting the major mode in the merge
512 ; buffer doesn't destroy Emerge's state.
513 ;
514 ; Added x c, x C, and x x commands to allow the A and B versions to be
515 ; combined into #ifdef - #endif forms.
516 ;
517 ; Replaced calls of "ding" to calls of "error" where appropriate.
518 ;
519 ; Added x m command to allow major mode of merge buffer to be changed.
520 ;
521 ; Added x 1 command to shrink the merge window to one line.
522 ;
523 ; Added emerge-startup-hook to allow customization.
524 ;
525 ; Fixed a bug that is activated when a remote merge request is made when
526 ; the minibuffer window is selected.
527 ;
528 ; - Changes from version 2 to version 3
529 ;
530 ; The directory into which temporary files are written is now controlled
531 ; by a user option (emerge-temp-file-prefix).
532 ;
533 ; The A and B versions of the difference can be loaded into the kill
534 ; ring with the "c a" and "c b" commands.
535 ;
536 ; The A and B versions of the difference can be inserted into the merge
537 ; buffer with the "i a" and "i b" commands.
538 ;
539 ; The difference region of the merge buffer can be surrounded by the
540 ; point and mark with the "m" command.
541 ;
542 ; The three windows can be scrolled together with the "^", "v", "<",
543 ; ">", and "|" commands.
544 ;
545 ; The "s s" and "s a" commands report the state of the option in the
546 ; echo area. Similarly, the "f" and "e" commands report what they do in
547 ; the echo area.
548 ;
549 ; The "q" command has been revamped, and its behavior is now controlled
550 ; by the manner in which Emerge is started. In particular, if you wish
551 ; to write the merge buffer into a file upon exiting, invoke
552 ; emerge-files[-with-ancestor] with a prefix argument, and it will
553 ; prompt you for the file name. Then exiting will write the merge
554 ; buffer to the file, unless "q" is given a prefix argument.
555 ;
556 ; The "i a" and "i b" commands now work in fast mode.
557 ;
558 ; The modifications that Emerge makes to save-buffer and write-file are
559 ; described.
560 ;
561 ; Emerge now handles merging narrowed buffers correctly.
562 ;
563 ; Emerge now isn't fooled when the buffer visiting a file is not the
564 ; same as the file on disk.
565
566 ;;; Code:
567 26
568 ;;; Macros 27 ;;; Macros
569 28
570 (defmacro emerge-eval-in-buffer (buffer &rest forms) 29 (defmacro emerge-eval-in-buffer (buffer &rest forms)
571 "Macro to switch to BUFFER, evaluate FORMS, returns to original buffer. 30 "Macro to switch to BUFFER, evaluate FORMS, returns to original buffer.
572 Differs from `save-excursion' in that it doesn't save the point and mark." 31 Differs from save-excursion in that it doesn't save the point and mark."
573 (` (let ((StartBuffer (current-buffer))) 32 (` (let ((StartBuffer (current-buffer)))
574 (unwind-protect 33 (unwind-protect
575 (progn 34 (progn
576 (set-buffer (, buffer)) 35 (set-buffer (, buffer))
577 (,@ forms)) 36 (,@ forms))
578 (set-buffer StartBuffer))))) 37 (set-buffer StartBuffer)))))
579 38
580 (defmacro emerge-defvar-local (var value doc) 39 (defmacro emerge-defvar-local (var value doc)
581 "Defines SYMBOL as an advertised variable. 40 "Defines SYMBOL as an advertised variable. Performs a defvar, then
582 Performs a defvar, then executes `make-variable-buffer-local' on 41 executes make-variable-buffer-local on the variable. Also sets the
583 the variable. Also sets the 'preserved' property, so that 42 'preserved' property, so that kill-all-local-variables (called by major-mode
584 `kill-all-local-variables' (called by major-mode setting commands) 43 setting commands) won't destroy Emerge control variables."
585 won't destroy Emerge control variables."
586 (` (progn 44 (` (progn
587 (defvar (, var) (, value) (, doc)) 45 (defvar (, var) (, value) (, doc))
588 (make-variable-buffer-local '(, var)) 46 (make-variable-buffer-local '(, var))
589 (put '(, var) 'preserved t)))) 47 (put '(, var) 'preserved t))))
590 48
598 (setq minor-mode-alist (append emerge-minor-modes-list 56 (setq minor-mode-alist (append emerge-minor-modes-list
599 minor-mode-alist))) 57 minor-mode-alist)))
600 58
601 ;; We need to define this function so describe-mode can describe Emerge mode. 59 ;; We need to define this function so describe-mode can describe Emerge mode.
602 (defun emerge-mode () 60 (defun emerge-mode ()
603 "Emerge mode is used by the Emerge file-merging package. 61 "Emerge mode is used by the Emerge file-merging package. It is entered only
604 It is entered only through one of the functions: 62 through one of the functions:
605 `emerge-files' 63 emerge-files
606 `emerge-files-with-ancestor' 64 emerge-files-with-ancestor
607 `emerge-buffers' 65 emerge-buffers
608 `emerge-buffers-with-ancestor' 66 emerge-buffers-with-ancestor
609 `emerge-files-command' 67 emerge-files-command
610 `emerge-files-with-ancestor-command' 68 emerge-files-with-ancestor-command
611 `emerge-files-remote' 69 emerge-files-remote
612 `emerge-files-with-ancestor-remote' 70 emerge-files-with-ancestor-remote
613 71
614 Commands: 72 Commands:
615 \\{emerge-basic-keymap} 73 \\{emerge-basic-keymap}
616 Commands must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode, but can be invoked directly 74 Commands must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode, but can be invoked directly
617 in 'fast' mode.") 75 in 'fast' mode.")
618 76
619 (defvar emerge-version "4" 77 (defvar emerge-version "5"
620 "The version of Emerge.") 78 "The version of Emerge.")
621 79
622 (defun emerge-version () 80 (defun emerge-version ()
623 "Return string describing the version of Emerge. 81 "Return string describing the version of Emerge. When called interactively,
624 When called interactively, displays the version." 82 displays the version."
625 (interactive) 83 (interactive)
626 (if (interactive-p) 84 (if (interactive-p)
627 (message "Emerge version %s" (emerge-version)) 85 (message "Emerge version %s" (emerge-version))
628 emerge-version)) 86 emerge-version))
629 87
658 (defvar emerge-diff3-ok-lines 116 (defvar emerge-diff3-ok-lines
659 "^\\([1-3]:\\|====\\| \\)" 117 "^\\([1-3]:\\|====\\| \\)"
660 "*Regexp that matches normal output lines from emerge-diff3-program . 118 "*Regexp that matches normal output lines from emerge-diff3-program .
661 Lines that do not match are assumed to be error output.") 119 Lines that do not match are assumed to be error output.")
662 120
121 (defvar emerge-rcs-ci-program "ci"
122 "*Name of the program that checks in RCS revisions.")
123 (defvar emerge-rcs-co-program "co"
124 "*Name of the program that checks out RCS revisions.")
125
126 (defvar emerge-process-local-variables nil
127 "*Non-nil if Emerge should process the local-variables list in newly created
128 merge buffers. (The local-variables list can be processed manually by
129 executing \"(hack-local-variables)\".)")
130 (defvar emerge-execute-line-deletions nil
131 "*If non-nil: When emerge-execute-line discovers a situation which
132 appears to show that a file has been deleted from one version of the
133 files being merged (when an ancestor entry is present, only one
134 A or B entry is present, and an output entry is present), no output
135 file will be created.
136 If nil: In such circumstances, the A or B file that is present will be
137 copied to the designated output file.")
138
139 ;; Hook variables
140
141 (defvar emerge-startup-hooks nil
142 "*Hooks to run in the merge buffer after the merge has been set up.")
143 (defvar emerge-select-hooks nil
144 "*Hooks to run after a difference has been selected.
145 `n' is the (internal) number of the difference.")
146 (defvar emerge-unselect-hooks nil
147 "*Hooks to run after a difference has been unselected.
148 `n' is the (internal) number of the difference.")
149
150 ;; Variables to control the default directories of the arguments to
151 ;; Emerge commands.
152
153 (defvar emerge-default-last-directories nil
154 "*If nil, filenames for emerge-files-* commands complete in
155 default-directory (like an ordinary command).
156 If non-nil, filenames complete in the directory of the last argument of the
157 same type to an emerge-files-* command.")
158
159 (defvar emerge-last-dir-A nil
160 "Last directory for the first file of an emerge-files command.")
161 (defvar emerge-last-dir-B nil
162 "Last directory for the second file of an emerge-files command.")
163 (defvar emerge-last-dir-ancestor nil
164 "Last directory for the ancestor file of an emerge-files command.")
165 (defvar emerge-last-dir-output nil
166 "Last directory for the output file of an emerge-files command.")
167 (defvar emerge-last-revision-A nil
168 "Last RCS revision use for the first file of an emerge-revisions command.")
169 (defvar emerge-last-revision-B nil
170 "Last RCS revision use for the second file of an emerge-revisions command.")
171 (defvar emerge-last-revision-ancestor nil
172 "Last RCS revision use for the ancestor file of an emerge-revisions command.")
173
663 ;; The flags used to mark differences in the buffers. 174 ;; The flags used to mark differences in the buffers.
664 175
665 ;; These function definitions need to be up here, because they are used 176 ;; These function definitions need to be up here, because they are used
666 ;; during loading. 177 ;; during loading.
667 (defun emerge-new-flags () 178 (defun emerge-new-flags ()
668 "Function to be called after `emerge-{before,after}-flag'. 179 "Function to be called after emerge-{before,after}-flag are changed to
669 This is called after these functions are changed to compute values that 180 compute values that depend on the flags."
670 depend on the flags."
671 (setq emerge-before-flag-length (length emerge-before-flag)) 181 (setq emerge-before-flag-length (length emerge-before-flag))
672 (setq emerge-before-flag-lines 182 (setq emerge-before-flag-lines
673 (count-matches-string emerge-before-flag "\n")) 183 (count-matches-string emerge-before-flag "\n"))
674 (setq emerge-before-flag-match (regexp-quote emerge-before-flag)) 184 (setq emerge-before-flag-match (regexp-quote emerge-before-flag))
675 (setq emerge-after-flag-length (length emerge-after-flag)) 185 (setq emerge-after-flag-length (length emerge-after-flag))
877 "*If non-nil, emerge-select-A and emerge-select-B automatically advance to 387 "*If non-nil, emerge-select-A and emerge-select-B automatically advance to
878 the next difference.") 388 the next difference.")
879 (emerge-defvar-local emerge-skip-prefers nil 389 (emerge-defvar-local emerge-skip-prefers nil
880 "*If non-nil, differences for which there is a preference are automatically 390 "*If non-nil, differences for which there is a preference are automatically
881 skipped.") 391 skipped.")
882 (emerge-defvar-local emerge-startup-hook nil 392 (emerge-defvar-local emerge-quit-hooks nil
883 "*Hooks to run in the merge buffer after the merge has been set up.")
884 (emerge-defvar-local emerge-quit-hook nil
885 "Hooks to run in the merge buffer after the merge has been finished. 393 "Hooks to run in the merge buffer after the merge has been finished.
886 emerge-prefix-argument will be bound to the prefix argument of the emerge-quit 394 emerge-prefix-argument will be bound to the prefix argument of the emerge-quit
887 command. 395 command.
888 This is not a user option, since Emerge uses it for its own processing.") 396 This is not a user option, since Emerge uses it for its own processing.")
889 (emerge-defvar-local emerge-output-description nil 397 (emerge-defvar-local emerge-output-description nil
890 "Describes output destination merge, for the use of `emerge-file-names'.") 398 "Describes output destination of the merge, for the use of
399 emerge-file-names.")
891 400
892 ;;; Setup functions for two-file mode. 401 ;;; Setup functions for two-file mode.
893 402
894 (defun emerge-files-internal (file-A file-B &optional startup-hooks quit-hooks 403 (defun emerge-files-internal (file-A file-B &optional startup-hooks quit-hooks
895 output-file) 404 output-file)
405 (if (not (file-readable-p file-A))
406 (error "File '%s' does not exist or is not readable" file-A))
407 (if (not (file-readable-p file-B))
408 (error "File '%s' does not exist or is not readable" file-B))
896 (let ((buffer-A (find-file-noselect file-A)) 409 (let ((buffer-A (find-file-noselect file-A))
897 (buffer-B (find-file-noselect file-B))) 410 (buffer-B (find-file-noselect file-B)))
411 ;; Record the directories of the files
412 (setq emerge-last-dir-A (file-name-directory file-A))
413 (setq emerge-last-dir-B (file-name-directory file-B))
414 (if output-file
415 (setq emerge-last-dir-output (file-name-directory output-file)))
898 ;; Make sure the entire files are seen, and they reflect what is on disk 416 ;; Make sure the entire files are seen, and they reflect what is on disk
899 (emerge-eval-in-buffer buffer-A 417 (emerge-eval-in-buffer
900 (widen) 418 buffer-A
901 (emerge-verify-file-buffer)) 419 (widen)
902 (emerge-eval-in-buffer buffer-B 420 (if (emerge-remote-file-p)
903 (widen) 421 (progn
904 (emerge-verify-file-buffer)) 422 ;; Store in a local file
423 (setq file-A (emerge-make-temp-file "A"))
424 (write-region (point-min) (point-max) file-A nil 'no-message)
425 (setq startup-hooks
426 (cons (` (lambda () (delete-file (, file-A))))
427 startup-hooks)))
428 ;; Verify that the file matches the buffer
429 (emerge-verify-file-buffer)))
430 (emerge-eval-in-buffer
431 buffer-B
432 (widen)
433 (if (emerge-remote-file-p)
434 (progn
435 ;; Store in a local file
436 (setq file-B (emerge-make-temp-file "B"))
437 (write-region (point-min) (point-max) file-B nil 'no-message)
438 (setq startup-hooks
439 (cons (` (lambda () (delete-file (, file-B))))
440 startup-hooks)))
441 ;; Verify that the file matches the buffer
442 (emerge-verify-file-buffer)))
905 (emerge-setup buffer-A file-A buffer-B file-B startup-hooks quit-hooks 443 (emerge-setup buffer-A file-A buffer-B file-B startup-hooks quit-hooks
906 output-file))) 444 output-file)))
907 445
908 ;; Start up Emerge on two files 446 ;; Start up Emerge on two files
909 (defun emerge-setup (buffer-A file-A buffer-B file-B startup-hooks quit-hooks 447 (defun emerge-setup (buffer-A file-A buffer-B file-B startup-hooks quit-hooks
935 (emerge-set-keys) 473 (emerge-set-keys)
936 (setq emerge-difference-list (emerge-make-diff-list file-A file-B)) 474 (setq emerge-difference-list (emerge-make-diff-list file-A file-B))
937 (setq emerge-number-of-differences (length emerge-difference-list)) 475 (setq emerge-number-of-differences (length emerge-difference-list))
938 (setq emerge-current-difference -1) 476 (setq emerge-current-difference -1)
939 (setq emerge-quit-hooks quit-hooks) 477 (setq emerge-quit-hooks quit-hooks)
940 (emerge-remember-buffer-characteristics)) 478 (emerge-remember-buffer-characteristics)
479 (emerge-handle-local-variables))
941 (emerge-setup-windows buffer-A buffer-B merge-buffer t) 480 (emerge-setup-windows buffer-A buffer-B merge-buffer t)
942 (emerge-eval-in-buffer merge-buffer 481 (emerge-eval-in-buffer merge-buffer
943 (run-hooks 'startup-hooks 'emerge-startup-hook) 482 (run-hooks 'startup-hooks 'emerge-startup-hooks)
944 (setq buffer-read-only t)))) 483 (setq buffer-read-only t))))
945 484
946 ;; Generate the Emerge difference list between two files 485 ;; Generate the Emerge difference list between two files
947 (defun emerge-make-diff-list (file-A file-B) 486 (defun emerge-make-diff-list (file-A file-B)
948 (setq emerge-diff-buffer (get-buffer-create "*emerge-diff*")) 487 (setq emerge-diff-buffer (get-buffer-create "*emerge-diff*"))
949 (emerge-eval-in-buffer 488 (emerge-eval-in-buffer
950 emerge-diff-buffer 489 emerge-diff-buffer
951 (erase-buffer) 490 (erase-buffer)
952 (shell-command 491 (shell-command
953 (format "%s %s %s %s" 492 (format "%s %s %s %s"
954 emerge-diff-program emerge-diff-options file-A file-B) 493 emerge-diff-program emerge-diff-options
494 (emerge-protect-metachars file-A)
495 (emerge-protect-metachars file-B))
955 t)) 496 t))
956 (emerge-prepare-error-list emerge-diff-ok-lines) 497 (emerge-prepare-error-list emerge-diff-ok-lines)
957 (emerge-convert-diffs-to-markers 498 (emerge-convert-diffs-to-markers
958 emerge-A-buffer emerge-B-buffer emerge-merge-buffer 499 emerge-A-buffer emerge-B-buffer emerge-merge-buffer
959 (emerge-extract-diffs emerge-diff-buffer))) 500 (emerge-extract-diffs emerge-diff-buffer)))
1013 ;;; Top-level and setup functions for three-file mode. 554 ;;; Top-level and setup functions for three-file mode.
1014 555
1015 (defun emerge-files-with-ancestor-internal (file-A file-B file-ancestor 556 (defun emerge-files-with-ancestor-internal (file-A file-B file-ancestor
1016 &optional startup-hooks quit-hooks 557 &optional startup-hooks quit-hooks
1017 output-file) 558 output-file)
559 (if (not (file-readable-p file-A))
560 (error "File '%s' does not exist or is not readable" file-A))
561 (if (not (file-readable-p file-B))
562 (error "File '%s' does not exist or is not readable" file-B))
563 (if (not (file-readable-p file-ancestor))
564 (error "File '%s' does not exist or is not readable" file-ancestor))
1018 (let ((buffer-A (find-file-noselect file-A)) 565 (let ((buffer-A (find-file-noselect file-A))
1019 (buffer-B (find-file-noselect file-B)) 566 (buffer-B (find-file-noselect file-B))
1020 (buffer-ancestor (find-file-noselect file-ancestor))) 567 (buffer-ancestor (find-file-noselect file-ancestor)))
568 ;; Record the directories of the files
569 (setq emerge-last-dir-A (file-name-directory file-A))
570 (setq emerge-last-dir-B (file-name-directory file-B))
571 (setq emerge-last-dir-ancestor (file-name-directory file-ancestor))
572 (if output-file
573 (setq emerge-last-dir-output (file-name-directory output-file)))
1021 ;; Make sure the entire files are seen, and they reflect what is on disk 574 ;; Make sure the entire files are seen, and they reflect what is on disk
1022 (emerge-eval-in-buffer buffer-A 575 (emerge-eval-in-buffer
1023 (widen) 576 buffer-A
1024 (emerge-verify-file-buffer)) 577 (widen)
1025 (emerge-eval-in-buffer buffer-B 578 (if (emerge-remote-file-p)
1026 (widen) 579 (progn
1027 (emerge-verify-file-buffer)) 580 ;; Store in a local file
1028 (emerge-eval-in-buffer buffer-ancestor 581 (setq file-A (emerge-make-temp-file "A"))
1029 (widen) 582 (write-region (point-min) (point-max) file-A nil 'no-message)
1030 (emerge-verify-file-buffer)) 583 (setq startup-hooks
584 (cons (` (lambda () (delete-file (, file-A))))
585 startup-hooks)))
586 ;; Verify that the file matches the buffer
587 (emerge-verify-file-buffer)))
588 (emerge-eval-in-buffer
589 buffer-B
590 (widen)
591 (if (emerge-remote-file-p)
592 (progn
593 ;; Store in a local file
594 (setq file-B (emerge-make-temp-file "B"))
595 (write-region (point-min) (point-max) file-B nil 'no-message)
596 (setq startup-hooks
597 (cons (` (lambda () (delete-file (, file-B))))
598 startup-hooks)))
599 ;; Verify that the file matches the buffer
600 (emerge-verify-file-buffer)))
601 (emerge-eval-in-buffer
602 buffer-ancestor
603 (widen)
604 (if (emerge-remote-file-p)
605 (progn
606 ;; Store in a local file
607 (Setq file-ancestor (emerge-make-temp-file "anc"))
608 (write-region (point-min) (point-max) file-ancestor nil 'no-message)
609 (setq startup-hooks
610 (cons (` (lambda () (delete-file (, file-ancestor))))
611 startup-hooks)))
612 ;; Verify that the file matches the buffer
613 (emerge-verify-file-buffer)))
1031 (emerge-setup-with-ancestor buffer-A file-A buffer-B file-B 614 (emerge-setup-with-ancestor buffer-A file-A buffer-B file-B
1032 buffer-ancestor file-ancestor 615 buffer-ancestor file-ancestor
1033 startup-hooks quit-hooks output-file))) 616 startup-hooks quit-hooks output-file)))
1034 617
1035 ;; Start up Emerge on two files with an ancestor 618 ;; Start up Emerge on two files with an ancestor
1065 (emerge-set-keys) 648 (emerge-set-keys)
1066 (setq emerge-difference-list 649 (setq emerge-difference-list
1067 (emerge-make-diff3-list file-A file-B file-ancestor)) 650 (emerge-make-diff3-list file-A file-B file-ancestor))
1068 (setq emerge-number-of-differences (length emerge-difference-list)) 651 (setq emerge-number-of-differences (length emerge-difference-list))
1069 (setq emerge-current-difference -1) 652 (setq emerge-current-difference -1)
1070 (setq emerge-quit-hook quit-hooks) 653 (setq emerge-quit-hooks quit-hooks)
1071 (emerge-remember-buffer-characteristics) 654 (emerge-remember-buffer-characteristics)
1072 (emerge-select-prefer-Bs)) 655 (emerge-select-prefer-Bs)
656 (emerge-handle-local-variables))
1073 (emerge-setup-windows buffer-A buffer-B merge-buffer t) 657 (emerge-setup-windows buffer-A buffer-B merge-buffer t)
1074 (emerge-eval-in-buffer merge-buffer 658 (emerge-eval-in-buffer merge-buffer
1075 (run-hooks 'startup-hooks 'emerge-startup-hook) 659 (run-hooks 'startup-hooks 'emerge-startup-hooks)
1076 (setq buffer-read-only t)))) 660 (setq buffer-read-only t))))
1077 661
1078 ;; Generate the Emerge difference list between two files with an ancestor 662 ;; Generate the Emerge difference list between two files with an ancestor
1079 (defun emerge-make-diff3-list (file-A file-B file-ancestor) 663 (defun emerge-make-diff3-list (file-A file-B file-ancestor)
1080 (setq emerge-diff-buffer (get-buffer-create "*emerge-diff*")) 664 (setq emerge-diff-buffer (get-buffer-create "*emerge-diff*"))
1082 emerge-diff-buffer 666 emerge-diff-buffer
1083 (erase-buffer) 667 (erase-buffer)
1084 (shell-command 668 (shell-command
1085 (format "%s %s %s %s %s" 669 (format "%s %s %s %s %s"
1086 emerge-diff3-program emerge-diff-options 670 emerge-diff3-program emerge-diff-options
1087 file-ancestor file-A file-B) 671 (emerge-protect-metachars file-ancestor)
672 (emerge-protect-metachars file-A)
673 (emerge-protect-metachars file-B))
1088 t)) 674 t))
1089 (emerge-prepare-error-list emerge-diff3-ok-lines) 675 (emerge-prepare-error-list emerge-diff3-ok-lines)
1090 (emerge-convert-diffs-to-markers 676 (emerge-convert-diffs-to-markers
1091 emerge-A-buffer emerge-B-buffer emerge-merge-buffer 677 emerge-A-buffer emerge-B-buffer emerge-merge-buffer
1092 (emerge-extract-diffs3 emerge-diff-buffer))) 678 (emerge-extract-diffs3 emerge-diff-buffer)))
1101 (let ((agreement (buffer-substring (match-beginning 1) (match-end 1)))) 687 (let ((agreement (buffer-substring (match-beginning 1) (match-end 1))))
1102 ;; if the A and B files are the same, ignore the difference 688 ;; if the A and B files are the same, ignore the difference
1103 (if (not (string-equal agreement "1")) 689 (if (not (string-equal agreement "1"))
1104 (setq list 690 (setq list
1105 (cons 691 (cons
1106 (let (group-2 group-3 pos) 692 (let ((group-2 (emerge-get-diff3-group "2"))
1107 (setq pos (point)) 693 (group-3 (emerge-get-diff3-group "3")))
1108 (setq group-2 (emerge-get-diff3-group "2"))
1109 (goto-char pos)
1110 (setq group-3 (emerge-get-diff3-group "3"))
1111 (vector (car group-2) (car (cdr group-2)) 694 (vector (car group-2) (car (cdr group-2))
1112 (car group-3) (car (cdr group-3)) 695 (car group-3) (car (cdr group-3))
1113 (cond ((string-equal agreement "2") 'prefer-A) 696 (cond ((string-equal agreement "2") 'prefer-A)
1114 ((string-equal agreement "3") 'prefer-B) 697 ((string-equal agreement "3") 'prefer-B)
1115 (t 'default-A)))) 698 (t 'default-A))))
1143 (buffer-substring (match-beginning 1) (match-end 1)))))) 726 (buffer-substring (match-beginning 1) (match-end 1))))))
1144 (list x x))))) 727 (list x x)))))
1145 728
1146 ;;; Functions to start Emerge on files 729 ;;; Functions to start Emerge on files
1147 730
1148 ;;;###autoload
1149 (defun emerge-files (arg file-A file-B file-out &optional startup-hooks 731 (defun emerge-files (arg file-A file-B file-out &optional startup-hooks
1150 quit-hooks) 732 quit-hooks)
1151 "Run Emerge on two files." 733 "Run Emerge on two files."
1152 (interactive 734 (interactive
1153 (let (f) 735 (let (f)
1154 (list current-prefix-arg 736 (list current-prefix-arg
1155 (setq f (read-file-name "File A to merge: " nil nil 'confirm)) 737 (setq f (emerge-read-file-name "File A to merge" emerge-last-dir-A
1156 (read-file-name "File B to merge: " nil nil 'confirm) 738 nil nil))
739 (emerge-read-file-name "File B to merge" emerge-last-dir-B nil f)
1157 (and current-prefix-arg 740 (and current-prefix-arg
1158 (read-file-name 741 (emerge-read-file-name "Output file" emerge-last-dir-output
1159 (format "Output file: (default %s) " f) 742 f f)))))
1160 nil f nil)))))
1161 (emerge-files-internal 743 (emerge-files-internal
1162 file-A file-B startup-hooks 744 file-A file-B startup-hooks
1163 (if arg 745 (if arg
1164 (cons (` (lambda () (emerge-files-exit (, file-out)))) 746 (cons (` (lambda () (emerge-files-exit (, file-out))))
1165 quit-hooks) 747 quit-hooks)
1166 quit-hooks) 748 quit-hooks)
1167 file-out)) 749 file-out))
1168 750
1169 ;;;###autoload
1170 (defun emerge-files-with-ancestor (arg file-A file-B file-ancestor file-out 751 (defun emerge-files-with-ancestor (arg file-A file-B file-ancestor file-out
1171 &optional startup-hooks quit-hooks) 752 &optional startup-hooks quit-hooks)
1172 "Run Emerge on two files, giving another file as the ancestor." 753 "Run Emerge on two files, giving another file as the ancestor."
1173 (interactive 754 (interactive
1174 (let (f) 755 (let (f)
1175 (list current-prefix-arg 756 (list current-prefix-arg
1176 (setq f (read-file-name "File A to merge: " nil nil 'confirm)) 757 (setq f (emerge-read-file-name "File A to merge" emerge-last-dir-A
1177 (read-file-name "File B to merge: " nil nil 'confirm) 758 nil nil))
1178 (read-file-name "Ancestor file: " nil nil 'confirm) 759 (emerge-read-file-name "File B to merge" emerge-last-dir-B nil f)
760 (emerge-read-file-name "Ancestor file" emerge-last-dir-ancestor
761 nil f)
1179 (and current-prefix-arg 762 (and current-prefix-arg
1180 (read-file-name 763 (emerge-read-file-name "Output file" emerge-last-dir-output
1181 (format "Output file: (default %s) " f) 764 f f)))))
1182 nil f nil)))))
1183 (emerge-files-with-ancestor-internal 765 (emerge-files-with-ancestor-internal
1184 file-A file-B file-ancestor startup-hooks 766 file-A file-B file-ancestor startup-hooks
1185 (if arg 767 (if arg
1186 (cons (` (lambda () (emerge-files-exit (, file-out)))) 768 (cons (` (lambda () (emerge-files-exit (, file-out))))
1187 quit-hooks) 769 quit-hooks)
1194 (if (not emerge-prefix-argument) 776 (if (not emerge-prefix-argument)
1195 (emerge-write-and-delete file-out))) 777 (emerge-write-and-delete file-out)))
1196 778
1197 ;;; Functions to start Emerge on buffers 779 ;;; Functions to start Emerge on buffers
1198 780
1199 ;;;###autoload
1200 (defun emerge-buffers (buffer-A buffer-B &optional startup-hooks quit-hooks) 781 (defun emerge-buffers (buffer-A buffer-B &optional startup-hooks quit-hooks)
1201 "Run Emerge on two buffers." 782 "Run Emerge on two buffers."
1202 (interactive "bBuffer A to merge: \nbBuffer B to merge: ") 783 (interactive "bBuffer A to merge: \nbBuffer B to merge: ")
1203 (let ((emerge-file-A (emerge-make-temp-file "A")) 784 (let ((emerge-file-A (emerge-make-temp-file "A"))
1204 (emerge-file-B (emerge-make-temp-file "B"))) 785 (emerge-file-B (emerge-make-temp-file "B")))
1208 (emerge-eval-in-buffer 789 (emerge-eval-in-buffer
1209 buffer-B 790 buffer-B
1210 (write-region (point-min) (point-max) emerge-file-B nil 'no-message)) 791 (write-region (point-min) (point-max) emerge-file-B nil 'no-message))
1211 (emerge-setup (get-buffer buffer-A) emerge-file-A 792 (emerge-setup (get-buffer buffer-A) emerge-file-A
1212 (get-buffer buffer-B) emerge-file-B 793 (get-buffer buffer-B) emerge-file-B
1213 (cons (function (lambda () 794 (cons (` (lambda ()
1214 (delete-file emerge-file-A) 795 (delete-file (, emerge-file-A))
1215 (delete-file emerge-file-B))) 796 (delete-file (, emerge-file-B))))
1216 startup-hooks) 797 startup-hooks)
1217 quit-hooks 798 quit-hooks
1218 nil))) 799 nil)))
1219 800
1220 ;;;###autoload
1221 (defun emerge-buffers-with-ancestor (buffer-A buffer-B buffer-ancestor 801 (defun emerge-buffers-with-ancestor (buffer-A buffer-B buffer-ancestor
1222 &optional startup-hooks 802 &optional startup-hooks
1223 quit-hooks) 803 quit-hooks)
1224 "Run Emerge on two buffers, giving another buffer as the ancestor." 804 "Run Emerge on two buffers, giving another buffer as the ancestor."
1225 (interactive 805 (interactive
1239 'no-message)) 819 'no-message))
1240 (emerge-setup-with-ancestor (get-buffer buffer-A) emerge-file-A 820 (emerge-setup-with-ancestor (get-buffer buffer-A) emerge-file-A
1241 (get-buffer buffer-B) emerge-file-B 821 (get-buffer buffer-B) emerge-file-B
1242 (get-buffer buffer-ancestor) 822 (get-buffer buffer-ancestor)
1243 emerge-file-ancestor 823 emerge-file-ancestor
1244 (cons (function (lambda () 824 (cons (` (lambda ()
1245 (delete-file emerge-file-A) 825 (delete-file (, emerge-file-A))
1246 (delete-file emerge-file-B) 826 (delete-file (, emerge-file-B))
1247 (delete-file 827 (delete-file
1248 emerge-file-ancestor))) 828 (, emerge-file-ancestor))))
1249 startup-hooks) 829 startup-hooks)
1250 quit-hooks 830 quit-hooks
1251 nil))) 831 nil)))
1252 832
1253 ;;; Functions to start Emerge from the command line 833 ;;; Functions to start Emerge from the command line
1254 834
1255 ;;;###autoload
1256 (defun emerge-files-command () 835 (defun emerge-files-command ()
1257 (let ((file-a (nth 0 command-line-args-left)) 836 (let ((file-a (nth 0 command-line-args-left))
1258 (file-b (nth 1 command-line-args-left)) 837 (file-b (nth 1 command-line-args-left))
1259 (file-out (nth 2 command-line-args-left))) 838 (file-out (nth 2 command-line-args-left)))
1260 (setq command-line-args-left (nthcdr 3 command-line-args-left)) 839 (setq command-line-args-left (nthcdr 3 command-line-args-left))
1261 (emerge-files-internal 840 (emerge-files-internal
1262 file-a file-b nil 841 file-a file-b nil
1263 (list (` (lambda () (emerge-command-exit (, file-out)))))))) 842 (list (` (lambda () (emerge-command-exit (, file-out))))))))
1264 843
1265 ;;;###autoload
1266 (defun emerge-files-with-ancestor-command () 844 (defun emerge-files-with-ancestor-command ()
1267 (let (file-a file-b file-anc file-out) 845 (let (file-a file-b file-anc file-out)
1268 ;; check for a -a flag, for filemerge compatibility 846 ;; check for a -a flag, for filemerge compatibility
1269 (if (string= (car command-line-args-left) "-a") 847 (if (string= (car command-line-args-left) "-a")
1270 ;; arguments are "-a ancestor file-a file-b file-out" 848 ;; arguments are "-a ancestor file-a file-b file-out"
1288 (emerge-write-and-delete file-out) 866 (emerge-write-and-delete file-out)
1289 (kill-emacs (if emerge-prefix-argument 1 0))) 867 (kill-emacs (if emerge-prefix-argument 1 0)))
1290 868
1291 ;;; Functions to start Emerge via remote request 869 ;;; Functions to start Emerge via remote request
1292 870
1293 ;;;###autoload
1294 (defun emerge-files-remote (file-a file-b file-out) 871 (defun emerge-files-remote (file-a file-b file-out)
1295 (setq emerge-file-out file-out) 872 (setq emerge-file-out file-out)
1296 (emerge-files-internal 873 (emerge-files-internal
1297 file-a file-b nil 874 file-a file-b nil
1298 (list (` (lambda () (emerge-remote-exit (, file-out) '(, exit-func))))) 875 (list (` (lambda () (emerge-remote-exit (, file-out) '(, exit-func)))))
1299 file-out) 876 file-out)
1300 (throw 'client-wait nil)) 877 (throw 'client-wait nil))
1301 878
1302 ;;;###autoload
1303 (defun emerge-files-with-ancestor-remote (file-a file-b file-anc file-out) 879 (defun emerge-files-with-ancestor-remote (file-a file-b file-anc file-out)
1304 (setq emerge-file-out file-out) 880 (setq emerge-file-out file-out)
1305 (emerge-files-with-ancestor-internal 881 (emerge-files-with-ancestor-internal
1306 file-a file-b file-anc nil 882 file-a file-b file-anc nil
1307 (list (` (lambda () (emerge-remote-exit (, file-out) '(, exit-func))))) 883 (list (` (lambda () (emerge-remote-exit (, file-out) '(, exit-func)))))
1310 886
1311 (defun emerge-remote-exit (file-out exit-func) 887 (defun emerge-remote-exit (file-out exit-func)
1312 (emerge-write-and-delete file-out) 888 (emerge-write-and-delete file-out)
1313 (kill-buffer emerge-merge-buffer) 889 (kill-buffer emerge-merge-buffer)
1314 (funcall exit-func (if emerge-prefix-argument 1 0))) 890 (funcall exit-func (if emerge-prefix-argument 1 0)))
891
892 ;;; Functions to start Emerge on RCS versions
893
894 (defun emerge-revisions (arg file revision-A revision-B
895 &optional startup-hooks quit-hooks)
896 "Emerge two RCS revisions of a file."
897 (interactive
898 (list current-prefix-arg
899 (read-file-name "File to merge: " nil nil 'confirm)
900 (read-string "Revision A to merge: " emerge-last-revision-A)
901 (read-string "Revision B to merge: " emerge-last-revision-B)))
902 (setq emerge-last-revision-A revision-A
903 emerge-last-revision-B revision-B)
904 (emerge-revisions-internal
905 file revision-A revision-B startup-hooks
906 (if arg
907 (cons (` (lambda ()
908 (shell-command
909 (, (format "%s %s" emerge-rcs-ci-program file)))))
910 quit-hooks)
911 quit-hooks)))
912
913 (defun emerge-revisions-with-ancestor (arg file revision-A
914 revision-B ancestor
915 &optional
916 startup-hooks quit-hooks)
917 "Emerge two RCS revisions of a file, giving another revision as
918 the ancestor."
919 (interactive
920 (list current-prefix-arg
921 (read-file-name "File to merge: " nil nil 'confirm)
922 (read-string "Revision A to merge: " emerge-last-revision-A)
923 (read-string "Revision B to merge: " emerge-last-revision-B)
924 (read-string "Ancestor: " emerge-last-revision-ancestor)))
925 (setq emerge-last-revision-A revision-A
926 emerge-last-revision-B revision-B
927 emerge-last-revision-ancestor ancestor)
928 (emerge-revision-with-ancestor-internal
929 file revision-A revision-B ancestor startup-hooks
930 (if arg
931 (let ((cmd ))
932 (cons (` (lambda ()
933 (shell-command
934 (, (format "%s %s" emerge-rcs-ci-program file)))))
935 quit-hooks))
936 quit-hooks)))
937
938 (defun emerge-revisions-internal (file revision-A revision-B &optional
939 startup-hooks quit-hooks output-file)
940 (let ((buffer-A (get-buffer-create (format "%s,%s" file revision-A)))
941 (buffer-B (get-buffer-create (format "%s,%s" file revision-B)))
942 (emerge-file-A (emerge-make-temp-file "A"))
943 (emerge-file-B (emerge-make-temp-file "B")))
944 ;; Get the revisions into buffers
945 (emerge-eval-in-buffer
946 buffer-A
947 (erase-buffer)
948 (shell-command
949 (format "%s -q -p%s %s" emerge-rcs-co-program revision-A file)
950 t)
951 (write-region (point-min) (point-max) emerge-file-A nil 'no-message)
952 (set-buffer-modified-p nil))
953 (emerge-eval-in-buffer
954 buffer-B
955 (erase-buffer)
956 (shell-command
957 (format "%s -q -p%s %s" emerge-rcs-co-program revision-B file)
958 t)
959 (write-region (point-min) (point-max) emerge-file-B nil 'no-message)
960 (set-buffer-modified-p nil))
961 ;; Do the merge
962 (emerge-setup buffer-A emerge-file-A
963 buffer-B emerge-file-B
964 (cons (` (lambda ()
965 (delete-file (, emerge-file-A))
966 (delete-file (, emerge-file-B))))
967 startup-hooks)
968 (cons (` (lambda () (emerge-files-exit (, file))))
969 quit-hooks)
970 nil)))
971
972 (defun emerge-revision-with-ancestor-internal (file revision-A revision-B
973 ancestor
974 &optional startup-hooks
975 quit-hooks output-file)
976 (let ((buffer-A (get-buffer-create (format "%s,%s" file revision-A)))
977 (buffer-B (get-buffer-create (format "%s,%s" file revision-B)))
978 (buffer-ancestor (get-buffer-create (format "%s,%s" file ancestor)))
979 (emerge-file-A (emerge-make-temp-file "A"))
980 (emerge-file-B (emerge-make-temp-file "B"))
981 (emerge-ancestor (emerge-make-temp-file "ancestor")))
982 ;; Get the revisions into buffers
983 (emerge-eval-in-buffer
984 buffer-A
985 (erase-buffer)
986 (shell-command
987 (format "%s -q -p%s %s" emerge-rcs-co-program
988 revision-A file)
989 t)
990 (write-region (point-min) (point-max) emerge-file-A nil 'no-message)
991 (set-buffer-modified-p nil))
992 (emerge-eval-in-buffer
993 buffer-B
994 (erase-buffer)
995 (shell-command
996 (format "%s -q -p%s %s" emerge-rcs-co-program revision-B file)
997 t)
998 (write-region (point-min) (point-max) emerge-file-B nil 'no-message)
999 (set-buffer-modified-p nil))
1000 (emerge-eval-in-buffer
1001 buffer-ancestor
1002 (erase-buffer)
1003 (shell-command
1004 (format "%s -q -p%s %s" emerge-rcs-co-program ancestor file)
1005 t)
1006 (write-region (point-min) (point-max) emerge-ancestor nil 'no-message)
1007 (set-buffer-modified-p nil))
1008 ;; Do the merge
1009 (emerge-setup-with-ancestor
1010 buffer-A emerge-file-A buffer-B emerge-file-B
1011 buffer-ancestor emerge-ancestor
1012 (cons (` (lambda ()
1013 (delete-file (, emerge-file-A))
1014 (delete-file (, emerge-file-B))
1015 (delete-file (, emerge-ancestor))))
1016 startup-hooks)
1017 (cons (` (lambda () (emerge-files-exit (, file))))
1018 quit-hooks)
1019 output-file)))
1020
1021 ;;; Function to start Emerge based on a line in a file
1022
1023 (defun emerge-execute-line ()
1024 "Process the current line, looking for entries of the form:
1025 a=file1
1026 b=file2
1027 ancestor=file3
1028 output=file4
1029 seperated by whitespace. Based on entries found, call emerge correctly
1030 on the files files listed.
1031
1032 In addition, if only one of \"a=file\" or \"b=file\" is present, and \"output=file\"
1033 is present:
1034 If emerge-execute-line-deletions is non-nil and \"ancestor=file\" is present,
1035 it is assumed that the file in question has been deleted, and it is
1036 not copied to the output file.
1037 Otherwise, the A or B file present is copied to the output file."
1038 (interactive)
1039 (let (file-A file-B file-ancestor file-out
1040 (case-fold-search t))
1041 ;; Stop if at end of buffer (even though we might be in a line, if
1042 ;; the line does not end with newline)
1043 (if (eobp)
1044 (error "At end of buffer"))
1045 ;; Go to the beginning of the line
1046 (beginning-of-line)
1047 ;; Skip any initial whitespace
1048 (if (looking-at "[ \t]*")
1049 (goto-char (match-end 0)))
1050 ;; Process the entire line
1051 (while (not (eolp))
1052 ;; Get the next entry
1053 (if (looking-at "\\([a-z]+\\)=\\([^ \t\n]+\\)[ \t]*")
1054 ;; Break apart the tab (before =) and the filename (after =)
1055 (let ((tag (downcase
1056 (buffer-substring (match-beginning 1) (match-end 1))))
1057 (file (buffer-substring (match-beginning 2) (match-end 2))))
1058 ;; Move point after the entry
1059 (goto-char (match-end 0))
1060 ;; Store the filename in the right variable
1061 (cond
1062 ((string-equal tag "a")
1063 (if file-A
1064 (error "This line has two 'A' entries"))
1065 (setq file-A file))
1066 ((string-equal tag "b")
1067 (if file-B
1068 (error "This line has two 'B' entries"))
1069 (setq file-B file))
1070 ((or (string-equal tag "anc") (string-equal tag "ancestor"))
1071 (if file-ancestor
1072 (error "This line has two 'ancestor' entries"))
1073 (setq file-ancestor file))
1074 ((or (string-equal tag "out") (string-equal tag "output"))
1075 (if file-out
1076 (error "This line has two 'output' entries"))
1077 (setq file-out file))
1078 (t
1079 (error "Unrecognized entry"))))
1080 ;; If the match on the entry pattern failed
1081 (error "Unparseable entry")))
1082 ;; Make sure that file-A and file-B are present
1083 (if (not (or (and file-A file-B) file-out))
1084 (error "Must have both 'A' and 'B' entries"))
1085 (if (not (or file-A file-B))
1086 (error "Must have 'A' or 'B' entry"))
1087 ;; Go to the beginning of the next line, so next execution will use
1088 ;; next line in buffer.
1089 (beginning-of-line 2)
1090 ;; Execute the correct command
1091 (cond
1092 ;; Merge of two files with ancestor
1093 ((and file-A file-B file-ancestor)
1094 (message "Merging %s and %s..." file-A file-B)
1095 (emerge-files-with-ancestor (not (not file-out)) file-A file-B
1096 file-ancestor file-out
1097 nil
1098 ;; When done, return to this buffer.
1099 (list
1100 (` (lambda ()
1101 (switch-to-buffer (, (current-buffer)))
1102 (message "Merge done."))))))
1103 ;; Merge of two files without ancestor
1104 ((and file-A file-B)
1105 (message "Merging %s and %s..." file-A file-B)
1106 (emerge-files (not (not file-out)) file-A file-B file-out
1107 nil
1108 ;; When done, return to this buffer.
1109 (list
1110 (` (lambda ()
1111 (switch-to-buffer (, (current-buffer)))
1112 (message "Merge done."))))))
1113 ;; There is an output file (or there would have been an error above),
1114 ;; but only one input file.
1115 ;; The file appears to have been deleted in one version; do nothing.
1116 ((and file-ancestor emerge-execute-line-deletions)
1117 (message "No action."))
1118 ;; The file should be copied from the version that contains it
1119 (t (let ((input-file (or file-A file-B)))
1120 (message "Copying...")
1121 (copy-file input-file file-out)
1122 (message "%s copied to %s." input-file file-out))))))
1123
1124 ;;; Sample function for creating information for emerge-execute-line
1125
1126 (defvar emerge-merge-directories-filename-regexp "[^.]"
1127 "Regexp describing files to be processed by emerge-merge-directories.")
1128
1129 (defun emerge-merge-directories (a-dir b-dir ancestor-dir output-dir)
1130 (interactive
1131 (list
1132 (read-file-name "A directory: " nil nil 'confirm)
1133 (read-file-name "B directory: " nil nil 'confirm)
1134 (read-file-name "Ancestor directory (null for none): " nil nil 'confirm)
1135 (read-file-name "Output directory (null for none): " nil nil 'confirm)))
1136 ;; Check that we're not on a line
1137 (if (not (and (bolp) (eolp)))
1138 (error "There is text on this line"))
1139 ;; Turn null strings into nil to indicate directories not used.
1140 (if (and ancestor-dir (string-equal ancestor-dir ""))
1141 (setq ancestor-dir nil))
1142 (if (and output-dir (string-equal output-dir ""))
1143 (setq output-dir nil))
1144 ;; Canonicalize the directory names
1145 (setq a-dir (expand-file-name a-dir))
1146 (if (not (string-equal (substring a-dir -1) "/"))
1147 (setq a-dir (concat a-dir "/")))
1148 (setq b-dir (expand-file-name b-dir))
1149 (if (not (string-equal (substring b-dir -1) "/"))
1150 (setq b-dir (concat b-dir "/")))
1151 (if ancestor-dir
1152 (progn
1153 (setq ancestor-dir (expand-file-name ancestor-dir))
1154 (if (not (string-equal (substring ancestor-dir -1) "/"))
1155 (setq ancestor-dir (concat ancestor-dir "/")))))
1156 (if output-dir
1157 (progn
1158 (setq output-dir (expand-file-name output-dir))
1159 (if (not (string-equal (substring output-dir -1) "/"))
1160 (setq output-dir (concat output-dir "/")))))
1161 ;; Set the mark to where we start
1162 (push-mark)
1163 ;; Find out what files are in the directories.
1164 (let* ((a-dir-files
1165 (directory-files a-dir nil emerge-merge-directories-filename-regexp))
1166 (b-dir-files
1167 (directory-files b-dir nil emerge-merge-directories-filename-regexp))
1168 (ancestor-dir-files
1169 (and ancestor-dir
1170 (directory-files ancestor-dir nil
1171 emerge-merge-directories-filename-regexp)))
1172 (all-files (sort (nconc (copy-sequence a-dir-files)
1173 (copy-sequence b-dir-files)
1174 (copy-sequence ancestor-dir-files))
1175 (function string-lessp))))
1176 ;; Remove duplicates from all-files.
1177 (let ((p all-files))
1178 (while p
1179 (if (and (cdr p) (string-equal (car p) (car (cdr p))))
1180 (setcdr p (cdr (cdr p)))
1181 (setq p (cdr p)))))
1182 ;; Generate the control lines for the various files.
1183 (while all-files
1184 (let ((f (car all-files)))
1185 (setq all-files (cdr all-files))
1186 (if (and a-dir-files (string-equal (car a-dir-files) f))
1187 (progn
1188 (insert "A=" a-dir f "\t")
1189 (setq a-dir-files (cdr a-dir-files))))
1190 (if (and b-dir-files (string-equal (car b-dir-files) f))
1191 (progn
1192 (insert "B=" b-dir f "\t")
1193 (setq b-dir-files (cdr b-dir-files))))
1194 (if (and ancestor-dir-files (string-equal (car ancestor-dir-files) f))
1195 (progn
1196 (insert "ancestor=" ancestor-dir f "\t")
1197 (setq ancestor-dir-files (cdr ancestor-dir-files))))
1198 (if output-dir
1199 (insert "output=" output-dir f "\t"))
1200 (backward-delete-char 1)
1201 (insert "\n")))))
1315 1202
1316 ;;; Common setup routines 1203 ;;; Common setup routines
1317 1204
1318 ;; Set up the window configuration. If POS is given, set the points to 1205 ;; Set up the window configuration. If POS is given, set the points to
1319 ;; the beginnings of the buffers. 1206 ;; the beginnings of the buffers.
1373 (use-local-map emerge-fast-keymap) 1260 (use-local-map emerge-fast-keymap)
1374 (setq emerge-edit-mode nil) 1261 (setq emerge-edit-mode nil)
1375 (setq emerge-fast-mode t)) 1262 (setq emerge-fast-mode t))
1376 1263
1377 (defun emerge-remember-buffer-characteristics () 1264 (defun emerge-remember-buffer-characteristics ()
1378 "Remembers certain properties of the buffers being merged. 1265 "Must be called in the merge buffer. Remembers certain properties of the
1379 Must be called in the merge buffer. Remembers read-only, modified, 1266 buffers being merged (read-only, modified, auto-save), and saves them in
1380 auto-save, and saves them in buffer local variables. Sets the buffers 1267 buffer local variables. Sets the buffers read-only and turns off auto-save.
1381 read-only and turns off `auto-save-mode'.
1382 These characteristics are restored by emerge-restore-buffer-characteristics." 1268 These characteristics are restored by emerge-restore-buffer-characteristics."
1383 ;; force auto-save, because we will turn off auto-saving in buffers for the 1269 ;; force auto-save, because we will turn off auto-saving in buffers for the
1384 ;; duration 1270 ;; duration
1385 (do-auto-save) 1271 (do-auto-save)
1386 ;; remember and alter buffer characteristics 1272 ;; remember and alter buffer characteristics
1433 (let* ((list-element (car lineno-list)) 1319 (let* ((list-element (car lineno-list))
1434 a-begin-marker 1320 a-begin-marker
1435 a-end-marker 1321 a-end-marker
1436 b-begin-marker 1322 b-begin-marker
1437 b-end-marker 1323 b-end-marker
1324 merge-begin-marker
1325 merge-end-marker
1438 (a-begin (aref list-element 0)) 1326 (a-begin (aref list-element 0))
1439 (a-end (aref list-element 1)) 1327 (a-end (aref list-element 1))
1440 (b-begin (aref list-element 2)) 1328 (b-begin (aref list-element 2))
1441 (b-end (aref list-element 3)) 1329 (b-end (aref list-element 3))
1442 (state (aref list-element 4))) 1330 (state (aref list-element 4)))
1484 (emerge-select-B) 1372 (emerge-select-B)
1485 (aset (aref emerge-difference-list n) 6 'prefer-B))) 1373 (aset (aref emerge-difference-list n) 6 'prefer-B)))
1486 (setq n (1+ n)))) 1374 (setq n (1+ n))))
1487 (emerge-unselect-and-select-difference -1)) 1375 (emerge-unselect-and-select-difference -1))
1488 1376
1377 ;; Process the local-variables list at the end of the merged file, if
1378 ;; requested.
1379 (defun emerge-handle-local-variables ()
1380 (if emerge-process-local-variables
1381 (condition-case err
1382 (hack-local-variables t)
1383 (error (message "Local-variables error in merge buffer: %s"
1384 (prin1-to-string err))))))
1385
1489 ;;; Common exit routines 1386 ;;; Common exit routines
1490 1387
1491 (defun emerge-write-and-delete (file-out) 1388 (defun emerge-write-and-delete (file-out)
1492 ;; clear screen format 1389 ;; clear screen format
1493 (delete-other-windows) 1390 (delete-other-windows)
1503 (write-file file-out)) 1400 (write-file file-out))
1504 1401
1505 ;;; Commands 1402 ;;; Commands
1506 1403
1507 (defun emerge-recenter (&optional arg) 1404 (defun emerge-recenter (&optional arg)
1508 "Bring the highlighted region of all three merge buffers into view. 1405 "Bring the highlighted region of all three merge buffers into view,
1509 This brings the buffers into view if they are in windows. 1406 if they are in windows. If an ARGUMENT is given, the default three-window
1510 If an ARGUMENT is given, the default three-window display is reestablished." 1407 display is reestablished."
1511 (interactive "P") 1408 (interactive "P")
1512 ;; If there is an argument, rebuild the window structure 1409 ;; If there is an argument, rebuild the window structure
1513 (if arg 1410 (if arg
1514 (emerge-setup-windows emerge-A-buffer emerge-B-buffer 1411 (emerge-setup-windows emerge-A-buffer emerge-B-buffer
1515 emerge-merge-buffer)) 1412 emerge-merge-buffer))
1636 default-amount))))))) 1533 default-amount)))))))
1637 1534
1638 (defun emerge-scroll-left (&optional arg) 1535 (defun emerge-scroll-left (&optional arg)
1639 "Scroll left all three merge buffers, if they are in windows. 1536 "Scroll left all three merge buffers, if they are in windows.
1640 If an ARGUMENT is given, that is how many columns are scrolled, else nearly 1537 If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1641 the width of the A and B windows. C-u - alone as argument scrolls half the 1538 the width of the A and B windows. `C-u -' alone as argument scrolls half the
1642 width of the A and B windows." 1539 width of the A and B windows."
1643 (interactive "P") 1540 (interactive "P")
1644 (emerge-operate-on-windows 1541 (emerge-operate-on-windows
1645 'scroll-left 1542 'scroll-left
1646 ;; calculate argument to scroll-left 1543 ;; calculate argument to scroll-left
1664 default-amount))))))) 1561 default-amount)))))))
1665 1562
1666 (defun emerge-scroll-right (&optional arg) 1563 (defun emerge-scroll-right (&optional arg)
1667 "Scroll right all three merge buffers, if they are in windows. 1564 "Scroll right all three merge buffers, if they are in windows.
1668 If an ARGUMENT is given, that is how many columns are scrolled, else nearly 1565 If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1669 the width of the A and B windows. C-u - alone as argument scrolls half the 1566 the width of the A and B windows. `C-u -' alone as argument scrolls half the
1670 width of the A and B windows." 1567 width of the A and B windows."
1671 (interactive "P") 1568 (interactive "P")
1672 (emerge-operate-on-windows 1569 (emerge-operate-on-windows
1673 'scroll-right 1570 'scroll-right
1674 ;; calculate argument to scroll-right 1571 ;; calculate argument to scroll-right
1690 (/ default-amount 2) 1587 (/ default-amount 2)
1691 ;; no argument means default amount 1588 ;; no argument means default amount
1692 default-amount))))))) 1589 default-amount)))))))
1693 1590
1694 (defun emerge-scroll-reset () 1591 (defun emerge-scroll-reset ()
1695 "Reset horizontal scrolling. 1592 "Reset horizontal scrolling of all three merge buffers to the left margin,
1696 This resets the horizontal scrolling of all three merge buffers 1593 if they are in windows."
1697 to the left margin, if they are in windows."
1698 (interactive) 1594 (interactive)
1699 (emerge-operate-on-windows 1595 (emerge-operate-on-windows
1700 (function (lambda (x) (set-window-hscroll (selected-window) 0))) 1596 (function (lambda (x) (set-window-hscroll (selected-window) 0)))
1701 nil)) 1597 nil))
1702 1598
1721 (point))))) 1617 (point)))))
1722 ;; We failed that test, see if it fits at all 1618 ;; We failed that test, see if it fits at all
1723 ;; Meanwhile positioning it correctly in case it doesn't fit 1619 ;; Meanwhile positioning it correctly in case it doesn't fit
1724 (progn 1620 (progn
1725 (set-window-start (selected-window) beg) 1621 (set-window-start (selected-window) beg)
1726 (setq fits (pos-visible-in-window-p end)) 1622 (if (pos-visible-in-window-p end)
1727 (if fits
1728 ;; Determine the number of lines that the region occupies 1623 ;; Determine the number of lines that the region occupies
1729 (let ((lines 0)) 1624 (let ((lines 0))
1730 (while (> end (progn 1625 (while (> end (progn
1731 (move-to-window-line lines) 1626 (move-to-window-line lines)
1732 (point))) 1627 (point)))
1775 (< difference-number (1+ emerge-number-of-differences))) 1670 (< difference-number (1+ emerge-number-of-differences)))
1776 (emerge-unselect-and-select-difference difference-number) 1671 (emerge-unselect-and-select-difference difference-number)
1777 (error "Bad difference number")))) 1672 (error "Bad difference number"))))
1778 1673
1779 (defun emerge-quit (arg) 1674 (defun emerge-quit (arg)
1780 "Finish an Emerge session. 1675 "Finish an Emerge session. Prefix ARGUMENT means to abort rather than
1781 Prefix argument means to abort rather than successfully finish. 1676 successfully finish. The difference depends on how the merge was started,
1782 The difference depends on how the merge was started,
1783 but usually means to not write over one of the original files, or to signal 1677 but usually means to not write over one of the original files, or to signal
1784 to some process which invoked Emerge a failure code. 1678 to some process which invoked Emerge a failure code.
1785 1679
1786 Unselects the selected difference, if any, restores the read-only and modified 1680 Unselects the selected difference, if any, restores the read-only and modified
1787 flags of the merged file buffers, restores the local keymap of the merge 1681 flags of the merged file buffers, restores the local keymap of the merge
1822 (setq emerge-auto-advance nil) 1716 (setq emerge-auto-advance nil)
1823 (setq emerge-skip-prefers nil) 1717 (setq emerge-skip-prefers nil)
1824 ;; restore mode line 1718 ;; restore mode line
1825 (kill-local-variable 'mode-line-buffer-identification) 1719 (kill-local-variable 'mode-line-buffer-identification)
1826 (let ((emerge-prefix-argument arg)) 1720 (let ((emerge-prefix-argument arg))
1827 (run-hooks 'emerge-quit-hook))) 1721 (run-hooks 'emerge-quit-hooks)))
1828 1722
1829 (defun emerge-select-A (&optional force) 1723 (defun emerge-select-A (&optional force)
1830 "Select the A variant of this difference. 1724 "Select the A variant of this difference. Refuses to function if this
1831 Refuses to function if this difference has been edited, i.e., if it 1725 difference has been edited, i.e., if it is neither the A nor the B variant.
1832 is neither the A nor the B variant.
1833 An ARGUMENT forces the variant to be selected even if the difference has 1726 An ARGUMENT forces the variant to be selected even if the difference has
1834 been edited." 1727 been edited."
1835 (interactive "P") 1728 (interactive "P")
1836 (let ((operate 1729 (let ((operate
1837 (function (lambda () 1730 (function (lambda ()
1854 (goto-char merge-begin) 1747 (goto-char merge-begin)
1855 (aset diff-vector 6 'A) 1748 (aset diff-vector 6 'A)
1856 (emerge-refresh-mode-line))) 1749 (emerge-refresh-mode-line)))
1857 1750
1858 (defun emerge-select-B (&optional force) 1751 (defun emerge-select-B (&optional force)
1859 "Select the B variant of this difference. 1752 "Select the B variant of this difference. Refuses to function if this
1860 Refuses to function if this difference has been edited, i.e., if it 1753 difference has been edited, i.e., if it is neither the A nor the B variant.
1861 is neither the A nor the B variant. An ARGUMENT forces the variant to be selected even if the difference has 1754 An ARGUMENT forces the variant to be selected even if the difference has
1862 been edited." 1755 been edited."
1863 (interactive "P") 1756 (interactive "P")
1864 (let ((operate 1757 (let ((operate
1865 (function (lambda () 1758 (function (lambda ()
1866 (emerge-select-B-edit merge-begin merge-end B-begin B-end) 1759 (emerge-select-B-edit merge-begin merge-end B-begin B-end)
1882 (goto-char merge-begin) 1775 (goto-char merge-begin)
1883 (aset diff-vector 6 'B) 1776 (aset diff-vector 6 'B)
1884 (emerge-refresh-mode-line))) 1777 (emerge-refresh-mode-line)))
1885 1778
1886 (defun emerge-default-A () 1779 (defun emerge-default-A ()
1887 "Selects the A variant. 1780 "Selects the A variant for all differences from here down in the buffer
1888 This selects the A variant for all differences from here down in the buffer
1889 which are still defaulted, i.e., which the user has not selected and for 1781 which are still defaulted, i.e., which the user has not selected and for
1890 which there is no preference." 1782 which there is no preference."
1891 (interactive) 1783 (interactive)
1892 (let ((buffer-read-only nil)) 1784 (let ((buffer-read-only nil))
1893 (let ((selected-difference emerge-current-difference) 1785 (let ((selected-difference emerge-current-difference)
1904 (message "Setting default to A...%d" n))) 1796 (message "Setting default to A...%d" n)))
1905 (emerge-unselect-and-select-difference selected-difference))) 1797 (emerge-unselect-and-select-difference selected-difference)))
1906 (message "Default A set")) 1798 (message "Default A set"))
1907 1799
1908 (defun emerge-default-B () 1800 (defun emerge-default-B ()
1909 "Selects the B variant. 1801 "Selects the B variant for all differences from here down in the buffer
1910 This selects the B variant for all differences from here down in the buffer
1911 which are still defaulted, i.e., which the user has not selected and for 1802 which are still defaulted, i.e., which the user has not selected and for
1912 which there is no preference." 1803 which there is no preference."
1913 (interactive) 1804 (interactive)
1914 (let ((buffer-read-only nil)) 1805 (let ((buffer-read-only nil))
1915 (let ((selected-difference emerge-current-difference) 1806 (let ((selected-difference emerge-current-difference)
1926 (message "Setting default to B...%d" n))) 1817 (message "Setting default to B...%d" n)))
1927 (emerge-unselect-and-select-difference selected-difference))) 1818 (emerge-unselect-and-select-difference selected-difference)))
1928 (message "Default B set")) 1819 (message "Default B set"))
1929 1820
1930 (defun emerge-fast-mode () 1821 (defun emerge-fast-mode ()
1931 "Set fast mode. 1822 "Set fast mode, in which ordinary Emacs commands are disabled, and Emerge
1932 In this mode ordinary Emacs commands are disabled, and Emerge commands 1823 commands are need not be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1933 are need not be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1934 (interactive) 1824 (interactive)
1935 (setq buffer-read-only t) 1825 (setq buffer-read-only t)
1936 (use-local-map emerge-fast-keymap) 1826 (use-local-map emerge-fast-keymap)
1937 (setq emerge-mode t) 1827 (setq emerge-mode t)
1938 (setq emerge-fast-mode t) 1828 (setq emerge-fast-mode t)
1940 (message "Fast mode set") 1830 (message "Fast mode set")
1941 ;; force mode line redisplay 1831 ;; force mode line redisplay
1942 (set-buffer-modified-p (buffer-modified-p))) 1832 (set-buffer-modified-p (buffer-modified-p)))
1943 1833
1944 (defun emerge-edit-mode () 1834 (defun emerge-edit-mode ()
1945 "Set edit mode. 1835 "Set edit mode, in which ordinary Emacs commands are available, and Emerge
1946 In this mode ordinary Emacs commands are available, and Emerge commands 1836 commands must be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1947 must be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1948 (interactive) 1837 (interactive)
1949 (setq buffer-read-only nil) 1838 (setq buffer-read-only nil)
1950 (use-local-map emerge-edit-keymap) 1839 (use-local-map emerge-edit-keymap)
1951 (setq emerge-mode t) 1840 (setq emerge-mode t)
1952 (setq emerge-fast-mode nil) 1841 (setq emerge-fast-mode nil)
1954 (message "Edit mode set") 1843 (message "Edit mode set")
1955 ;; force mode line redisplay 1844 ;; force mode line redisplay
1956 (set-buffer-modified-p (buffer-modified-p))) 1845 (set-buffer-modified-p (buffer-modified-p)))
1957 1846
1958 (defun emerge-auto-advance (arg) 1847 (defun emerge-auto-advance (arg)
1959 "Toggle auto-advance mode. 1848 "Toggle auto-advance mode, which causes emerge-select-A and
1960 This mode causes `emerge-select-A' and `emerge-select-B' to automatically 1849 emerge-select-B to automatically advance to the next difference. (See
1961 advance to the next difference. (See `emerge-auto-advance'.) 1850 emerge-auto-advance.)
1962 If a positive ARGUMENT is given, it turns on `auto-advance-mode'. 1851 If a positive ARGUMENT is given, it turns on auto-advance mode.
1963 If a negative ARGUMENT is given, it turns off `auto-advance-mode'." 1852 If a negative ARGUMENT is given, it turns off auto-advance mode."
1964 (interactive "P") 1853 (interactive "P")
1965 (setq emerge-auto-advance (if (null arg) 1854 (setq emerge-auto-advance (if (null arg)
1966 (not emerge-auto-advance) 1855 (not emerge-auto-advance)
1967 (> (prefix-numeric-value arg) 0))) 1856 (> (prefix-numeric-value arg) 0)))
1968 (message (if emerge-skip-prefers 1857 (message (if emerge-skip-prefers
1970 "Auto-advance cleared")) 1859 "Auto-advance cleared"))
1971 ;; force mode line redisplay 1860 ;; force mode line redisplay
1972 (set-buffer-modified-p (buffer-modified-p))) 1861 (set-buffer-modified-p (buffer-modified-p)))
1973 1862
1974 (defun emerge-skip-prefers (arg) 1863 (defun emerge-skip-prefers (arg)
1975 "Toggle skip-prefers mode. 1864 "Toggle skip-prefers mode, which causes emerge-next-difference and
1976 This mode causes `emerge-next-difference' and `emerge-previous-difference' 1865 emerge-previous-difference to automatically skip over differences for which
1977 to automatically skip over differences for which there is a preference. 1866 there is a preference. (See emerge-skip-prefers.)
1978 (See `emerge-skip-prefers'.) If a positive ARG is given, it turns on 1867 If a positive ARGUMENT is given, it turns on skip-prefers mode.
1979 `skip-prefers' mode. 1868 If a negative ARGUMENT is given, it turns off skip-prefers mode."
1980 If a negative ARG is given, it turns off `skip-prefers' mode."
1981 (interactive "P") 1869 (interactive "P")
1982 (setq emerge-skip-prefers (if (null arg) 1870 (setq emerge-skip-prefers (if (null arg)
1983 (not emerge-skip-prefers) 1871 (not emerge-skip-prefers)
1984 (> (prefix-numeric-value arg) 0))) 1872 (> (prefix-numeric-value arg) 0)))
1985 (message (if emerge-skip-prefers 1873 (message (if emerge-skip-prefers
2068 (goto-char merge-end) 1956 (goto-char merge-end)
2069 (set-mark merge-begin)))) 1957 (set-mark merge-begin))))
2070 1958
2071 (defun emerge-file-names () 1959 (defun emerge-file-names ()
2072 "Show the names of the buffers or files being operated on by Emerge. 1960 "Show the names of the buffers or files being operated on by Emerge.
2073 Use C-u l to reset the windows afterward." 1961 Use ^U L to reset the windows afterward."
2074 (interactive) 1962 (interactive)
2075 (delete-other-windows) 1963 (delete-other-windows)
2076 (let ((temp-buffer-show-function 1964 (let ((temp-buffer-show-hook
2077 (function (lambda (buf) 1965 (function (lambda (buf)
2078 (split-window-vertically) 1966 (split-window-vertically)
2079 (switch-to-buffer buf) 1967 (switch-to-buffer buf)
2080 (other-window 1))))) 1968 (other-window 1)))))
2081 (with-output-to-temp-buffer "*Help*" 1969 (with-output-to-temp-buffer "*Help*"
2108 (princ (buffer-name)))) 1996 (princ (buffer-name))))
2109 (princ "\n"))) 1997 (princ "\n")))
2110 (princ emerge-output-description)))) 1998 (princ emerge-output-description))))
2111 1999
2112 (defun emerge-join-differences (arg) 2000 (defun emerge-join-differences (arg)
2113 "Join the selected difference with the following one. 2001 "Join the selected difference with the following one. With a prefix
2114 With a prefix argument, join with the preceeding one." 2002 argument, join with the preceeding one."
2115 (interactive "P") 2003 (interactive "P")
2116 (let ((n emerge-current-difference)) 2004 (let ((n emerge-current-difference))
2117 ;; adjust n to be first difference to join 2005 ;; adjust n to be first difference to join
2118 (if arg 2006 (if arg
2119 (setq n (1- n))) 2007 (setq n (1- n)))
2223 ;; reinsert the flags 2111 ;; reinsert the flags
2224 (emerge-select-difference emerge-current-difference) 2112 (emerge-select-difference emerge-current-difference)
2225 (emerge-recenter)))) 2113 (emerge-recenter))))
2226 2114
2227 (defun emerge-trim-difference () 2115 (defun emerge-trim-difference ()
2228 "Trim lines off top and bottom of difference that are the same. 2116 "Trim lines off the top and bottom of a difference that are the same in
2229 If lines are the same in both the A and the B versions, strip them off. 2117 both the A and B versions. (This can happen when the A and B versions
2230 (This can happen when the A and B versions have common lines that the 2118 have common lines that the ancestor version does not share.)"
2231 ancestor version does not share.)"
2232 (interactive) 2119 (interactive)
2233 ;; make sure we are in a real difference 2120 ;; make sure we are in a real difference
2234 (emerge-validate-difference) 2121 (emerge-validate-difference)
2235 ;; remove the flags 2122 ;; remove the flags
2236 (emerge-unselect-difference emerge-current-difference) 2123 (emerge-unselect-difference emerge-current-difference)
2322 ;; search for the point in the merge buffer, using the markers 2209 ;; search for the point in the merge buffer, using the markers
2323 ;; for the beginning and end of the differences in the merge buffer 2210 ;; for the beginning and end of the differences in the merge buffer
2324 (emerge-find-difference1 arg (point) 4 5)) 2211 (emerge-find-difference1 arg (point) 4 5))
2325 2212
2326 (defun emerge-find-difference-A (arg) 2213 (defun emerge-find-difference-A (arg)
2327 "Find the difference containing the position of the point in the A buffer. 2214 "Find the difference containing the current position of the point in the
2328 This command must be executed in the merge buffer. 2215 A buffer. (Nonetheless, this command must be executed in the merge buffer.)
2329 If there is no containing difference and the prefix argument is positive, 2216 If there is no containing difference and the prefix argument is positive,
2330 it finds the nearest following difference. A negative prefix argument finds 2217 it finds the nearest following difference. A negative prefix argument finds
2331 the nearest previous difference." 2218 the nearest previous difference."
2332 (interactive "P") 2219 (interactive "P")
2333 ;; search for the point in the A buffer, using the markers 2220 ;; search for the point in the A buffer, using the markers
2335 (emerge-find-difference1 arg 2222 (emerge-find-difference1 arg
2336 (emerge-eval-in-buffer emerge-A-buffer (point)) 2223 (emerge-eval-in-buffer emerge-A-buffer (point))
2337 0 1)) 2224 0 1))
2338 2225
2339 (defun emerge-find-difference-B (arg) 2226 (defun emerge-find-difference-B (arg)
2340 "Find the difference containing the position of the point in the B buffer. 2227 "Find the difference containing the current position of the point in the
2341 This command must be executed in the merge buffer. 2228 B buffer. (Nonetheless, this command must be executed in the merge buffer.)
2342 If there is no containing difference and the prefix argument is positive, 2229 If there is no containing difference and the prefix argument is positive,
2343 it finds the nearest following difference. A negative prefix argument finds 2230 it finds the nearest following difference. A negative prefix argument finds
2344 the nearest previous difference." 2231 the nearest previous difference."
2345 (interactive "P") 2232 (interactive "P")
2346 ;; search for the point in the B buffer, using the markers 2233 ;; search for the point in the B buffer, using the markers
2385 (if (> index 0) 2272 (if (> index 0)
2386 (1- index) 2273 (1- index)
2387 (error "No difference contains or preceeds point"))))))) 2274 (error "No difference contains or preceeds point")))))))
2388 2275
2389 (defun emerge-line-numbers () 2276 (defun emerge-line-numbers ()
2390 "Display the current line numbers. 2277 "Display the current line numbers of the points in the A, B, and
2391 This function displays the line numbers of the points in the A, B, and
2392 merge buffers." 2278 merge buffers."
2393 (interactive) 2279 (interactive)
2394 (let* ((valid-diff 2280 (let* ((valid-diff
2395 (and (>= emerge-current-difference 0) 2281 (and (>= emerge-current-difference 0)
2396 (< emerge-current-difference emerge-number-of-differences))) 2282 (< emerge-current-difference emerge-number-of-differences)))
2416 (if (> (point) (aref diff end-marker)) 2302 (if (> (point) (aref diff end-marker))
2417 (setq temp (- temp emerge-after-flag-lines))))) 2303 (setq temp (- temp emerge-after-flag-lines)))))
2418 temp)) 2304 temp))
2419 2305
2420 (defun emerge-set-combine-versions-template (start end &optional localize) 2306 (defun emerge-set-combine-versions-template (start end &optional localize)
2421 "Copy region into `emerge-combine-versions-template'. 2307 "Copy region into emerge-combine-versions-template which controls how
2422 This controls how `emerge-combine-versions' will combine the two versions. 2308 emerge-combine-versions will combine the two versions.
2423 With prefix argument, `emerge-combine-versions' is made local to this 2309 With prefix argument, emerge-combine-versions is made local to this
2424 merge buffer. Localization is permanent for any particular merge buffer." 2310 merge buffer. Localization is permanent for any particular merge buffer."
2425 (interactive "r\nP") 2311 (interactive "r\nP")
2426 (if localize 2312 (if localize
2427 (make-local-variable 'emerge-combine-versions-template)) 2313 (make-local-variable 'emerge-combine-versions-template))
2428 (setq emerge-combine-versions-template (buffer-substring start end)) 2314 (setq emerge-combine-versions-template (buffer-substring start end))
2430 (if (assq 'emerge-combine-versions-template (buffer-local-variables)) 2316 (if (assq 'emerge-combine-versions-template (buffer-local-variables))
2431 "emerge-set-combine-versions-template set locally." 2317 "emerge-set-combine-versions-template set locally."
2432 "emerge-set-combine-versions-template set."))) 2318 "emerge-set-combine-versions-template set.")))
2433 2319
2434 (defun emerge-combine-versions (&optional force) 2320 (defun emerge-combine-versions (&optional force)
2435 "Combine versions using the template in `emerge-combine-versions-template'. 2321 "Combine the two versions using the template in
2322 emerge-combine-versions-template.
2436 Refuses to function if this difference has been edited, i.e., if it is 2323 Refuses to function if this difference has been edited, i.e., if it is
2437 neither the A nor the B variant. 2324 neither the A nor the B variant.
2438 An argument forces the variant to be selected even if the difference has 2325 An ARGUMENT forces the variant to be selected even if the difference has
2439 been edited." 2326 been edited."
2440 (interactive "P") 2327 (interactive "P")
2441 (emerge-combine-versions-internal emerge-combine-versions-template force)) 2328 (emerge-combine-versions-internal emerge-combine-versions-template force))
2442 2329
2443 (defun emerge-combine-versions-register (char &optional force) 2330 (defun emerge-combine-versions-register (char &optional force)
2444 "Combine the two versions using the template in register REG. 2331 "Combine the two versions using the template in register REG.
2445 See documentation of the variable `emerge-combine-versions-template' 2332 See documentation of the variable emerge-combine-versions-template
2446 for how the template is interpreted. 2333 for how the template is interpreted.
2447 Refuses to function if this difference has been edited, i.e., if it is 2334 Refuses to function if this difference has been edited, i.e., if it is
2448 neither the A nor the B variant. 2335 neither the A nor the B variant.
2449 An argument forces the variant to be selected even if the difference has 2336 An ARGUMENT forces the variant to be selected even if the difference has
2450 been edited." 2337 been edited."
2451 (interactive "cRegister containing template: \nP") 2338 (interactive "cRegister containing template: \nP")
2452 (let ((template (get-register char))) 2339 (let ((template (get-register char)))
2453 (if (not (stringp template)) 2340 (if (not (stringp template))
2454 (error "Register does not contain text")) 2341 (error "Register does not contain text"))
2482 (cond ((= c ?a) 2369 (cond ((= c ?a)
2483 (insert-buffer-substring emerge-A-buffer A-begin A-end)) 2370 (insert-buffer-substring emerge-A-buffer A-begin A-end))
2484 ((= c ?b) 2371 ((= c ?b)
2485 (insert-buffer-substring emerge-B-buffer B-begin B-end)) 2372 (insert-buffer-substring emerge-B-buffer B-begin B-end))
2486 ((= c ?%) 2373 ((= c ?%)
2487 (insert ?%)) 2374 (insert ?%)
2488 (t 2375 (t
2489 (insert c)))) 2376 (insert c)))))
2490 (insert c))) 2377 (insert c)))
2491 (setq i (1+ i)))) 2378 (setq i (1+ i))))
2492 (goto-char merge-begin) 2379 (goto-char merge-begin)
2493 (aset diff-vector 6 'combined) 2380 (aset diff-vector 6 'combined)
2494 (emerge-refresh-mode-line))) 2381 (emerge-refresh-mode-line)))
2495 2382
2496 (defun emerge-set-merge-mode (mode) 2383 (defun emerge-set-merge-mode (mode)
2497 "Set the major mode in a merge buffer. 2384 "Set the major mode in a merge buffer. Overrides any change that the mode
2498 Overrides any change that the mode might make to the mode line or local 2385 might make to the mode line or local keymap. Leaves merge in fast mode."
2499 keymap. Leaves merge in fast mode."
2500 (interactive 2386 (interactive
2501 (list (intern (completing-read "New major mode for merge buffer: " 2387 (list (intern (completing-read "New major mode for merge buffer: "
2502 obarray 'commandp t nil)))) 2388 obarray 'commandp t nil))))
2503 (funcall mode) 2389 (funcall mode)
2504 (emerge-refresh-mode-line) 2390 (emerge-refresh-mode-line)
2514 ;;; Support routines 2400 ;;; Support routines
2515 2401
2516 ;; Select a difference by placing the visual flags around the appropriate 2402 ;; Select a difference by placing the visual flags around the appropriate
2517 ;; group of lines in the A, B, and merge buffers 2403 ;; group of lines in the A, B, and merge buffers
2518 (defun emerge-select-difference (n) 2404 (defun emerge-select-difference (n)
2519 (let ((diff-vector (aref emerge-difference-list n))) 2405 (let ((emerge-globalized-difference-list emerge-difference-list)
2520 (emerge-place-flags-in-buffer emerge-A-buffer 2406 (emerge-globalized-number-of-differences emerge-number-of-differences))
2521 (aref diff-vector 0) (aref diff-vector 1)) 2407 (emerge-place-flags-in-buffer emerge-A-buffer n 0 1)
2522 (emerge-place-flags-in-buffer emerge-B-buffer 2408 (emerge-place-flags-in-buffer emerge-B-buffer n 2 3)
2523 (aref diff-vector 2) (aref diff-vector 3)) 2409 (emerge-place-flags-in-buffer nil n 4 5))
2524 (emerge-place-flags-in-buffer emerge-merge-buffer 2410 (run-hooks 'emerge-select-hooks))
2525 (aref diff-vector 4) (aref diff-vector 5)))) 2411
2526 2412 (defun emerge-place-flags-in-buffer (buffer difference before-index
2527 (defun emerge-place-flags-in-buffer (buffer before after) 2413 after-index)
2528 (if (eq buffer emerge-merge-buffer) 2414 (if buffer
2529 (emerge-place-flags-in-buffer1 buffer before after) 2415 (emerge-eval-in-buffer
2530 (emerge-eval-in-buffer 2416 buffer
2531 buffer 2417 (emerge-place-flags-in-buffer1 difference before-index after-index))
2532 (emerge-place-flags-in-buffer1 buffer before after)))) 2418 (emerge-place-flags-in-buffer1 difference before-index after-index)))
2533 2419
2534 (defun emerge-place-flags-in-buffer1 (buffer before after) 2420 (defun emerge-place-flags-in-buffer1 (difference before-index after-index)
2535 (let ((buffer-read-only nil)) 2421 (let ((buffer-read-only nil))
2536 ;; insert the flags 2422 ;; insert the flag before the difference
2537 (goto-char before) 2423 (let ((before (aref (aref emerge-globalized-difference-list difference)
2538 (insert-before-markers emerge-before-flag) 2424 before-index))
2539 (goto-char after) 2425 here)
2540 (insert emerge-after-flag) 2426 (goto-char before)
2541 ;; put the markers into the flags, so alterations above or below won't move 2427 ;; insert the flag itself
2542 ;; them 2428 (insert-before-markers emerge-before-flag)
2543 ;; before marker is one char before the end of the before flag 2429 (setq here (point))
2544 ;; after marker is one char after the beginning of the after flag 2430 ;; Put the marker(s) referring to this position 1 character before the
2545 (set-marker before (1- before)) 2431 ;; end of the flag, so it won't be damaged by the user.
2546 (set-marker after (1+ after)))) 2432 ;; This gets a bit tricky, as there could be a number of markers
2433 ;; that have to be moved.
2434 (set-marker before (1- before))
2435 (let ((n (1- difference)) after-marker before-marker diff-list)
2436 (while (and
2437 (>= n 0)
2438 (progn
2439 (setq diff-list (aref emerge-globalized-difference-list n)
2440 after-marker (aref diff-list after-index))
2441 (= after-marker here)))
2442 (set-marker after-marker (1- after-marker))
2443 (setq before-marker (aref diff-list before-index))
2444 (if (= before-marker here)
2445 (setq before-marker (1- before-marker)))
2446 (setq n (1- n)))))
2447 ;; insert the flag after the difference
2448 (let* ((after (aref (aref emerge-globalized-difference-list difference)
2449 after-index))
2450 (here (marker-position after)))
2451 (goto-char here)
2452 ;; insert the flag itself
2453 (insert emerge-after-flag)
2454 ;; Put the marker(s) referring to this position 1 character after the
2455 ;; beginning of the flag, so it won't be damaged by the user.
2456 ;; This gets a bit tricky, as there could be a number of markers
2457 ;; that have to be moved.
2458 (set-marker after (1+ after))
2459 (let ((n (1+ difference)) before-marker after-marker diff-list)
2460 (while (and
2461 (< n emerge-globalized-number-of-differences)
2462 (progn
2463 (setq diff-list (aref emerge-globalized-difference-list n)
2464 before-marker (aref diff-list before-index))
2465 (= before-marker here)))
2466 (set-marker before-marker (1+ before-marker))
2467 (setq after-marker (aref diff-list after-index))
2468 (if (= after-marker here)
2469 (setq after-marker (1+ after-marker)))
2470 (setq n (1+ n)))))))
2547 2471
2548 ;; Unselect a difference by removing the visual flags in the buffers. 2472 ;; Unselect a difference by removing the visual flags in the buffers.
2549 (defun emerge-unselect-difference (n) 2473 (defun emerge-unselect-difference (n)
2550 (let ((diff-vector (aref emerge-difference-list n))) 2474 (let ((diff-vector (aref emerge-difference-list n)))
2551 (emerge-remove-flags-in-buffer emerge-A-buffer 2475 (emerge-remove-flags-in-buffer emerge-A-buffer
2552 (aref diff-vector 0) (aref diff-vector 1)) 2476 (aref diff-vector 0) (aref diff-vector 1))
2553 (emerge-remove-flags-in-buffer emerge-B-buffer 2477 (emerge-remove-flags-in-buffer emerge-B-buffer
2554 (aref diff-vector 2) (aref diff-vector 3)) 2478 (aref diff-vector 2) (aref diff-vector 3))
2555 (emerge-remove-flags-in-buffer emerge-merge-buffer 2479 (emerge-remove-flags-in-buffer emerge-merge-buffer
2556 (aref diff-vector 4) (aref diff-vector 5)))) 2480 (aref diff-vector 4) (aref diff-vector 5)))
2481 (run-hooks 'emerge-unselect-hooks))
2557 2482
2558 (defun emerge-remove-flags-in-buffer (buffer before after) 2483 (defun emerge-remove-flags-in-buffer (buffer before after)
2559 (emerge-eval-in-buffer 2484 (emerge-eval-in-buffer
2560 buffer 2485 buffer
2561 (let ((buffer-read-only nil)) 2486 (let ((buffer-read-only nil))
2562 ;; put the markers at the beginning of the flags 2487 ;; remove the flags, if they're there
2563 (set-marker before (- before (1- emerge-before-flag-length))) 2488 (goto-char (- before (1- emerge-before-flag-length)))
2564 (set-marker after (1- after))
2565 ;; remove the flags
2566 (goto-char before)
2567 (if (looking-at emerge-before-flag-match) 2489 (if (looking-at emerge-before-flag-match)
2568 (delete-char emerge-before-flag-length) 2490 (delete-char emerge-before-flag-length)
2569 ;; the flag isn't there 2491 ;; the flag isn't there
2570 (ding) 2492 (ding)
2571 (message "Trouble removing flag.")) 2493 (message "Trouble removing flag."))
2572 (goto-char after) 2494 (goto-char (1- after))
2573 (if (looking-at emerge-after-flag-match) 2495 (if (looking-at emerge-after-flag-match)
2574 (delete-char emerge-after-flag-length) 2496 (delete-char emerge-after-flag-length)
2575 ;; the flag isn't there 2497 ;; the flag isn't there
2576 (ding) 2498 (ding)
2577 (message "Trouble removing flag."))))) 2499 (message "Trouble removing flag.")))))
2578 2500
2579 ;; Select a difference, removing an flags that exist now. 2501 ;; Select a difference, removing any flags that exist now.
2580 (defun emerge-unselect-and-select-difference (n &optional suppress-display) 2502 (defun emerge-unselect-and-select-difference (n &optional suppress-display)
2581 (if (and (>= emerge-current-difference 0) 2503 (if (and (>= emerge-current-difference 0)
2582 (< emerge-current-difference emerge-number-of-differences)) 2504 (< emerge-current-difference emerge-number-of-differences))
2583 (emerge-unselect-difference emerge-current-difference)) 2505 (emerge-unselect-difference emerge-current-difference))
2584 (if (and (>= n 0) (< n emerge-number-of-differences)) 2506 (if (and (>= n 0) (< n emerge-number-of-differences))
2624 emerge-merge-buffer merge-begin 2546 emerge-merge-buffer merge-begin
2625 merge-end) 2547 merge-end)
2626 (funcall b-version) 2548 (funcall b-version)
2627 (if (or force (= merge-begin merge-end)) 2549 (if (or force (= merge-begin merge-end))
2628 (funcall neither-version) 2550 (funcall neither-version)
2629 (error "This difference region has been edited."))))))) 2551 (error "This difference region has been edited")))))))
2552
2553 ;; Read a file name, handling all of the various defaulting rules.
2554
2555 (defun emerge-read-file-name (prompt alternative-default-dir default-file
2556 A-file)
2557 ;; 'prompt' should not have trailing ": ", so that it can be modified
2558 ;; according to context.
2559 ;; If alternative-default-dir is non-nil, it should be used as the default
2560 ;; directory instead if default-directory, if emerge-default-last-directories
2561 ;; is set.
2562 ;; If default-file is set, it should be used as the default value.
2563 ;; If A-file is set, and its directory is different from
2564 ;; alternative-default-dir, and if emerge-default-last-directories is set,
2565 ;; the default file should be the last part of A-file in the default
2566 ;; directory. (Overriding default-file.)
2567 (cond
2568 ;; If this is not the A-file argument (shown by non-nil A-file), and
2569 ;; if emerge-default-last-directories is set, and
2570 ;; the default directory exists but is not the same as the directory of the
2571 ;; A-file,
2572 ;; then make the default file have the same name as the A-file, but in
2573 ;; the default directory.
2574 ((and emerge-default-last-directories
2575 A-file
2576 alternative-default-dir
2577 (not (string-equal alternative-default-dir
2578 (file-name-directory A-file))))
2579 (read-file-name (format "%s (default %s): "
2580 prompt (file-name-nondirectory A-file))
2581 alternative-default-dir
2582 (concat alternative-default-dir
2583 (file-name-nondirectory A-file))
2584 'confirm))
2585 ;; If there is a default file, use it.
2586 (default-file
2587 (read-file-name (format "%s (default %s): " prompt default-file)
2588 ;; If emerge-default-last-directories is set, use the
2589 ;; directory from the same argument of the last call of
2590 ;; Emerge as the default for this argument.
2591 (and emerge-default-last-directories
2592 alternative-default-dir)
2593 default-file 'confirm))
2594 (t
2595 (read-file-name (concat prompt ": ")
2596 ;; If emerge-default-last-directories is set, use the
2597 ;; directory from the same argument of the last call of
2598 ;; Emerge as the default for this argument.
2599 (and emerge-default-last-directories
2600 alternative-default-dir)
2601 nil 'confirm))))
2630 2602
2631 ;; Revise the mode line to display which difference we have selected 2603 ;; Revise the mode line to display which difference we have selected
2632 2604
2633 (defun emerge-refresh-mode-line () 2605 (defun emerge-refresh-mode-line ()
2634 (setq mode-line-buffer-identification 2606 (setq mode-line-buffer-identification
2726 2698
2727 ;;; Functions that query the user before he can write out the current buffer. 2699 ;;; Functions that query the user before he can write out the current buffer.
2728 2700
2729 (defun emerge-query-write-file () 2701 (defun emerge-query-write-file ()
2730 "Query the user if he really wants to write out the incomplete merge. 2702 "Query the user if he really wants to write out the incomplete merge.
2731 If he says yes, call `write-file' to do so. See `emerge-query-and-call' 2703 If he says yes, call write-file to do so. See emerge-query-and-call
2732 for details of the querying process." 2704 for details of the querying process."
2733 (interactive) 2705 (interactive)
2734 (emerge-query-and-call 'write-file)) 2706 (emerge-query-and-call 'write-file))
2735 2707
2736 (defun emerge-query-save-buffer () 2708 (defun emerge-query-save-buffer ()
2737 "Query the user if he really wants to write out the incomplete merge. 2709 "Query the user if he really wants to write out the incomplete merge.
2738 If he says yes, call `save-buffer' to do so. See `emerge-query-and-call' 2710 If he says yes, call save-buffer to do so. See emerge-query-and-call
2739 for details of the querying process." 2711 for details of the querying process."
2740 (interactive) 2712 (interactive)
2741 (emerge-query-and-call 'save-buffer)) 2713 (emerge-query-and-call 'save-buffer))
2742 2714
2743 (defun emerge-query-and-call (command) 2715 (defun emerge-query-and-call (command)
2782 (error "Buffer out of sync for file %s" buffer-file-name) 2754 (error "Buffer out of sync for file %s" buffer-file-name)
2783 ;; If buffer is obsolete and is not modified, offer to revert 2755 ;; If buffer is obsolete and is not modified, offer to revert
2784 (if (yes-or-no-p (format "Revert file %s? " buffer-file-name)) 2756 (if (yes-or-no-p (format "Revert file %s? " buffer-file-name))
2785 (revert-buffer t t) 2757 (revert-buffer t t)
2786 (error "Buffer out of sync for file %s" buffer-file-name))))) 2758 (error "Buffer out of sync for file %s" buffer-file-name)))))
2759
2760 ;; Returns true if the file visited in the current buffer is not accessible
2761 ;; through its filename, or for some other reason should be stored in a
2762 ;; temporary file for input to diff.
2763 ;; As written, checks whether this is an ange-ftp file. It may be modified
2764 ;; for customization.
2765 (defun emerge-remote-file-p ()
2766 (and (boundp 'ange-ftp-path-format)
2767 ange-ftp-path-format
2768 (string-match (car ange-ftp-path-format) buffer-file-name)))
2787 2769
2788 ;; Utilities that might have value outside of Emerge. 2770 ;; Utilities that might have value outside of Emerge.
2789 2771
2790 ;; Set up the mode in the current buffer to duplicate the mode in another 2772 ;; Set up the mode in the current buffer to duplicate the mode in another
2791 ;; buffer. 2773 ;; buffer.
2793 ;; Set the major mode 2775 ;; Set the major mode
2794 (funcall (emerge-eval-in-buffer buffer major-mode))) 2776 (funcall (emerge-eval-in-buffer buffer major-mode)))
2795 2777
2796 ;; Define a key, even if a prefix of it is defined 2778 ;; Define a key, even if a prefix of it is defined
2797 (defun emerge-force-define-key (keymap key definition) 2779 (defun emerge-force-define-key (keymap key definition)
2798 "Like `define-key', but isn't stopped if a prefix of KEY is a defined 2780 "Like define-key, but is not stopped if a prefix of KEY is a defined
2799 command." 2781 command."
2800 ;; Find out if a prefix of key is defined 2782 ;; Find out if a prefix of key is defined
2801 (let ((v (lookup-key keymap key))) 2783 (let ((v (lookup-key keymap key)))
2802 ;; If so, undefine it 2784 ;; If so, undefine it
2803 (if (integerp v) 2785 (if (integerp v)
2810 (defun describe-mode (&optional minor) 2792 (defun describe-mode (&optional minor)
2811 "Display documentation of current major mode. 2793 "Display documentation of current major mode.
2812 If optional MINOR is non-nil (or prefix argument is given if interactive), 2794 If optional MINOR is non-nil (or prefix argument is given if interactive),
2813 display documentation of acive minor modes as well. 2795 display documentation of acive minor modes as well.
2814 For this to work correctly for a minor mode, the mode's indicator variable 2796 For this to work correctly for a minor mode, the mode's indicator variable
2815 (listed in `minor-mode-alist') must also be a function whose documentation 2797 (listed in minor-mode-alist) must also be a function whose documentation
2816 describes the minor mode." 2798 describes the minor mode."
2817 (interactive) 2799 (interactive)
2818 (with-output-to-temp-buffer "*Help*" 2800 (with-output-to-temp-buffer "*Help*"
2819 (princ mode-name) 2801 (princ mode-name)
2820 (princ " Mode:\n") 2802 (princ " Mode:\n")
2885 ;; if there is no present definition, define it 2867 ;; if there is no present definition, define it
2886 (if (not present) 2868 (if (not present)
2887 (define-key keymap key definition))))) 2869 (define-key keymap key definition)))))
2888 2870
2889 (defun emerge-recursively-substitute-key-definition (olddef newdef keymap) 2871 (defun emerge-recursively-substitute-key-definition (olddef newdef keymap)
2890 "Like `substitute-key-definition', but examines and substitutes in all 2872 "Like substitute-key-definition, but examines and substitutes in all
2891 keymaps accessible from KEYMAP. Make sure that subordinate keymaps aren't 2873 keymaps accessible from KEYMAP. Make sure that subordinate keymaps aren't
2892 shared with other keymaps! (`copy-keymap' will suffice.)" 2874 shared with other keymaps! (copy-keymap will suffice.)"
2893 ;; Loop through all keymaps accessible from keymap 2875 ;; Loop through all keymaps accessible from keymap
2894 (let ((maps (accessible-keymaps keymap))) 2876 (let ((maps (accessible-keymaps keymap)))
2895 (while maps 2877 (while maps
2896 ;; Substitute in this keymap 2878 ;; Substitute in this keymap
2897 (substitute-key-definition olddef newdef (cdr (car maps))) 2879 (substitute-key-definition olddef newdef (cdr (car maps)))
2912 (erase-buffer) 2894 (erase-buffer)
2913 (insert name) 2895 (insert name)
2914 (if (not (pos-visible-in-window-p)) 2896 (if (not (pos-visible-in-window-p))
2915 (let ((echo-keystrokes 0)) 2897 (let ((echo-keystrokes 0))
2916 (while (and (not (pos-visible-in-window-p)) 2898 (while (and (not (pos-visible-in-window-p))
2917 (> (1- (frame-height)) (window-height))) 2899 (> (1- (screen-height)) (window-height)))
2918 (enlarge-window 1)) 2900 (enlarge-window 1))
2919 (let ((c (read-event))) 2901 (let ((c (read-char)))
2920 (if (not (eq c 32)) 2902 (if (/= c 32)
2921 (setq unread-command-events (list c))))))))) 2903 (setq unread-command-char c))))))))
2922 2904
2923 ;; Improved auto-save file names. 2905 ;; Improved auto-save file names.
2924 ;; This function fixes many problems with the standard auto-save file names: 2906 ;; This function fixes many problems with the standard auto-save file names:
2925 ;; Auto-save files for non-file buffers get put in the default directory 2907 ;; Auto-save files for non-file buffers get put in the default directory
2926 ;; for the buffer, whether that makes sense or not. 2908 ;; for the buffer, whether that makes sense or not.
2995 "\\\\") 2977 "\\\\")
2996 (substring s (match-end 0)))) 2978 (substring s (match-end 0))))
2997 (setq limit (1+ (match-end 0))))) 2979 (setq limit (1+ (match-end 0)))))
2998 s) 2980 s)
2999 2981
3000 (provide 'emerge) 2982 ;; Metacharacters that have to be protected from the shell when executing
3001 2983 ;; a diff/diff3 command.
3002 ;;; emerge.el ends here 2984 (defvar emerge-metachars "[ \t\n!\"#$&'()*;<=>?[\\^`{|~]"
2985 "Characters that must be quoted with \\ when used in a shell command
2986 line, specified as a [...] regexp.")
2987
2988 ;; Quote metacharacters (using \) when executing a diff/diff3 command.
2989 (defun emerge-protect-metachars (s)
2990 (let ((limit 0))
2991 (while (string-match emerge-metachars s limit)
2992 (setq s (concat (substring s 0 (match-beginning 0))
2993 "\\"
2994 (substring s (match-beginning 0))))
2995 (setq limit (1+ (match-end 0)))))
2996 s)
2997