git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[ILLUSTRATION PATCH] color-words: take an optional regular expression describing words

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Jan 9, 2009, 11:59 UTC
Message-ID
<alpine.DEB.1.00.0901091255230.30769@pacific.mpi-cbg.de>
In-Reply-To
<alpine.DEB.1.00.0901091202250.30769@pacific.mpi-cbg.de>

In some applications, words are not delimited by white space. To allow for that, you can specify a regular expression describing what makes a word with

	git diff --color-words='^[A-Za-z0-9]*'
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
	On Fri, 9 Jan 2009, Johannes Schindelin wrote:
	> Intuitively, all you would have to do is to replace this part in 
	> diff_words_show()
	> 
	>         for (i = 0; i < minus.size; i++)
	>                 if (isspace(minus.ptr[i]))
	>                         minus.ptr[i] = '\n';
	> 
	> by a loop finding the next word boundary.  I would suggest making that a 
	> function, say,
	> 
	> 	int find_word_boundary(struct diff_words_data *data, char *minus);
	> 
	> This function would also be responsible to initialize the regexp.
	> 
	> However, as I said, I think it would be much more intuitive to 
	> characterize the _words_ instead of the _word boundaries_.
	> 
	> And I would like to keep the default as-is (together _with_ the 
	> performance.  IOW if the user did not specify a regexp, it should fall 
	> back to what it does now, which is slow enough).
	And this patch does all that, and it _is_ substantially more 
	compact, as promised.
	It lacks testing, a test script and documentation, as well as 
	configurability via config and/or attributes, but that's your
	job, as I am not really _that_ interested in the feature myself.
 diff.c |   45 +++++++++++++++++++++++++++++++++++++++------
 diff.h |    1 +
 2 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/diff.c b/diff.c
index 4643ffc..c7ddb60 100644
--- a/diff.c
+++ b/diff.c
@@ -339,6 +339,7 @@ static void diff_words_append(char *line, unsigned long len,
 struct diff_words_data {
 	struct diff_words_buffer minus, plus;
 	FILE *file;
+	regex_t *word_regex;
 };
 
 static void print_word(FILE *file, struct diff_words_buffer *buffer, int len, int color,
@@ -398,6 +399,25 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
 	}
 }
 
+static int find_word_boundary(struct diff_words_data *diff_words,
+		mmfile_t *buffer, int i)
+{
+	if (i >= buffer->size)
+		return i;
+
+	if (diff_words->word_regex) {
+		regmatch_t match[1];
+		if (!regexec(diff_words->word_regex, buffer->ptr + i,
+				1, match, 0))
+			i += match[0].rm_eo;
+	}
+	else
+		while (i < buffer->size && !isspace(i))
+			i++;
+
+	return i;
+}
+
 /* this executes the word diff on the accumulated buffers */
 static void diff_words_show(struct diff_words_data *diff_words)
 {
@@ -412,17 +432,17 @@ static void diff_words_show(struct diff_words_data *diff_words)
 	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';
+	for (i = 0; (i = find_word_boundary(diff_words, &minus, i))
+			< minus.size; 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';
+	for (i = 0; (i = find_word_boundary(diff_words, &plus, i))
+			< plus.size; i++)
+		plus.ptr[i] = '\n';
 	diff_words->plus.current = 0;
 
 	xpp.flags = XDF_NEED_MINIMAL;
@@ -461,6 +481,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)
 
 		free (ecbdata->diff_words->minus.text.ptr);
 		free (ecbdata->diff_words->plus.text.ptr);
+		free(ecbdata->diff_words->word_regex);
 		free(ecbdata->diff_words);
 		ecbdata->diff_words = NULL;
 	}
@@ -1483,6 +1504,14 @@ static void builtin_diff(const char *name_a,
 			ecbdata.diff_words =
 				xcalloc(1, sizeof(struct diff_words_data));
 			ecbdata.diff_words->file = o->file;
+			if (o->word_regex) {
+				ecbdata.diff_words->word_regex = (regex_t *)
+					xmalloc(sizeof(regex_t));
+				if (regcomp(ecbdata.diff_words->word_regex,
+						o->word_regex, REG_EXTENDED))
+					die ("Invalid regular expression: %s",
+							o->word_regex);
+			}
 		}
 		xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
 			      &xpp, &xecfg, &ecb);
@@ -2496,6 +2525,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 		DIFF_OPT_CLR(options, COLOR_DIFF);
 	else if (!strcmp(arg, "--color-words"))
 		options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
+	else if (!prefixcmp(arg, "--color-words=")) {
+		options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
+		options->word_regex = arg + 14;
+	}
 	else if (!strcmp(arg, "--exit-code"))
 		DIFF_OPT_SET(options, EXIT_WITH_STATUS);
 	else if (!strcmp(arg, "--quiet"))
diff --git a/diff.h b/diff.h
index 4d5a327..23cd90c 100644
--- a/diff.h
+++ b/diff.h
@@ -98,6 +98,7 @@ struct diff_options {
 
 	int stat_width;
 	int stat_name_width;
+	const char *word_regex;
 
 	/* this is set by diffcore for DIFF_FORMAT_PATCH */
 	int found_changes;
-- 
1.6.1.203.gc8be3
Previous: Johannes SchindelinNext: Thomas Rast
Message 5 of 34 in “make diff --color-words customizable”
  1. make diff --color-words customizableThomas Rast, Jan 9, 2009
  2. Johannes SchindelinJan 9, 2009
  3. Thomas RastJan 9, 2009
  4. Johannes SchindelinJan 9, 2009
  5. color-words: take an optional regular expression describing wordsJohannes Schindelin, Jan 9, 2009
  6. Thomas RastJan 9, 2009
  7. Teemu LikonenJan 9, 2009
  8. make diff --color-words customizableThomas Rast, Jan 10, 2009
  9. Jakub NarebskiJan 10, 2009
  10. Johannes SchindelinJan 10, 2009
  11. Jakub NarebskiJan 10, 2009
  12. Johannes SchindelinJan 10, 2009
  13. Jakub NarebskiJan 12, 2009
  14. Johannes SchindelinJan 13, 2009
  15. Davide LibenziJan 10, 2009
  16. Jakub NarebskiJan 13, 2009
  17. Davide LibenziJan 13, 2009
  18. Johannes SchindelinJan 10, 2009
  19. Thomas RastJan 10, 2009
  20. Johannes SchindelinJan 10, 2009
  21. Junio C HamanoJan 11, 2009
  22. 0/4 customizable --color-wordsThomas Rast, Jan 11, 2009
  23. 1/4 word diff: comments, preparations for regex customizationThomas Rast, Jan 11, 2009
  24. 2/4 word diff: customizable word splitsThomas Rast, Jan 11, 2009
  25. 3/4 word diff: make regex configurable via attributesThomas Rast, Jan 11, 2009
  26. 4/4 word diff: test customizable word splitsThomas Rast, Jan 11, 2009
  27. Junio C HamanoJan 11, 2009
  28. Junio C HamanoJan 11, 2009
  29. Johannes SchindelinJan 11, 2009
  30. Johannes SchindelinJan 11, 2009
  31. Junio C HamanoJan 11, 2009
  32. Jeff KingJan 9, 2009
  33. Johannes SchindelinJan 9, 2009
  34. Jeff KingJan 9, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.