aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1993-05-13 19:24:38 +0000
committerRichard M. Stallman1993-05-13 19:24:38 +0000
commit151e4b9ca8a693ed79d29f66be463392d4077d57 (patch)
tree79acb571d16c6fcc0d13b8b3262e4ccdc8cdf517
parent36bed8bc8c065de1d27b73cb03222db46da6b43f (diff)
downloademacs-151e4b9ca8a693ed79d29f66be463392d4077d57.tar.gz
emacs-151e4b9ca8a693ed79d29f66be463392d4077d57.zip
Install DRW's version 5.
-rw-r--r--lisp/emerge.el1527
1 files changed, 761 insertions, 766 deletions
diff --git a/lisp/emerge.el b/lisp/emerge.el
index 77eac433200..a9e76098f55 100644
--- a/lisp/emerge.el
+++ b/lisp/emerge.el
@@ -1,575 +1,34 @@
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.
572Differs from `save-excursion' in that it doesn't save the point and mark." 31Differs 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
@@ -578,11 +37,10 @@ Differs from `save-excursion' in that it doesn't save the point and mark."
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
582Performs a defvar, then executes `make-variable-buffer-local' on 41executes make-variable-buffer-local on the variable. Also sets the
583the 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) 43setting commands) won't destroy Emerge control variables."
585won'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))
@@ -600,28 +58,28 @@ won't destroy Emerge control variables."
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
604It is entered only through one of the functions: 62through 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
614Commands: 72Commands:
615\\{emerge-basic-keymap} 73\\{emerge-basic-keymap}
616Commands must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode, but can be invoked directly 74Commands must be prefixed by \\<emerge-fast-keymap>\\[emerge-basic-keymap] in 'edit' mode, but can be invoked directly
617in 'fast' mode.") 75in '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,
624When called interactively, displays the version." 82displays 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))
@@ -660,14 +118,66 @@ Lines that do not match are assumed to be error output.")
660 "*Regexp that matches normal output lines from emerge-diff3-program . 118 "*Regexp that matches normal output lines from emerge-diff3-program .
661Lines that do not match are assumed to be error output.") 119Lines 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
128merge buffers. (The local-variables list can be processed manually by
129executing \"(hack-local-variables)\".)")
130(defvar emerge-execute-line-deletions nil
131 "*If non-nil: When emerge-execute-line discovers a situation which
132appears to show that a file has been deleted from one version of the
133files being merged (when an ancestor entry is present, only one
134A or B entry is present, and an output entry is present), no output
135file will be created.
136If nil: In such circumstances, the A or B file that is present will be
137copied 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).
156If non-nil, filenames complete in the directory of the last argument of the
157same 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
669This is called after these functions are changed to compute values that 180compute values that depend on the flags."
670depend 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"))
@@ -879,29 +389,57 @@ 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
881skipped.") 391skipped.")
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.
886emerge-prefix-argument will be bound to the prefix argument of the emerge-quit 394emerge-prefix-argument will be bound to the prefix argument of the emerge-quit
887command. 395command.
888This is not a user option, since Emerge uses it for its own processing.") 396This 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
399emerge-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
@@ -937,10 +475,11 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -951,7 +490,9 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1015,19 +556,61 @@ This is not a user option, since Emerge uses it for its own processing.")
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)))
@@ -1067,12 +650,13 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1084,7 +668,9 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1103,11 +689,8 @@ This is not a user option, since Emerge uses it for its own processing.")
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)
@@ -1145,19 +728,18 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1166,20 +748,20 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1196,7 +778,6 @@ This is not a user option, since Emerge uses it for its own processing.")
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: ")
@@ -1210,14 +791,13 @@ This is not a user option, since Emerge uses it for its own processing.")
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)
@@ -1241,18 +821,17 @@ This is not a user option, since Emerge uses it for its own processing.")
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))
@@ -1262,7 +841,6 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1290,7 +868,6 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1299,7 +876,6 @@ This is not a user option, since Emerge uses it for its own processing.")
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
@@ -1313,6 +889,317 @@ This is not a user option, since Emerge uses it for its own processing.")
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)))
1315 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
918the 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
1029seperated by whitespace. Based on entries found, call emerge correctly
1030on the files files listed.
1031
1032In addition, if only one of \"a=file\" or \"b=file\" is present, and \"output=file\"
1033is present:
1034If emerge-execute-line-deletions is non-nil and \"ancestor=file\" is present,
1035it is assumed that the file in question has been deleted, and it is
1036not copied to the output file.
1037Otherwise, 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")))))
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
@@ -1375,10 +1262,9 @@ This is not a user option, since Emerge uses it for its own processing.")
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
1379Must be called in the merge buffer. Remembers read-only, modified, 1266buffers being merged (read-only, modified, auto-save), and saves them in
1380auto-save, and saves them in buffer local variables. Sets the buffers 1267buffer local variables. Sets the buffers read-only and turns off auto-save.
1381read-only and turns off `auto-save-mode'.
1382These characteristics are restored by emerge-restore-buffer-characteristics." 1268These 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
@@ -1435,6 +1321,8 @@ emerge-remember-buffer-characteristics."
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))
@@ -1486,6 +1374,15 @@ emerge-remember-buffer-characteristics."
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)
@@ -1505,9 +1402,9 @@ emerge-remember-buffer-characteristics."
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,
1509This brings the buffers into view if they are in windows. 1406if they are in windows. If an ARGUMENT is given, the default three-window
1510If an ARGUMENT is given, the default three-window display is reestablished." 1407display 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
@@ -1638,7 +1535,7 @@ size of the merge window."
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.
1640If an ARGUMENT is given, that is how many columns are scrolled, else nearly 1537If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1641the width of the A and B windows. C-u - alone as argument scrolls half the 1538the width of the A and B windows. `C-u -' alone as argument scrolls half the
1642width of the A and B windows." 1539width of the A and B windows."
1643 (interactive "P") 1540 (interactive "P")
1644 (emerge-operate-on-windows 1541 (emerge-operate-on-windows
@@ -1666,7 +1563,7 @@ width of the A and B windows."
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.
1668If an ARGUMENT is given, that is how many columns are scrolled, else nearly 1565If an ARGUMENT is given, that is how many columns are scrolled, else nearly
1669the width of the A and B windows. C-u - alone as argument scrolls half the 1566the width of the A and B windows. `C-u -' alone as argument scrolls half the
1670width of the A and B windows." 1567width of the A and B windows."
1671 (interactive "P") 1568 (interactive "P")
1672 (emerge-operate-on-windows 1569 (emerge-operate-on-windows
@@ -1692,9 +1589,8 @@ width of the A and B windows."
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,
1696This resets the horizontal scrolling of all three merge buffers 1593if they are in windows."
1697to 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)))
@@ -1723,8 +1619,7 @@ to the left margin, if they are in windows."
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
@@ -1777,9 +1672,8 @@ to the left margin, if they are in windows."
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
1781Prefix argument means to abort rather than successfully finish. 1676successfully finish. The difference depends on how the merge was started,
1782The difference depends on how the merge was started,
1783but usually means to not write over one of the original files, or to signal 1677but usually means to not write over one of the original files, or to signal
1784to some process which invoked Emerge a failure code. 1678to some process which invoked Emerge a failure code.
1785 1679
@@ -1824,12 +1718,11 @@ buffer after this will cause serious problems."
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
1831Refuses to function if this difference has been edited, i.e., if it 1725difference has been edited, i.e., if it is neither the A nor the B variant.
1832is neither the A nor the B variant.
1833An ARGUMENT forces the variant to be selected even if the difference has 1726An ARGUMENT forces the variant to be selected even if the difference has
1834been edited." 1727been edited."
1835 (interactive "P") 1728 (interactive "P")
@@ -1856,9 +1749,9 @@ been edited."
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
1860Refuses to function if this difference has been edited, i.e., if it 1753difference has been edited, i.e., if it is neither the A nor the B variant.
1861is neither the A nor the B variant. An ARGUMENT forces the variant to be selected even if the difference has 1754An ARGUMENT forces the variant to be selected even if the difference has
1862been edited." 1755been edited."
1863 (interactive "P") 1756 (interactive "P")
1864 (let ((operate 1757 (let ((operate
@@ -1884,8 +1777,7 @@ been edited."
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
1888This selects the A variant for all differences from here down in the buffer
1889which are still defaulted, i.e., which the user has not selected and for 1781which are still defaulted, i.e., which the user has not selected and for
1890which there is no preference." 1782which there is no preference."
1891 (interactive) 1783 (interactive)
@@ -1906,8 +1798,7 @@ which there is no preference."
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
1910This selects the B variant for all differences from here down in the buffer
1911which are still defaulted, i.e., which the user has not selected and for 1802which are still defaulted, i.e., which the user has not selected and for
1912which there is no preference." 1803which there is no preference."
1913 (interactive) 1804 (interactive)
@@ -1928,9 +1819,8 @@ which there is no preference."
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
1932In this mode ordinary Emacs commands are disabled, and Emerge commands 1823commands are need not be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1933are 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)
@@ -1942,9 +1832,8 @@ are need not be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
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
1946In this mode ordinary Emacs commands are available, and Emerge commands 1836commands must be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
1947must 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)
@@ -1956,11 +1845,11 @@ must be prefixed with \\<emerge-fast-keymap>\\[emerge-basic-keymap]."
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
1960This mode causes `emerge-select-A' and `emerge-select-B' to automatically 1849 emerge-select-B to automatically advance to the next difference. (See
1961advance to the next difference. (See `emerge-auto-advance'.) 1850emerge-auto-advance.)
1962If a positive ARGUMENT is given, it turns on `auto-advance-mode'. 1851If a positive ARGUMENT is given, it turns on auto-advance mode.
1963If a negative ARGUMENT is given, it turns off `auto-advance-mode'." 1852If 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)
@@ -1972,12 +1861,11 @@ If a negative ARGUMENT is given, it turns off `auto-advance-mode'."
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
1976This mode causes `emerge-next-difference' and `emerge-previous-difference' 1865 emerge-previous-difference to automatically skip over differences for which
1977to automatically skip over differences for which there is a preference. 1866there is a preference. (See emerge-skip-prefers.)
1978(See `emerge-skip-prefers'.) If a positive ARG is given, it turns on 1867If a positive ARGUMENT is given, it turns on skip-prefers mode.
1979`skip-prefers' mode. 1868If a negative ARGUMENT is given, it turns off skip-prefers mode."
1980If 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)
@@ -2070,10 +1958,10 @@ With prefix argument, puts mark before, point after."
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.
2073Use C-u l to reset the windows afterward." 1961Use ^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)
@@ -2110,8 +1998,8 @@ Use C-u l to reset the windows afterward."
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
2114With a prefix argument, join with the preceeding one." 2002argument, 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
@@ -2225,10 +2113,9 @@ With a prefix argument, join with the preceeding one."
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
2229If lines are the same in both the A and the B versions, strip them off. 2117both 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 2118have common lines that the ancestor version does not share.)"
2231ancestor 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)
@@ -2324,8 +2211,8 @@ the nearest previous difference."
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
2328This command must be executed in the merge buffer. 2215A buffer. (Nonetheless, this command must be executed in the merge buffer.)
2329If there is no containing difference and the prefix argument is positive, 2216If there is no containing difference and the prefix argument is positive,
2330it finds the nearest following difference. A negative prefix argument finds 2217it finds the nearest following difference. A negative prefix argument finds
2331the nearest previous difference." 2218the nearest previous difference."
@@ -2337,8 +2224,8 @@ the nearest previous difference."
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
2341This command must be executed in the merge buffer. 2228B buffer. (Nonetheless, this command must be executed in the merge buffer.)
2342If there is no containing difference and the prefix argument is positive, 2229If there is no containing difference and the prefix argument is positive,
2343it finds the nearest following difference. A negative prefix argument finds 2230it finds the nearest following difference. A negative prefix argument finds
2344the nearest previous difference." 2231the nearest previous difference."
@@ -2387,8 +2274,7 @@ the nearest previous difference."
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
2391This function displays the line numbers of the points in the A, B, and
2392merge buffers." 2278merge buffers."
2393 (interactive) 2279 (interactive)
2394 (let* ((valid-diff 2280 (let* ((valid-diff
@@ -2418,9 +2304,9 @@ merge buffers."
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
2422This controls how `emerge-combine-versions' will combine the two versions. 2308emerge-combine-versions will combine the two versions.
2423With prefix argument, `emerge-combine-versions' is made local to this 2309With prefix argument, emerge-combine-versions is made local to this
2424merge buffer. Localization is permanent for any particular merge buffer." 2310merge buffer. Localization is permanent for any particular merge buffer."
2425 (interactive "r\nP") 2311 (interactive "r\nP")
2426 (if localize 2312 (if localize
@@ -2432,21 +2318,22 @@ merge buffer. Localization is permanent for any particular merge buffer."
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
2322emerge-combine-versions-template.
2436Refuses to function if this difference has been edited, i.e., if it is 2323Refuses to function if this difference has been edited, i.e., if it is
2437neither the A nor the B variant. 2324neither the A nor the B variant.
2438An argument forces the variant to be selected even if the difference has 2325An ARGUMENT forces the variant to be selected even if the difference has
2439been edited." 2326been 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.
2445See documentation of the variable `emerge-combine-versions-template' 2332See documentation of the variable emerge-combine-versions-template
2446for how the template is interpreted. 2333for how the template is interpreted.
2447Refuses to function if this difference has been edited, i.e., if it is 2334Refuses to function if this difference has been edited, i.e., if it is
2448neither the A nor the B variant. 2335neither the A nor the B variant.
2449An argument forces the variant to be selected even if the difference has 2336An ARGUMENT forces the variant to be selected even if the difference has
2450been edited." 2337been 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)))
@@ -2484,9 +2371,9 @@ been edited."
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)
@@ -2494,9 +2381,8 @@ been edited."
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
2498Overrides any change that the mode might make to the mode line or local 2385might make to the mode line or local keymap. Leaves merge in fast mode."
2499keymap. 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))))
@@ -2516,34 +2402,72 @@ keymap. Leaves merge in fast mode."
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)
@@ -2553,30 +2477,28 @@ keymap. Leaves merge in fast mode."
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))
@@ -2626,7 +2548,57 @@ keymap. Leaves merge in fast mode."
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
@@ -2728,14 +2700,14 @@ keymap. Leaves merge in fast mode."
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.
2731If he says yes, call `write-file' to do so. See `emerge-query-and-call' 2703If he says yes, call write-file to do so. See emerge-query-and-call
2732for details of the querying process." 2704for 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.
2738If he says yes, call `save-buffer' to do so. See `emerge-query-and-call' 2710If he says yes, call save-buffer to do so. See emerge-query-and-call
2739for details of the querying process." 2711for details of the querying process."
2740 (interactive) 2712 (interactive)
2741 (emerge-query-and-call 'save-buffer)) 2713 (emerge-query-and-call 'save-buffer))
@@ -2784,6 +2756,16 @@ around the current difference are removed."
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
@@ -2795,7 +2777,7 @@ around the current difference are removed."
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
2799command." 2781command."
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)))
@@ -2812,7 +2794,7 @@ command."
2812If optional MINOR is non-nil (or prefix argument is given if interactive), 2794If optional MINOR is non-nil (or prefix argument is given if interactive),
2813display documentation of acive minor modes as well. 2795display documentation of acive minor modes as well.
2814For this to work correctly for a minor mode, the mode's indicator variable 2796For 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
2816describes the minor mode." 2798describes the minor mode."
2817 (interactive) 2799 (interactive)
2818 (with-output-to-temp-buffer "*Help*" 2800 (with-output-to-temp-buffer "*Help*"
@@ -2887,9 +2869,9 @@ including those whose definition is OLDDEF."
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
2891keymaps accessible from KEYMAP. Make sure that subordinate keymaps aren't 2873keymaps accessible from KEYMAP. Make sure that subordinate keymaps aren't
2892shared with other keymaps! (`copy-keymap' will suffice.)" 2874shared 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
@@ -2914,11 +2896,11 @@ SPC, it is ignored; if it is anything else, it is processed as a command."
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:
@@ -2997,6 +2979,19 @@ See also auto-save-file-name-p."
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
2983;; a diff/diff3 command.
2984(defvar emerge-metachars "[ \t\n!\"#$&'()*;<=>?[\\^`{|~]"
2985 "Characters that must be quoted with \\ when used in a shell command
2986line, 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)
3001 2997
3002;;; emerge.el ends here