From: Neil Brown Date: Mon, 7 May 2012 21:59:27 +0000 (+1000) Subject: Add --show-wiggle flag. X-Git-Tag: v0.9~35 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=acac69914562efd8cf1b43427c6bb05727384d87;p=wiggle.git Add --show-wiggle flag. --show-wiggle modifies --merge so that chunks which need to be wiggled into place are presented as full conflicts with an extra stanza which shows what the resulting wiggle would look like. Suggested-by: Alessandro Salvatori Signed-off-by: NeilBrown --- diff --git a/ReadMe.c b/ReadMe.c index d754edf..1844005 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -31,8 +31,8 @@ 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'}, @@ -50,6 +50,7 @@ struct option long_options[] = { {"quiet", 0, 0, 'q'}, {"strip", 1, 0, 'p'}, {"no-ignore", 0, 0, 'i'}, + {"show-wiggle", 0, 0, 'W'}, {0, 0, 0, 0} }; @@ -77,6 +78,8 @@ char Help[] = "\n" " --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" diff --git a/TODO b/TODO index 57b1f4c..09af8d6 100644 --- a/TODO +++ b/TODO @@ -1,16 +1,3 @@ -- --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 diff --git a/dotest b/dotest index 19aa75e..18fdf05 100755 --- a/dotest +++ b/dotest @@ -36,7 +36,8 @@ fail=0 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 @@ -86,6 +87,11 @@ 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` diff --git a/merge2.c b/merge2.c index 425208d..73b7347 100644 --- a/merge2.c +++ b/merge2.c @@ -81,7 +81,7 @@ static int check_alreadyapplied(struct file af, struct file cf, 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. @@ -97,13 +97,26 @@ static int isolate_conflicts(struct file af, struct file bf, struct file cf, * 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, @@ -160,15 +173,7 @@ static int isolate_conflicts(struct file af, struct file bf, struct file cf, 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; @@ -211,12 +216,17 @@ static int isolate_conflicts(struct file af, struct file bf, struct file cf, } 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 */ @@ -336,7 +346,8 @@ struct ci make_merger(struct file af, struct file bf, struct file cf, } 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; @@ -353,10 +364,10 @@ static void printrange(FILE *out, struct file *f, int start, int len) 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++) { @@ -379,6 +390,7 @@ struct ci print_merge2(FILE *out, struct file *a, struct file *b, struct file *c /* 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) @@ -409,6 +421,8 @@ struct ci print_merge2(FILE *out, struct file *a, struct file *b, struct file *c 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); @@ -441,6 +455,40 @@ struct ci print_merge2(FILE *out, struct file *a, struct file *b, struct file *c 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 diff --git a/tests/simple/show-wiggle-1/Wmerge b/tests/simple/show-wiggle-1/Wmerge new file mode 100644 index 0000000..2bb7d41 --- /dev/null +++ b/tests/simple/show-wiggle-1/Wmerge @@ -0,0 +1,14 @@ + +<<<<<<< +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 diff --git a/tests/simple/show-wiggle-1/new b/tests/simple/show-wiggle-1/new new file mode 100644 index 0000000..6f588b7 --- /dev/null +++ b/tests/simple/show-wiggle-1/new @@ -0,0 +1,5 @@ + +This is 1 line of the file + +I think this is another line + diff --git a/tests/simple/show-wiggle-1/new2 b/tests/simple/show-wiggle-1/new2 new file mode 100644 index 0000000..7f6b98d --- /dev/null +++ b/tests/simple/show-wiggle-1/new2 @@ -0,0 +1,5 @@ + +This is 1 line of the document + +I think this is another line + diff --git a/tests/simple/show-wiggle-1/orig b/tests/simple/show-wiggle-1/orig new file mode 100644 index 0000000..4f791aa --- /dev/null +++ b/tests/simple/show-wiggle-1/orig @@ -0,0 +1,6 @@ + +This is one line of the file + +I think this is another line + +So is this diff --git a/tests/simple/show-wiggle-2/Wmerge b/tests/simple/show-wiggle-2/Wmerge new file mode 100644 index 0000000..dadabc6 --- /dev/null +++ b/tests/simple/show-wiggle-2/Wmerge @@ -0,0 +1,13 @@ +Openning line + +<<<<<<< +content line with content +||||||| +content line content +======= +middle line content +&&&&&&& +middle line with content +>>>>>>> + +closing line diff --git a/tests/simple/show-wiggle-2/new b/tests/simple/show-wiggle-2/new new file mode 100644 index 0000000..c3e9e7e --- /dev/null +++ b/tests/simple/show-wiggle-2/new @@ -0,0 +1,5 @@ +Openning line + +content line content + +closing line diff --git a/tests/simple/show-wiggle-2/new2 b/tests/simple/show-wiggle-2/new2 new file mode 100644 index 0000000..ce25b4c --- /dev/null +++ b/tests/simple/show-wiggle-2/new2 @@ -0,0 +1,5 @@ +Openning line + +middle line content + +closing line diff --git a/tests/simple/show-wiggle-2/orig b/tests/simple/show-wiggle-2/orig new file mode 100644 index 0000000..c15140e --- /dev/null +++ b/tests/simple/show-wiggle-2/orig @@ -0,0 +1,5 @@ +Openning line + +content line with content + +closing line diff --git a/vpatch.c b/vpatch.c index 6a8a7ed..4411b4c 100644 --- a/vpatch.c +++ b/vpatch.c @@ -1168,7 +1168,7 @@ static void merge_window(struct plist *p, FILE *f, int reverse) 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(); @@ -2059,7 +2059,7 @@ static void calc_one(struct plist *pl, FILE *f, int reverse) 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); diff --git a/wiggle.1 b/wiggle.1 index a51dc30..5b6e8c9 100644 --- a/wiggle.1 +++ b/wiggle.1 @@ -162,6 +162,32 @@ Normally wiggle will ignore changes in the patch which appear to 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 diff --git a/wiggle.c b/wiggle.c index e87b3a0..634df42 100644 --- a/wiggle.c +++ b/wiggle.c @@ -446,7 +446,7 @@ static int do_diff(int argc, char *argv[], int obj, int ispatch, } 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 @@ -554,7 +554,7 @@ static int do_merge(int argc, char *argv[], int obj, 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", @@ -595,6 +595,7 @@ int main(int argc, char *argv[]) int strip = -1; int exit_status = 0; int ignore = 1; + int show_wiggles = 0; char *helpmsg; char *trace; @@ -667,6 +668,10 @@ int main(int argc, char *argv[]) case 'i': ignore = 0; continue; + case 'W': + show_wiggles = 1; + ignore = 0; + continue; case '1': case '2': @@ -746,7 +751,7 @@ int main(int argc, char *argv[]) break; case 'm': exit_status = do_merge(argc, argv, obj, reverse, replace, - ignore, quiet); + ignore, show_wiggles, quiet); break; } exit(exit_status); diff --git a/wiggle.h b/wiggle.h index 68dd177..1bbe4dd 100644 --- a/wiggle.h +++ b/wiggle.h @@ -136,12 +136,12 @@ struct ci { 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);