static int diff_detect_rename_default;
static int diff_rename_limit_default = 200;
+static int diff_suppress_blank_empty;
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 */
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.")) {
return 0;
}
+ /* like GNU diff's --suppress-blank-empty option */
+ if (!strcmp(var, "diff.suppress-blank-empty")) {
+ diff_suppress_blank_empty = git_config_bool(var, value);
+ return 0;
+ }
+
if (!prefixcmp(var, "diff.")) {
const char *ep = strrchr(var, '.');
if (ep != var + 4) {
{
int need_one = quote_c_style(one, NULL, NULL, 1);
int need_two = quote_c_style(two, NULL, NULL, 1);
- struct strbuf res;
+ struct strbuf res = STRBUF_INIT;
- strbuf_init(&res, 0);
if (need_one + need_two) {
strbuf_addch(&res, '"');
quote_c_style(one, &res, NULL, 1);
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);
}
struct diff_words_data {
- struct xdiff_emit_state xm;
struct diff_words_buffer minus, plus;
FILE *file;
};
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
- ecb.outf = xdiff_outf;
- ecb.priv = diff_words;
- diff_words->xm.consume = fn_out_diff_words_aux;
- xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
-
+ xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
+ &xpp, &xecfg, &ecb);
free(minus.ptr);
free(plus.ptr);
diff_words->minus.text.size = diff_words->plus.text.size = 0;
typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
struct emit_callback {
- struct xdiff_emit_state xm;
int nparents, color_diff;
unsigned ws_rule;
sane_truncate_fn truncate;
ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
}
+ if (diff_suppress_blank_empty
+ && len == 2 && line[0] == ' ' && line[1] == '\n') {
+ line[0] = '\n';
+ len = 1;
+ }
+
/* This is not really necessary for now because
* this codepath only deals with two-way diffs.
*/
{
const char *old = a;
const char *new = b;
- struct strbuf name;
+ struct strbuf name = STRBUF_INIT;
int pfx_length, sfx_length;
int len_a = strlen(a);
int len_b = strlen(b);
int qlen_a = quote_c_style(a, NULL, NULL, 0);
int qlen_b = quote_c_style(b, NULL, NULL, 0);
- strbuf_init(&name, 0);
if (qlen_a || qlen_b) {
quote_c_style(a, &name, NULL, 0);
strbuf_addstr(&name, " => ");
}
struct diffstat_t {
- struct xdiff_emit_state xm;
-
int nr;
int alloc;
struct diffstat_file {
return;
if (!file->is_renamed) {
- struct strbuf buf;
- strbuf_init(&buf, 0);
+ struct strbuf buf = STRBUF_INIT;
if (quote_c_style(file->name, &buf, NULL, 0)) {
pname = strbuf_detach(&buf, NULL);
} else {
/*
* 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;
}
struct checkdiff_t {
- struct xdiff_emit_state xm;
const char *filename;
int lineno;
struct diff_options *o;
}
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 },
+ { "objc",
+ /* Negate C statements that can look like functions */
+ "!^[ \t]*(do|for|if|else|return|switch|while)\n"
+ /* Objective-C methods */
+ "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n"
+ /* C functions */
+ "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n"
+ /* Objective-C class/protocol definitions */
+ "^(@(implementation|interface|protocol)[ \t].*)$",
+ REG_EXTENDED },
{ "pascal",
"^((procedure|function|constructor|destructor|interface|"
"implementation|initialization|finalization)[ \t]*.*)$"
- "|"
+ "\n"
"^(.*=[ \t]*(class|record).*)$",
REG_EXTENDED },
- { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
+ { "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 },
- { "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
- REG_EXTENDED },
};
static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
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);
xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
else if (!prefixcmp(diffopts, "-u"))
xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
- ecb.outf = xdiff_outf;
- ecb.priv = &ecbdata;
- ecbdata.xm.consume = fn_out_consume;
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) {
ecbdata.diff_words =
xcalloc(1, sizeof(struct diff_words_data));
ecbdata.diff_words->file = o->file;
}
- xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
+ &xpp, &xecfg, &ecb);
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
free_diff_words_data(&ecbdata);
}
memset(&xecfg, 0, sizeof(xecfg));
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
- ecb.outf = xdiff_outf;
- ecb.priv = diffstat;
- xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
+ &xpp, &xecfg, &ecb);
}
free_and_return:
return;
memset(&data, 0, sizeof(data));
- data.xm.consume = checkdiff_consume;
data.filename = name_b ? name_b : name_a;
data.lineno = 0;
data.o = o;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 1; /* at least one context line */
xpp.flags = XDF_NEED_MINIMAL;
- ecb.outf = xdiff_outf;
- ecb.priv = &data;
- xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
+ &xpp, &xecfg, &ecb);
if ((data.ws_rule & WS_TRAILING_SPACE) &&
data.trailing_blanks_start) {
static int populate_from_stdin(struct diff_filespec *s)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
size_t size = 0;
- strbuf_init(&buf, 0);
if (strbuf_read(&buf, 0, 0) < 0)
return error("error while reading from stdin %s",
strerror(errno));
if (!s->sha1_valid ||
reuse_worktree_file(s->path, s->sha1, 0)) {
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
struct stat st;
int fd;
/*
* Convert from working tree format to canonical git format
*/
- strbuf_init(&buf, 0);
if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) {
size_t size = 0;
munmap(s->data, s->size);
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)
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;
}
struct patch_id_t {
- struct xdiff_emit_state xm;
- 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;
- data.xm.consume = patch_id_consume;
for (i = 0; i < q->nr; i++) {
xpparam_t xpp;
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;
xecfg.flags = XDL_EMIT_FUNCNAMES;
- ecb.outf = xdiff_outf;
- ecb.priv = &data;
- xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
+ &xpp, &xecfg, &ecb);
}
- SHA1_Final(sha1, &ctx);
+ git_SHA1_Final(sha1, &ctx);
return 0;
}
struct diffstat_t diffstat;
memset(&diffstat, 0, sizeof(struct diffstat_t));
- diffstat.xm.consume = diffstat_consume;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (check_pair_status(p))