]> git.neil.brown.name Git - wiggle.git/commitdiff
Add --show-wiggle flag.
authorNeil Brown <neilb@suse.de>
Mon, 7 May 2012 21:59:27 +0000 (07:59 +1000)
committerNeil Brown <neilb@suse.de>
Mon, 7 May 2012 21:59:27 +0000 (07:59 +1000)
--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 <sandr8@gmail.com>
Signed-off-by: NeilBrown <neilb@suse.de>
16 files changed:
ReadMe.c
TODO
dotest
merge2.c
tests/simple/show-wiggle-1/Wmerge [new file with mode: 0644]
tests/simple/show-wiggle-1/new [new file with mode: 0644]
tests/simple/show-wiggle-1/new2 [new file with mode: 0644]
tests/simple/show-wiggle-1/orig [new file with mode: 0644]
tests/simple/show-wiggle-2/Wmerge [new file with mode: 0644]
tests/simple/show-wiggle-2/new [new file with mode: 0644]
tests/simple/show-wiggle-2/new2 [new file with mode: 0644]
tests/simple/show-wiggle-2/orig [new file with mode: 0644]
vpatch.c
wiggle.1
wiggle.c
wiggle.h

index d754edf35434a8607e6ce483c161fa0bb5d0896d..18440056a53ec2902af830089ea0be3fb2028c0e 100644 (file)
--- 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 57b1f4c44684e92ee5639bce617528487dc80e87..09af8d6710e643f5f9c194480e866ac007f39735 100644 (file)
--- 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 19aa75e398c32a1057d45be49d3c5a1033417080..18fdf05ccc6e586df6a53201300d2da37de947af 100755 (executable)
--- 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`
index 425208d869438b7822fcac2eb38bdbd66bb54fac..73b7347299721bed65600ddc186b3cba3f35d702 100644 (file)
--- 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 (file)
index 0000000..2bb7d41
--- /dev/null
@@ -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 (file)
index 0000000..6f588b7
--- /dev/null
@@ -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 (file)
index 0000000..7f6b98d
--- /dev/null
@@ -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 (file)
index 0000000..4f791aa
--- /dev/null
@@ -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 (file)
index 0000000..dadabc6
--- /dev/null
@@ -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 (file)
index 0000000..c3e9e7e
--- /dev/null
@@ -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 (file)
index 0000000..ce25b4c
--- /dev/null
@@ -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 (file)
index 0000000..c15140e
--- /dev/null
@@ -0,0 +1,5 @@
+Openning line
+
+content line with content
+
+closing line
index 6a8a7edf70af5566e50df55e948b940dabfa6ed5..4411b4c8be064709b5cac7067f4d27b144c793f3 100644 (file)
--- 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);
index a51dc300ea29dbfc2c231b6465c67063ffad15af..5b6e8c903504639ea62f0ddff03972b8aa1bb992 100644 (file)
--- 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
index e87b3a05b8420a41d03386a439a2d5235d885c4f..634df42479e64d8dc75cd6788c0df72858c55626 100644 (file)
--- 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);
index 68dd17745d0717d4ecfb8313aac16b6a0d8de93e..1bbe4ddd95f65601ed7af21a271e588ece9858d4 100644 (file)
--- 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);