summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 65cdb5f)
raw | patch | inline | side by side (parent: 65cdb5f)
author | Johannes Schindelin <Johannes.Schindelin@gmx.de> | |
Fri, 28 Jul 2006 21:56:15 +0000 (23:56 +0200) | ||
committer | Junio C Hamano <junkio@cox.net> | |
Thu, 10 Aug 2006 22:28:57 +0000 (15:28 -0700) |
With this option, the changed words are shown inline. For example,
if a file containing "This is foo" is changed to "This is bar", the diff
will now show "This is " in plain text, "foo" in red, and "bar" in green.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
if a file containing "This is foo" is changed to "This is bar", the diff
will now show "This is " in plain text, "foo" in red, and "bar" in green.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
Documentation/diff-options.txt | patch | blob | history | |
diff.c | patch | blob | history | |
diff.h | patch | blob | history |
index 47ba9a403ae9379b87c54f0103297da9157237cb..b5d9763594b3fcb4dcc273c0118f7edbf236380d 100644 (file)
Turn off colored diff, even when the configuration file
gives the default to color output.
+--color-words::
+ Show colored word diff, i.e. color words which have changed.
+
--no-renames::
Turn off rename detection, even when the configuration
file gives the default to do so.
index b3b1781a9cac05457e42691970c93b6e1501f68c..a8710cb9e2388ce915fabc99cb86caacd1020961 100644 (file)
--- a/diff.c
+++ b/diff.c
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)
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')
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:
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