]> git.ipfire.org Git - thirdparty/git.git/blobdiff - range-diff.c
Merge branch 'jk/use-compat-util-in-test-tool'
[thirdparty/git.git] / range-diff.c
index 15d418afa674c2ed9d4739740a502b6b83071cdf..b6b9abac266f3a6a2abdfcdd815f80b7da930854 100644 (file)
@@ -6,13 +6,17 @@
 #include "hashmap.h"
 #include "xdiff-interface.h"
 #include "linear-assignment.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "pretty.h"
+#include "userdiff.h"
 
 struct patch_util {
        /* For the search for an exact match */
        struct hashmap_entry e;
        const char *diff, *patch;
 
-       int i;
+       int i, shown;
        int diffsize;
        size_t diff_offset;
        /* the index of the matching item in the other branch, or -1 */
@@ -84,6 +88,7 @@ static int read_patches(const char *range, struct string_list *list)
                                strbuf_addbuf(&buf, &line);
                                strbuf_addstr(&buf, "\n\n");
                        } else if (starts_with(line.buf, "    ")) {
+                               strbuf_rtrim(&line);
                                strbuf_addbuf(&buf, &line);
                                strbuf_addch(&buf, '\n');
                        }
@@ -253,40 +258,159 @@ static void get_correspondences(struct string_list *a, struct string_list *b,
        free(b2a);
 }
 
-static const char *short_oid(struct patch_util *util)
+static void output_pair_header(struct diff_options *diffopt,
+                              int patch_no_width,
+                              struct strbuf *buf,
+                              struct strbuf *dashes,
+                              struct patch_util *a_util,
+                              struct patch_util *b_util)
 {
-       return find_unique_abbrev(&util->oid, DEFAULT_ABBREV);
+       struct object_id *oid = a_util ? &a_util->oid : &b_util->oid;
+       struct commit *commit;
+       char status;
+       const char *color_reset = diff_get_color_opt(diffopt, DIFF_RESET);
+       const char *color_old = diff_get_color_opt(diffopt, DIFF_FILE_OLD);
+       const char *color_new = diff_get_color_opt(diffopt, DIFF_FILE_NEW);
+       const char *color_commit = diff_get_color_opt(diffopt, DIFF_COMMIT);
+       const char *color;
+
+       if (!dashes->len)
+               strbuf_addchars(dashes, '-',
+                               strlen(find_unique_abbrev(oid,
+                                                         DEFAULT_ABBREV)));
+
+       if (!b_util) {
+               color = color_old;
+               status = '<';
+       } else if (!a_util) {
+               color = color_new;
+               status = '>';
+       } else if (strcmp(a_util->patch, b_util->patch)) {
+               color = color_commit;
+               status = '!';
+       } else {
+               color = color_commit;
+               status = '=';
+       }
+
+       strbuf_reset(buf);
+       strbuf_addstr(buf, status == '!' ? color_old : color);
+       if (!a_util)
+               strbuf_addf(buf, "%*s:  %s ", patch_no_width, "-", dashes->buf);
+       else
+               strbuf_addf(buf, "%*d:  %s ", patch_no_width, a_util->i + 1,
+                           find_unique_abbrev(&a_util->oid, DEFAULT_ABBREV));
+
+       if (status == '!')
+               strbuf_addf(buf, "%s%s", color_reset, color);
+       strbuf_addch(buf, status);
+       if (status == '!')
+               strbuf_addf(buf, "%s%s", color_reset, color_new);
+
+       if (!b_util)
+               strbuf_addf(buf, " %*s:  %s", patch_no_width, "-", dashes->buf);
+       else
+               strbuf_addf(buf, " %*d:  %s", patch_no_width, b_util->i + 1,
+                           find_unique_abbrev(&b_util->oid, DEFAULT_ABBREV));
+
+       commit = lookup_commit_reference(the_repository, oid);
+       if (commit) {
+               if (status == '!')
+                       strbuf_addf(buf, "%s%s", color_reset, color);
+
+               strbuf_addch(buf, ' ');
+               pp_commit_easy(CMIT_FMT_ONELINE, commit, buf);
+       }
+       strbuf_addf(buf, "%s\n", color_reset);
+
+       fwrite(buf->buf, buf->len, 1, stdout);
 }
 
-static void output(struct string_list *a, struct string_list *b)
+static struct userdiff_driver no_func_name = {
+       .funcname = { "$^", 0 }
+};
+
+static struct diff_filespec *get_filespec(const char *name, const char *p)
 {
-       int i;
+       struct diff_filespec *spec = alloc_filespec(name);
 
-       for (i = 0; i < b->nr; i++) {
-               struct patch_util *util = b->items[i].util, *prev;
-
-               if (util->matching < 0)
-                       printf("-: -------- > %d: %s\n",
-                                       i + 1, short_oid(util));
-               else {
-                       prev = a->items[util->matching].util;
-                       printf("%d: %s ! %d: %s\n",
-                              util->matching + 1, short_oid(prev),
-                              i + 1, short_oid(util));
+       fill_filespec(spec, &null_oid, 0, 0644);
+       spec->data = (char *)p;
+       spec->size = strlen(p);
+       spec->should_munmap = 0;
+       spec->is_stdin = 1;
+       spec->driver = &no_func_name;
+
+       return spec;
+}
+
+static void patch_diff(const char *a, const char *b,
+                             struct diff_options *diffopt)
+{
+       diff_queue(&diff_queued_diff,
+                  get_filespec("a", a), get_filespec("b", b));
+
+       diffcore_std(diffopt);
+       diff_flush(diffopt);
+}
+
+static void output(struct string_list *a, struct string_list *b,
+                  struct diff_options *diffopt)
+{
+       struct strbuf buf = STRBUF_INIT, dashes = STRBUF_INIT;
+       int patch_no_width = decimal_width(1 + (a->nr > b->nr ? a->nr : b->nr));
+       int i = 0, j = 0;
+
+       /*
+        * We assume the user is really more interested in the second argument
+        * ("newer" version). To that end, we print the output in the order of
+        * the RHS (the `b` parameter). To put the LHS (the `a` parameter)
+        * commits that are no longer in the RHS into a good place, we place
+        * them once we have shown all of their predecessors in the LHS.
+        */
+
+       while (i < a->nr || j < b->nr) {
+               struct patch_util *a_util, *b_util;
+               a_util = i < a->nr ? a->items[i].util : NULL;
+               b_util = j < b->nr ? b->items[j].util : NULL;
+
+               /* Skip all the already-shown commits from the LHS. */
+               while (i < a->nr && a_util->shown)
+                       a_util = ++i < a->nr ? a->items[i].util : NULL;
+
+               /* Show unmatched LHS commit whose predecessors were shown. */
+               if (i < a->nr && a_util->matching < 0) {
+                       output_pair_header(diffopt, patch_no_width,
+                                          &buf, &dashes, a_util, NULL);
+                       i++;
+                       continue;
                }
-       }
 
-       for (i = 0; i < a->nr; i++) {
-               struct patch_util *util = a->items[i].util;
+               /* Show unmatched RHS commits. */
+               while (j < b->nr && b_util->matching < 0) {
+                       output_pair_header(diffopt, patch_no_width,
+                                          &buf, &dashes, NULL, b_util);
+                       b_util = ++j < b->nr ? b->items[j].util : NULL;
+               }
 
-               if (util->matching < 0)
-                       printf("%d: %s < -: --------\n",
-                              i + 1, short_oid(util));
+               /* Show matching LHS/RHS pair. */
+               if (j < b->nr) {
+                       a_util = a->items[b_util->matching].util;
+                       output_pair_header(diffopt, patch_no_width,
+                                          &buf, &dashes, a_util, b_util);
+                       if (!(diffopt->output_format & DIFF_FORMAT_NO_OUTPUT))
+                               patch_diff(a->items[b_util->matching].string,
+                                          b->items[j].string, diffopt);
+                       a_util->shown = 1;
+                       j++;
+               }
        }
+       strbuf_release(&buf);
+       strbuf_release(&dashes);
 }
 
 int show_range_diff(const char *range1, const char *range2,
-                   int creation_factor)
+                   int creation_factor, struct diff_options *diffopt)
 {
        int res = 0;
 
@@ -301,7 +425,7 @@ int show_range_diff(const char *range1, const char *range2,
        if (!res) {
                find_exact_matches(&branch1, &branch2);
                get_correspondences(&branch1, &branch2, creation_factor);
-               output(&branch1, &branch2);
+               output(&branch1, &branch2, diffopt);
        }
 
        string_list_clear(&branch1, 1);