Code

Merge branch 'jc/diff-algo-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Mon, 16 Apr 2012 05:51:14 +0000 (22:51 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 16 Apr 2012 05:51:15 +0000 (22:51 -0700)
Resurrects the preparatory clean-up patches from another topic that was
discarded, as this would give a saner foundation to build on diff.algo
configuration option series.

* jc/diff-algo-cleanup:
  xdiff: PATIENCE/HISTOGRAM are not independent option bits
  xdiff: remove XDL_PATCH_* macros

1  2 
diff.c
diff.h
merge-recursive.c

diff --combined diff.c
index 377ec1ea4cd90524f7c7525846fc95c3a9e66920,52cda7a0da154029eac675cea8acdbbe5b45ebf8..f43b581f41617af61d985fe1f07e99c45f5ebcc5
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -31,7 -31,6 +31,7 @@@ static const char *external_diff_cmd_cf
  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;
  
@@@ -157,10 -156,6 +157,10 @@@ int git_diff_ui_config(const char *var
                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"))
@@@ -182,8 -177,11 +182,8 @@@ int git_diff_basic_config(const char *v
                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);
@@@ -1115,15 -1113,6 +1115,15 @@@ static void fn_out_consume(void *priv, 
                        diff_words_append(line, len,
                                          &ecbdata->diff_words->plus);
                        return;
 +              } else if (!prefixcmp(line, "\\ ")) {
 +                      /*
 +                       * Eat the "no newline at eof" marker as if we
 +                       * saw a "+" or "-" line with nothing on it,
 +                       * and return without diff_words_flush() to
 +                       * defer processing. If this is the end of
 +                       * preimage, more "+" lines may come after it.
 +                       */
 +                      return;
                }
                diff_words_flush(ecbdata);
                if (ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) {
@@@ -1278,15 -1267,13 +1278,15 @@@ const char mime_boundary_leader[] = "--
  
  static int scale_linear(int it, int width, int max_change)
  {
 +      if (!it)
 +              return 0;
        /*
 -       * make sure that at least one '-' is printed if there were deletions,
 -       * and likewise for '+'.
 +       * make sure that at least one '-' or '+' is printed if
 +       * there is any change to this path. The easiest way is to
 +       * scale linearly as if the alloted width is one column shorter
 +       * than it is, and then add 1 to the result.
         */
 -      if (max_change < 2)
 -              return it;
 -      return ((it - 1) * (width - 1) + max_change - 1) / (max_change - 1);
 +      return 1 + (it * (width - 1) / max_change);
  }
  
  static void show_name(FILE *file,
@@@ -1326,61 -1313,12 +1326,61 @@@ static void fill_print_name(struct diff
        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;
        uintmax_t max_change = 0, max_len = 0;
        int total_files = data->nr;
 -      int width, name_width, count;
 +      int width, name_width, graph_width, number_width = 4, count;
        const char *reset, *add_c, *del_c;
        const char *line_prefix = "";
        int extra_shown = 0;
                line_prefix = msg->buf;
        }
  
 -      width = options->stat_width ? options->stat_width : 80;
 -      name_width = options->stat_name_width ? options->stat_name_width : 50;
        count = options->stat_count ? options->stat_count : data->nr;
  
 -      /* Sanity: give at least 5 columns to the graph,
 -       * but leave at least 10 columns for the name.
 -       */
 -      if (width < 25)
 -              width = 25;
 -      if (name_width < 10)
 -              name_width = 10;
 -      else if (width < name_width + 15)
 -              name_width = width - 15;
 -
 -      /* Find the longest filename and max number of changes */
        reset = diff_get_color_opt(options, DIFF_RESET);
        add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
        del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
  
 +      /*
 +       * Find the longest filename and max number of changes
 +       */
        for (i = 0; (i < count) && (i < data->nr); i++) {
                struct diffstat_file *file = data->files[i];
                uintmax_t change = file->added + file->deleted;
        }
        count = i; /* min(count, data->nr) */
  
 -      /* Compute the width of the graph part;
 -       * 10 is for one blank at the beginning of the line plus
 -       * " | count " between the name and the graph.
 +      /*
 +       * We have width = stat_width or term_columns() columns total.
 +       * We want a maximum of min(max_len, stat_name_width) for the name part.
 +       * We want a maximum of min(max_change, stat_graph_width) for the +- part.
 +       * We also need 1 for " " and 4 + decimal_width(max_change)
 +       * for " | NNNN " and one the empty column at the end, altogether
 +       * 6 + decimal_width(max_change).
         *
 -       * From here on, name_width is the width of the name area,
 -       * and width is the width of the graph area.
 +       * If there's not enough space, we will use the smaller of
 +       * stat_name_width (if set) and 5/8*width for the filename,
 +       * and the rest for constant elements + graph part, but no more
 +       * than stat_graph_width for the graph part.
 +       * (5/8 gives 50 for filename and 30 for the constant parts + graph
 +       * for the standard terminal size).
 +       *
 +       * In other words: stat_width limits the maximum width, and
 +       * stat_name_width fixes the maximum width of the filename,
 +       * and is also used to divide available columns if there
 +       * aren't enough.
         */
 -      name_width = (name_width < max_len) ? name_width : max_len;
 -      if (width < (name_width + 10) + max_change)
 -              width = width - (name_width + 10);
 +
 +      if (options->stat_width == -1)
 +              width = term_columns();
        else
 -              width = max_change;
 +              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
 +       */
 +      if (width < 16 + 6 + number_width)
 +              width = 16 + 6 + number_width;
 +
 +      /*
 +       * First assign sizes that are wanted, ignoring available width.
 +       */
 +      graph_width = (options->stat_graph_width &&
 +                     options->stat_graph_width < max_change) ?
 +              options->stat_graph_width : max_change;
 +      name_width = (options->stat_name_width > 0 &&
 +                    options->stat_name_width < max_len) ?
 +              options->stat_name_width : max_len;
 +
 +      /*
 +       * Adjust adjustable widths not to exceed maximum width
 +       */
 +      if (name_width + number_width + 6 + graph_width > width) {
 +              if (graph_width > width * 3/8 - number_width - 6)
 +                      graph_width = width * 3/8 - number_width - 6;
 +              if (options->stat_graph_width &&
 +                  graph_width > options->stat_graph_width)
 +                      graph_width = options->stat_graph_width;
 +              if (name_width > width - number_width - 6 - graph_width)
 +                      name_width = width - number_width - 6 - graph_width;
 +              else
 +                      graph_width = width - number_width - 6 - name_width;
 +      }
  
 +      /*
 +       * From here name_width is the width of the name area,
 +       * and graph_width is the width of the graph area.
 +       * max_change is used to scale graph properly.
 +       */
        for (i = 0; i < count; i++) {
                const char *prefix = "";
                char *name = data->files[i]->print_name;
                adds += add;
                dels += del;
  
 -              if (width <= max_change) {
 -                      add = scale_linear(add, width, max_change);
 -                      del = scale_linear(del, width, max_change);
 +              if (graph_width <= max_change) {
 +                      int total = add + del;
 +
 +                      total = scale_linear(add + del, graph_width, max_change);
 +                      if (total < 2 && add && del)
 +                              /* width >= 2 due to the sanity check */
 +                              total = 2;
 +                      if (add < del) {
 +                              add = scale_linear(add, graph_width, max_change);
 +                              del = total - add;
 +                      } else {
 +                              del = scale_linear(del, graph_width, max_change);
 +                              add = total - del;
 +                      }
                }
                fprintf(options->file, "%s", line_prefix);
                show_name(options->file, prefix, name, len);
                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)
                                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)
@@@ -2255,7 -2142,7 +2255,7 @@@ static void builtin_diff(const char *na
                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);
                }
@@@ -3347,7 -3234,6 +3347,7 @@@ static int stat_opt(struct diff_option
        char *end;
        int width = options->stat_width;
        int name_width = options->stat_name_width;
 +      int graph_width = options->stat_graph_width;
        int count = options->stat_count;
        int argcount = 1;
  
                                name_width = strtoul(av[1], &end, 10);
                                argcount = 2;
                        }
 +              } else if (!prefixcmp(arg, "-graph-width")) {
 +                      arg += strlen("-graph-width");
 +                      if (*arg == '=')
 +                              graph_width = strtoul(arg + 1, &end, 10);
 +                      else if (!*arg && !av[1])
 +                              die("Option '--stat-graph-width' requires a value");
 +                      else if (!*arg) {
 +                              graph_width = strtoul(av[1], &end, 10);
 +                              argcount = 2;
 +                      }
                } else if (!prefixcmp(arg, "-count")) {
                        arg += strlen("-count");
                        if (*arg == '=')
                return 0;
        options->output_format |= DIFF_FORMAT_DIFFSTAT;
        options->stat_name_width = name_width;
 +      options->stat_graph_width = graph_width;
        options->stat_width = width;
        options->stat_count = count;
        return argcount;
@@@ -3525,9 -3400,9 +3525,9 @@@ int diff_opt_parse(struct diff_options 
        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")) {
diff --combined diff.h
index cb687436a0ddb9a08fc1a9e9cec569233284e01f,e688a48d10de628415129c334e96361be973abcd..e9e3d44c674a39bb1912ca366ca12512dfb4d2c7
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -12,8 -12,6 +12,8 @@@ struct diff_queue_struct
  struct strbuf;
  struct diff_filespec;
  struct userdiff_driver;
 +struct sha1_array;
 +struct commit;
  
  typedef void (*change_fn_t)(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
@@@ -82,7 -80,6 +82,7 @@@ typedef struct strbuf *(*diff_prefix_fn
  #define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
  #define DIFF_OPT_DIRSTAT_BY_LINE     (1 << 28)
  #define DIFF_OPT_FUNCCONTEXT         (1 << 29)
 +#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
  
  #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
  #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)
@@@ -91,6 -88,8 +91,8 @@@
  #define DIFF_XDL_SET(opts, flag)    ((opts)->xdl_opts |= XDF_##flag)
  #define DIFF_XDL_CLR(opts, flag)    ((opts)->xdl_opts &= ~XDF_##flag)
  
+ #define DIFF_WITH_ALG(opts, flag)   (((opts)->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | XDF_##flag)
  enum diff_words_type {
        DIFF_WORDS_NONE = 0,
        DIFF_WORDS_PORCELAIN,
@@@ -130,7 -129,6 +132,7 @@@ struct diff_options 
  
        int stat_width;
        int stat_name_width;
 +      int stat_graph_width;
        int stat_count;
        const char *word_regex;
        enum diff_words_type word_diff;
@@@ -199,9 -197,9 +201,9 @@@ struct combine_diff_path 
  extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
                              int dense, struct rev_info *);
  
 -extern void diff_tree_combined(const unsigned char *sha1, const unsigned char parent[][20], int num_parent, int dense, struct rev_info *rev);
 +extern void diff_tree_combined(const unsigned char *sha1, const struct sha1_array *parents, int dense, struct rev_info *rev);
  
 -extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *);
 +extern void diff_tree_combined_merge(const struct commit *commit, int dense, struct rev_info *rev);
  
  void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b);
  
@@@ -326,7 -324,4 +328,7 @@@ extern struct userdiff_driver *get_text
  
  extern int parse_rename_score(const char **cp_p);
  
 +extern int print_stat_summary(FILE *fp, int files,
 +                            int insertions, int deletions);
 +
  #endif /* DIFF_H */
diff --combined merge-recursive.c
index 6479a60cd112c5b06b354b1a251c60bb4bce972a,1d574fee8b61b3273787f0b9085a45c59b454d42..857f03dc6112ed5bce6b77b7da9535330ea29015
@@@ -38,15 -38,16 +38,15 @@@ static struct tree *shift_tree_object(s
        return lookup_tree(shifted);
  }
  
 -/*
 - * A virtual commit has (const char *)commit->util set to the name.
 - */
 -
  static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
  {
        struct commit *commit = xcalloc(1, sizeof(struct commit));
 +      struct merge_remote_desc *desc = xmalloc(sizeof(*desc));
 +
 +      desc->name = comment;
 +      desc->obj = (struct object *)commit;
        commit->tree = tree;
 -      commit->util = (void*)comment;
 -      /* avoid warnings */
 +      commit->util = desc;
        commit->object.parsed = 1;
        return commit;
  }
@@@ -183,7 -184,7 +183,7 @@@ static void output_commit_title(struct 
        for (i = o->call_depth; i--;)
                fputs("  ", stdout);
        if (commit->util)
 -              printf("virtual %s\n", (char *)commit->util);
 +              printf("virtual %s\n", merge_remote_util(commit)->name);
        else {
                printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
                if (parse_commit(commit) != 0)
@@@ -264,7 -265,7 +264,7 @@@ struct tree *write_tree_from_memory(str
  
        if (!cache_tree_fully_valid(active_cache_tree) &&
            cache_tree_update(active_cache_tree,
 -                            active_cache, active_nr, 0, 0) < 0)
 +                            active_cache, active_nr, 0) < 0)
                die("error building trees");
  
        result = lookup_tree(active_cache_tree->sha1);
@@@ -2068,9 -2069,9 +2068,9 @@@ int parse_merge_opt(struct merge_option
        else if (!prefixcmp(s, "subtree="))
                o->subtree_shift = s + strlen("subtree=");
        else if (!strcmp(s, "patience"))
-               o->xdl_opts |= XDF_PATIENCE_DIFF;
+               o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
        else if (!strcmp(s, "histogram"))
-               o->xdl_opts |= XDF_HISTOGRAM_DIFF;
+               o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
        else if (!strcmp(s, "ignore-space-change"))
                o->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else if (!strcmp(s, "ignore-all-space"))