Code

RelNotes: the first batch of topics graduated to 'master'
[git.git] / diff.c
diff --git a/diff.c b/diff.c
index 8f2abc8fe4b73590cbdecbaaa5cfe75eb1a4829c..b020c070cac15e7448178db67a480fc311f18ad9 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg;
 int diff_auto_refresh_index = 1;
 static int diff_mnemonic_prefix;
 static int diff_no_prefix;
+static int diff_stat_graph_width;
 static int diff_dirstat_permille_default = 30;
 static struct diff_options default_diff_options;
 
@@ -156,6 +157,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_no_prefix = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "diff.statgraphwidth")) {
+               diff_stat_graph_width = git_config_int(var, value);
+               return 0;
+       }
        if (!strcmp(var, "diff.external"))
                return git_config_string(&external_diff_cmd_cfg, var, value);
        if (!strcmp(var, "diff.wordregex"))
@@ -177,11 +182,8 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       switch (userdiff_config(var, value)) {
-               case 0: break;
-               case -1: return -1;
-               default: return 0;
-       }
+       if (userdiff_config(var, value) < 0)
+               return -1;
 
        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
@@ -987,10 +989,74 @@ static void diff_words_flush(struct emit_callback *ecbdata)
                diff_words_show(ecbdata->diff_words);
 }
 
+static void diff_filespec_load_driver(struct diff_filespec *one)
+{
+       /* Use already-loaded driver */
+       if (one->driver)
+               return;
+
+       if (S_ISREG(one->mode))
+               one->driver = userdiff_find_by_path(one->path);
+
+       /* Fallback to default settings */
+       if (!one->driver)
+               one->driver = userdiff_find_by_name("default");
+}
+
+static const char *userdiff_word_regex(struct diff_filespec *one)
+{
+       diff_filespec_load_driver(one);
+       return one->driver->word_regex;
+}
+
+static void init_diff_words_data(struct emit_callback *ecbdata,
+                                struct diff_options *orig_opts,
+                                struct diff_filespec *one,
+                                struct diff_filespec *two)
+{
+       int i;
+       struct diff_options *o = xmalloc(sizeof(struct diff_options));
+       memcpy(o, orig_opts, sizeof(struct diff_options));
+
+       ecbdata->diff_words =
+               xcalloc(1, sizeof(struct diff_words_data));
+       ecbdata->diff_words->type = o->word_diff;
+       ecbdata->diff_words->opt = o;
+       if (!o->word_regex)
+               o->word_regex = userdiff_word_regex(one);
+       if (!o->word_regex)
+               o->word_regex = userdiff_word_regex(two);
+       if (!o->word_regex)
+               o->word_regex = diff_word_regex_cfg;
+       if (o->word_regex) {
+               ecbdata->diff_words->word_regex = (regex_t *)
+                       xmalloc(sizeof(regex_t));
+               if (regcomp(ecbdata->diff_words->word_regex,
+                           o->word_regex,
+                           REG_EXTENDED | REG_NEWLINE))
+                       die ("Invalid regular expression: %s",
+                            o->word_regex);
+       }
+       for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
+               if (o->word_diff == diff_words_styles[i].type) {
+                       ecbdata->diff_words->style =
+                               &diff_words_styles[i];
+                       break;
+               }
+       }
+       if (want_color(o->use_color)) {
+               struct diff_words_style *st = ecbdata->diff_words->style;
+               st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD);
+               st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW);
+               st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN);
+       }
+}
+
 static void free_diff_words_data(struct emit_callback *ecbdata)
 {
        if (ecbdata->diff_words) {
                diff_words_flush(ecbdata);
+               free (ecbdata->diff_words->opt);
                free (ecbdata->diff_words->minus.text.ptr);
                free (ecbdata->diff_words->minus.orig);
                free (ecbdata->diff_words->plus.text.ptr);
@@ -1324,6 +1390,55 @@ static void fill_print_name(struct diffstat_file *file)
        file->print_name = pname;
 }
 
+int print_stat_summary(FILE *fp, int files, int insertions, int deletions)
+{
+       struct strbuf sb = STRBUF_INIT;
+       int ret;
+
+       if (!files) {
+               assert(insertions == 0 && deletions == 0);
+               return fputs(_(" 0 files changed\n"), fp);
+       }
+
+       strbuf_addf(&sb,
+                   Q_(" %d file changed", " %d files changed", files),
+                   files);
+
+       /*
+        * For binary diff, the caller may want to print "x files
+        * changed" with insertions == 0 && deletions == 0.
+        *
+        * Not omitting "0 insertions(+), 0 deletions(-)" in this case
+        * is probably less confusing (i.e skip over "2 files changed
+        * but nothing about added/removed lines? Is this a bug in Git?").
+        */
+       if (insertions || deletions == 0) {
+               /*
+                * TRANSLATORS: "+" in (+) is a line addition marker;
+                * do not translate it.
+                */
+               strbuf_addf(&sb,
+                           Q_(", %d insertion(+)", ", %d insertions(+)",
+                              insertions),
+                           insertions);
+       }
+
+       if (deletions || insertions == 0) {
+               /*
+                * TRANSLATORS: "-" in (-) is a line removal marker;
+                * do not translate it.
+                */
+               strbuf_addf(&sb,
+                           Q_(", %d deletion(-)", ", %d deletions(-)",
+                              deletions),
+                           deletions);
+       }
+       strbuf_addch(&sb, '\n');
+       ret = fputs(sb.buf, fp);
+       strbuf_release(&sb);
+       return ret;
+}
+
 static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
        int i, len, add, del, adds = 0, dels = 0;
@@ -1398,6 +1513,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
        else
                width = options->stat_width ? options->stat_width : 80;
 
+       if (options->stat_graph_width == -1)
+               options->stat_graph_width = diff_stat_graph_width;
+
        /*
         * Guarantee 3/8*16==6 for the graph part
         * and 5/8*16==10 for the filename part
@@ -1528,9 +1646,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                extra_shown = 1;
        }
        fprintf(options->file, "%s", line_prefix);
-       fprintf(options->file,
-              " %d files changed, %d insertions(+), %d deletions(-)\n",
-              total_files, adds, dels);
+       print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_shortstats(struct diffstat_t *data, struct diff_options *options)
@@ -1560,8 +1676,7 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option
                                options->output_prefix_data);
                fprintf(options->file, "%s", msg->buf);
        }
-       fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n",
-              total_files, adds, dels);
+       print_stat_summary(options->file, total_files, adds, dels);
 }
 
 static void show_numstat(struct diffstat_t *data, struct diff_options *options)
@@ -2010,20 +2125,6 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two, char *pre
        emit_binary_diff_body(file, two, one, prefix);
 }
 
-static void diff_filespec_load_driver(struct diff_filespec *one)
-{
-       /* Use already-loaded driver */
-       if (one->driver)
-               return;
-
-       if (S_ISREG(one->mode))
-               one->driver = userdiff_find_by_path(one->path);
-
-       /* Fallback to default settings */
-       if (!one->driver)
-               one->driver = userdiff_find_by_name("default");
-}
-
 int diff_filespec_is_binary(struct diff_filespec *one)
 {
        if (one->is_binary == -1) {
@@ -2049,12 +2150,6 @@ static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespe
        return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
 }
 
-static const char *userdiff_word_regex(struct diff_filespec *one)
-{
-       diff_filespec_load_driver(one);
-       return one->driver->word_regex;
-}
-
 void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
 {
        if (!options->a_prefix)
@@ -2204,7 +2299,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) || must_show_header) {
+               if (must_show_header) {
                        fprintf(o->file, "%s", header.buf);
                        strbuf_reset(&header);
                }
@@ -2241,42 +2336,8 @@ static void builtin_diff(const char *name_a,
                        xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
                else if (!prefixcmp(diffopts, "-u"))
                        xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
-               if (o->word_diff) {
-                       int i;
-
-                       ecbdata.diff_words =
-                               xcalloc(1, sizeof(struct diff_words_data));
-                       ecbdata.diff_words->type = o->word_diff;
-                       ecbdata.diff_words->opt = o;
-                       if (!o->word_regex)
-                               o->word_regex = userdiff_word_regex(one);
-                       if (!o->word_regex)
-                               o->word_regex = userdiff_word_regex(two);
-                       if (!o->word_regex)
-                               o->word_regex = diff_word_regex_cfg;
-                       if (o->word_regex) {
-                               ecbdata.diff_words->word_regex = (regex_t *)
-                                       xmalloc(sizeof(regex_t));
-                               if (regcomp(ecbdata.diff_words->word_regex,
-                                               o->word_regex,
-                                               REG_EXTENDED | REG_NEWLINE))
-                                       die ("Invalid regular expression: %s",
-                                                       o->word_regex);
-                       }
-                       for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
-                               if (o->word_diff == diff_words_styles[i].type) {
-                                       ecbdata.diff_words->style =
-                                               &diff_words_styles[i];
-                                       break;
-                               }
-                       }
-                       if (want_color(o->use_color)) {
-                               struct diff_words_style *st = ecbdata.diff_words->style;
-                               st->old.color = diff_get_color_opt(o, DIFF_FILE_OLD);
-                               st->new.color = diff_get_color_opt(o, DIFF_FILE_NEW);
-                               st->ctx.color = diff_get_color_opt(o, DIFF_PLAIN);
-                       }
-               }
+               if (o->word_diff)
+                       init_diff_words_data(&ecbdata, o, one, two);
                xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
                              &xpp, &xecfg);
                if (o->word_diff)
@@ -3474,9 +3535,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if (!strcmp(arg, "--ignore-space-at-eol"))
                DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL);
        else if (!strcmp(arg, "--patience"))
-               DIFF_XDL_SET(options, PATIENCE_DIFF);
+               options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
        else if (!strcmp(arg, "--histogram"))
-               DIFF_XDL_SET(options, HISTOGRAM_DIFF);
+               options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF);
 
        /* flags options */
        else if (!strcmp(arg, "--binary")) {