{"thread":{"id":"21275","subject":"[PATCH v2 0/3] nested expansion","startedAt":"2009-10-19T07:30:11Z","lastAt":"2009-10-19T07:30:14Z","messageCount":4,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"125347","messageId":"1255937414-10043-1-git-send-email-gitster@pobox.com","threadId":"21275","inReplyTo":null,"subject":"[PATCH v2 0/3] nested expansion","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-19T07:30:11Z","receivedAt":"2009-10-19T07:30:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is a re-roll of the earlier \"general syntax for applying functions to\npretty-print format output\" series, rebased on two patches from Dscho to\nimplement strbuf_add_wrapped_text().  In other words, this will apply on\ntop of b4d784c (Add strbuf_add_wrapped_text() to utf8.[ch], 2008-11-10).\n\nThe first one is almost the same, except that it drops the unnecessary\ncast (pointed out by Dscho) and instead changes the type of return value\nfrom expand callback to ssize_t.\n\nThe second one has two changes:\n\n 1. w() is renamed to wrap();\n 2. it actually rewraps the text by using Dscho's strbuf_add_wrapped_text().\n\nThe third one is new.  It teaches wrap() to just indent without wrapping\nwhen the width parameter is zero or negative.\n\nJunio C Hamano (3):\n  strbuf_nested_expand(): allow expansion to interrupt in the middle\n  Add %[wrap(width,in1,in2)<<any-string>>%] implementation\n  Teach --wrap to only indent without wrapping\n\n pretty.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n strbuf.c |   29 +++++++++++++++++-----\n strbuf.h |    5 ++-\n utf8.c   |   13 ++++++++++\n 4 files changed, 115 insertions(+), 11 deletions(-)\n"},{"id":"125350","messageId":"1255937414-10043-2-git-send-email-gitster@pobox.com","threadId":"21275","inReplyTo":"1255937414-10043-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 1/3] strbuf_nested_expand(): allow expansion to interrupt in the middle","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-19T07:30:12Z","receivedAt":"2009-10-19T07:30:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This itself does not do a \"nested\" expansion, but it paves a way for\nsupporting an extended syntax to express a function that works on an\nexpanded substring, e.g. %[function(param...)expanded-string%], by\nallowing the callback function to tell where the argument to the function\nends.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\nDropped sloppy casts, as suggested by Dscho.\n\n pretty.c |    4 ++--\n strbuf.c |   29 ++++++++++++++++++++++-------\n strbuf.h |    5 +++--\n 3 files changed, 27 insertions(+), 11 deletions(-)\n\ndiff --git a/pretty.c b/pretty.c\nindex 587101f..126be56 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -595,8 +595,8 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)\n \t\tstrbuf_addch(sb, ')');\n }\n \n-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,\n-                               void *context)\n+static ssize_t format_commit_item(struct strbuf *sb, const char *placeholder,\n+\t\t\t\t  void *context)\n {\n \tstruct format_commit_context *c = context;\n \tconst struct commit *commit = c->commit;\ndiff --git a/strbuf.c b/strbuf.c\nindex a6153dc..af96155 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -214,29 +214,44 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_setlen(sb, sb->len + len);\n }\n \n-void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,\n-\t\t   void *context)\n+void strbuf_nested_expand(struct strbuf *sb, const char **format_p,\n+\t\t\t  expand_fn_t fn, void *context)\n {\n+\tconst char *format = *format_p;\n \tfor (;;) {\n \t\tconst char *percent;\n-\t\tsize_t consumed;\n+\t\tssize_t consumed;\n \n \t\tpercent = strchrnul(format, '%');\n \t\tstrbuf_add(sb, format, percent - format);\n+\t\tformat = percent;\n \t\tif (!*percent)\n \t\t\tbreak;\n-\t\tformat = percent + 1;\n+\t\tformat++;\n \n \t\tconsumed = fn(sb, format, context);\n-\t\tif (consumed)\n+\t\tif (consumed < 0)\n+\t\t\tbreak;\n+\t\telse if (consumed)\n \t\t\tformat += consumed;\n \t\telse\n \t\t\tstrbuf_addch(sb, '%');\n \t}\n+\t*format_p = format;\n+}\n+\n+void strbuf_expand(struct strbuf *sb, const char *o_format, expand_fn_t fn,\n+\t\t   void *context)\n+{\n+\tconst char *format = o_format;\n+\tstrbuf_nested_expand(sb, &format, fn, context);\n+\tif (*format)\n+\t\tdie(\"format error: negative return from expand function: %s\",\n+\t\t    o_format);\n }\n \n-size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,\n-\t\tvoid *context)\n+ssize_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,\n+\t\t\t      void *context)\n {\n \tstruct strbuf_expand_dict_entry *e = context;\n \tsize_t len;\ndiff --git a/strbuf.h b/strbuf.h\nindex d05e056..256d615 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -109,13 +109,14 @@ static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {\n }\n extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);\n \n-typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);\n+typedef ssize_t (*expand_fn_t)(struct strbuf *sb, const char *placeholder, void *context);\n extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);\n+extern void strbuf_nested_expand(struct strbuf *sb, const char **format_p, expand_fn_t fn, void *context);\n struct strbuf_expand_dict_entry {\n \tconst char *placeholder;\n \tconst char *value;\n };\n-extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);\n+extern ssize_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);\n \n __attribute__((format(printf,2,3)))\n extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n-- \n1.6.5.1.95.g09fbd\n"},{"id":"125348","messageId":"1255937414-10043-3-git-send-email-gitster@pobox.com","threadId":"21275","inReplyTo":"1255937414-10043-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 2/3] Add %[wrap(width,in1,in2)<<any-string>>%] implementation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-19T07:30:13Z","receivedAt":"2009-10-19T07:30:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This uses the strbuf_nested_expand() mechanism introduced earlier to\ndemonstrate how to implement a nested string function, by plugging Dscho's\nimplementation of strbuf_add_wrapped_text().\n\nThe log is much more pleasant to read with\n\n    $ git log --format='commit %H%nAuthor: %an%n%n%[wrap(66,4,4)%s%n%n%b%]'\n\nin some repositories (e.g. git-svn conversion of rockbox).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\nRenamed w() to wrap() and actually plugged Dscho's strbuf_add_wrapped_text().\n\n pretty.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 76 insertions(+), 0 deletions(-)\n\ndiff --git a/pretty.c b/pretty.c\nindex 126be56..bc74c25 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -595,6 +595,72 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)\n \t\tstrbuf_addch(sb, ')');\n }\n \n+typedef int (*string_fmt_fn)(struct strbuf *sb, const char *placeholder, void *context);\n+static ssize_t format_commit_item(struct strbuf *, const char *, void *);\n+\n+static int wrap_fn(struct strbuf *sb, const char *placeholder, void *context)\n+{\n+\tconst char *template = placeholder;\n+\tchar *endptr, *nested;\n+\tlong width = 0, indent1 = 0, indent2 = 0;\n+\n+\twidth = strtol(template, &endptr, 10);\n+\tif (*endptr == ',') {\n+\t\ttemplate = endptr + 1;\n+\t\tindent1 = strtol(template, &endptr, 10);\n+\t\tif (*endptr == ',') {\n+\t\t\ttemplate = endptr + 1;\n+\t\t\tindent2 = strtol(template, &endptr, 10);\n+\t\t}\n+\t}\n+\tif (*endptr++ != ')')\n+\t\treturn 0;\n+\n+\ttemplate = endptr;\n+\tstrbuf_nested_expand(sb, &template, format_commit_item, context);\n+\tif (*template++ != ']')\n+\t\treturn 0;\n+\n+\tnested = strbuf_detach(sb, NULL);\n+\tstrbuf_add_wrapped_text(sb, nested, indent1, indent2, width);\n+\tfree(nested);\n+\n+\treturn template - placeholder;\n+}\n+\n+static struct {\n+\tconst char *name;\n+\tstring_fmt_fn fn;\n+} format_fn_list[] = {\n+\t{ \"wrap(\", wrap_fn }\n+};\n+\n+static size_t format_fn(struct strbuf *sb, const char *placeholder,\n+\t\t\tvoid *context)\n+{\n+\tconst char *template = placeholder;\n+\tsize_t consumed;\n+\tstruct strbuf substr = STRBUF_INIT;\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(format_fn_list); i++)\n+\t\tif (!prefixcmp(template, format_fn_list[i].name))\n+\t\t\tbreak;\n+\tif (ARRAY_SIZE(format_fn_list) <= i)\n+\t\treturn 0;\n+\ttemplate += strlen(format_fn_list[i].name);\n+\tconsumed = format_fn_list[i].fn(&substr, template, context);\n+\tif (!consumed) {\n+\t\tstrbuf_release(&substr);\n+\t\treturn 0;\n+\t}\n+\n+\tstrbuf_add(sb, substr.buf, substr.len);\n+\ttemplate += consumed;\n+\tstrbuf_release(&substr);\n+\treturn template - placeholder;\n+}\n+\n static ssize_t format_commit_item(struct strbuf *sb, const char *placeholder,\n \t\t\t\t  void *context)\n {\n@@ -603,9 +669,19 @@ static ssize_t format_commit_item(struct strbuf *sb, const char *placeholder,\n \tconst char *msg = commit->buffer;\n \tstruct commit_list *p;\n \tint h1, h2;\n+\tssize_t nested;\n \n \t/* these are independent of the commit */\n \tswitch (placeholder[0]) {\n+\tcase ']':\n+\t\treturn -1;\n+\tcase '[':\n+\t\t/*\n+\t\t * %[func(arg...) string %]: we consumed the opening '['\n+\t\t * and the callee consumed up to the closing '%]'.\n+\t\t */\n+\t\tnested = format_fn(sb, placeholder + 1, context);\n+\t\treturn nested ? 1 + nested : 0;\n \tcase 'C':\n \t\tif (placeholder[1] == '(') {\n \t\t\tconst char *end = strchr(placeholder + 2, ')');\n"},{"id":"125349","messageId":"1255937414-10043-4-git-send-email-gitster@pobox.com","threadId":"21275","inReplyTo":"1255937414-10043-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 3/3] Teach --wrap to only indent without wrapping","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-19T07:30:14Z","receivedAt":"2009-10-19T07:30:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When a zero or negative width is given to \"shortlog -w<width>,<in1>,<in2>\"\nand --format=%[wrap(w,in1,in2)...%], just indent the text by in1 without\nwrapping.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n utf8.c |   13 +++++++++++++\n 1 files changed, 13 insertions(+), 0 deletions(-)\n\ndiff --git a/utf8.c b/utf8.c\nindex da99669..5c18f0c 100644\n--- a/utf8.c\n+++ b/utf8.c\n@@ -310,6 +310,19 @@ int strbuf_add_wrapped_text(struct strbuf *buf,\n \tint w = indent, assume_utf8 = is_utf8(text);\n \tconst char *bol = text, *space = NULL;\n \n+\tif (width <= 0) {\n+\t\t/* just indent */\n+\t\twhile (*text) {\n+\t\t\tconst char *eol = strchrnul(text, '\\n');\n+\t\t\tif (*eol == '\\n')\n+\t\t\t\teol++;\n+\t\t\tprint_spaces(buf, indent);\n+\t\t\tstrbuf_write(buf, text, eol-text);\n+\t\t\ttext = eol;\n+\t\t}\n+\t\treturn 1;\n+\t}\n+\n \tif (indent < 0) {\n \t\tw = -indent;\n \t\tspace = text;\n-- \n1.6.5.1.95.g09fbd\n"}]}