char Version[] = "wiggle 0.8 2010-03-24 GPL-2+ http://neil.brown.name/wiggle/\n";
-char short_options1[] = "xdmwlrhi123pVRvqB"; /* not mode B */
-char short_options2[] = "xdmwlrhi123p::VRvqB"; /* mode B */
+char short_options1[] = "xdmwlrhiW123pVRvqB"; /* not mode B */
+char short_options2[] = "xdmwlrhiW123p::VRvqB"; /* mode B */
struct option long_options[] = {
{"browse", 0, 0, 'B'},
{"quiet", 0, 0, 'q'},
{"strip", 1, 0, 'p'},
{"no-ignore", 0, 0, 'i'},
+ {"show-wiggle", 0, 0, 'W'},
{0, 0, 0, 0}
};
" --patch -p : treat last file as a patch file.\n"
" -1 -2 -3 : select which component of patch or merge to use.\n"
" --reverse -R : swap 'before' and 'after' for diff function.\n"
+" --no-ignore -i : Don't ignore already-applied changes.\n"
+" --show-wiggle -W : Report wiggles like conflicts with an extra stanza.\n"
"\n"
" --help -h : get help.\n"
" --version -V : get version of wiggle.\n"
-- --no-wiggle mode does line-mode merge, but for any conflict it adds
- a section to show what the wiggle would have looked like
- <<<<
- I found this
- |||||
- but wanted this
- ====
- and would replace it with this
- &&&&
- and my best guess is this.
- >>>>
-
- best guess only included if there is one.
- search should go to right column and highlight
- do we always recenter top when we split - what if near but not at bottom
find . -name core | xargs rm -f
list=$(find . -type f \( -name script -o -name diff -o -name ldiff \
- -o -name rediff -o -name merge -o -name wmerge -o -name lmerge -o -name replace \)
+ -o -name rediff -o -name merge -o -name wmerge -o -name lmerge \
+ -o -name replace -o -name Wmerge \)
)
for path in $list
do
else $TIME $WIGGLE -mw orig new new2 | diff -u wmerge - ; xit=$?
fi
;;
+ Wmerge ) if [ -f patch ]
+ then $TIME $WIGGLE -mW orig patch | diff -u Wmerge - ; xit=$?
+ else $TIME $WIGGLE -mW orig new new2 | diff -u Wmerge - ; xit=$?
+ fi
+ ;;
esac
if [ $xit = 0 ]; then msg=SUCCEEDED; else msg=FAILED; fi
echo $path $msg `grep -v 'Command exited' .time 2> /dev/null`
static int isolate_conflicts(struct file af, struct file bf, struct file cf,
struct csl *csl1, struct csl *csl2, int words,
- struct merge *m)
+ struct merge *m, int show_wiggles)
{
/* A conflict indicates that something is definitely wrong
* and so we need to be a bit suspicious of nearby apparent matches.
* conflict as does any part of the original before
* a newline.
*
+ * If 'show_wiggles' is set we treat wiggles like conflicts.
+ * A 'wiggle' is implied by any Extraneous text being ignored,
+ * or any line that has both Changed and Unmatched content.
+ * (Unmatched content where nothing is changed is common and not
+ * really a 'wiggle').
*/
int i, j, k;
int cnt = 0;
+ int changed = 0;
+ int unmatched = 0;
- for (i = 0; m[i].type != End; i++)
- if (m[i].type == Conflict) {
- /* We have a conflict here.
+ for (i = 0; m[i].type != End; i++) {
+ if (m[i].type == Changed)
+ changed = 1;
+ if (m[i].type == Unmatched)
+ unmatched = 1;
+ if (m[i].type == Conflict ||
+ (show_wiggles && ((changed && unmatched)
+ || m[i].type == Extraneous))) {
+ /* We have a conflict (or wiggle) here.
* First search backwards for an Unchanged marking
* things as in_conflict. Then find the
* cut-point in the Unchanged. If there isn't one,
break;
}
}
-#if 0
- if (j >= 0 && m[j].in_conflict && m[j].type == Unchanged &&
- m[j].hi == m[j].lo) {
- /* nothing to separate conflicts, merge them */
- m[j].lo = 0;
- m[j].hi = -1;
- cnt--;
- }
-#endif
+
/* now the forward search */
for (j = i+1; m[j].type != End; j++) {
m[j].in_conflict = 1;
}
i = j - 1;
}
+ if (ends_line(af.list[m[i].a+m[i].al-1])) {
+ unmatched = 0;
+ changed = 0;
+ }
+ }
return cnt;
}
struct ci make_merger(struct file af, struct file bf, struct file cf,
struct csl *csl1, struct csl *csl2, int words,
- int ignore_already)
+ int ignore_already, int show_wiggles)
{
/* find the wiggles and conflicts between csl1 and csl2
*/
}
rv.merger[i].type = End;
rv.merger[i].in_conflict = 0;
- rv.conflicts = isolate_conflicts(af, bf, cf, csl1, csl2, words, rv.merger);
+ rv.conflicts = isolate_conflicts(af, bf, cf, csl1, csl2, words,
+ rv.merger, show_wiggles);
if (wiggle_found)
rv.wiggles++;
return rv;
struct ci print_merge2(FILE *out, struct file *a, struct file *b, struct file *c,
struct csl *c1, struct csl *c2,
- int words, int ignore_already)
+ int words, int ignore_already, int show_wiggles)
{
struct ci rv = make_merger(*a, *b, *c, c1, c2,
- words, ignore_already);
+ words, ignore_already, show_wiggles);
struct merge *m;
for (m = rv.merger; m->type != End ; m++) {
/* need to print from 'hi' to 'lo' of next
* Unchanged which is < it's hi
*/
+ int found_conflict = 0;
int st = 0, st1;
if (m->type == Unchanged || m->type == Changed)
if (m->hi >= m->lo)
fputs(words ? "<<<---" : "<<<<<<<\n", out);
for (cm = m; cm->in_conflict; cm++) {
+ if (cm->type == Conflict)
+ found_conflict = 1;
if ((cm->type == Unchanged || cm->type == Changed)
&& cm != m && cm->lo < cm->hi) {
printrange(out, a, cm->a, cm->lo);
printrange(out, c, cm->c+st1, cm->cl-st1);
st1 = 0;
}
+ if (!found_conflict) {
+ /* This section was wiggled in successfully,
+ * but full conflict display was requested.
+ * So now print out the wiggled result as well.
+ */
+ fputs(words ? "&&&" : "&&&&&&&\n", out);
+ st1 = st;
+ for (cm = m; cm->in_conflict; cm++) {
+ int last = 0;
+ if ((cm->type == Unchanged || cm->type == Changed)
+ && cm != m && cm->lo < cm->hi)
+ last = 1;
+ switch (cm->type) {
+ case Unchanged:
+ case AlreadyApplied:
+ case Unmatched:
+ printrange(out, a, cm->a+st1,
+ last ? cm->lo : cm->al-st1);
+ break;
+ case Extraneous:
+ break;
+ case Changed:
+ printrange(out, c, cm->c+st1,
+ last ? cm->lo : cm->cl-st1);
+ break;
+ case Conflict:
+ case End:
+ assert(0);
+ }
+ if (last)
+ break;
+ st1 = 0;
+ }
+ }
fputs(words ? "--->>>" : ">>>>>>>\n", out);
m = cm;
if (m->in_conflict && m->type == Unchanged
--- /dev/null
+
+<<<<<<<
+This is one line of the file
+|||||||
+This is 1 line of the file
+=======
+This is 1 line of the document
+&&&&&&&
+This is one line of the document
+>>>>>>>
+
+I think this is another line
+
+So is this
--- /dev/null
+
+This is 1 line of the file
+
+I think this is another line
+
--- /dev/null
+
+This is 1 line of the document
+
+I think this is another line
+
--- /dev/null
+
+This is one line of the file
+
+I think this is another line
+
+So is this
--- /dev/null
+Openning line
+
+<<<<<<<
+content line with content
+|||||||
+content line content
+=======
+middle line content
+&&&&&&&
+middle line with content
+>>>>>>>
+
+closing line
--- /dev/null
+Openning line
+
+content line content
+
+closing line
--- /dev/null
+Openning line
+
+middle line content
+
+closing line
--- /dev/null
+Openning line
+
+content line with content
+
+closing line
csl1 = diff(fm, fb);
csl2 = diff(fb, fa);
- ci = make_merger(fm, fb, fa, csl1, csl2, 0, 1);
+ ci = make_merger(fm, fb, fa, csl1, csl2, 0, 1, 0);
term_init();
else
csl1 = diff(ff, fp1);
csl2 = diff(fp1, fp2);
- ci = make_merger(ff, fp1, fp2, csl1, csl2, 0, 1);
+ ci = make_merger(ff, fp1, fp2, csl1, csl2, 0, 1, 0);
pl->wiggles = ci.wiggles;
pl->conflicts = ci.conflicts;
free(csl1);
already have been applied in the original. With this flag those
changes are reported as conflicts rather than being ignored.
+.TP
+.BR -W ", " \-\-show\-wiggle
+When used with
+.IR \-\-merge ,
+conflicts that can be wiggled into place are reported as conflicts
+with an extra stanza which shows what the result would be if this flag
+had not been used. The extra stanza is introduce with a line
+containing 7 ampersand
+.RB ( & )
+characters thus:
+.in +5
+.nf
+.ft CW
+<<<<<<<
+Some portion of the original file
+|||||||
+text to replace
+=======
+text to replace it with
+&&&&&&&
+Text that would result from a successful wiggle
+>>>>>>>
+.ft
+.fi
+.in -5
+
.TP
.BR -h ", " \-\-help
Print a simple help message. If given after one of the function
}
static int do_merge(int argc, char *argv[], int obj,
- int reverse, int replace, int ignore,
+ int reverse, int replace, int ignore, int show_wiggles,
int quiet)
{
/* merge three files, A B C, so changed between B and C get made to A
ci = print_merge2(outfile, &fl[0], &fl[1], &fl[2],
csl1, csl2, obj == 'w',
- ignore);
+ ignore, show_wiggles);
if (!quiet && ci.conflicts)
fprintf(stderr,
"%d unresolved conflict%s found\n",
int strip = -1;
int exit_status = 0;
int ignore = 1;
+ int show_wiggles = 0;
char *helpmsg;
char *trace;
case 'i':
ignore = 0;
continue;
+ case 'W':
+ show_wiggles = 1;
+ ignore = 0;
+ continue;
case '1':
case '2':
break;
case 'm':
exit_status = do_merge(argc, argv, obj, reverse, replace,
- ignore, quiet);
+ ignore, show_wiggles, quiet);
break;
}
exit(exit_status);
extern struct ci print_merge2(FILE *out,
struct file *a, struct file *b, struct file *c,
struct csl *c1, struct csl *c2,
- int words, int ignore_already);
+ int words, int ignore_already, int show_wiggles);
extern void printword(FILE *f, struct elmnt e);
extern struct ci make_merger(struct file a, struct file b, struct file c,
struct csl *c1, struct csl *c2, int words,
- int ignore_already);
+ int ignore_already, int show_wiggles);
extern void die(void);
extern void *xmalloc(int len);