|
|
|
@ -358,12 +358,152 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
@@ -358,12 +358,152 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct diff_words_buffer { |
|
|
|
|
mmfile_t text; |
|
|
|
|
long alloc; |
|
|
|
|
long current; /* output pointer */ |
|
|
|
|
int suppressed_newline; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void diff_words_append(char *line, unsigned long len, |
|
|
|
|
struct diff_words_buffer *buffer) |
|
|
|
|
{ |
|
|
|
|
if (buffer->text.size + len > buffer->alloc) { |
|
|
|
|
buffer->alloc = (buffer->text.size + len) * 3 / 2; |
|
|
|
|
buffer->text.ptr = xrealloc(buffer->text.ptr, buffer->alloc); |
|
|
|
|
} |
|
|
|
|
line++; |
|
|
|
|
len--; |
|
|
|
|
memcpy(buffer->text.ptr + buffer->text.size, line, len); |
|
|
|
|
buffer->text.size += len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct diff_words_data { |
|
|
|
|
struct xdiff_emit_state xm; |
|
|
|
|
struct diff_words_buffer minus, plus; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void print_word(struct diff_words_buffer *buffer, int len, int color, |
|
|
|
|
int suppress_newline) |
|
|
|
|
{ |
|
|
|
|
const char *ptr; |
|
|
|
|
int eol = 0; |
|
|
|
|
|
|
|
|
|
if (len == 0) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
ptr = buffer->text.ptr + buffer->current; |
|
|
|
|
buffer->current += len; |
|
|
|
|
|
|
|
|
|
if (ptr[len - 1] == '\n') { |
|
|
|
|
eol = 1; |
|
|
|
|
len--; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fputs(diff_get_color(1, color), stdout); |
|
|
|
|
fwrite(ptr, len, 1, stdout); |
|
|
|
|
fputs(diff_get_color(1, DIFF_RESET), stdout); |
|
|
|
|
|
|
|
|
|
if (eol) { |
|
|
|
|
if (suppress_newline) |
|
|
|
|
buffer->suppressed_newline = 1; |
|
|
|
|
else |
|
|
|
|
putchar('\n'); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) |
|
|
|
|
{ |
|
|
|
|
struct diff_words_data *diff_words = priv; |
|
|
|
|
|
|
|
|
|
if (diff_words->minus.suppressed_newline) { |
|
|
|
|
if (line[0] != '+') |
|
|
|
|
putchar('\n'); |
|
|
|
|
diff_words->minus.suppressed_newline = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
len--; |
|
|
|
|
switch (line[0]) { |
|
|
|
|
case '-': |
|
|
|
|
print_word(&diff_words->minus, len, DIFF_FILE_OLD, 1); |
|
|
|
|
break; |
|
|
|
|
case '+': |
|
|
|
|
print_word(&diff_words->plus, len, DIFF_FILE_NEW, 0); |
|
|
|
|
break; |
|
|
|
|
case ' ': |
|
|
|
|
print_word(&diff_words->plus, len, DIFF_PLAIN, 0); |
|
|
|
|
diff_words->minus.current += len; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* this executes the word diff on the accumulated buffers */ |
|
|
|
|
static void diff_words_show(struct diff_words_data *diff_words) |
|
|
|
|
{ |
|
|
|
|
xpparam_t xpp; |
|
|
|
|
xdemitconf_t xecfg; |
|
|
|
|
xdemitcb_t ecb; |
|
|
|
|
mmfile_t minus, plus; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
minus.size = diff_words->minus.text.size; |
|
|
|
|
minus.ptr = xmalloc(minus.size); |
|
|
|
|
memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size); |
|
|
|
|
for (i = 0; i < minus.size; i++) |
|
|
|
|
if (isspace(minus.ptr[i])) |
|
|
|
|
minus.ptr[i] = '\n'; |
|
|
|
|
diff_words->minus.current = 0; |
|
|
|
|
|
|
|
|
|
plus.size = diff_words->plus.text.size; |
|
|
|
|
plus.ptr = xmalloc(plus.size); |
|
|
|
|
memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size); |
|
|
|
|
for (i = 0; i < plus.size; i++) |
|
|
|
|
if (isspace(plus.ptr[i])) |
|
|
|
|
plus.ptr[i] = '\n'; |
|
|
|
|
diff_words->plus.current = 0; |
|
|
|
|
|
|
|
|
|
xpp.flags = XDF_NEED_MINIMAL; |
|
|
|
|
xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; |
|
|
|
|
xecfg.flags = 0; |
|
|
|
|
ecb.outf = xdiff_outf; |
|
|
|
|
ecb.priv = diff_words; |
|
|
|
|
diff_words->xm.consume = fn_out_diff_words_aux; |
|
|
|
|
xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb); |
|
|
|
|
|
|
|
|
|
free(minus.ptr); |
|
|
|
|
free(plus.ptr); |
|
|
|
|
diff_words->minus.text.size = diff_words->plus.text.size = 0; |
|
|
|
|
|
|
|
|
|
if (diff_words->minus.suppressed_newline) { |
|
|
|
|
putchar('\n'); |
|
|
|
|
diff_words->minus.suppressed_newline = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct emit_callback { |
|
|
|
|
struct xdiff_emit_state xm; |
|
|
|
|
int nparents, color_diff; |
|
|
|
|
const char **label_path; |
|
|
|
|
struct diff_words_data *diff_words; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void free_diff_words_data(struct emit_callback *ecbdata) |
|
|
|
|
{ |
|
|
|
|
if (ecbdata->diff_words) { |
|
|
|
|
/* flush buffers */ |
|
|
|
|
if (ecbdata->diff_words->minus.text.size || |
|
|
|
|
ecbdata->diff_words->plus.text.size) |
|
|
|
|
diff_words_show(ecbdata->diff_words); |
|
|
|
|
|
|
|
|
|
if (ecbdata->diff_words->minus.text.ptr) |
|
|
|
|
free (ecbdata->diff_words->minus.text.ptr); |
|
|
|
|
if (ecbdata->diff_words->plus.text.ptr) |
|
|
|
|
free (ecbdata->diff_words->plus.text.ptr); |
|
|
|
|
free(ecbdata->diff_words); |
|
|
|
|
ecbdata->diff_words = NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const char *diff_get_color(int diff_use_color, enum color_diff ix) |
|
|
|
|
{ |
|
|
|
|
if (diff_use_color) |
|
|
|
@ -398,12 +538,31 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
@@ -398,12 +538,31 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|
|
|
|
else { |
|
|
|
|
int nparents = ecbdata->nparents; |
|
|
|
|
int color = DIFF_PLAIN; |
|
|
|
|
for (i = 0; i < nparents && len; i++) { |
|
|
|
|
if (line[i] == '-') |
|
|
|
|
color = DIFF_FILE_OLD; |
|
|
|
|
else if (line[i] == '+') |
|
|
|
|
color = DIFF_FILE_NEW; |
|
|
|
|
} |
|
|
|
|
if (ecbdata->diff_words && nparents != 1) |
|
|
|
|
/* fall back to normal diff */ |
|
|
|
|
free_diff_words_data(ecbdata); |
|
|
|
|
if (ecbdata->diff_words) { |
|
|
|
|
if (line[0] == '-') { |
|
|
|
|
diff_words_append(line, len, |
|
|
|
|
&ecbdata->diff_words->minus); |
|
|
|
|
return; |
|
|
|
|
} else if (line[0] == '+') { |
|
|
|
|
diff_words_append(line, len, |
|
|
|
|
&ecbdata->diff_words->plus); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (ecbdata->diff_words->minus.text.size || |
|
|
|
|
ecbdata->diff_words->plus.text.size) |
|
|
|
|
diff_words_show(ecbdata->diff_words); |
|
|
|
|
line++; |
|
|
|
|
len--; |
|
|
|
|
} else |
|
|
|
|
for (i = 0; i < nparents && len; i++) { |
|
|
|
|
if (line[i] == '-') |
|
|
|
|
color = DIFF_FILE_OLD; |
|
|
|
|
else if (line[i] == '+') |
|
|
|
|
color = DIFF_FILE_NEW; |
|
|
|
|
} |
|
|
|
|
set = diff_get_color(ecbdata->color_diff, color); |
|
|
|
|
} |
|
|
|
|
if (len > 0 && line[len-1] == '\n') |
|
|
|
@ -836,7 +995,12 @@ static void builtin_diff(const char *name_a,
@@ -836,7 +995,12 @@ static void builtin_diff(const char *name_a,
|
|
|
|
|
ecb.outf = xdiff_outf; |
|
|
|
|
ecb.priv = &ecbdata; |
|
|
|
|
ecbdata.xm.consume = fn_out_consume; |
|
|
|
|
if (o->color_diff_words) |
|
|
|
|
ecbdata.diff_words = |
|
|
|
|
xcalloc(1, sizeof(struct diff_words_data)); |
|
|
|
|
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); |
|
|
|
|
if (o->color_diff_words) |
|
|
|
|
free_diff_words_data(&ecbdata); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
free_ab_and_return: |
|
|
|
@ -1697,6 +1861,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
@@ -1697,6 +1861,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
|
|
|
|
options->xdl_opts |= XDF_IGNORE_WHITESPACE; |
|
|
|
|
else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change")) |
|
|
|
|
options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE; |
|
|
|
|
else if (!strcmp(arg, "--color-words")) |
|
|
|
|
options->color_diff = options->color_diff_words = 1; |
|
|
|
|
else if (!strcmp(arg, "--no-renames")) |
|
|
|
|
options->detect_rename = 0; |
|
|
|
|
else |
|
|
|
|