git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] nested expansion
@ 2009-10-19  7:30 Junio C Hamano
  2009-10-19  7:30 ` [PATCH v2 1/3] strbuf_nested_expand(): allow expansion to interrupt in the middle Junio C Hamano
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Junio C Hamano @ 2009-10-19  7:30 UTC (permalink / raw)
  To: git

This is a re-roll of the earlier "general syntax for applying functions to
pretty-print format output" series, rebased on two patches from Dscho to
implement strbuf_add_wrapped_text().  In other words, this will apply on
top of b4d784c (Add strbuf_add_wrapped_text() to utf8.[ch], 2008-11-10).

The first one is almost the same, except that it drops the unnecessary
cast (pointed out by Dscho) and instead changes the type of return value
from expand callback to ssize_t.

The second one has two changes:

 1. w() is renamed to wrap();
 2. it actually rewraps the text by using Dscho's strbuf_add_wrapped_text().

The third one is new.  It teaches wrap() to just indent without wrapping
when the width parameter is zero or negative.

Junio C Hamano (3):
  strbuf_nested_expand(): allow expansion to interrupt in the middle
  Add %[wrap(width,in1,in2)<<any-string>>%] implementation
  Teach --wrap to only indent without wrapping

 pretty.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 strbuf.c |   29 +++++++++++++++++-----
 strbuf.h |    5 ++-
 utf8.c   |   13 ++++++++++
 4 files changed, 115 insertions(+), 11 deletions(-)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/3] strbuf_nested_expand(): allow expansion to interrupt in the middle
  2009-10-19  7:30 [PATCH v2 0/3] nested expansion Junio C Hamano
@ 2009-10-19  7:30 ` Junio C Hamano
  2009-10-19  7:30 ` [PATCH v2 2/3] Add %[wrap(width,in1,in2)<<any-string>>%] implementation Junio C Hamano
  2009-10-19  7:30 ` [PATCH v2 3/3] Teach --wrap to only indent without wrapping Junio C Hamano
  2 siblings, 0 replies; 4+ messages in thread
From: Junio C Hamano @ 2009-10-19  7:30 UTC (permalink / raw)
  To: git

This itself does not do a "nested" expansion, but it paves a way for
supporting an extended syntax to express a function that works on an
expanded substring, e.g. %[function(param...)expanded-string%], by
allowing the callback function to tell where the argument to the function
ends.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

Dropped sloppy casts, as suggested by Dscho.

 pretty.c |    4 ++--
 strbuf.c |   29 ++++++++++++++++++++++-------
 strbuf.h |    5 +++--
 3 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/pretty.c b/pretty.c
index 587101f..126be56 100644
--- a/pretty.c
+++ b/pretty.c
@@ -595,8 +595,8 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)
 		strbuf_addch(sb, ')');
 }
 
-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
-                               void *context)
+static ssize_t format_commit_item(struct strbuf *sb, const char *placeholder,
+				  void *context)
 {
 	struct format_commit_context *c = context;
 	const struct commit *commit = c->commit;
diff --git a/strbuf.c b/strbuf.c
index a6153dc..af96155 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -214,29 +214,44 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 	strbuf_setlen(sb, sb->len + len);
 }
 
-void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
-		   void *context)
+void strbuf_nested_expand(struct strbuf *sb, const char **format_p,
+			  expand_fn_t fn, void *context)
 {
+	const char *format = *format_p;
 	for (;;) {
 		const char *percent;
-		size_t consumed;
+		ssize_t consumed;
 
 		percent = strchrnul(format, '%');
 		strbuf_add(sb, format, percent - format);
+		format = percent;
 		if (!*percent)
 			break;
-		format = percent + 1;
+		format++;
 
 		consumed = fn(sb, format, context);
-		if (consumed)
+		if (consumed < 0)
+			break;
+		else if (consumed)
 			format += consumed;
 		else
 			strbuf_addch(sb, '%');
 	}
+	*format_p = format;
+}
+
+void strbuf_expand(struct strbuf *sb, const char *o_format, expand_fn_t fn,
+		   void *context)
+{
+	const char *format = o_format;
+	strbuf_nested_expand(sb, &format, fn, context);
+	if (*format)
+		die("format error: negative return from expand function: %s",
+		    o_format);
 }
 
-size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
-		void *context)
+ssize_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
+			      void *context)
 {
 	struct strbuf_expand_dict_entry *e = context;
 	size_t len;
diff --git a/strbuf.h b/strbuf.h
index d05e056..256d615 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -109,13 +109,14 @@ static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {
 }
 extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
 
-typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
+typedef ssize_t (*expand_fn_t)(struct strbuf *sb, const char *placeholder, void *context);
 extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
+extern void strbuf_nested_expand(struct strbuf *sb, const char **format_p, expand_fn_t fn, void *context);
 struct strbuf_expand_dict_entry {
 	const char *placeholder;
 	const char *value;
 };
-extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
+extern ssize_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
 
 __attribute__((format(printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
-- 
1.6.5.1.95.g09fbd

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/3] Add %[wrap(width,in1,in2)<<any-string>>%] implementation
  2009-10-19  7:30 [PATCH v2 0/3] nested expansion Junio C Hamano
  2009-10-19  7:30 ` [PATCH v2 1/3] strbuf_nested_expand(): allow expansion to interrupt in the middle Junio C Hamano
@ 2009-10-19  7:30 ` Junio C Hamano
  2009-10-19  7:30 ` [PATCH v2 3/3] Teach --wrap to only indent without wrapping Junio C Hamano
  2 siblings, 0 replies; 4+ messages in thread
From: Junio C Hamano @ 2009-10-19  7:30 UTC (permalink / raw)
  To: git

This uses the strbuf_nested_expand() mechanism introduced earlier to
demonstrate how to implement a nested string function, by plugging Dscho's
implementation of strbuf_add_wrapped_text().

The log is much more pleasant to read with

    $ git log --format='commit %H%nAuthor: %an%n%n%[wrap(66,4,4)%s%n%n%b%]'

in some repositories (e.g. git-svn conversion of rockbox).

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

Renamed w() to wrap() and actually plugged Dscho's strbuf_add_wrapped_text().

 pretty.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/pretty.c b/pretty.c
index 126be56..bc74c25 100644
--- a/pretty.c
+++ b/pretty.c
@@ -595,6 +595,72 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)
 		strbuf_addch(sb, ')');
 }
 
+typedef int (*string_fmt_fn)(struct strbuf *sb, const char *placeholder, void *context);
+static ssize_t format_commit_item(struct strbuf *, const char *, void *);
+
+static int wrap_fn(struct strbuf *sb, const char *placeholder, void *context)
+{
+	const char *template = placeholder;
+	char *endptr, *nested;
+	long width = 0, indent1 = 0, indent2 = 0;
+
+	width = strtol(template, &endptr, 10);
+	if (*endptr == ',') {
+		template = endptr + 1;
+		indent1 = strtol(template, &endptr, 10);
+		if (*endptr == ',') {
+			template = endptr + 1;
+			indent2 = strtol(template, &endptr, 10);
+		}
+	}
+	if (*endptr++ != ')')
+		return 0;
+
+	template = endptr;
+	strbuf_nested_expand(sb, &template, format_commit_item, context);
+	if (*template++ != ']')
+		return 0;
+
+	nested = strbuf_detach(sb, NULL);
+	strbuf_add_wrapped_text(sb, nested, indent1, indent2, width);
+	free(nested);
+
+	return template - placeholder;
+}
+
+static struct {
+	const char *name;
+	string_fmt_fn fn;
+} format_fn_list[] = {
+	{ "wrap(", wrap_fn }
+};
+
+static size_t format_fn(struct strbuf *sb, const char *placeholder,
+			void *context)
+{
+	const char *template = placeholder;
+	size_t consumed;
+	struct strbuf substr = STRBUF_INIT;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(format_fn_list); i++)
+		if (!prefixcmp(template, format_fn_list[i].name))
+			break;
+	if (ARRAY_SIZE(format_fn_list) <= i)
+		return 0;
+	template += strlen(format_fn_list[i].name);
+	consumed = format_fn_list[i].fn(&substr, template, context);
+	if (!consumed) {
+		strbuf_release(&substr);
+		return 0;
+	}
+
+	strbuf_add(sb, substr.buf, substr.len);
+	template += consumed;
+	strbuf_release(&substr);
+	return template - placeholder;
+}
+
 static ssize_t format_commit_item(struct strbuf *sb, const char *placeholder,
 				  void *context)
 {
@@ -603,9 +669,19 @@ static ssize_t format_commit_item(struct strbuf *sb, const char *placeholder,
 	const char *msg = commit->buffer;
 	struct commit_list *p;
 	int h1, h2;
+	ssize_t nested;
 
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
+	case ']':
+		return -1;
+	case '[':
+		/*
+		 * %[func(arg...) string %]: we consumed the opening '['
+		 * and the callee consumed up to the closing '%]'.
+		 */
+		nested = format_fn(sb, placeholder + 1, context);
+		return nested ? 1 + nested : 0;
 	case 'C':
 		if (placeholder[1] == '(') {
 			const char *end = strchr(placeholder + 2, ')');

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 3/3] Teach --wrap to only indent without wrapping
  2009-10-19  7:30 [PATCH v2 0/3] nested expansion Junio C Hamano
  2009-10-19  7:30 ` [PATCH v2 1/3] strbuf_nested_expand(): allow expansion to interrupt in the middle Junio C Hamano
  2009-10-19  7:30 ` [PATCH v2 2/3] Add %[wrap(width,in1,in2)<<any-string>>%] implementation Junio C Hamano
@ 2009-10-19  7:30 ` Junio C Hamano
  2 siblings, 0 replies; 4+ messages in thread
From: Junio C Hamano @ 2009-10-19  7:30 UTC (permalink / raw)
  To: git

When a zero or negative width is given to "shortlog -w<width>,<in1>,<in2>"
and --format=%[wrap(w,in1,in2)...%], just indent the text by in1 without
wrapping.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 utf8.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/utf8.c b/utf8.c
index da99669..5c18f0c 100644
--- a/utf8.c
+++ b/utf8.c
@@ -310,6 +310,19 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
 	int w = indent, assume_utf8 = is_utf8(text);
 	const char *bol = text, *space = NULL;
 
+	if (width <= 0) {
+		/* just indent */
+		while (*text) {
+			const char *eol = strchrnul(text, '\n');
+			if (*eol == '\n')
+				eol++;
+			print_spaces(buf, indent);
+			strbuf_write(buf, text, eol-text);
+			text = eol;
+		}
+		return 1;
+	}
+
 	if (indent < 0) {
 		w = -indent;
 		space = text;
-- 
1.6.5.1.95.g09fbd

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-10-19  7:30 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-19  7:30 [PATCH v2 0/3] nested expansion Junio C Hamano
2009-10-19  7:30 ` [PATCH v2 1/3] strbuf_nested_expand(): allow expansion to interrupt in the middle Junio C Hamano
2009-10-19  7:30 ` [PATCH v2 2/3] Add %[wrap(width,in1,in2)<<any-string>>%] implementation Junio C Hamano
2009-10-19  7:30 ` [PATCH v2 3/3] Teach --wrap to only indent without wrapping Junio C Hamano

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).