From: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> Pretty placeholders %>(N) and %<(N) require a user provided width N, which makes sense because the commit chain could be really long and the user only needs to look at a few at the top, going to the end just to calculate the best width wastes CPU cycles. for-each-ref is different; the display set is small, and we display them all at once. We even support sorting, which goes through all display items anyway. This patch introduces new %>(*) and %<(*), which are supposed to be followed immediately by %(fieldname) (i.e. original for-each-ref specifiers, not ones coming from pretty.c). They calculate the best width for the %(fieldname), ignoring ansi escape sequences if any. [rr: documentation] Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> Signed-off-by: Ramkumar Ramachandra <artagnon@xxxxxxxxx> --- Documentation/git-for-each-ref.txt | 7 +++++++ builtin/for-each-ref.c | 38 ++++++++++++++++++++++++++++++++++++++ t/t6300-for-each-ref.sh | 20 ++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index d8ad758..8cbc08c 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -47,6 +47,10 @@ OPTIONS are hex digits interpolates to character with hex code `xx`; for example `%00` interpolates to `\0` (NUL), `%09` to `\t` (TAB) and `%0a` to `\n` (LF). ++ +Placeholders `%<(*)` and `%>(*)` work like `%<(<N>)` and `%>(<N>)` +respectively, except that the width of the next placeholder is +calculated. <pretty>:: A format string with supporting placeholders described in the @@ -68,6 +72,9 @@ Caveats: 3. Only the placeholders inherited from `<format>` will respect quoting settings. +3. Only the placeholders inherited from `<format>` will work with the + alignment placeholders `%<(*)` and '%>(*)`. + <pattern>...:: If one or more patterns are given, only refs are shown that match against at least one pattern, either using fnmatch(3) or diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 39454fb..da479d1 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -9,6 +9,7 @@ #include "quote.h" #include "parse-options.h" #include "remote.h" +#include "utf8.h" /* Quoting styles */ #define QUOTE_NONE 0 @@ -966,10 +967,30 @@ static void show_refs(struct refinfo **refs, int maxcount, } struct format_one_atom_context { + struct refinfo **refs; + int maxcount; + struct refinfo *info; int quote_style; }; +static unsigned int get_atom_width(struct format_one_atom_context *ctx, + const char *start, const char *end) +{ + struct strbuf sb = STRBUF_INIT; + int i, atom = parse_atom(start, end); + unsigned int len = 0, sb_len; + for (i = 0; i < ctx->maxcount; i++) { + print_value(&sb, ctx->refs[i], atom, ctx->quote_style); + sb_len = utf8_strnwidth(sb.buf, sb.len, 1); + if (sb_len > len) + len = sb_len; + strbuf_reset(&sb); + } + strbuf_release(&sb); + return len; +} + static size_t format_one_atom(struct strbuf *sb, const char *placeholder, void *format_context, void *user_data, struct strbuf *subst) @@ -982,6 +1003,21 @@ static size_t format_one_atom(struct strbuf *sb, const char *placeholder, return 1; } + /* + * Substitute %>(*)%(atom) and friends with real width. + */ + if (*placeholder == '>' || *placeholder == '<') { + const char *star = placeholder + 1; + if (!prefixcmp(star, "(*)%(") && + ((ep = strchr(star + strlen("(*)%("), ')')) != NULL)) { + star++; + strbuf_addf(subst, "%c(%u)", + *placeholder, + get_atom_width(ctx, star + strlen("*)%("), ep)); + return 1 + strlen("(*)"); + } + } + if (*placeholder != '(') return 0; @@ -1008,6 +1044,8 @@ static void show_pretty_refs(struct refinfo **refs, int maxcount, ctx.abbrev = DEFAULT_ABBREV; ctx.format = format_one_atom; ctx.user_data = &fctx; + fctx.refs = refs; + fctx.maxcount = maxcount; fctx.quote_style = quote_style; for (i = 0; i < maxcount; i++) { struct commit *commit = NULL; diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index d39e0b4..160018c 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -196,6 +196,26 @@ test_pretty head '%<(20)%(committername) end' 'C O Mitter end' test_pretty head '%>(20)%(committername) end' ' C O Mitter end' test_pretty head '%><(20)%(committername) end' ' C O Mitter end' +test_expect_success '%<(*)%(refname) A' ' + git for-each-ref --pretty="%<(*)%(refname) A" >actual && + cat >expected <<EOF && +refs/heads/master A +refs/remotes/origin/master A +refs/tags/testtag A +EOF + test_cmp expected actual +' + +test_expect_success '%>(*)%(refname) A' ' + git for-each-ref --pretty="%>(*)%(refname) A" >actual && + qz_to_tab_space >expected <<EOF && +Z refs/heads/master A +refs/remotes/origin/master A +Z refs/tags/testtag A +EOF + test_cmp expected actual +' + test_pretty tag '%(refname)' refs/tags/testtag test_pretty tag '%(upstream)' '' test_pretty tag '%(objecttype)' tag -- 1.8.3.2.736.g869de25 -- 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