static int diff_detect_rename_default;
static int diff_rename_limit_default = 100;
static int diff_use_color_default;
+static const char *external_diff_cmd_cfg;
int diff_auto_refresh_index = 1;
static char diff_colors[][COLOR_MAXLEN] = {
diff_auto_refresh_index = git_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "diff.external")) {
+ external_diff_cmd_cfg = xstrdup(value);
+ return 0;
+ }
if (!prefixcmp(var, "diff.")) {
const char *ep = strrchr(var, '.');
if (done_preparing)
return external_diff_cmd;
external_diff_cmd = getenv("GIT_EXTERNAL_DIFF");
+ if (!external_diff_cmd)
+ external_diff_cmd = external_diff_cmd_cfg;
done_preparing = 1;
return external_diff_cmd;
}
const char *name_b,
struct diff_filespec *one,
struct diff_filespec *two,
- int color_diff)
+ struct diff_options *o)
{
int lc_a, lc_b;
+ int color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
const char *name_a_tab, *name_b_tab;
const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
diff_populate_filespec(two, 0);
lc_a = count_lines(one->data, one->size);
lc_b = count_lines(two->data, two->size);
- printf("%s--- a/%s%s%s\n%s+++ b/%s%s%s\n%s@@ -",
- metainfo, name_a, name_a_tab, reset,
- metainfo, name_b, name_b_tab, reset, fraginfo);
+ printf("%s--- %s%s%s%s\n%s+++ %s%s%s%s\n%s@@ -",
+ metainfo, o->a_prefix, name_a, name_a_tab, reset,
+ metainfo, o->b_prefix, name_b, name_b_tab, reset, fraginfo);
print_line_count(lc_a);
printf(" +");
print_line_count(lc_b);
ecb.outf = xdiff_outf;
ecb.priv = diff_words;
diff_words->xm.consume = fn_out_diff_words_aux;
- xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
+ xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
free(plus.ptr);
static void emit_line(const char *set, const char *reset, const char *line, int len)
{
- if (len > 0 && line[len-1] == '\n')
- len--;
fputs(set, stdout);
fwrite(line, len, 1, stdout);
- puts(reset);
-}
-
-static void emit_line_with_ws(int nparents,
- const char *set, const char *reset, const char *ws,
- const char *line, int len, unsigned ws_rule)
-{
- int col0 = nparents;
- int last_tab_in_indent = -1;
- int last_space_in_indent = -1;
- int i;
- int tail = len;
- int need_highlight_leading_space = 0;
- /*
- * The line is a newly added line. Does it have funny leading
- * whitespaces? In indent, SP should never precede a TAB. In
- * addition, under "indent with non tab" rule, there should not
- * be more than 8 consecutive spaces.
- */
- for (i = col0; i < len; i++) {
- if (line[i] == '\t') {
- last_tab_in_indent = i;
- if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
- 0 <= last_space_in_indent)
- need_highlight_leading_space = 1;
- }
- else if (line[i] == ' ')
- last_space_in_indent = i;
- else
- break;
- }
- if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
- 0 <= last_space_in_indent &&
- last_tab_in_indent < 0 &&
- 8 <= (i - col0)) {
- last_tab_in_indent = i;
- need_highlight_leading_space = 1;
- }
- fputs(set, stdout);
- fwrite(line, col0, 1, stdout);
fputs(reset, stdout);
- if (((i == len) || line[i] == '\n') && i != col0) {
- /* The whole line was indent */
- emit_line(ws, reset, line + col0, len - col0);
- return;
- }
- i = col0;
- if (need_highlight_leading_space) {
- while (i < last_tab_in_indent) {
- if (line[i] == ' ') {
- fputs(ws, stdout);
- putchar(' ');
- fputs(reset, stdout);
- }
- else
- putchar(line[i]);
- i++;
- }
- }
- tail = len - 1;
- if (line[tail] == '\n' && i < tail)
- tail--;
- if (ws_rule & WS_TRAILING_SPACE) {
- while (i < tail) {
- if (!isspace(line[tail]))
- break;
- tail--;
- }
- }
- if ((i < tail && line[tail + 1] != '\n')) {
- /* This has whitespace between tail+1..len */
- fputs(set, stdout);
- fwrite(line + i, tail - i + 1, 1, stdout);
- fputs(reset, stdout);
- emit_line(ws, reset, line + tail + 1, len - tail - 1);
- }
- else
- emit_line(set, reset, line + i, len - i);
}
static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
if (!*ws)
emit_line(set, reset, line, len);
- else
- emit_line_with_ws(ecbdata->nparents, set, reset, ws,
- line, len, ecbdata->ws_rule);
+ else {
+ /* Emit just the prefix, then the rest. */
+ emit_line(set, reset, line, ecbdata->nparents);
+ (void)check_and_emit_line(line + ecbdata->nparents,
+ len - ecbdata->nparents, ecbdata->ws_rule,
+ stdout, set, reset, ws);
+ }
}
static void fn_out_consume(void *priv, char *line, unsigned long len)
const char *filename;
int lineno, color_diff;
unsigned ws_rule;
+ unsigned status;
};
static void checkdiff_consume(void *priv, char *line, unsigned long len)
const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE);
const char *reset = diff_get_color(data->color_diff, DIFF_RESET);
const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW);
+ char *err;
if (line[0] == '+') {
- int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
-
- /* check space before tab */
- for (i = 1; i < len; i++) {
- if (line[i] == ' ')
- spaces++;
- else if (line[i] == '\t') {
- if (spaces) {
- space_before_tab = 1;
- break;
- }
- }
- else
- break;
- }
-
- /* check whitespace at line end */
- if (line[len - 1] == '\n')
- len--;
- if (isspace(line[len - 1]))
- white_space_at_end = 1;
-
- if (space_before_tab || white_space_at_end) {
- printf("%s:%d: %s", data->filename, data->lineno, ws);
- if (space_before_tab) {
- printf("space before tab");
- if (white_space_at_end)
- putchar(',');
- }
- if (white_space_at_end)
- printf("whitespace at end");
- printf(":%s ", reset);
- emit_line_with_ws(1, set, reset, ws, line, len,
- data->ws_rule);
- }
-
+ data->status = check_and_emit_line(line + 1, len - 1,
+ data->ws_rule, NULL, NULL, NULL, NULL);
+ if (!data->status)
+ return;
+ err = whitespace_error_string(data->status);
+ printf("%s:%d: %s.\n", data->filename, data->lineno, err);
+ free(err);
+ emit_line(set, reset, line, 1);
+ (void)check_and_emit_line(line + 1, len - 1, data->ws_rule,
+ stdout, set, reset, ws);
data->lineno++;
} else if (line[0] == ' ')
data->lineno++;
const char *set = diff_get_color_opt(o, DIFF_METAINFO);
const char *reset = diff_get_color_opt(o, DIFF_RESET);
- a_one = quote_two("a/", name_a + (*name_a == '/'));
- b_two = quote_two("b/", name_b + (*name_b == '/'));
+ a_one = quote_two(o->a_prefix, name_a + (*name_a == '/'));
+ b_two = quote_two(o->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";
printf("%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
if ((one->mode ^ two->mode) & S_IFMT)
goto free_ab_and_return;
if (complete_rewrite) {
- emit_rewrite_diff(name_a, name_b, one, two,
- DIFF_OPT_TST(o, COLOR_DIFF));
+ emit_rewrite_diff(name_a, name_b, one, two, o);
o->found_changes = 1;
goto free_ab_and_return;
}
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
ecbdata.diff_words =
xcalloc(1, sizeof(struct diff_words_data));
- xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
free_diff_words_data(&ecbdata);
}
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
ecb.outf = xdiff_outf;
ecb.priv = diffstat;
- xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
free_and_return:
xpp.flags = XDF_NEED_MINIMAL;
ecb.outf = xdiff_outf;
ecb.priv = &data;
- xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
free_and_return:
diff_free_filespec_data(one);
diff_free_filespec_data(two);
+ if (data.status)
+ DIFF_OPT_SET(o, CHECK_FAILED);
}
struct diff_filespec *alloc_filespec(const char *path)
else
DIFF_OPT_CLR(options, COLOR_DIFF);
options->detect_rename = diff_detect_rename_default;
+
+ options->a_prefix = "a/";
+ options->b_prefix = "b/";
}
int diff_setup_done(struct diff_options *options)
else if (40 < options->abbrev)
options->abbrev = 40;
}
+ else if (!prefixcmp(arg, "--src-prefix="))
+ options->a_prefix = arg + 13;
+ else if (!prefixcmp(arg, "--dst-prefix="))
+ options->b_prefix = arg + 13;
+ else if (!strcmp(arg, "--no-prefix"))
+ options->a_prefix = options->b_prefix = "";
else
return 0;
return 1;
xecfg.flags = XDL_EMIT_FUNCNAMES;
ecb.outf = xdiff_outf;
ecb.priv = &data;
- xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+ xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
SHA1_Final(sha1, &ctx);
DIFF_OPT_CLR(options, HAS_CHANGES);
}
+int diff_result_code(struct diff_options *opt, int status)
+{
+ int result = 0;
+ if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+ !(opt->output_format & DIFF_FORMAT_CHECKDIFF))
+ return status;
+ if (DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+ DIFF_OPT_TST(opt, HAS_CHANGES))
+ result |= 01;
+ if ((opt->output_format & DIFF_FORMAT_CHECKDIFF) &&
+ DIFF_OPT_TST(opt, CHECK_FAILED))
+ result |= 02;
+ return result;
+}
void diff_addremove(struct diff_options *options,
int addremove, unsigned mode,