]> git.neil.brown.name Git - wiggle.git/commitdiff
Allow diffs to be browsed.
authorNeilBrown <neilb@suse.de>
Wed, 21 Aug 2013 07:20:51 +0000 (17:20 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 21 Aug 2013 07:20:51 +0000 (17:20 +1000)
If --diff is given with --browse, then the diff can
be explored with colourful highlighting.

Signed-off-by: NeilBrown <neilb@suse.de>
vpatch.c
wiggle.1
wiggle.c

index 5a24eeaf302a1d5312cb10b56525c4f0f18ce80c..8f44f42fbba779a4cc4ed089e633dc75f697d28d 100644 (file)
--- a/vpatch.c
+++ b/vpatch.c
@@ -1042,17 +1042,13 @@ static void draw_mside(int mode, int row, int offset, int start, int cols,
        if (e.start && e.start[0] == 0) {
                char b[100];
                struct elmnt e1;
-               if (pos.p.s == 2 && m[pos.p.m].type == Extraneous) {
-                       int A, B, C, D, E, F;
-                       e1 = fb.list[m[pos.p.m].b + pos.p.o];
-                       sscanf(e1.start+1, "%d %d %d", &A, &B, &C);
-                       sscanf(e.start+1, "%d %d %d", &D, &E, &F);
-                       snprintf(b, sizeof(b), "@@ -%d,%d +%d,%d @@%s", B, C, E, F, e1.start+18);
-                       (void)attrset(a_sep);
-               } else {
-                       (void)attrset(visible(mode, m, &pos));
-                       sprintf(b, "<%.17s>", e.start+1);
-               }
+               int A, B, C, D, E, F;
+               e1 = fb.list[m[pos.p.m].b + pos.p.o];
+               sscanf(e1.start+1, "%d %d %d", &A, &B, &C);
+               sscanf(e.start+1, "%d %d %d", &D, &E, &F);
+               snprintf(b, sizeof(b), "@@ -%d,%d +%d,%d @@%s", B, C, E, F, e1.start+18);
+               (void)attrset(a_sep);
+
                mvaddstr(row, col-start+offset, b);
                col += strlen(b);
        }
@@ -1280,7 +1276,7 @@ static void do_edit(char *file)
 
 
 static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
-                       int selftest, int ignore_blanks)
+                       int selftest, int ignore_blanks, int just_diff)
 {
        /* Display the merge window in one of the selectable modes,
         * starting with the 'merge' mode.
@@ -1309,10 +1305,10 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
        int lastrow = 0; /* end of screen, or just above 'splitrow' */
        int i, c, cswitch;
        MEVENT mevent;
-       int mode = ORIG|RESULT;
+       int mode = just_diff ? (BEFORE|AFTER) : (ORIG|RESULT);
        int mmode = mode; /* Mode for moving - used when in 'other' pane */
-       char *modename = "merge";
-       char **modehelp = merge_help;
+       char *modename = just_diff ? "diff" : "merge";
+       char **modehelp = just_diff ? diff_help : merge_help;
        char *mesg = NULL;
 
        int row, start = 0;
@@ -1385,7 +1381,7 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
                fb = split_stream(sb, ByWord | ignore_blanks);
                fa = split_stream(sa, ByWord | ignore_blanks);
 
-               if (ch)
+               if (ch && !just_diff)
                        csl1 = pdiff(fm, fb, ch);
                else
                        csl1 = diff(fm, fb);
@@ -1404,9 +1400,12 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
        if (f == NULL) {
                if (!p->is_merge) {
                        /* three separate files */
-                       sm = load_file(p->file);
                        sb = load_file(p->before);
                        sa = load_file(p->after);
+                       if (just_diff)
+                               sm = sb;
+                       else
+                               sm = load_file(p->file);
                } else {
                        /* One merge file */
                        sp = load_file(p->file);
@@ -1430,13 +1429,16 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
                                ch = split_patch(sp, &sa, &sb);
                        else
                                ch = split_patch(sp, &sb, &sa);
-
-                       sm = load_file(p->file);
+                       if (just_diff)
+                               sm = sb;
+                       else
+                               sm = load_file(p->file);
                }
                free(sp.body);
        }
        if (!sm.body || !sb.body || !sa.body) {
-               free(sm.body);
+               if (!just_diff)
+                       free(sm.body);
                free(sb.body);
                free(sa.body);
                term_init(1);
@@ -1660,8 +1662,10 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
                {
                        int l = 0;
                        char buf[100];
-                       snprintf(buf, 100, "File: %s%s Mode: %s",
-                               p->file, reverse ? " - reversed" : "", modename);
+                       if (p->file)
+                               l = snprintf(buf, 100, "File: %s%s ",
+                               p->file, reverse ? " - reversed" : "");
+                       snprintf(buf+l, 100-l, "Mode: %s", modename);
                        (void)attrset(A_BOLD);
                        mvaddstr(0, 0, buf);
                        (void)attrset(A_NORMAL);
@@ -1801,7 +1805,8 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
                                save_merge(fm, fb, fa, ci.merger,
                                           p->file, !p->is_merge);
                        }
-                       free(sm.body);
+                       if (!just_diff)
+                               free(sm.body);
                        free(sb.body);
                        free(sa.body);
                        free_stuff();
@@ -1825,6 +1830,10 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
                        break;
 
                case 'v':
+                       if (!p->file || just_diff) {
+                               mesg = "Cannot run editor when diffing";
+                               break;
+                       }
                        save_merge(fm, fb, fa, ci.merger,
                                   p->file, !p->is_merge);
                        p->is_merge = 1;
@@ -2374,7 +2383,8 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace,
 
 static int show_merge(char *origname, FILE *patch, int reverse,
                      int is_merge, char *before, char *after,
-                     int replace, int selftest, int ignore_blanks)
+                     int replace, int selftest, int ignore_blanks,
+                     int just_diff)
 {
        struct plist p;
 
@@ -2392,11 +2402,11 @@ static int show_merge(char *origname, FILE *patch, int reverse,
 
        freopen("/dev/null","w",stderr);
        return merge_window(&p, patch, reverse, replace, selftest,
-                           ignore_blanks);
+                           ignore_blanks, just_diff);
 }
 
 static void calc_one(struct plist *pl, FILE *f, int reverse,
-                    int ignore_blanks)
+                    int ignore_blanks, int just_diff)
 {
        struct stream s1, s2;
        struct stream s = load_segment(f, pl->start, pl->end);
@@ -2408,11 +2418,14 @@ static void calc_one(struct plist *pl, FILE *f, int reverse,
                        split_merge(s, &sf, &s1, &s2);
                pl->chunks = 0;
        } else {
-               sf = load_file(pl->file);
                if (reverse)
                        pl->chunks = split_patch(s, &s2, &s1);
                else
                        pl->chunks = split_patch(s, &s1, &s2);
+               if (just_diff)
+                       sf = s1;
+               else
+                       sf = load_file(pl->file);
        }
        if (sf.body == NULL || s1.body == NULL || s1.body == NULL) {
                pl->wiggles = pl->conflicts = -1;
@@ -2423,7 +2436,7 @@ static void calc_one(struct plist *pl, FILE *f, int reverse,
                ff = split_stream(sf, ByWord | ignore_blanks);
                fp1 = split_stream(s1, ByWord | ignore_blanks);
                fp2 = split_stream(s2, ByWord | ignore_blanks);
-               if (pl->chunks)
+               if (pl->chunks && !just_diff)
                        csl1 = pdiff(ff, fp1, pl->chunks);
                else
                        csl1 = diff(ff, fp1);
@@ -2442,7 +2455,8 @@ static void calc_one(struct plist *pl, FILE *f, int reverse,
        free(s1.body);
        free(s2.body);
        free(s.body);
-       free(sf.body);
+       if (!just_diff)
+               free(sf.body);
        pl->calced = 1;
 }
 
@@ -2472,7 +2486,7 @@ static int get_prev(int pos, struct plist *pl, int n, int mode)
 }
 
 static int get_next(int pos, struct plist *pl, int n, int mode,
-                   FILE *f, int reverse, int ignore_blanks)
+                   FILE *f, int reverse, int ignore_blanks, int just_diff)
 {
        int found = 0;
        if (pos == -1)
@@ -2492,7 +2506,7 @@ static int get_next(int pos, struct plist *pl, int n, int mode,
                if (pos < 0)
                        return -1;
                if (pl[pos].calced == 0 && pl[pos].end)
-                       calc_one(pl+pos, f, reverse, ignore_blanks);
+                       calc_one(pl+pos, f, reverse, ignore_blanks, just_diff);
                if (pl[pos].last >= 0)
                        /* always see directories */
                        found = 1;
@@ -2507,7 +2521,7 @@ static int get_next(int pos, struct plist *pl, int n, int mode,
 }
 
 static void draw_one(int row, struct plist *pl, FILE *f, int reverse,
-                    int ignore_blanks)
+                    int ignore_blanks, int just_diff)
 {
        char hdr[12];
        hdr[0] = 0;
@@ -2519,7 +2533,7 @@ static void draw_one(int row, struct plist *pl, FILE *f, int reverse,
        }
        if (pl->calced == 0 && pl->end)
                /* better load the patch and count the chunks */
-               calc_one(pl, f, reverse, ignore_blanks);
+               calc_one(pl, f, reverse, ignore_blanks, just_diff);
        if (pl->end == 0) {
                strcpy(hdr, "         ");
        } else {
@@ -2636,7 +2650,7 @@ static char *saveall_query[] = {
        NULL
 };
 static void main_window(struct plist *pl, int *np, FILE *f, int reverse,
-                       int replace, int ignore_blanks)
+                       int replace, int ignore_blanks, int just_diff)
 {
        /* The main window lists all files together with summary information:
         * number of chunks, number of wiggles, number of conflicts.
@@ -2725,16 +2739,16 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse,
                        /* Ok, row and pos could be trustworthy now */
                        tpos = pos;
                        for (i = row; i >= 1; i--) {
-                               draw_one(i, &pl[tpos], f, reverse, ignore_blanks);
+                               draw_one(i, &pl[tpos], f, reverse, ignore_blanks, just_diff);
                                tpos = get_prev(tpos, pl, *np, mode);
                        }
                        tpos = pos;
                        for (i = row+1; i < rows; i++) {
-                               tpos = get_next(tpos, pl, *np, mode, f, reverse,ignore_blanks);
+                               tpos = get_next(tpos, pl, *np, mode, f, reverse,ignore_blanks, just_diff);
                                if (tpos >= 0)
-                                       draw_one(i, &pl[tpos], f, reverse, ignore_blanks);
+                                       draw_one(i, &pl[tpos], f, reverse, ignore_blanks, just_diff);
                                else
-                                       draw_one(i, NULL, f, reverse, ignore_blanks);
+                                       draw_one(i, NULL, f, reverse, ignore_blanks, just_diff);
                        }
                }
                attrset(0);
@@ -2764,7 +2778,7 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse,
                case 'N':
                case 'N'-64:
                case KEY_DOWN:
-                       tpos = get_next(pos, pl, *np, mode, f, reverse, ignore_blanks);
+                       tpos = get_next(pos, pl, *np, mode, f, reverse, ignore_blanks, just_diff);
                        if (tpos >= 0) {
                                pos = tpos;
                                row++;
@@ -2786,7 +2800,7 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse,
                        if (getmouse(&mevent) != OK)
                                break;
                        while (row < mevent.y &&
-                              (tpos = get_next(pos, pl, *np, mode, f, reverse, ignore_blanks))
+                              (tpos = get_next(pos, pl, *np, mode, f, reverse, ignore_blanks, just_diff))
                               >= 0) {
                                pos = tpos;
                                row++;
@@ -2812,9 +2826,9 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse,
                        } else {
                                int c;
                                if (pl[pos].is_merge)
-                                       c = merge_window(&pl[pos], NULL, reverse, 0, 0, ignore_blanks);
+                                       c = merge_window(&pl[pos], NULL, reverse, 0, 0, ignore_blanks, just_diff);
                                else
-                                       c = merge_window(&pl[pos], f, reverse, 0, 0, ignore_blanks);
+                                       c = merge_window(&pl[pos], f, reverse, 0, 0, ignore_blanks, just_diff);
                                refresh = 2;
                                if (c) {
                                        pl[pos].is_merge = 1;
@@ -2932,7 +2946,7 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse,
                                        mesg = "File has been restored.";
                                        pl[pos].is_merge = 0;
                                        refresh = 1;
-                                       calc_one(&pl[pos], f, reverse, ignore_blanks);
+                                       calc_one(&pl[pos], f, reverse, ignore_blanks, just_diff);
                                } else
                                        mesg = "Could not restore file!";
                        }
@@ -3038,14 +3052,19 @@ int vpatch(int argc, char *argv[], int patch, int strip,
           int reverse, int replace, int selftest, int ignore_blanks)
 {
        /* NOTE argv[0] is first arg...
-        * Behaviour depends on number of args:
-        * 0: A multi-file patch is read from stdin
-        * 1: if 'patch', parse it as a multi-file patch and allow
+        * Behaviour depends on number of args and 'patch'.
+        * If 'patch' is '1', assume a patch. if '2', assume a diff.
+        * 0: A multi-file patch or diff is read from stdin.
+        *    A 'patch' is applies to relevant files. A 'diff' is just
+        *    displayed.
+        * 1: if 'patch', parse it as a multi-file patch/diff and allow
         *    the files to be browsed.
-        *    if filename ends '.rej', then treat it as a patch again
+        *    if filename ends '.rej', then treat it as a patch/diff again
         *    a file with the same basename
         *    Else treat the file as a merge (with conflicts) and view it.
-        * 2: First file is original, second is patch
+        *
+        * 2: First file is original, second is patch unless patch==2,
+        *    then two files need to be diffed.
         * 3: Files are: original previous new.  The diff between 'previous' and
         *    'new' needs to be applied to 'original'.
         *
@@ -3059,13 +3078,14 @@ int vpatch(int argc, char *argv[], int patch, int strip,
        FILE *f;
        struct plist *pl;
        int num_patches;
+       int just_diff = (patch == 2);
 
        switch (argc) {
        default:
                fprintf(stderr, "%s: too many file names given.\n", Cmd);
                exit(1);
 
-       case 0: /* stdin is a patch */
+       case 0: /* stdin is a patch or diff */
                if (lseek(fileno(stdin), 0L, 1) == -1) {
                        /* cannot seek, so need to copy to a temp file */
                        f = tmpfile();
@@ -3081,16 +3101,17 @@ int vpatch(int argc, char *argv[], int patch, int strip,
                }
                /* use stderr for keyboard input */
                dup2(2, 0);
-               if (set_prefix(pl, num_patches, strip) == 0) {
+               if (!just_diff &&
+                   set_prefix(pl, num_patches, strip) == 0) {
                        fprintf(stderr, "%s: aborting\n", Cmd);
                        exit(2);
                }
-               main_window(pl, &num_patches, in, reverse, replace, ignore_blanks);
+               main_window(pl, &num_patches, in, reverse, replace, ignore_blanks, just_diff);
                plist_free(pl, num_patches);
                fclose(in);
                break;
 
-       case 1: /* a patch, a .rej, or a merge file */
+       case 1: /* a patch/diff, a .rej, or a merge file */
                f = fopen(argv[0], "r");
                if (!f) {
                        fprintf(stderr, "%s: cannot open %s\n", Cmd, argv[0]);
@@ -3099,24 +3120,29 @@ int vpatch(int argc, char *argv[], int patch, int strip,
                check_dir(argv[0], fileno(f));
                if (patch) {
                        pl = parse_patch(f, NULL, &num_patches);
-                       if (set_prefix(pl, num_patches, strip) == 0) {
+                       if (!just_diff && set_prefix(pl, num_patches, strip) == 0) {
                                fprintf(stderr, "%s: aborting\n", Cmd);
                                exit(2);
                        }
-                       main_window(pl, &num_patches, f, reverse, replace,ignore_blanks);
+                       main_window(pl, &num_patches, f, reverse, replace,ignore_blanks, just_diff);
                        plist_free(pl, num_patches);
                } else if (strlen(argv[0]) > 4 &&
                         strcmp(argv[0]+strlen(argv[0])-4, ".rej") == 0) {
                        char *origname = strdup(argv[0]);
                        origname[strlen(origname) - 4] = '\0';
                        show_merge(origname, f, reverse, 0, NULL, NULL,
-                                  replace, selftest, ignore_blanks);
+                                  replace, selftest, ignore_blanks, just_diff);
                } else
                        show_merge(argv[0], f, reverse, 1, NULL, NULL,
-                                  replace, selftest, ignore_blanks);
+                                  replace, selftest, ignore_blanks, just_diff);
 
                break;
-       case 2: /* an orig and a diff/.ref */
+       case 2: /* an orig and a diff/.rej  or two files */
+               if (just_diff) {
+                       show_merge(NULL, NULL, reverse, 0, argv[0], argv[1],
+                                  replace, selftest, ignore_blanks, just_diff);
+                       break;
+               }
                f = fopen(argv[1], "r");
                check_dir(argv[1], fileno(f));
                if (!f) {
@@ -3124,11 +3150,11 @@ int vpatch(int argc, char *argv[], int patch, int strip,
                        exit(1);
                }
                show_merge(argv[0], f, reverse, 0, NULL, NULL,
-                          replace, selftest, ignore_blanks);
+                          replace, selftest, ignore_blanks, just_diff);
                break;
        case 3: /* orig, before, after */
                show_merge(argv[0], NULL, reverse, 0, argv[1], argv[2],
-                          replace, selftest, ignore_blanks);
+                          replace, selftest, ignore_blanks, just_diff);
                break;
        }
 
index 858b3d1daf7e9758b2c3e046df74f73340175f80..ebfeada91e3913a87833b50cb2844e5a91e6bfcd 100644 (file)
--- a/wiggle.1
+++ b/wiggle.1
@@ -128,7 +128,12 @@ Select the "merge" function.  This is the default function.
 
 .TP
 .BR \-d ", " \-\-diff
-Select the "diff" function.  This displays the differences between files.
+Select the "diff" function.  This displays the differences between
+files.  This can be given after
+.B \-\-browse
+(see below) in which case a patch or diff of two files can be viewed
+without the originals.
+
 
 .TP
 .BR \-x ", " \-\-extract
@@ -137,12 +142,12 @@ merge file.
 
 .TP
 .BR \-B ", " \-\-browse
-Select the "browse" function.  This is similar to "merge" only with a
-different presentation.  Instead of the result simply being sent to
-standard output, it is presented using an ncurses-based GUI so that
-each hunk of the patch can be examined to understand what conflicts
-where involved and what needed to be ignored in order of the patch to
-be wiggled in to place.
+Select the "browse" function.  This is similar to "merge" (or "diff")
+only with a different presentation.  Instead of the result simply
+being sent to standard output, it is presented using an ncurses-based
+GUI so that each hunk of the patch can be examined to understand what
+conflicts where involved and what needed to be ignored in order of the
+patch to be wiggled in to place.
 
 .TP
 .BR \-w ", " \-\-words
@@ -515,10 +520,12 @@ with obvious meanings.
 
 The browse function of
 .I wiggle
-presents the result of a merge in a text-based GUI that can be
+presents the result of a merge or (with
+.B \-d
+a diff) in a text-based GUI that can be
 navigated using keystrokes similar to vi(1) or emacs(1).
 
-The browser allows each of the three streams to be viewed individually
+The browser allows each of the two or  three streams to be viewed individually
 with colours used to highlight different sorts of text - green for
 added text, red for deleted text etc.  It can also show the patch by
 itself, the full result of the merge, or the merge and the patch
@@ -529,21 +536,39 @@ can be accessed by typing '?'
 
 A limited amount of editing is permitted while in
 .B browse
-mode.  Currently any Conflict or Changed section can be marked as
-"ignored" by using the
+mode.  Currently any Conflict or Changed section can be converted to
+Unchanged by using the
 .B x
 key (lower case), or all the Conflict and Changes sections in a line
-can be ignored by using
+can be converted to Unchanged.
 .B X
 (upper case).  The effect can be toggled by pressing
 .B x
 or
 .B X
-again.  If you make any changes, then wiggle will ask you if you want
+again.
+
+A Conflict section can also be converted to Change (so the result is
+accepted even though there wasn't a proper match) with the (lower
+case)
+.B c
+key.  Pressing
+.B c
+effects a toggle.
+
+If you make any changes, then wiggle will ask you if you want
 to save the changes, even if
 .B \-\-replace
 was not given.
 
+To make more sweeping changes you can use
+.B v
+which runs an editor, preferring
+.B $VISUAL
+or
+.B $EDITOR
+if they are set in the environment.
+
 .SH WARNING
 
 Caution should always be exercised when applying a rejected patch with
index 2cf6ac434ffbd709ab1e1bad31206fb5cd1cf6f7..44263034c6eca66fc98328356a79af32eb17b649 100644 (file)
--- a/wiggle.c
+++ b/wiggle.c
@@ -712,6 +712,11 @@ int main(int argc, char *argv[])
                                mode = opt;
                                continue;
                        }
+                       if (mode == 'B' && opt == 'd') {
+                               /* Browse/diff mode */
+                               ispatch = 2;
+                               continue;
+                       }
                        fprintf(stderr,
                                "%s: mode is '%c' - cannot set to '%c'\n",
                                Cmd, mode, opt);