Merge branch 'js/color-diff'

This commit is contained in:
Junio C Hamano 2006-08-12 19:24:47 -07:00
commit edbda4d6af
3 changed files with 177 additions and 7 deletions

View File

@ -36,6 +36,9 @@
Turn off colored diff, even when the configuration file Turn off colored diff, even when the configuration file
gives the default to color output. gives the default to color output.
--color-words::
Show colored word diff, i.e. color words which have changed.
--no-renames:: --no-renames::
Turn off rename detection, even when the configuration Turn off rename detection, even when the configuration
file gives the default to do so. file gives the default to do so.

178
diff.c
View File

@ -358,12 +358,152 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
return 0; 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 emit_callback {
struct xdiff_emit_state xm; struct xdiff_emit_state xm;
int nparents, color_diff; int nparents, color_diff;
const char **label_path; 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) const char *diff_get_color(int diff_use_color, enum color_diff ix)
{ {
if (diff_use_color) if (diff_use_color)
@ -398,12 +538,31 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
else { else {
int nparents = ecbdata->nparents; int nparents = ecbdata->nparents;
int color = DIFF_PLAIN; int color = DIFF_PLAIN;
for (i = 0; i < nparents && len; i++) { if (ecbdata->diff_words && nparents != 1)
if (line[i] == '-') /* fall back to normal diff */
color = DIFF_FILE_OLD; free_diff_words_data(ecbdata);
else if (line[i] == '+') if (ecbdata->diff_words) {
color = DIFF_FILE_NEW; 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); set = diff_get_color(ecbdata->color_diff, color);
} }
if (len > 0 && line[len-1] == '\n') if (len > 0 && line[len-1] == '\n')
@ -836,7 +995,12 @@ static void builtin_diff(const char *name_a,
ecb.outf = xdiff_outf; ecb.outf = xdiff_outf;
ecb.priv = &ecbdata; ecb.priv = &ecbdata;
ecbdata.xm.consume = fn_out_consume; 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); xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
if (o->color_diff_words)
free_diff_words_data(&ecbdata);
} }
free_ab_and_return: free_ab_and_return:
@ -1697,6 +1861,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->xdl_opts |= XDF_IGNORE_WHITESPACE; options->xdl_opts |= XDF_IGNORE_WHITESPACE;
else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change")) else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
options->xdl_opts |= XDF_IGNORE_WHITESPACE_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")) else if (!strcmp(arg, "--no-renames"))
options->detect_rename = 0; options->detect_rename = 0;
else else

3
diff.h
View File

@ -46,7 +46,8 @@ struct diff_options {
full_index:1, full_index:1,
silent_on_remove:1, silent_on_remove:1,
find_copies_harder:1, find_copies_harder:1,
color_diff:1; color_diff:1,
color_diff_words:1;
int context; int context;
int break_opt; int break_opt;
int detect_rename; int detect_rename;