log --decorate: Colorize commit decorations
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 974b6a997a8ee506a0fec05e513374085c85aec6..2327cea5b2c9ebe8d545b5a648910077ee67cd64 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -30,6 +30,7 @@ static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
+static int diff_no_prefix;
 
 static char diff_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_RESET,
@@ -101,6 +102,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_mnemonic_prefix = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "diff.noprefix")) {
+               diff_no_prefix = git_config_bool(var, value);
+               return 0;
+       }
        if (!strcmp(var, "diff.external"))
                return git_config_string(&external_diff_cmd_cfg, var, value);
        if (!strcmp(var, "diff.wordregex"))
@@ -875,7 +880,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
        memset(&xecfg, 0, sizeof(xecfg));
        diff_words_fill(&diff_words->minus, &minus, diff_words->word_regex);
        diff_words_fill(&diff_words->plus, &plus, diff_words->word_regex);
-       xpp.flags = XDF_NEED_MINIMAL;
+       xpp.flags = 0;
        /* as only the hunk header will be parsed, we need a 0-context */
        xecfg.ctxlen = 0;
        xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
@@ -1832,6 +1837,7 @@ static void builtin_diff(const char *name_a,
                         struct diff_filespec *one,
                         struct diff_filespec *two,
                         const char *xfrm_msg,
+                        int must_show_header,
                         struct diff_options *o,
                         int complete_rewrite)
 {
@@ -1889,21 +1895,24 @@ static void builtin_diff(const char *name_a,
        if (lbl[0][0] == '/') {
                /* /dev/null */
                strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, set, two->mode, reset);
-               if (xfrm_msg && xfrm_msg[0])
-                       strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+               if (xfrm_msg)
+                       strbuf_addstr(&header, xfrm_msg);
+               must_show_header = 1;
        }
        else if (lbl[1][0] == '/') {
                strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, set, one->mode, reset);
-               if (xfrm_msg && xfrm_msg[0])
-                       strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+               if (xfrm_msg)
+                       strbuf_addstr(&header, xfrm_msg);
+               must_show_header = 1;
        }
        else {
                if (one->mode != two->mode) {
                        strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, set, one->mode, reset);
                        strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, set, two->mode, reset);
+                       must_show_header = 1;
                }
-               if (xfrm_msg && xfrm_msg[0])
-                       strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+               if (xfrm_msg)
+                       strbuf_addstr(&header, xfrm_msg);
 
                /*
                 * we do not run diff between different kind
@@ -1930,8 +1939,11 @@ static void builtin_diff(const char *name_a,
                        die("unable to read files to diff");
                /* Quite common confusing case */
                if (mf1.size == mf2.size &&
-                   !memcmp(mf1.ptr, mf2.ptr, mf1.size))
+                   !memcmp(mf1.ptr, mf2.ptr, mf1.size)) {
+                       if (must_show_header)
+                               fprintf(o->file, "%s", header.buf);
                        goto free_ab_and_return;
+               }
                fprintf(o->file, "%s", header.buf);
                strbuf_reset(&header);
                if (DIFF_OPT_TST(o, BINARY))
@@ -1949,7 +1961,7 @@ static void builtin_diff(const char *name_a,
                struct emit_callback ecbdata;
                const struct userdiff_funcname *pe;
 
-               if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS)) {
+               if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS) || must_show_header) {
                        fprintf(o->file, "%s", header.buf);
                        strbuf_reset(&header);
                }
@@ -1972,7 +1984,7 @@ static void builtin_diff(const char *name_a,
                        check_blank_at_eof(&mf1, &mf2, &ecbdata);
                ecbdata.opt = o;
                ecbdata.header = header.len ? &header : NULL;
-               xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
+               xpp.flags = o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
@@ -2077,7 +2089,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
 
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
-               xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
+               xpp.flags = o->xdl_opts;
                xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
                              &xpp, &xecfg);
        }
@@ -2125,7 +2137,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
                xecfg.ctxlen = 1; /* at least one context line */
-               xpp.flags = XDF_NEED_MINIMAL;
+               xpp.flags = 0;
                xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
                              &xpp, &xecfg);
 
@@ -2562,44 +2574,54 @@ static void fill_metainfo(struct strbuf *msg,
                          struct diff_filespec *one,
                          struct diff_filespec *two,
                          struct diff_options *o,
-                         struct diff_filepair *p)
+                         struct diff_filepair *p,
+                         int *must_show_header,
+                         int use_color)
 {
+       const char *set = diff_get_color(use_color, DIFF_METAINFO);
+       const char *reset = diff_get_color(use_color, DIFF_RESET);
        struct strbuf *msgbuf;
        char *line_prefix = "";
 
+       *must_show_header = 1;
        if (o->output_prefix) {
                msgbuf = o->output_prefix(o, o->output_prefix_data);
                line_prefix = msgbuf->buf;
        }
-
        strbuf_init(msg, PATH_MAX * 2 + 300);
        switch (p->status) {
        case DIFF_STATUS_COPIED:
-               strbuf_addf(msg, "%ssimilarity index %d%%", line_prefix, similarity_index(p));
-               strbuf_addf(msg, "\n%scopy from ", line_prefix);
+               strbuf_addf(msg, "%s%ssimilarity index %d%%",
+                           line_prefix, set, similarity_index(p));
+               strbuf_addf(msg, "%s\n%s%scopy from ",
+                           reset,  line_prefix, set);
                quote_c_style(name, msg, NULL, 0);
-               strbuf_addf(msg, "\n%scopy to ", line_prefix);
+               strbuf_addf(msg, "%s\n%s%scopy to ", reset, line_prefix, set);
                quote_c_style(other, msg, NULL, 0);
-               strbuf_addch(msg, '\n');
+               strbuf_addf(msg, "%s\n", reset);
                break;
        case DIFF_STATUS_RENAMED:
-               strbuf_addf(msg, "%ssimilarity index %d%%", line_prefix, similarity_index(p));
-               strbuf_addf(msg, "\n%srename from ", line_prefix);
+               strbuf_addf(msg, "%s%ssimilarity index %d%%",
+                           line_prefix, set, similarity_index(p));
+               strbuf_addf(msg, "%s\n%s%srename from ",
+                           reset, line_prefix, set);
                quote_c_style(name, msg, NULL, 0);
-               strbuf_addf(msg, "\n%srename to ", line_prefix);
+               strbuf_addf(msg, "%s\n%s%srename to ",
+                           reset, line_prefix, set);
                quote_c_style(other, msg, NULL, 0);
-               strbuf_addch(msg, '\n');
+               strbuf_addf(msg, "%s\n", reset);
                break;
        case DIFF_STATUS_MODIFIED:
                if (p->score) {
-                       strbuf_addf(msg, "%sdissimilarity index %d%%\n",
-                                   line_prefix, similarity_index(p));
+                       strbuf_addf(msg, "%s%sdissimilarity index %d%%%s\n",
+                                   line_prefix,
+                                   set, similarity_index(p), reset);
                        break;
                }
                /* fallthru */
        default:
                /* nothing */
-               ;
+               *must_show_header = 0;
        }
        if (one && two && hashcmp(one->sha1, two->sha1)) {
                int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
@@ -2610,15 +2632,14 @@ static void fill_metainfo(struct strbuf *msg,
                            (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
                                abbrev = 40;
                }
-               strbuf_addf(msg, "%sindex %.*s..%.*s",
-                           line_prefix, abbrev, sha1_to_hex(one->sha1),
-                           abbrev, sha1_to_hex(two->sha1));
+               strbuf_addf(msg, "%s%sindex %s..", set,
+                           line_prefix,
+                           find_unique_abbrev(one->sha1, abbrev));
+               strbuf_addstr(msg, find_unique_abbrev(two->sha1, abbrev));
                if (one->mode == two->mode)
                        strbuf_addf(msg, " %06o", one->mode);
-               strbuf_addch(msg, '\n');
+               strbuf_addf(msg, "%s\n", reset);
        }
-       if (msg->len)
-               strbuf_setlen(msg, msg->len - 1);
 }
 
 static void run_diff_cmd(const char *pgm,
@@ -2633,11 +2654,7 @@ static void run_diff_cmd(const char *pgm,
 {
        const char *xfrm_msg = NULL;
        int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score;
-
-       if (msg) {
-               fill_metainfo(msg, name, other, one, two, o, p);
-               xfrm_msg = msg->len ? msg->buf : NULL;
-       }
+       int must_show_header = 0;
 
        if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
                pgm = NULL;
@@ -2647,6 +2664,17 @@ static void run_diff_cmd(const char *pgm,
                        pgm = drv->external;
        }
 
+       if (msg) {
+               /*
+                * don't use colors when the header is intended for an
+                * external diff driver
+                */
+               fill_metainfo(msg, name, other, one, two, o, p,
+                             &must_show_header,
+                             DIFF_OPT_TST(o, COLOR_DIFF) && !pgm);
+               xfrm_msg = msg->len ? msg->buf : NULL;
+       }
+
        if (pgm) {
                run_external_diff(pgm, name, other, one, two, xfrm_msg,
                                  complete_rewrite);
@@ -2654,7 +2682,8 @@ static void run_diff_cmd(const char *pgm,
        }
        if (one && two)
                builtin_diff(name, other ? other : name,
-                            one, two, xfrm_msg, o, complete_rewrite);
+                            one, two, xfrm_msg, must_show_header,
+                            o, complete_rewrite);
        else
                fprintf(o->file, "* Unmerged path %s\n", name);
 }
@@ -2807,7 +2836,9 @@ void diff_setup(struct diff_options *options)
                DIFF_OPT_SET(options, COLOR_DIFF);
        options->detect_rename = diff_detect_rename_default;
 
-       if (!diff_mnemonic_prefix) {
+       if (diff_no_prefix) {
+               options->a_prefix = options->b_prefix = "";
+       } else if (!diff_mnemonic_prefix) {
                options->a_prefix = "a/";
                options->b_prefix = "b/";
        }
@@ -3731,7 +3762,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
                                        len2, p->two->path);
                git_SHA1_Update(&ctx, buffer, len1);
 
-               xpp.flags = XDF_NEED_MINIMAL;
+               xpp.flags = 0;
                xecfg.ctxlen = 3;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
                xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,