This uses the strbuf_nested_expand() mechanism introduced earlier to demonstrate how to implement a nested string function. It does not "wrap" using the line-wrap code, but lifting the change by Dscho and plugging it in should be a trivial exercise. The overall idea is to parse something like "%[w(72,4,8)%an %ae %s%]" in these steps: #1 "%[" introduces the nested string function. #2 After that, a name identifies what function to call. #3 The function parses its parameters ("(72,4,8)" in the above example), and makes a nested expansion on the remainder of the format string. #4 The nested expansion is terminated at "%]" and returned to the function. #5 The function massages the string returned from #4, and the result becomes the expansion of the whole thing. Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx> --- pretty.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 84 insertions(+), 0 deletions(-) diff --git a/pretty.c b/pretty.c index 587101f..a8a38c3 100644 --- a/pretty.c +++ b/pretty.c @@ -595,6 +595,80 @@ 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 size_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; + 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; + + /* + * NEEDSWORK: here you wrap the contents of substr with + * strbuf_wrap(&substr, width, indent1, indent2); + * + * ... but I am too lazy to do that here, and I just demonstrate + * how it should work by just upcasing the result ;-) + */ + { + int i; + for (i = 0; i < sb->len; i++) + sb->buf[i] = toupper(sb->buf[i]); + } + return template - placeholder; +} + +static struct { + const char *name; + string_fmt_fn fn; +} format_fn_list[] = { + { "w(", 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 size_t format_commit_item(struct strbuf *sb, const char *placeholder, void *context) { @@ -603,9 +677,19 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, const char *msg = commit->buffer; struct commit_list *p; int h1, h2; + size_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, ')'); -- 1.6.5.99.g9ed7e -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html