Merge branch 'jc/test-lib-source-build-options-early'
[gitweb.git] / builtin / blame.c
index 9ae5cf3a56e613280c137e55085b9c682fbd9612..0d50273ce975d956cba3c17160bf3704b57f3f9c 100644 (file)
@@ -88,6 +88,20 @@ struct origin {
        char path[FLEX_ARRAY];
 };
 
+static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen,
+                     xdl_emit_hunk_consume_func_t hunk_func, void *cb_data)
+{
+       xpparam_t xpp = {0};
+       xdemitconf_t xecfg = {0};
+       xdemitcb_t ecb = {NULL};
+
+       xpp.flags = xdl_opts;
+       xecfg.ctxlen = ctxlen;
+       xecfg.hunk_func = hunk_func;
+       ecb.priv = cb_data;
+       return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb);
+}
+
 /*
  * Prepare diff_filespec and convert it using diff textconv API
  * if the textconv driver exists.
@@ -781,9 +795,6 @@ static int pass_blame_to_parent(struct scoreboard *sb,
        int last_in_target;
        mmfile_t file_p, file_o;
        struct blame_chunk_cb_data d;
-       xpparam_t xpp;
-       xdemitconf_t xecfg;
-       xdemitcb_t ecb;
 
        memset(&d, 0, sizeof(d));
        d.sb = sb; d.target = target; d.parent = parent;
@@ -795,14 +806,7 @@ static int pass_blame_to_parent(struct scoreboard *sb,
        fill_origin_blob(&sb->revs->diffopt, target, &file_o);
        num_get_patch++;
 
-       memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = xdl_opts;
-       memset(&xecfg, 0, sizeof(xecfg));
-       xecfg.ctxlen = 0;
-       xecfg.hunk_func = blame_chunk_cb;
-       memset(&ecb, 0, sizeof(ecb));
-       ecb.priv = &d;
-       xdi_diff(&file_p, &file_o, &xpp, &xecfg, &ecb);
+       diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
        /* The rest (i.e. anything after tlno) are the same as the parent */
        blame_chunk(sb, d.tlno, d.plno, last_in_target, target, parent);
 
@@ -906,12 +910,15 @@ struct handle_split_cb_data {
        long tlno;
 };
 
-static void handle_split_cb(void *data, long same, long p_next, long t_next)
+static int handle_split_cb(long start_a, long count_a,
+                          long start_b, long count_b, void *data)
 {
        struct handle_split_cb_data *d = data;
-       handle_split(d->sb, d->ent, d->tlno, d->plno, same, d->parent, d->split);
-       d->plno = p_next;
-       d->tlno = t_next;
+       handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent,
+                    d->split);
+       d->plno = start_a + count_a;
+       d->tlno = start_b + count_b;
+       return 0;
 }
 
 /*
@@ -929,8 +936,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
        int cnt;
        mmfile_t file_o;
        struct handle_split_cb_data d;
-       xpparam_t xpp;
-       xdemitconf_t xecfg;
+
        memset(&d, 0, sizeof(d));
        d.sb = sb; d.ent = ent; d.parent = parent; d.split = split;
        /*
@@ -950,12 +956,8 @@ static void find_copy_in_blob(struct scoreboard *sb,
         * file_o is a part of final image we are annotating.
         * file_p partially may match that image.
         */
-       memset(&xpp, 0, sizeof(xpp));
-       xpp.flags = xdl_opts;
-       memset(&xecfg, 0, sizeof(xecfg));
-       xecfg.ctxlen = 1;
        memset(split, 0, sizeof(struct blame_entry [3]));
-       xdi_diff_hunks(file_p, &file_o, handle_split_cb, &d, &xpp, &xecfg);
+       diff_hunks(file_p, &file_o, 1, handle_split_cb, &d);
        /* remainder, if any, all match the preimage */
        handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
 }
@@ -1835,6 +1837,16 @@ static int read_ancestry(const char *graft_file)
        return 0;
 }
 
+static int update_auto_abbrev(int auto_abbrev, struct origin *suspect)
+{
+       const char *uniq = find_unique_abbrev(suspect->commit->object.sha1,
+                                             auto_abbrev);
+       int len = strlen(uniq);
+       if (auto_abbrev < len)
+               return len;
+       return auto_abbrev;
+}
+
 /*
  * How many columns do we need to show line numbers, authors,
  * and filenames?
@@ -1845,12 +1857,16 @@ static void find_alignment(struct scoreboard *sb, int *option)
        int longest_dst_lines = 0;
        unsigned largest_score = 0;
        struct blame_entry *e;
+       int compute_auto_abbrev = (abbrev < 0);
+       int auto_abbrev = default_abbrev;
 
        for (e = sb->ent; e; e = e->next) {
                struct origin *suspect = e->suspect;
                struct commit_info ci;
                int num;
 
+               if (compute_auto_abbrev)
+                       auto_abbrev = update_auto_abbrev(auto_abbrev, suspect);
                if (strcmp(suspect->path, sb->path))
                        *option |= OUTPUT_SHOW_NAME;
                num = strlen(suspect->path);
@@ -1878,6 +1894,10 @@ static void find_alignment(struct scoreboard *sb, int *option)
        max_orig_digits = decimal_width(longest_src_lines);
        max_digits = decimal_width(longest_dst_lines);
        max_score_digits = decimal_width(largest_score);
+
+       if (compute_auto_abbrev)
+               /* one more abbrev length is needed for the boundary commit */
+               abbrev = auto_abbrev + 1;
 }
 
 /*
@@ -2151,7 +2171,8 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        ce = xcalloc(1, size);
        hashcpy(ce->sha1, origin->blob_sha1);
        memcpy(ce->name, path, len);
-       ce->ce_flags = create_ce_flags(len, 0);
+       ce->ce_flags = create_ce_flags(0);
+       ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 
@@ -2351,10 +2372,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 parse_done:
        argc = parse_options_end(&ctx);
 
-       if (abbrev == -1)
-               abbrev = default_abbrev;
-       /* one more abbrev length is needed for the boundary commit */
-       abbrev++;
+       if (0 < abbrev)
+               /* one more abbrev length is needed for the boundary commit */
+               abbrev++;
 
        if (revs_file && read_ancestry(revs_file))
                die_errno("reading graft file '%s' failed", revs_file);