Merge branch 'nd/pack-objects-threading-doc'
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 7810a4733f8f230af54d1d8b8d96484ebea3a2bc..f830afac79134219e706730c05d98f81d4a1d8cd 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -13,6 +13,7 @@
 #include "attr.h"
 #include "run-command.h"
 #include "utf8.h"
+#include "object-store.h"
 #include "userdiff.h"
 #include "submodule-config.h"
 #include "submodule.h"
@@ -22,6 +23,7 @@
 #include "argv-array.h"
 #include "graph.h"
 #include "packfile.h"
+#include "help.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -35,6 +37,7 @@ static int diff_rename_limit_default = 400;
 static int diff_suppress_blank_empty;
 static int diff_use_color_default = -1;
 static int diff_color_moved_default;
+static int diff_color_moved_ws_default;
 static int diff_context_default = 3;
 static int diff_interhunk_context_default;
 static const char *diff_word_regex_cfg;
@@ -69,46 +72,37 @@ static char diff_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_FAINT_ITALIC, /* NEW_MOVED_ALTERNATIVE_DIM */
 };
 
+static const char *color_diff_slots[] = {
+       [DIFF_CONTEXT]                = "context",
+       [DIFF_METAINFO]               = "meta",
+       [DIFF_FRAGINFO]               = "frag",
+       [DIFF_FILE_OLD]               = "old",
+       [DIFF_FILE_NEW]               = "new",
+       [DIFF_COMMIT]                 = "commit",
+       [DIFF_WHITESPACE]             = "whitespace",
+       [DIFF_FUNCINFO]               = "func",
+       [DIFF_FILE_OLD_MOVED]         = "oldMoved",
+       [DIFF_FILE_OLD_MOVED_ALT]     = "oldMovedAlternative",
+       [DIFF_FILE_OLD_MOVED_DIM]     = "oldMovedDimmed",
+       [DIFF_FILE_OLD_MOVED_ALT_DIM] = "oldMovedAlternativeDimmed",
+       [DIFF_FILE_NEW_MOVED]         = "newMoved",
+       [DIFF_FILE_NEW_MOVED_ALT]     = "newMovedAlternative",
+       [DIFF_FILE_NEW_MOVED_DIM]     = "newMovedDimmed",
+       [DIFF_FILE_NEW_MOVED_ALT_DIM] = "newMovedAlternativeDimmed",
+};
+
 static NORETURN void die_want_option(const char *option_name)
 {
        die(_("option '%s' requires a value"), option_name);
 }
 
+define_list_config_array_extra(color_diff_slots, {"plain"});
+
 static int parse_diff_color_slot(const char *var)
 {
-       if (!strcasecmp(var, "context") || !strcasecmp(var, "plain"))
+       if (!strcasecmp(var, "plain"))
                return DIFF_CONTEXT;
-       if (!strcasecmp(var, "meta"))
-               return DIFF_METAINFO;
-       if (!strcasecmp(var, "frag"))
-               return DIFF_FRAGINFO;
-       if (!strcasecmp(var, "old"))
-               return DIFF_FILE_OLD;
-       if (!strcasecmp(var, "new"))
-               return DIFF_FILE_NEW;
-       if (!strcasecmp(var, "commit"))
-               return DIFF_COMMIT;
-       if (!strcasecmp(var, "whitespace"))
-               return DIFF_WHITESPACE;
-       if (!strcasecmp(var, "func"))
-               return DIFF_FUNCINFO;
-       if (!strcasecmp(var, "oldmoved"))
-               return DIFF_FILE_OLD_MOVED;
-       if (!strcasecmp(var, "oldmovedalternative"))
-               return DIFF_FILE_OLD_MOVED_ALT;
-       if (!strcasecmp(var, "oldmoveddimmed"))
-               return DIFF_FILE_OLD_MOVED_DIM;
-       if (!strcasecmp(var, "oldmovedalternativedimmed"))
-               return DIFF_FILE_OLD_MOVED_ALT_DIM;
-       if (!strcasecmp(var, "newmoved"))
-               return DIFF_FILE_NEW_MOVED;
-       if (!strcasecmp(var, "newmovedalternative"))
-               return DIFF_FILE_NEW_MOVED_ALT;
-       if (!strcasecmp(var, "newmoveddimmed"))
-               return DIFF_FILE_NEW_MOVED_DIM;
-       if (!strcasecmp(var, "newmovedalternativedimmed"))
-               return DIFF_FILE_NEW_MOVED_ALT_DIM;
-       return -1;
+       return LOOKUP_CONFIG(color_diff_slots, var);
 }
 
 static int parse_dirstat_params(struct diff_options *options, const char *params_string,
@@ -177,7 +171,7 @@ static int parse_submodule_params(struct diff_options *options, const char *valu
        return 0;
 }
 
-static int git_config_rename(const char *var, const char *value)
+int git_config_rename(const char *var, const char *value)
 {
        if (!value)
                return DIFF_DETECT_RENAME;
@@ -277,10 +271,12 @@ static int parse_color_moved(const char *arg)
                return COLOR_MOVED_ZEBRA;
        else if (!strcmp(arg, "default"))
                return COLOR_MOVED_DEFAULT;
+       else if (!strcmp(arg, "dimmed-zebra"))
+               return COLOR_MOVED_ZEBRA_DIM;
        else if (!strcmp(arg, "dimmed_zebra"))
                return COLOR_MOVED_ZEBRA_DIM;
        else
-               return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed_zebra', 'plain'"));
+               return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed-zebra', 'plain'"));
 }
 
 static int parse_color_moved_ws(const char *arg)
@@ -332,6 +328,13 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_color_moved_default = cm;
                return 0;
        }
+       if (!strcmp(var, "diff.colormovedws")) {
+               int cm = parse_color_moved_ws(value);
+               if (cm < 0)
+                       return -1;
+               diff_color_moved_ws_default = cm;
+               return 0;
+       }
        if (!strcmp(var, "diff.context")) {
                diff_context_default = git_config_int(var, value);
                if (diff_context_default < 0)
@@ -1381,7 +1384,7 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
                fputs(o->stat_sep, o->file);
                break;
        default:
-               die("BUG: unknown diff symbol");
+               BUG("unknown diff symbol");
        }
        strbuf_release(&sb);
 }
@@ -1540,7 +1543,7 @@ static struct diff_tempfile *claim_diff_tempfile(void) {
        for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
                if (!diff_temp[i].name)
                        return diff_temp + i;
-       die("BUG: diff is failing to clean up its tempfiles");
+       BUG("diff is failing to clean up its tempfiles");
 }
 
 static void remove_tempfile(void)
@@ -2068,8 +2071,8 @@ static void init_diff_words_data(struct emit_callback *ecbdata,
                if (regcomp(ecbdata->diff_words->word_regex,
                            o->word_regex,
                            REG_EXTENDED | REG_NEWLINE))
-                       die ("Invalid regular expression: %s",
-                            o->word_regex);
+                       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) {
@@ -3669,7 +3672,7 @@ static int reuse_worktree_file(const char *name, const struct object_id *oid, in
         * objects however would tend to be slower as they need
         * to be individually opened and inflated.
         */
-       if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(oid->hash))
+       if (!FAST_WORKING_DIRECTORY && !want_file && has_object_pack(oid))
                return 0;
 
        /*
@@ -3835,7 +3838,8 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
        else {
                enum object_type type;
                if (size_only || (flags & CHECK_BINARY)) {
-                       type = oid_object_info(&s->oid, &s->size);
+                       type = oid_object_info(the_repository, &s->oid,
+                                              &s->size);
                        if (type < 0)
                                die("unable to read %s",
                                    oid_to_hex(&s->oid));
@@ -4036,8 +4040,8 @@ static const char *diff_abbrev_oid(const struct object_id *oid, int abbrev)
                char *hex = oid_to_hex(oid);
                if (abbrev < 0)
                        abbrev = FALLBACK_DEFAULT_ABBREV;
-               if (abbrev > GIT_SHA1_HEXSZ)
-                       die("BUG: oid abbreviation out of range: %d", abbrev);
+               if (abbrev > the_hash_algo->hexsz)
+                       BUG("oid abbreviation out of range: %d", abbrev);
                if (abbrev)
                        hex[abbrev] = '\0';
                return hex;
@@ -4094,13 +4098,14 @@ static void fill_metainfo(struct strbuf *msg,
                *must_show_header = 0;
        }
        if (one && two && oidcmp(&one->oid, &two->oid)) {
-               int abbrev = o->flags.full_index ? 40 : DEFAULT_ABBREV;
+               const unsigned hexsz = the_hash_algo->hexsz;
+               int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV;
 
                if (o->flags.binary) {
                        mmfile_t mf;
                        if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
                            (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
-                               abbrev = 40;
+                               abbrev = hexsz;
                }
                strbuf_addf(msg, "%s%sindex %s..%s", line_prefix, set,
                            diff_abbrev_oid(&one->oid, abbrev),
@@ -4327,6 +4332,7 @@ void diff_setup(struct diff_options *options)
        }
 
        options->color_moved = diff_color_moved_default;
+       options->color_moved_ws_handling = diff_color_moved_ws_default;
 }
 
 void diff_setup_done(struct diff_options *options)
@@ -4335,6 +4341,11 @@ void diff_setup_done(struct diff_options *options)
                              DIFF_FORMAT_NAME_STATUS |
                              DIFF_FORMAT_CHECKDIFF |
                              DIFF_FORMAT_NO_OUTPUT;
+       /*
+        * This must be signed because we're comparing against a potentially
+        * negative value.
+        */
+       const int hexsz = the_hash_algo->hexsz;
 
        if (options->set_default)
                options->set_default(options);
@@ -4415,8 +4426,8 @@ void diff_setup_done(struct diff_options *options)
                         */
                        read_cache();
        }
-       if (40 < options->abbrev)
-               options->abbrev = 40; /* full */
+       if (hexsz < options->abbrev)
+               options->abbrev = hexsz; /* full */
 
        /*
         * It does not make sense to show the first hit we happened
@@ -4531,7 +4542,7 @@ static int stat_opt(struct diff_options *options, const char **av)
        int argcount = 1;
 
        if (!skip_prefix(arg, "--stat", &arg))
-               die("BUG: stat option does not begin with --stat: %s", arg);
+               BUG("stat option does not begin with --stat: %s", arg);
        end = (char *)arg;
 
        switch (*arg) {
@@ -4996,8 +5007,8 @@ int diff_opt_parse(struct diff_options *options,
                options->abbrev = strtoul(arg, NULL, 10);
                if (options->abbrev < MINIMUM_ABBREV)
                        options->abbrev = MINIMUM_ABBREV;
-               else if (40 < options->abbrev)
-                       options->abbrev = 40;
+               else if (the_hash_algo->hexsz < options->abbrev)
+                       options->abbrev = the_hash_algo->hexsz;
        }
        else if ((argcount = parse_long_opt("src-prefix", av, &optarg))) {
                options->a_prefix = optarg;
@@ -5147,7 +5158,7 @@ const char *diff_aligned_abbrev(const struct object_id *oid, int len)
        const char *abbrev;
 
        /* Do we want all 40 hex characters? */
-       if (len == GIT_SHA1_HEXSZ)
+       if (len == the_hash_algo->hexsz)
                return oid_to_hex(oid);
 
        /* An abbreviated value is fine, possibly followed by an ellipsis. */
@@ -5177,7 +5188,7 @@ const char *diff_aligned_abbrev(const struct object_id *oid, int len)
         * the automatic sizing is supposed to give abblen that ensures
         * uniqueness across all objects (statistically speaking).
         */
-       if (abblen < GIT_SHA1_HEXSZ - 3) {
+       if (abblen < the_hash_algo->hexsz - 3) {
                static char hex[GIT_MAX_HEXSZ + 1];
                if (len < abblen && abblen <= len + 2)
                        xsnprintf(hex, sizeof(hex), "%s%.*s", abbrev, len+3-abblen, "..");
@@ -5718,7 +5729,7 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
        struct diff_queue_struct *q = &diff_queued_diff;
 
        if (WSEH_NEW & WS_RULE_MASK)
-               die("BUG: WS rules bit mask overlaps with diff symbol flags");
+               BUG("WS rules bit mask overlaps with diff symbol flags");
 
        if (o->color_moved)
                o->emitted_symbols = &esm;
@@ -6254,7 +6265,7 @@ size_t fill_textconv(struct userdiff_driver *driver,
        }
 
        if (!driver->textconv)
-               die("BUG: fill_textconv called with non-textconv driver");
+               BUG("fill_textconv called with non-textconv driver");
 
        if (driver->textconv_cache && df->oid_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache,