Merge branch 'hv/submodule-path-unmatch'
[gitweb.git] / builtin / blame.c
index 324d476abf18c3a71378aa44841026e42b4a0b88..ed5d01b36a309a53619c2615aed2382b2aebf056 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.
@@ -96,6 +110,7 @@ struct origin {
 int textconv_object(const char *path,
                    unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    char **buf,
                    unsigned long *buf_size)
 {
@@ -103,7 +118,7 @@ int textconv_object(const char *path,
        struct userdiff_driver *textconv;
 
        df = alloc_filespec(path);
-       fill_filespec(df, sha1, mode);
+       fill_filespec(df, sha1, sha1_valid, mode);
        textconv = get_textconv(df);
        if (!textconv) {
                free_filespec(df);
@@ -128,7 +143,7 @@ static void fill_origin_blob(struct diff_options *opt,
 
                num_read_blob++;
                if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                   textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
+                   textconv_object(o->path, o->mode, o->blob_sha1, 1, &file->ptr, &file_size))
                        ;
                else
                        file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
@@ -392,8 +407,7 @@ static struct origin *find_origin(struct scoreboard *sb,
        paths[1] = NULL;
 
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -479,8 +493,7 @@ static struct origin *find_rename(struct scoreboard *sb,
        diff_opts.single_follow = origin->path;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -759,12 +772,14 @@ struct blame_chunk_cb_data {
        long tlno;
 };
 
-static void blame_chunk_cb(void *data, long same, long p_next, long t_next)
+static int blame_chunk_cb(long start_a, long count_a,
+                         long start_b, long count_b, void *data)
 {
        struct blame_chunk_cb_data *d = data;
-       blame_chunk(d->sb, d->tlno, d->plno, same, d->target, d->parent);
-       d->plno = p_next;
-       d->tlno = t_next;
+       blame_chunk(d->sb, d->tlno, d->plno, start_b, d->target, d->parent);
+       d->plno = start_a + count_a;
+       d->tlno = start_b + count_b;
+       return 0;
 }
 
 /*
@@ -779,8 +794,7 @@ 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;
+
        memset(&d, 0, sizeof(d));
        d.sb = sb; d.target = target; d.parent = parent;
        last_in_target = find_last_in_target(sb, target);
@@ -791,11 +805,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;
-       xdi_diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, &xpp, &xecfg);
+       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);
 
@@ -899,12 +909,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;
 }
 
 /*
@@ -922,8 +935,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;
        /*
@@ -943,12 +955,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);
 }
@@ -1065,8 +1073,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
 
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        /* Try "find copies harder" on new path if requested;
         * we do not want to use diffcore_rename() actually to
@@ -1828,6 +1835,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?
@@ -1838,12 +1855,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);
@@ -1871,6 +1892,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;
 }
 
 /*
@@ -2096,7 +2121,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
                        if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                           textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len))
+                           textconv_object(read_from, mode, null_sha1, 0, &buf_ptr, &buf_len))
                                strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
                                die_errno("cannot open or read '%s'", read_from);
@@ -2144,7 +2169,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);
 
@@ -2344,10 +2370,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);
@@ -2489,7 +2514,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        die("no such path %s in %s", path, final_commit_name);
 
                if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
-                   textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
+                   textconv_object(path, o->mode, o->blob_sha1, 1, (char **) &sb.final_buf,
                                    &sb.final_buf_size))
                        ;
                else