int diff_use_color_default = -1;
static const char *external_diff_cmd_cfg;
int diff_auto_refresh_index = 1;
+static int diff_mnemonic_prefix;
static char diff_colors[][COLOR_MAXLEN] = {
"\033[m", /* reset */
* to define a customized regexp to find the beginning of a function to
* be used for hunk header lines of "diff -p" style output.
*/
-static struct funcname_pattern {
+struct funcname_pattern_entry {
char *name;
char *pattern;
- struct funcname_pattern *next;
+ int cflags;
+};
+static struct funcname_pattern_list {
+ struct funcname_pattern_list *next;
+ struct funcname_pattern_entry e;
} *funcname_pattern_list;
-static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
+static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
{
const char *name;
int namelen;
- struct funcname_pattern *pp;
+ struct funcname_pattern_list *pp;
name = var + 5; /* "diff." */
namelen = ep - name;
for (pp = funcname_pattern_list; pp; pp = pp->next)
- if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
+ if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])
break;
if (!pp) {
pp = xcalloc(1, sizeof(*pp));
- pp->name = xmemdupz(name, namelen);
+ pp->e.name = xmemdupz(name, namelen);
pp->next = funcname_pattern_list;
funcname_pattern_list = pp;
}
- free(pp->pattern);
- pp->pattern = xstrdup(value);
+ free(pp->e.pattern);
+ pp->e.pattern = xstrdup(value);
+ pp->e.cflags = cflags;
return 0;
}
diff_auto_refresh_index = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "diff.mnemonicprefix")) {
+ diff_mnemonic_prefix = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp(var, "diff.external"))
return git_config_string(&external_diff_cmd_cfg, var, value);
if (!prefixcmp(var, "diff.")) {
if (!strcmp(ep, ".funcname")) {
if (!value)
return config_error_nonbool(var);
- return parse_funcname_pattern(var, ep, value);
+ return parse_funcname_pattern(var, ep, value,
+ 0);
+ } else if (!strcmp(ep, ".xfuncname")) {
+ if (!value)
+ return config_error_nonbool(var);
+ return parse_funcname_pattern(var, ep, value,
+ REG_EXTENDED);
}
}
}
const char *new = diff_get_color(color_diff, DIFF_FILE_NEW);
const char *reset = diff_get_color(color_diff, DIFF_RESET);
static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT;
+ const char *a_prefix, *b_prefix;
+
+ if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
+ a_prefix = o->b_prefix;
+ b_prefix = o->a_prefix;
+ } else {
+ a_prefix = o->a_prefix;
+ b_prefix = o->b_prefix;
+ }
name_a += (*name_a == '/');
name_b += (*name_b == '/');
strbuf_reset(&a_name);
strbuf_reset(&b_name);
- quote_two_c_style(&a_name, o->a_prefix, name_a, 0);
- quote_two_c_style(&b_name, o->b_prefix, name_b, 0);
+ quote_two_c_style(&a_name, a_prefix, name_a, 0);
+ quote_two_c_style(&b_name, b_prefix, name_b, 0);
diff_populate_filespec(one, 0);
diff_populate_filespec(two, 0);
static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
{
- int has_trailing_newline = (len > 0 && line[len-1] == '\n');
+ int has_trailing_newline, has_trailing_carriage_return;
+
+ has_trailing_newline = (len > 0 && line[len-1] == '\n');
if (has_trailing_newline)
len--;
+ has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
+ if (has_trailing_carriage_return)
+ len--;
fputs(set, file);
fwrite(line, len, 1, file);
fputs(reset, file);
+ if (has_trailing_carriage_return)
+ fputc('\r', file);
if (has_trailing_newline)
fputc('\n', file);
}
return this_dir;
}
+static int dirstat_compare(const void *_a, const void *_b)
+{
+ const struct dirstat_file *a = _a;
+ const struct dirstat_file *b = _b;
+ return strcmp(a->name, b->name);
+}
+
static void show_dirstat(struct diff_options *options)
{
int i;
dir.alloc = 0;
dir.nr = 0;
dir.percent = options->dirstat_percent;
- dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
+ dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
changed = 0;
for (i = 0; i < q->nr; i++) {
/*
* Original minus copied is the removed material,
* added is the new material. They are both damages
- * made to the preimage.
+ * made to the preimage. In --dirstat-by-file mode, count
+ * damaged files, not damaged lines. This is done by
+ * counting only a single damaged line per file.
*/
damage = (p->one->size - copied) + added;
+ if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0)
+ damage = 1;
ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
dir.files[dir.nr].name = name;
return;
/* Show all directories with more than x% of the changes */
+ qsort(dir.files, dir.nr, sizeof(dir.files[0]), dirstat_compare);
gather_dirstat(options->file, &dir, changed, "", 0);
}
return one->is_binary;
}
-static const char *funcname_pattern(const char *ident)
+static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
{
- struct funcname_pattern *pp;
+ struct funcname_pattern_list *pp;
for (pp = funcname_pattern_list; pp; pp = pp->next)
- if (!strcmp(ident, pp->name))
- return pp->pattern;
+ if (!strcmp(ident, pp->e.name))
+ return &pp->e;
return NULL;
}
-static struct builtin_funcname_pattern {
- const char *name;
- const char *pattern;
-} builtin_funcname_pattern[] = {
- { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" },
- { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" },
- { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
- "new\\|return\\|switch\\|throw\\|while\\)\n"
- "^[ ]*\\(\\([ ]*"
- "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
- "[ ]*([^;]*\\)$" },
- { "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
- "destructor\\|interface\\|implementation\\|"
- "initialization\\|finalization\\)[ \t]*.*\\)$"
- "\\|"
- "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$"
- },
- { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" },
- { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" },
- { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" },
+static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
+ { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
+ REG_EXTENDED },
+ { "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED },
+ { "java",
+ "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
+ "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
+ REG_EXTENDED },
+ { "pascal",
+ "^((procedure|function|constructor|destructor|interface|"
+ "implementation|initialization|finalization)[ \t]*.*)$"
+ "\n"
+ "^(.*=[ \t]*(class|record).*)$",
+ REG_EXTENDED },
+ { "php", "^[\t ]*((function|class).*)", REG_EXTENDED },
+ { "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED },
+ { "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
+ REG_EXTENDED },
+ { "tex",
+ "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
+ REG_EXTENDED },
};
-static const char *diff_funcname_pattern(struct diff_filespec *one)
+static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
{
- const char *ident, *pattern;
+ const char *ident;
+ const struct funcname_pattern_entry *pe;
int i;
diff_filespec_check_attr(one);
return funcname_pattern("default");
/* Look up custom "funcname.$ident" regexp from config. */
- pattern = funcname_pattern(ident);
- if (pattern)
- return pattern;
+ pe = funcname_pattern(ident);
+ if (pe)
+ return pe;
/*
* And define built-in fallback patterns here. Note that
*/
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
if (!strcmp(ident, builtin_funcname_pattern[i].name))
- return builtin_funcname_pattern[i].pattern;
+ return &builtin_funcname_pattern[i];
return NULL;
}
+void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
+{
+ if (!options->a_prefix)
+ options->a_prefix = a;
+ if (!options->b_prefix)
+ options->b_prefix = b;
+}
+
static void builtin_diff(const char *name_a,
const char *name_b,
struct diff_filespec *one,
char *a_one, *b_two;
const char *set = diff_get_color_opt(o, DIFF_METAINFO);
const char *reset = diff_get_color_opt(o, DIFF_RESET);
+ const char *a_prefix, *b_prefix;
+
+ diff_set_mnemonic_prefix(o, "a/", "b/");
+ if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+ a_prefix = o->b_prefix;
+ b_prefix = o->a_prefix;
+ } else {
+ a_prefix = o->a_prefix;
+ b_prefix = o->b_prefix;
+ }
+
+ /* Never use a non-valid filename anywhere if at all possible */
+ name_a = DIFF_FILE_VALID(one) ? name_a : name_b;
+ name_b = DIFF_FILE_VALID(two) ? name_b : name_a;
- a_one = quote_two(o->a_prefix, name_a + (*name_a == '/'));
- b_two = quote_two(o->b_prefix, name_b + (*name_b == '/'));
+ a_one = quote_two(a_prefix, name_a + (*name_a == '/'));
+ b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
fprintf(o->file, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
xdemitconf_t xecfg;
xdemitcb_t ecb;
struct emit_callback ecbdata;
- const char *funcname_pattern;
+ const struct funcname_pattern_entry *pe;
- funcname_pattern = diff_funcname_pattern(one);
- if (!funcname_pattern)
- funcname_pattern = diff_funcname_pattern(two);
+ pe = diff_funcname_pattern(one);
+ if (!pe)
+ pe = diff_funcname_pattern(two);
memset(&xecfg, 0, sizeof(xecfg));
memset(&ecbdata, 0, sizeof(ecbdata));
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
- if (funcname_pattern)
- xdiff_set_find_func(&xecfg, funcname_pattern);
+ if (pe)
+ xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
if (!diffopts)
;
else if (!prefixcmp(diffopts, "--unified="))
options->break_opt = -1;
options->rename_limit = -1;
options->dirstat_percent = 3;
+ DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
options->context = 3;
options->change = diff_change;
DIFF_OPT_CLR(options, COLOR_DIFF);
options->detect_rename = diff_detect_rename_default;
- options->a_prefix = "a/";
- options->b_prefix = "b/";
+ if (!diff_mnemonic_prefix) {
+ options->a_prefix = "a/";
+ options->b_prefix = "b/";
+ }
}
int diff_setup_done(struct diff_options *options)
DIFF_OPT_SET(options, EXIT_WITH_STATUS);
}
- /*
- * If we postprocess in diffcore, we cannot simply return
- * upon the first hit. We need to run diff as usual.
- */
- if (options->pickaxe || options->filter)
- DIFF_OPT_CLR(options, QUIET);
-
return 0;
}
options->output_format |= DIFF_FORMAT_SHORTSTAT;
else if (opt_arg(arg, 'X', "dirstat", &options->dirstat_percent))
options->output_format |= DIFF_FORMAT_DIRSTAT;
- else if (!strcmp(arg, "--cumulative"))
- options->output_format |= DIFF_FORMAT_CUMULATIVE;
+ else if (!strcmp(arg, "--cumulative")) {
+ options->output_format |= DIFF_FORMAT_DIRSTAT;
+ DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
+ } else if (opt_arg(arg, 0, "dirstat-by-file",
+ &options->dirstat_percent)) {
+ options->output_format |= DIFF_FORMAT_DIRSTAT;
+ DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
+ }
else if (!strcmp(arg, "--check"))
options->output_format |= DIFF_FORMAT_CHECKDIFF;
else if (!strcmp(arg, "--summary"))
}
struct patch_id_t {
- SHA_CTX *ctx;
+ git_SHA_CTX *ctx;
int patchlen;
};
new_len = remove_space(line, len);
- SHA1_Update(data->ctx, line, new_len);
+ git_SHA1_Update(data->ctx, line, new_len);
data->patchlen += new_len;
}
{
struct diff_queue_struct *q = &diff_queued_diff;
int i;
- SHA_CTX ctx;
+ git_SHA_CTX ctx;
struct patch_id_t data;
char buffer[PATH_MAX * 4 + 20];
- SHA1_Init(&ctx);
+ git_SHA1_Init(&ctx);
memset(&data, 0, sizeof(struct patch_id_t));
data.ctx = &ctx;
len2, p->two->path,
len1, p->one->path,
len2, p->two->path);
- SHA1_Update(&ctx, buffer, len1);
+ git_SHA1_Update(&ctx, buffer, len1);
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = 3;
&xpp, &xecfg, &ecb);
}
- SHA1_Final(sha1, &ctx);
+ git_SHA1_Final(sha1, &ctx);
return 0;
}
void diffcore_std(struct diff_options *options)
{
- if (DIFF_OPT_TST(options, QUIET))
- return;
-
- if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER))
+ if (options->skip_stat_unmatch)
diffcore_skip_stat_unmatch(options);
if (options->break_opt != -1)
diffcore_break(options->break_opt);