git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Rast <trast@student.ethz.ch>
To: <git@vger.kernel.org>
Cc: Johannes Schindelin <Johannes.Schindelin@gmx.de>,
	Eelis van der Weegen <eelis@eelis.net>,
	Paul Mackerras <paulus@samba.org>
Subject: [PATCH 1/2] Add diff --porcelain option for --color-words
Date: Wed, 31 Mar 2010 02:52:48 +0200	[thread overview]
Message-ID: <edaae0ea27b4b72e07af39a565dfceef7608af73.1269996525.git.trast@student.ethz.ch> (raw)
In-Reply-To: <cover.1269996525.git.trast@student.ethz.ch>

This teaches the --color-words mode a new option --porcelain that
disables color mode again and instead uses an ad-hoc format for the
word diff designed for machine reading:

* Newlines in the output are no longer significant

* Each diff unit is prefixed by [-+ ] and terminated by newline as
  before

* Newlines in the input are output as a line consisting only of a
  tilde '~'

Note that for backwards compatibility --color-words still implies
--color, so the order matters: if you say --porcelain --color-words,
the hunk headers will be colored; if you say --color-words
--porcelain, they won't.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
 color.c |   28 -----------------
 color.h |    1 -
 diff.c  |  105 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------
 diff.h  |    1 +
 4 files changed, 89 insertions(+), 46 deletions(-)

diff --git a/color.c b/color.c
index bcf4e2c..1b00554 100644
--- a/color.c
+++ b/color.c
@@ -211,31 +211,3 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
 	va_end(args);
 	return r;
 }
-
-/*
- * This function splits the buffer by newlines and colors the lines individually.
- *
- * Returns 0 on success.
- */
-int color_fwrite_lines(FILE *fp, const char *color,
-		size_t count, const char *buf)
-{
-	if (!*color)
-		return fwrite(buf, count, 1, fp) != 1;
-	while (count) {
-		char *p = memchr(buf, '\n', count);
-		if (p != buf && (fputs(color, fp) < 0 ||
-				fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
-				fputs(GIT_COLOR_RESET, fp) < 0))
-			return -1;
-		if (!p)
-			return 0;
-		if (fputc('\n', fp) < 0)
-			return -1;
-		count -= p + 1 - buf;
-		buf = p + 1;
-	}
-	return 0;
-}
-
-
diff --git a/color.h b/color.h
index 5c264b0..03ca064 100644
--- a/color.h
+++ b/color.h
@@ -61,6 +61,5 @@
 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
 __attribute__((format (printf, 3, 4)))
 int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
-int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
 
 #endif /* COLOR_H */
diff --git a/diff.c b/diff.c
index f5d93e9..1b4d620 100644
--- a/diff.c
+++ b/diff.c
@@ -577,8 +577,62 @@ struct diff_words_data {
 	const char *current_plus;
 	FILE *file;
 	regex_t *word_regex;
+	int porcelain;
 };
 
+int color_fwrite_lines(FILE *fp, const char *color,
+		size_t count, const char *buf)
+{
+	if (!*color)
+		return fwrite(buf, count, 1, fp) != 1;
+	while (count) {
+		char *p = memchr(buf, '\n', count);
+		if (p != buf && (fputs(color, fp) < 0 ||
+				fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
+				fputs(GIT_COLOR_RESET, fp) < 0))
+			return -1;
+		if (!p)
+			return 0;
+		if (fputc('\n', fp) < 0)
+			return -1;
+		count -= p + 1 - buf;
+		buf = p + 1;
+	}
+	return 0;
+}
+
+static int fn_out_diff_words_write_helper(FILE *fp,
+					   const char *color, const char *prefix,
+					   size_t count, const char *buf,
+					   int porcelain)
+{
+	const char *suffix = "\n";
+	const char *newline = "~\n";
+
+	if (!porcelain) {
+		if (!color)
+			return fwrite(buf, count, 1, fp);
+		prefix = color;
+		suffix = GIT_COLOR_RESET;
+		newline = "\n";
+	}
+
+	while (count) {
+		char *p = memchr(buf, '\n', count);
+		if (p != buf && (fputs(prefix, fp) < 0 ||
+				 fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
+				 fputs(suffix, fp) < 0))
+			return -1;
+		if (!p)
+			return 0;
+		if (fputs(newline, fp) < 0)
+			return -1;
+		count -= p + 1 - buf;
+		buf = p + 1;
+	}
+	return 0;
+}
+
 static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
 {
 	struct diff_words_data *diff_words = priv;
@@ -605,17 +659,21 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
 		plus_begin = plus_end = diff_words->plus.orig[plus_first].end;
 
 	if (diff_words->current_plus != plus_begin)
-		fwrite(diff_words->current_plus,
-				plus_begin - diff_words->current_plus, 1,
-				diff_words->file);
+		fn_out_diff_words_write_helper(diff_words->file,
+				NULL, " ",
+				plus_begin - diff_words->current_plus,
+				diff_words->current_plus,
+				diff_words->porcelain);
 	if (minus_begin != minus_end)
-		color_fwrite_lines(diff_words->file,
-				diff_get_color(1, DIFF_FILE_OLD),
-				minus_end - minus_begin, minus_begin);
+		fn_out_diff_words_write_helper(diff_words->file,
+				diff_get_color(1, DIFF_FILE_OLD), "-",
+				minus_end - minus_begin, minus_begin,
+				diff_words->porcelain);
 	if (plus_begin != plus_end)
-		color_fwrite_lines(diff_words->file,
-				diff_get_color(1, DIFF_FILE_NEW),
-				plus_end - plus_begin, plus_begin);
+		fn_out_diff_words_write_helper(diff_words->file,
+				diff_get_color(1, DIFF_FILE_NEW), "+",
+				plus_end - plus_begin, plus_begin,
+				diff_words->porcelain);
 
 	diff_words->current_plus = plus_end;
 }
@@ -700,9 +758,10 @@ static void diff_words_show(struct diff_words_data *diff_words)
 
 	/* special case: only removal */
 	if (!diff_words->plus.text.size) {
-		color_fwrite_lines(diff_words->file,
-			diff_get_color(1, DIFF_FILE_OLD),
-			diff_words->minus.text.size, diff_words->minus.text.ptr);
+		fn_out_diff_words_write_helper(diff_words->file,
+			diff_get_color(1, DIFF_FILE_OLD), "-",
+			diff_words->minus.text.size, diff_words->minus.text.ptr,
+			diff_words->porcelain);
 		diff_words->minus.text.size = 0;
 		return;
 	}
@@ -722,10 +781,11 @@ static void diff_words_show(struct diff_words_data *diff_words)
 	free(plus.ptr);
 	if (diff_words->current_plus != diff_words->plus.text.ptr +
 			diff_words->plus.text.size)
-		fwrite(diff_words->current_plus,
+		fn_out_diff_words_write_helper(diff_words->file,
+			NULL, " ",
 			diff_words->plus.text.ptr + diff_words->plus.text.size
-			- diff_words->current_plus, 1,
-			diff_words->file);
+			- diff_words->current_plus, diff_words->current_plus,
+			diff_words->porcelain);
 	diff_words->minus.text.size = diff_words->plus.text.size = 0;
 }
 
@@ -837,6 +897,8 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
 
 	if (len < 1) {
 		emit_line(ecbdata->file, reset, reset, line, len);
+		if (ecbdata->diff_words && ecbdata->diff_words->porcelain)
+			fputs("~\n", ecbdata->file);
 		return;
 	}
 
@@ -851,9 +913,13 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
 			return;
 		}
 		diff_words_flush(ecbdata);
-		line++;
-		len--;
+		if (!ecbdata->diff_words->porcelain) {
+			line++;
+			len--;
+		}
 		emit_line(ecbdata->file, plain, reset, line, len);
+		if (ecbdata->diff_words->porcelain)
+			fputs("~\n", ecbdata->file);
 		return;
 	}
 
@@ -1765,6 +1831,7 @@ static void builtin_diff(const char *name_a,
 				o->word_regex = userdiff_word_regex(two);
 			if (!o->word_regex)
 				o->word_regex = diff_word_regex_cfg;
+			ecbdata.diff_words->porcelain = DIFF_OPT_TST(o, PORCELAIN);
 			if (o->word_regex) {
 				ecbdata.diff_words->word_regex = (regex_t *)
 					xmalloc(sizeof(regex_t));
@@ -2852,6 +2919,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 		DIFF_OPT_SET(options, COLOR_DIFF_WORDS);
 		options->word_regex = arg + 14;
 	}
+	else if (!strcmp(arg, "--porcelain")) {
+		DIFF_OPT_SET(options, PORCELAIN);
+		DIFF_OPT_CLR(options, COLOR_DIFF);
+	}
 	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 6a71013..7fdd251 100644
--- a/diff.h
+++ b/diff.h
@@ -71,6 +71,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
 #define DIFF_OPT_SUBMODULE_LOG       (1 << 23)
 #define DIFF_OPT_DIRTY_SUBMODULES    (1 << 24)
 #define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25)
+#define DIFF_OPT_PORCELAIN           (1 <<  26)
 
 #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
 #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)
-- 
1.7.0.3.522.ga3f6f.dirty

  reply	other threads:[~2010-03-31  0:53 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-03-31  0:52 [RFC PATCH 0/2] gitk --color-words Thomas Rast
2010-03-31  0:52 ` Thomas Rast [this message]
2010-03-31  0:52 ` [PATCH 2/2] gitk: add the equivalent of diff --color-words Thomas Rast
2010-03-31 12:04   ` Thomas Rast
2010-04-03 18:06 ` [PATCH v2 0/2] gitk --color-words Thomas Rast
2010-04-03 18:06   ` [PATCH v2 1/2] Add diff --porcelain option for --color-words Thomas Rast
2010-04-03 19:15     ` Junio C Hamano
2010-04-03 22:38       ` Miles Bader
2010-04-03 18:06   ` [PATCH v2 2/2] gitk: add the equivalent of diff --color-words Thomas Rast
2010-04-05  6:40   ` [PATCH v2 0/2] gitk --color-words Paul Mackerras
2010-04-05 10:21     ` Thomas Rast

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=edaae0ea27b4b72e07af39a565dfceef7608af73.1269996525.git.trast@student.ethz.ch \
    --to=trast@student.ethz.ch \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=eelis@eelis.net \
    --cc=git@vger.kernel.org \
    --cc=paulus@samba.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).