Junio C Hamano [off-list ref] writes:
I haven't tested this at all (this is a lunchtime hack) and have a mild
suspicion that it may have corner case miscounting (e.g. I blindly
subtracts 3 from len when dealing with a line that represents a single
token from the internal diff output --- do I always have 3 there even when
the original file ends with an incomplete line? I didn't check), but
other than that I think this is a lot easier to read and follow.
And this adds "--color-words -b" support as an example.
The second hunk, however, is a bugfix to the previous one. The code wants
the LF at the end of the line always returned as a single token.
---
diff.c | 30 +++++++++++++++++++++++++++---
1 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/diff.c b/diff.c
index 344aaa6..bce0626 100644
--- a/diff.c
+++ b/diff.c
@@ -357,6 +357,7 @@ struct emit_callback {
struct xdiff_emit_state xm;
int nparents, color_diff;
unsigned ws_rule;
+ struct diff_options *diffopt;
sane_truncate_fn truncate;
const char **label_path;
struct diff_words_data *diff_words;@@ -378,19 +379,36 @@ static size_t diff_words_tokenize(struct emit_callback *ecbdata,
if (!len)
return 0;
+ /*
+ * Always return LF at the end as a single separate token.
+ */
+ if ((len == 1) && *line == '\n')
+ return 1;
is_space = isspace(*line);
while (len && (isspace(*line) == is_space)) {
line++;
len--;
}
+ if (is_space && !len)
+ line--;
return line - line0;
}
+static int token_is_ws_only(char *line, size_t len)
+{
+ while (len--)
+ if (!isspace(*line))
+ return 0;
+ return 1;
+}
+
static void diff_words_append(struct emit_callback *ecbdata,
char *line, unsigned long len,
struct strbuf *text)
{
+ struct diff_options *diffopt = ecbdata->diffopt;
+
/* Skip leading +/- first. */
line++;
len--;@@ -407,9 +425,14 @@ static void diff_words_append(struct emit_callback *ecbdata,
* so that we can recover the original
* end-of-line easily. Stupid, but works.
*/
- strbuf_add(text, " ", 1);
- strbuf_add(text, line, token_len);
- strbuf_add(text, "\n", 1);
+ if ((diffopt->xdl_opts & XDF_IGNORE_WHITESPACE) &&
+ token_is_ws_only(line, token_len)) {
+ strbuf_add(text, " \n", 3);
+ } else {
+ strbuf_add(text, " ", 1);
+ strbuf_add(text, line, token_len);
+ strbuf_add(text, "\n", 1);
+ }
len -= token_len;
line += token_len;
} else {@@ -1447,6 +1470,7 @@ static void builtin_diff(const char *name_a,
ecbdata.found_changesp = &o->found_changes;
ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
ecbdata.file = o->file;
+ ecbdata.diffopt = o;
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;