* [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