{"thread":{"id":"40098","subject":"[PATCH v11 00/13] port tag.c to use ref-filter APIs","startedAt":"2015-08-15T18:00:30Z","lastAt":"2015-08-16T08:15:57Z","messageCount":3,"participants":["Karthik Nayak","Jacob Keller"],"isPatch":true,"patchVersion":11,"patchTotal":13},"messages":[{"id":"268129","messageId":"1439661643-16094-1-git-send-email-Karthik.188@gmail.com","threadId":"40098","inReplyTo":null,"subject":"[PATCH v11 00/13] port tag.c to use ref-filter APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-15T18:00:30Z","receivedAt":"2015-08-15T18:00:30Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Karthik Nayak (13):\n  ref-filter: move `struct atom_value` to ref-filter.c\n  ref-filter: print output to strbuf for formatting\n  ref-filter: introduce ref_formatting_state\n  utf8: add function to align a string into given strbuf\n  ref-filter: implement an `align` atom\n  ref-filter: add option to filter out tags, branches and remotes\n  ref-filter: support printing N lines from tag annotation\n  ref-filter: add support to sort by version\n  ref-filter: add option to match literal pattern\n  tag.c: use 'ref-filter' data structures\n  tag.c: use 'ref-filter' APIs\n  tag.c: implement '--format' option\n  tag.c: implement '--merged' and '--no-merged' options\n\nChanges since v10:\n* Improve documentation.\n* Change the syntax used for the align atom and make left alignment\n  default whenever the position is not mentioned.\n* Instead of checking for modifier atoms, we have handler functions\n  for each atom and each state can have a attend function which is\n  called when the state is popped.\n* Nested alignment is now possible.\n* Change the way filter_refs() works and now we assign each ref its\n  kind so further filtering if needed can be done.\n* Rename some functions to have more meaningful names.\n* strbuf_utf8_align() now works with empty strings and also been\n  refactored to reduced the no of calls to strlen().\n\n Documentation/git-for-each-ref.txt |  11 ++\n Documentation/git-tag.txt          |  34 +++-\n builtin/for-each-ref.c             |   3 +-\n builtin/tag.c                      | 367 +++++++------------------------------\n ref-filter.c                       | 309 +++++++++++++++++++++++++++----\n ref-filter.h                       |  33 +++-\n refs.c                             |   7 +\n refs.h                             |   1 +\n t/t6302-for-each-ref-filter.sh     |  84 +++++++++\n t/t7004-tag.sh                     |  51 +++++-\n utf8.c                             |  21 +++\n utf8.h                             |  15 ++\n 12 files changed, 573 insertions(+), 363 deletions(-)\n\nInterDiff :\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex a795d5f..3099631 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -128,13 +128,12 @@ color::\n \tare described in `color.branch.*`.\n \n align::\n-\tImplement an `align` atom which left-, middle-, or\n-\tright-aligns the content between %(align:..)  and\n-\t%(end). Followed by `:<position>,<width>`, where the\n+\tleft-, middle-, or right-align the content between %(align:..)\n+\tand %(end). Followed by `:<position>,<width>`, where the\n \t`<position>` is either left, right or middle and `<width>` is\n \tthe total length of the content with alignment. If the\n \tcontents length is more than the width then no alignment is\n-\tperformed. Currently nested alignment is not supported.\n+\tperformed.\n \n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 22efbba..781d3e5 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -41,7 +41,7 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con\n \t\tfilter->lines = 0;\n \n \tif (filter->lines)\n-\t\tformat = \"%(align:left,16)%(refname:short)%(end)\";\n+\t\tformat = \"%(align:16,left)%(refname:short)%(end)\";\n \telse if (!format)\n \t\tformat = \"%(refname:short)\";\n \ndiff --git a/ref-filter.c b/ref-filter.c\nindex d22bf66..a6086b2 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -65,12 +65,19 @@ struct align {\n \tunsigned int width;\n };\n \n-struct atom_value{\n+struct ref_formatting_state {\n+\tstruct strbuf output;\n+\tstruct ref_formatting_state *prev;\n+\tvoid (*attend)(struct ref_formatting_state *state);\n+\tvoid *cb_data;\n+\tint quote_style;\n+};\n+\n+struct atom_value {\n \tconst char *s;\n \tstruct align *align;\n+\tvoid (*handler)(struct atom_value *atomv, struct ref_formatting_state **state);\n \tunsigned long ul; /* used for sorting when not FIELD_STR */\n-\tunsigned int modifier_atom : 1,\n-\t\tend : 1;\n };\n \n /*\n@@ -142,6 +149,26 @@ int parse_ref_filter_atom(const char *atom, const char *ep)\n \treturn at;\n }\n \n+static struct ref_formatting_state *push_new_state(struct ref_formatting_state **state)\n+{\n+\tstruct ref_formatting_state *new = xcalloc(1, sizeof(struct ref_formatting_state));\n+\tstruct ref_formatting_state *old = *state;\n+\n+\t*state = new;\n+\tnew->prev = old;\n+\treturn new;\n+}\n+\n+static void pop_state(struct ref_formatting_state **state)\n+{\n+\tstruct ref_formatting_state *current = *state;\n+\tstruct ref_formatting_state *prev = current->prev;\n+\n+\tstrbuf_release(&current->output);\n+\tfree(current);\n+\t*state = prev;\n+}\n+\n /*\n  * In a format string, find the next occurrence of %(atom).\n  */\n@@ -612,6 +639,34 @@ static inline char *copy_advance(char *dst, const char *src)\n \treturn dst;\n }\n \n+static void align_handler(struct ref_formatting_state *state)\n+{\n+\tstruct strbuf aligned = STRBUF_INIT;\n+\tstruct ref_formatting_state *return_to = state->prev;\n+\tstruct align *align = (struct align *)state->cb_data;\n+\n+\tstrbuf_utf8_align(&aligned, align->position, align->width, state->output.buf);\n+\tstrbuf_addbuf(&return_to->output, &aligned);\n+\tstrbuf_release(&aligned);\n+}\n+\n+static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_state **state)\n+{\n+\tstruct ref_formatting_state *new = push_new_state(state);\n+\tstrbuf_init(&new->output, 0);\n+\tnew->attend = align_handler;\n+\tnew->cb_data = atomv->align;\n+}\n+\n+static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state **state)\n+{\n+\tstruct ref_formatting_state *current = *state;\n+\tif (!current->attend)\n+\t\tdie(_(\"format: `end` atom used without a supporting atom\"));\n+\tcurrent->attend(current);\n+\tpop_state(state);\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -708,23 +763,31 @@ static void populate_value(struct ref_array_item *ref)\n \t\t\tcontinue;\n \t\t} else if (skip_prefix(name, \"align:\", &valp)) {\n \t\t\tstruct align *align = xmalloc(sizeof(struct align));\n+\t\t\tchar *ep = strchr(valp, ',');\n+\n+\t\t\tif (ep)\n+\t\t\t\t*ep = '\\0';\n+\n+\t\t\tif (strtoul_ui(valp, 10, &align->width))\n+\t\t\t\tdie(_(\"positive width expected align:%s\"), valp);\n \n-\t\t\tif (skip_prefix(valp, \"left,\", &valp))\n+\t\t\tif (!ep || starts_with(ep + 1, \"left\"))\n \t\t\t\talign->position = ALIGN_LEFT;\n-\t\t\telse if (skip_prefix(valp, \"right,\", &valp))\n+\t\t\telse if (starts_with(ep + 1, \"right\"))\n \t\t\t\talign->position = ALIGN_RIGHT;\n-\t\t\telse if (skip_prefix(valp, \"middle,\", &valp))\n+\t\t\telse if (starts_with(ep + 1, \"middle\"))\n \t\t\t\talign->position = ALIGN_MIDDLE;\n \t\t\telse\n-\t\t\t\tdie(_(\"improper format entered align:%s\"), valp);\n-\t\t\tif (strtoul_ui(valp, 10, &align->width))\n-\t\t\t\tdie(_(\"positive width expected align:%s\"), valp);\n+\t\t\t\tdie(_(\"improper format entered align:%s\"), ep + 1);\n+\n+\t\t\tif (ep)\n+\t\t\t\t*ep = ',';\n+\n \t\t\tv->align = align;\n-\t\t\tv->modifier_atom = 1;\n+\t\t\tv->handler = align_atom_handler;\n \t\t\tcontinue;\n \t\t} else if (!strcmp(name, \"end\")) {\n-\t\t\tv->end = 1;\n-\t\t\tv->modifier_atom = 1;\n+\t\t\tv->handler = end_atom_handler;\n \t\t\tcontinue;\n \t\t} else\n \t\t\tcontinue;\n@@ -979,7 +1042,8 @@ static int match_pattern(const char **patterns, const char *refname)\n \t */\n \t(void)(skip_prefix(refname, \"refs/tags/\", &refname) ||\n \t       skip_prefix(refname, \"refs/heads/\", &refname) ||\n-\t       skip_prefix(refname, \"refs/remotes/\", &refname));\n+\t       skip_prefix(refname, \"refs/remotes/\", &refname) ||\n+\t       skip_prefix(refname, \"refs/\", &refname));\n \n \tfor (; *patterns; patterns++) {\n \t\tif (!wildmatch(*patterns, refname, 0, NULL))\n@@ -1070,6 +1134,36 @@ static struct ref_array_item *new_ref_array_item(const char *refname,\n \treturn ref;\n }\n \n+static int filter_ref_kind(struct ref_filter *filter, const char *refname)\n+{\n+\tunsigned int i;\n+\n+\tstatic struct {\n+\t\tconst char *prefix;\n+\t\tunsigned int kind;\n+\t} ref_kind[] = {\n+\t\t{ \"refs/heads/\" , FILTER_REFS_BRANCHES },\n+\t\t{ \"refs/remotes/\" , FILTER_REFS_REMOTES },\n+\t\t{ \"refs/tags/\", FILTER_REFS_TAGS}\n+\t};\n+\n+\tif (filter->kind == FILTER_REFS_BRANCHES)\n+\t\treturn FILTER_REFS_BRANCHES;\n+\telse if (filter->kind == FILTER_REFS_REMOTES)\n+\t\treturn FILTER_REFS_REMOTES;\n+\telse if (filter->kind == FILTER_REFS_TAGS)\n+\t\treturn FILTER_REFS_TAGS;\n+\telse if (!strcmp(refname, \"HEAD\"))\n+\t\treturn FILTER_REFS_DETACHED_HEAD;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(ref_kind); i++) {\n+\t\tif (starts_with(refname, ref_kind[i].prefix))\n+\t\t\treturn ref_kind[i].kind;\n+\t}\n+\n+\treturn FILTER_REFS_OTHERS;\n+}\n+\n /*\n  * A call-back given to for_each_ref().  Filter refs and keep them for\n  * later object processing.\n@@ -1080,6 +1174,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \tstruct ref_filter *filter = ref_cbdata->filter;\n \tstruct ref_array_item *ref;\n \tstruct commit *commit = NULL;\n+\tunsigned int kind;\n \n \tif (flag & REF_BAD_NAME) {\n \t\twarning(\"ignoring ref with broken name %s\", refname);\n@@ -1091,6 +1186,10 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t\treturn 0;\n \t}\n \n+\tkind = filter_ref_kind(filter, refname);\n+\tif (!(kind & filter->kind))\n+\t\treturn 0;\n+\n \tif (!filter_pattern_match(filter, refname))\n \t\treturn 0;\n \n@@ -1122,6 +1221,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \n \tREALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);\n \tref_cbdata->array->items[ref_cbdata->array->nr++] = ref;\n+\tref->kind = kind;\n \treturn 0;\n }\n \n@@ -1198,18 +1298,29 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int\n {\n \tstruct ref_filter_cbdata ref_cbdata;\n \tint ret = 0;\n+\tunsigned int broken = 0;\n \n \tref_cbdata.array = array;\n \tref_cbdata.filter = filter;\n \n \t/*  Simple per-ref filtering */\n-\tif (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))\n-\t\tret = for_each_rawref(ref_filter_handler, &ref_cbdata);\n-\telse if (type & FILTER_REFS_ALL)\n-\t\tret = for_each_ref(ref_filter_handler, &ref_cbdata);\n-\telse if (type & FILTER_REFS_TAGS)\n-\t\tret = for_each_tag_ref_fullpath(ref_filter_handler, &ref_cbdata);\n-\telse if (type)\n+\tif (type & FILTER_REFS_INCLUDE_BROKEN) {\n+\t\ttype -= FILTER_REFS_INCLUDE_BROKEN;\n+\t\tbroken = 1;\n+\t}\n+\n+\tfilter->kind = type;\n+\tif (type == FILTER_REFS_BRANCHES)\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"refs/heads/\", broken, &ref_cbdata);\n+\telse if (type == FILTER_REFS_REMOTES)\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"refs/remotes/\", broken, &ref_cbdata);\n+\telse if (type == FILTER_REFS_TAGS)\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"refs/tags/\", broken, &ref_cbdata);\n+\telse if (type & FILTER_REFS_ALL) {\n+\t\tret = for_each_reftype_fullpath(ref_filter_handler, \"\", broken, &ref_cbdata);\n+\t\tif (type & FILTER_REFS_DETACHED_HEAD)\n+\t\t\thead_ref(ref_filter_handler, &ref_cbdata);\n+\t} else\n \t\tdie(\"filter_refs: invalid type\");\n \n \t/*  Filters that need revision walking */\n@@ -1264,15 +1375,7 @@ void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)\n \tqsort(array->items, array->nr, sizeof(struct ref_array_item *), compare_refs);\n }\n \n-\n-struct ref_formatting_state {\n-\tstruct strbuf output;\n-\tstruct align *align;\n-\tint quote_style;\n-\tunsigned int end : 1;\n-};\n-\n-static void format_quote_value(struct atom_value *v, struct ref_formatting_state *state)\n+static void append_atom(struct atom_value *v, struct ref_formatting_state *state)\n {\n \tswitch (state->quote_style) {\n \tcase QUOTE_NONE:\n@@ -1311,7 +1414,7 @@ static int hex2(const char *cp)\n \t\treturn -1;\n }\n \n-static void append_non_atom(const char *cp, const char *ep, struct ref_formatting_state *state)\n+static void append_literal(const char *cp, const char *ep, struct ref_formatting_state *state)\n {\n \twhile (*cp && (!ep || cp < ep)) {\n \t\tif (*cp == '%') {\n@@ -1331,37 +1434,6 @@ static void append_non_atom(const char *cp, const char *ep, struct ref_formattin\n \t}\n }\n \n-static void set_formatting_state(struct atom_value *atomv, struct ref_formatting_state *state)\n-{\n-\tif (atomv->align) {\n-\t\tstate->align = atomv->align;\n-\t\tatomv->align = NULL;\n-\t}\n-\tif (atomv->end)\n-\t\tstate->end = 1;\n-}\n-\n-static int align_ref_strbuf(struct ref_formatting_state *state, struct strbuf *final)\n-{\n-\tif (state->align && state->end) {\n-\t\tstruct align *align = state->align;\n-\t\tstrbuf_utf8_align(final, align->position, align->width, state->output.buf);\n-\t\tstrbuf_reset(&state->output);\n-\t\tstate->align = NULL;\n-\t\treturn 1;\n-\t} else if (state->align)\n-\t\treturn 1;\n-\treturn 0;\n-}\n-\n-static void perform_state_formatting(struct ref_formatting_state *state, struct strbuf *final)\n-{\n-\tif (align_ref_strbuf(state, final))\n-\t\treturn;\n-\tstrbuf_addbuf(final, &state->output);\n-\tstrbuf_reset(&state->output);\n-}\n-\n /*\n  * If 'lines' is greater than 0, print that many lines from the given\n  * object_id 'oid'.\n@@ -1409,38 +1481,26 @@ void show_ref_array_item(struct ref_array_item *info, const char *format,\n \t\t\t int quote_style, unsigned int lines)\n {\n \tconst char *cp, *sp, *ep;\n-\tstruct strbuf final_buf = STRBUF_INIT;\n-\tstruct ref_formatting_state state;\n+\tstruct strbuf *final_buf;\n+\tstruct ref_formatting_state *state = NULL;\n \n-\tstate.quote_style = quote_style;\n-\tstrbuf_init(&state.output, 0);\n-\tstate.align = NULL;\n-\tstate.end = 0;\n+\tstate = push_new_state(&state);\n+\tstate->quote_style = quote_style;\n \n \tfor (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {\n \t\tstruct atom_value *atomv;\n \n \t\tep = strchr(sp, ')');\n-\t\tif (cp < sp) {\n-\t\t\tappend_non_atom(cp, sp, &state);\n-\t\t\tperform_state_formatting(&state, &final_buf);\n-\t\t}\n+\t\tif (cp < sp)\n+\t\t\tappend_literal(cp, sp, state);\n \t\tget_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);\n-\t\tif (atomv->modifier_atom)\n-\t\t\tset_formatting_state(atomv, &state);\n-\t\telse {\n-\t\t\tformat_quote_value(atomv, &state);\n-\t\t\tperform_state_formatting(&state, &final_buf);\n-\t\t}\n-\t\tif (atomv->end)\n-\t\t\tperform_state_formatting(&state, &final_buf);\n+\t\tif (atomv->handler)\n+\t\t\tatomv->handler(atomv, &state);\n+\t\tappend_atom(atomv, state);\n \t}\n-\tif (state.align)\n-\t\tdie(_(\"format: align used without an `end` atom\"));\n \tif (*cp) {\n \t\tsp = cp + strlen(cp);\n-\t\tappend_non_atom(cp, sp, &state);\n-\t\tperform_state_formatting(&state, &final_buf);\n+\t\tappend_literal(cp, sp, state);\n \t}\n \tif (need_color_reset_at_eol) {\n \t\tstruct atom_value resetv;\n@@ -1449,13 +1509,11 @@ void show_ref_array_item(struct ref_array_item *info, const char *format,\n \t\tif (color_parse(\"reset\", color) < 0)\n \t\t\tdie(\"BUG: couldn't parse 'reset' as a color\");\n \t\tresetv.s = color;\n-\t\tformat_quote_value(&resetv, &state);\n-\t\tperform_state_formatting(&state, &final_buf);\n+\t\tappend_atom(&resetv, state);\n \t}\n-\n-\tfwrite(final_buf.buf, 1, final_buf.len, stdout);\n-\tstrbuf_release(&final_buf);\n-\tstrbuf_release(&state.output);\n+\tfinal_buf = &state->output;\n+\tfwrite(final_buf->buf, 1, final_buf->len, stdout);\n+\tpop_state(&state);\n \n \tif (lines > 0) {\n \t\tstruct object_id oid;\ndiff --git a/ref-filter.h b/ref-filter.h\nindex 75bf989..72fdf9e 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -14,9 +14,14 @@\n #define QUOTE_PYTHON 4\n #define QUOTE_TCL 8\n \n-#define FILTER_REFS_INCLUDE_BROKEN 0x1\n-#define FILTER_REFS_ALL 0x2\n-#define FILTER_REFS_TAGS 0x4\n+#define FILTER_REFS_INCLUDE_BROKEN 0x0001\n+#define FILTER_REFS_TAGS           0x0002\n+#define FILTER_REFS_BRANCHES       0x0004\n+#define FILTER_REFS_REMOTES        0x0008\n+#define FILTER_REFS_OTHERS         0x0010\n+#define FILTER_REFS_ALL            (FILTER_REFS_TAGS | FILTER_REFS_BRANCHES | \\\n+\t\t\t\t    FILTER_REFS_REMOTES | FILTER_REFS_OTHERS)\n+#define FILTER_REFS_DETACHED_HEAD  0x0020\n \n struct atom_value;\n \n@@ -30,6 +35,7 @@ struct ref_sorting {\n struct ref_array_item {\n \tunsigned char objectname[20];\n \tint flag;\n+\tunsigned int kind;\n \tconst char *symref;\n \tstruct commit *commit;\n \tstruct atom_value *value;\n@@ -55,7 +61,8 @@ struct ref_filter {\n \n \tunsigned int with_commit_tag_algo : 1,\n \t\tmatch_as_path : 1;\n-\tunsigned int lines;\n+\tunsigned int kind,\n+\t\tlines;\n };\n \n struct ref_filter_cbdata {\ndiff --git a/refs.c b/refs.c\nindex 0103a88..0f18c34 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2114,11 +2114,6 @@ int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n \treturn for_each_ref_in(\"refs/tags/\", fn, cb_data);\n }\n \n-int for_each_tag_ref_fullpath(each_ref_fn fn, void *cb_data)\n-{\n-\treturn do_for_each_ref(&ref_cache, \"refs/tags/\", fn, 0, 0, cb_data);\n-}\n-\n int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n {\n \treturn for_each_ref_in_submodule(submodule, \"refs/tags/\", fn, cb_data);\n@@ -2150,6 +2145,13 @@ int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n \t\t\t       strlen(git_replace_ref_base), 0, cb_data);\n }\n \n+int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data)\n+{\n+\tif (broken)\n+\t\tbroken = DO_FOR_EACH_INCLUDE_BROKEN;\n+\treturn do_for_each_ref(&ref_cache, type, fn, 0, broken, cb_data);\n+}\n+\n int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/refs.h b/refs.h\nindex 0956255..7f91a72 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -174,12 +174,12 @@ extern int head_ref(each_ref_fn fn, void *cb_data);\n extern int for_each_ref(each_ref_fn fn, void *cb_data);\n extern int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);\n extern int for_each_tag_ref(each_ref_fn fn, void *cb_data);\n-extern int for_each_tag_ref_fullpath(each_ref_fn fn, void *cb_data);\n extern int for_each_branch_ref(each_ref_fn fn, void *cb_data);\n extern int for_each_remote_ref(each_ref_fn fn, void *cb_data);\n extern int for_each_replace_ref(each_ref_fn fn, void *cb_data);\n extern int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);\n extern int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data);\n+extern int for_each_reftype_fullpath(each_ref_fn fn, char *type, unsigned int broken, void *cb_data);\n \n extern int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);\n extern int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex ce455d9..1c56879 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -93,7 +93,7 @@ test_expect_success 'left alignment' '\n \trefname is refs/tags/three    |refs/tags/three\n \trefname is refs/tags/two      |refs/tags/two\n \tEOF\n-\tgit for-each-ref --format=\"%(align:left,30)refname is %(refname)%(end)|%(refname)\" >actual &&\n+\tgit for-each-ref --format=\"%(align:30,left)refname is %(refname)%(end)|%(refname)\" >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -109,7 +109,7 @@ test_expect_success 'middle alignment' '\n \t|  refname is refs/tags/three  |refs/tags/three\n \t|   refname is refs/tags/two   |refs/tags/two\n \tEOF\n-\tgit for-each-ref --format=\"|%(align:middle,30)refname is %(refname)%(end)|%(refname)\" >actual &&\n+\tgit for-each-ref --format=\"|%(align:30,middle)refname is %(refname)%(end)|%(refname)\" >actual &&\n \ttest_cmp expect actual\n '\n \n@@ -125,7 +125,7 @@ test_expect_success 'right alignment' '\n \t|    refname is refs/tags/three|refs/tags/three\n \t|      refname is refs/tags/two|refs/tags/two\n \tEOF\n-\tgit for-each-ref --format=\"|%(align:right,30)refname is %(refname)%(end)|%(refname)\" >actual &&\n+\tgit for-each-ref --format=\"|%(align:30,right)refname is %(refname)%(end)|%(refname)\" >actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/utf8.c b/utf8.c\nindex 65e55cc..0fb8e9d 100644\n--- a/utf8.c\n+++ b/utf8.c\n@@ -648,21 +648,20 @@ int skip_utf8_bom(char **text, size_t len)\n void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int width,\n \t\t       const char *s)\n {\n-\tint display_len = utf8_strnwidth(s, strlen(s), 0);\n-\tint utf8_compenstation = strlen(s) - display_len;\n+\tint slen = strlen(s);\n+\tint display_len = utf8_strnwidth(s, slen, 0);\n+\tint utf8_compensation = slen - display_len;\n \n-\tif (!strlen(s))\n-\t\treturn;\n \tif (display_len >= width) {\n \t\tstrbuf_addstr(buf, s);\n \t\treturn;\n \t}\n \n \tif (position == ALIGN_LEFT)\n-\t\tstrbuf_addf(buf, \"%-*s\", width + utf8_compenstation, s);\n+\t\tstrbuf_addf(buf, \"%-*s\", width + utf8_compensation, s);\n \telse if (position == ALIGN_MIDDLE) {\n \t\tint left = (width - display_len)/2;\n-\t\tstrbuf_addf(buf, \"%*s%-*s\", left, \"\", width - left + utf8_compenstation, s);\n+\t\tstrbuf_addf(buf, \"%*s%-*s\", left, \"\", width - left + utf8_compensation, s);\n \t} else if (position == ALIGN_RIGHT)\n-\t\tstrbuf_addf(buf, \"%*s\", width + utf8_compenstation, s);\n+\t\tstrbuf_addf(buf, \"%*s\", width + utf8_compensation, s);\n }\ndiff --git a/utf8.h b/utf8.h\nindex db8ca63..7930b44 100644\n--- a/utf8.h\n+++ b/utf8.h\n@@ -62,8 +62,10 @@ typedef enum {\n } align_type;\n \n /*\n- * Align the string given and store it into a strbuf as per the type\n- * and width.\n+ * Align the string given and store it into a strbuf as per the\n+ * 'position' and 'width'. If the given string length is larger than\n+ * 'width' than then the input string is not truncated and no\n+ * alignment is done.\n  */\n void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int width,\n \t\t       const char *s);\n\n-- \n2.5.0\n"},{"id":"268146","messageId":"CA+P7+xpWFT=NJC2VdnamjA86LcYRc4z__La91ca_yGdtFPHahw@mail.gmail.com","threadId":"40098","inReplyTo":"1439661643-16094-1-git-send-email-Karthik.188@gmail.com","subject":"Re: [PATCH v11 00/13] port tag.c to use ref-filter APIs","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2015-08-16T07:38:59Z","receivedAt":"2015-08-16T07:38:59Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Sat, Aug 15, 2015 at 11:00 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n\n>\n>  align::\n> -       Implement an `align` atom which left-, middle-, or\n> -       right-aligns the content between %(align:..)  and\n> -       %(end). Followed by `:<position>,<width>`, where the\n> +       left-, middle-, or right-align the content between %(align:..)\n> +       and %(end). Followed by `:<position>,<width>`, where the\n\n\nEverywhere else in the code seems to now put position second now, but\nthe documentation here doesn't say this is allowed or required.\n\nRegards,\nJake\n\n>         `<position>` is either left, right or middle and `<width>` is\n>         the total length of the content with alignment. If the\n>         contents length is more than the width then no alignment is\n> -       performed. Currently nested alignment is not supported.\n> +       performed.\n>\n"},{"id":"268148","messageId":"CAOLa=ZTGpg1AfkrFhspsZd60z4yow+rxG-_HZ=EaUhv_k3i-Uw@mail.gmail.com","threadId":"40098","inReplyTo":"CA+P7+xpWFT=NJC2VdnamjA86LcYRc4z__La91ca_yGdtFPHahw@mail.gmail.com","subject":"Re: [PATCH v11 00/13] port tag.c to use ref-filter APIs","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-08-16T08:15:57Z","receivedAt":"2015-08-16T08:15:57Z","isPatch":true,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"On Sun, Aug 16, 2015 at 1:08 PM, Jacob Keller <jacob.keller@gmail.com> wrote:\n> On Sat, Aug 15, 2015 at 11:00 AM, Karthik Nayak <karthik.188@gmail.com> wrote:\n>\n>>\n>>  align::\n>> -       Implement an `align` atom which left-, middle-, or\n>> -       right-aligns the content between %(align:..)  and\n>> -       %(end). Followed by `:<position>,<width>`, where the\n>> +       left-, middle-, or right-align the content between %(align:..)\n>> +       and %(end). Followed by `:<position>,<width>`, where the\n>\n>\n> Everywhere else in the code seems to now put position second now, but\n> the documentation here doesn't say this is allowed or required.\n>\n\nOops! you're right, that needs to be swapped.\n\n-- \nRegards,\nKarthik Nayak\n"}]}