* [RFC] Add the --color-words option to the diff options family
@ 2006-07-28 21:56 Johannes Schindelin
2006-07-30 0:57 ` Matthias Lederhofer
2006-07-31 10:54 ` Junio C Hamano
0 siblings, 2 replies; 5+ messages in thread
From: Johannes Schindelin @ 2006-07-28 21:56 UTC (permalink / raw)
To: git
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>
---
I am probably the only person who finds it useful, but there
is a high coolness factor attached to it.
And the libxdiff library actually made it very easy to do. (Yes,
there are two nested calls to xdiff...)
Documentation/diff-options.txt | 3 +
diff.c | 178 +++++++++++++++++++++++++++++++++++++++-
diff.h | 3 -
3 files changed, 177 insertions(+), 7 deletions(-)
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 47ba9a4..b5d9763 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -36,6 +36,9 @@
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.
diff --git a/diff.c b/diff.c
index 6198a61..e910971 100644
--- a/diff.c
+++ b/diff.c
@@ -358,12 +358,152 @@ static int fill_mmfile(mmfile_t *mf, str
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, c
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 *nam
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:
@@ -1712,6 +1876,8 @@ int diff_opt_parse(struct diff_options *
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
diff --git a/diff.h b/diff.h
index 0d32830..51c163b 100644
--- a/diff.h
+++ b/diff.h
@@ -46,7 +46,8 @@ struct diff_options {
full_index:1,
silent_on_remove:1,
find_copies_harder:1,
- color_diff:1;
+ color_diff:1,
+ color_diff_words:1;
int context;
int break_opt;
int detect_rename;
--
1.4.2.rc2.g8b063-dirty
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC] Add the --color-words option to the diff options family
2006-07-28 21:56 [RFC] Add the --color-words option to the diff options family Johannes Schindelin
@ 2006-07-30 0:57 ` Matthias Lederhofer
2006-07-30 9:36 ` Johannes Schindelin
2006-07-31 10:54 ` Junio C Hamano
1 sibling, 1 reply; 5+ messages in thread
From: Matthias Lederhofer @ 2006-07-30 0:57 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> 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>
>
> ---
>
> I am probably the only person who finds it useful, but there
> is a high coolness factor attached to it.
>
> And the libxdiff library actually made it very easy to do. (Yes,
> there are two nested calls to xdiff...)
I'd probably find it more useful if it would still show two lines but
only the relevant part in red/green.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC] Add the --color-words option to the diff options family
2006-07-30 0:57 ` Matthias Lederhofer
@ 2006-07-30 9:36 ` Johannes Schindelin
0 siblings, 0 replies; 5+ messages in thread
From: Johannes Schindelin @ 2006-07-30 9:36 UTC (permalink / raw)
To: Matthias Lederhofer; +Cc: git
Hi,
On Sun, 30 Jul 2006, Matthias Lederhofer wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
>
> > 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.
>
> I'd probably find it more useful if it would still show two lines but
> only the relevant part in red/green.
I could do that if you want, but it is a little more involved. Besides, in
my use case, which is text with _long_ lines, it would be less useful, so
I would make it a switch.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC] Add the --color-words option to the diff options family
2006-07-28 21:56 [RFC] Add the --color-words option to the diff options family Johannes Schindelin
2006-07-30 0:57 ` Matthias Lederhofer
@ 2006-07-31 10:54 ` Junio C Hamano
2006-07-31 11:00 ` Johannes Schindelin
1 sibling, 1 reply; 5+ messages in thread
From: Junio C Hamano @ 2006-07-31 10:54 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 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>
This looks sooooooooooo strange (and I do not particularly like
colours, so I am biased). We might want to disable it when the
output would not be colored under diff.color = auto, at least,
but if the user asks to shoot himself in the foot that is fine
as well ;-).
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC] Add the --color-words option to the diff options family
2006-07-31 10:54 ` Junio C Hamano
@ 2006-07-31 11:00 ` Johannes Schindelin
0 siblings, 0 replies; 5+ messages in thread
From: Johannes Schindelin @ 2006-07-31 11:00 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Hi,
On Mon, 31 Jul 2006, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > 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>
>
> This looks sooooooooooo strange (and I do not particularly like
> colours, so I am biased).
I thought so, too, after playing around with wdiff. But I do use it
regularly, and it is helpful. It is my equivalent to the word processor
option to show all changes (yes, live and in colour).
> We might want to disable it when the output would not be colored under
> diff.color = auto, at least, but if the user asks to shoot himself in
> the foot that is fine as well ;-).
At the moment, this is _only_ enabled when the user explicitely asks for
it: no --color-words, no word colours. Do you want to be able to say
"git-diff --color-words | patch -p1 -R"?
Ciao,
Dscho
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-07-31 11:00 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-28 21:56 [RFC] Add the --color-words option to the diff options family Johannes Schindelin
2006-07-30 0:57 ` Matthias Lederhofer
2006-07-30 9:36 ` Johannes Schindelin
2006-07-31 10:54 ` Junio C Hamano
2006-07-31 11:00 ` Johannes Schindelin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox