[PATCH v3] Allow combined diff to ignore white-spaces

2013-03-14 Thread Antoine Pelisse
Currently, it's not possible to use the space-ignoring options (-b, -w,
--ignore-space-at-eol) with combined diff. It makes it pretty impossible
to read a merge between a branch that changed all tabs to spaces, and a
branch with functional changes.

Pass diff flags to diff engine, so that combined diff behaves as normal
diff does with spaces.
Also coalesce lines that are removed from both (or more) parents.

It also means that a conflict-less merge done using a ignore-* strategy
option will not show any conflict if shown in combined-diff using the
same option.

Signed-off-by: Antoine Pelisse apeli...@gmail.com
---
Changes:
- Fixed comments
- Fixed tests (following Johannes suggestions)

 combine-diff.c   |   57 +---
 t/t4038-diff-combined.sh |  111 ++
 2 files changed, 161 insertions(+), 7 deletions(-)

diff --git a/combine-diff.c b/combine-diff.c
index 35d41cd..6288485 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -5,6 +5,7 @@
 #include diffcore.h
 #include quote.h
 #include xdiff-interface.h
+#include xdiff/xmacros.h
 #include log-tree.h
 #include refs.h
 #include userdiff.h
@@ -122,7 +123,47 @@ static char *grab_blob(const unsigned char *sha1, unsigned 
int mode,
return blob;
 }

-static void append_lost(struct sline *sline, int n, const char *line, int len)
+static int match_string_spaces(const char *line1, int len1,
+  const char *line2, int len2,
+  long flags)
+{
+   if (flags  XDF_WHITESPACE_FLAGS) {
+   for (; len1  0  XDL_ISSPACE(line1[len1 - 1]); len1--);
+   for (; len2  0  XDL_ISSPACE(line2[len2 - 1]); len2--);
+   }
+
+   if (!(flags  (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
+   return (len1 == len2  !memcmp(line1, line2, len1));
+
+   while (len1  0  len2  0) {
+   len1--;
+   len2--;
+   if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
+   if ((flags  XDF_IGNORE_WHITESPACE_CHANGE) 
+   (!XDL_ISSPACE(line1[len1]) || 
!XDL_ISSPACE(line2[len2])))
+   return 0;
+
+   for (; len1  0  XDL_ISSPACE(line1[len1]); len1--);
+   for (; len2  0  XDL_ISSPACE(line2[len2]); len2--);
+   }
+   if (line1[len1] != line2[len2])
+   return 0;
+   }
+
+   if (flags  XDF_IGNORE_WHITESPACE) {
+   /* Consume remaining spaces */
+   for (; len1  0  XDL_ISSPACE(line1[len1 - 1]); len1--);
+   for (; len2  0  XDL_ISSPACE(line2[len2 - 1]); len2--);
+   }
+
+   /* We matched full line1 and line2 */
+   if (!len1  !len2)
+   return 1;
+
+   return 0;
+}
+
+static void append_lost(struct sline *sline, int n, const char *line, int len, 
long flags)
 {
struct lline *lline;
unsigned long this_mask = (1ULn);
@@ -133,8 +174,8 @@ static void append_lost(struct sline *sline, int n, const 
char *line, int len)
if (sline-lost_head) {
lline = sline-next_lost;
while (lline) {
-   if (lline-len == len 
-   !memcmp(lline-line, line, len)) {
+   if (match_string_spaces(lline-line, lline-len,
+   line, len, flags)) {
lline-parent_map |= this_mask;
sline-next_lost = lline-next;
return;
@@ -162,6 +203,7 @@ struct combine_diff_state {
int n;
struct sline *sline;
struct sline *lost_bucket;
+   long flags;
 };

 static void consume_line(void *state_, char *line, unsigned long len)
@@ -201,7 +243,7 @@ static void consume_line(void *state_, char *line, unsigned 
long len)
return; /* not in any hunk yet */
switch (line[0]) {
case '-':
-   append_lost(state-lost_bucket, state-n, line+1, len-1);
+   append_lost(state-lost_bucket, state-n, line+1, len-1, 
state-flags);
break;
case '+':
state-sline[state-lno-1].flag |= state-nmask;
@@ -215,7 +257,7 @@ static void combine_diff(const unsigned char *parent, 
unsigned int mode,
 struct sline *sline, unsigned int cnt, int n,
 int num_parent, int result_deleted,
 struct userdiff_driver *textconv,
-const char *path)
+const char *path, long flags)
 {
unsigned int p_lno, lno;
unsigned long nmask = (1UL  n);
@@ -231,9 +273,10 @@ static void combine_diff(const unsigned char *parent, 
unsigned int mode,
parent_file.ptr = grab_blob(parent, mode, sz, textconv, path);
parent_file.size = sz;
memset(xpp, 

Re: [PATCH v3] Allow combined diff to ignore white-spaces

2013-03-14 Thread Junio C Hamano
Antoine Pelisse apeli...@gmail.com writes:

 +test_expect_success 'check combined output (no ignore space)' '
 + git show actual.tmp 
 + sed -e 1,/^@@@/d  actual.tmp actual 
 + tr -d Q -\EOF expected 
 + --always coalesce
 + - eol space coalesce
 + - space change coalesce
 + - all spaces coalesce
 + - eol spaces
 + - space change
 + - all spaces
 +  -eol space coalesce Q
 +  -space  change coalesce
 +  -all spa ces coalesce
 + + eol spaces Q
 + + space  change
 + + all spa ces
 + EOF
 + compare_diff_patch expected actual
 +'

Nicely constructed ;-)

Thanks.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html