diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 7bfffae765..079598307a 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -102,120 +102,160 @@ The title was >>t4119: test autocomputing -p for traditional diff input.<< + The placeholders are: -- '%H': commit hash -- '%h': abbreviated commit hash -- '%T': tree hash -- '%t': abbreviated tree hash -- '%P': parent hashes -- '%p': abbreviated parent hashes -- '%an': author name -- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] - or linkgit:git-blame[1]) -- '%ae': author email -- '%aE': author email (respecting .mailmap, see - linkgit:git-shortlog[1] or linkgit:git-blame[1]) -- '%ad': author date (format respects --date= option) -- '%aD': author date, RFC2822 style -- '%ar': author date, relative -- '%at': author date, UNIX timestamp -- '%ai': author date, ISO 8601-like format -- '%aI': author date, strict ISO 8601 format -- '%cn': committer name -- '%cN': committer name (respecting .mailmap, see - linkgit:git-shortlog[1] or linkgit:git-blame[1]) -- '%ce': committer email -- '%cE': committer email (respecting .mailmap, see - linkgit:git-shortlog[1] or linkgit:git-blame[1]) -- '%cd': committer date (format respects --date= option) -- '%cD': committer date, RFC2822 style -- '%cr': committer date, relative -- '%ct': committer date, UNIX timestamp -- '%ci': committer date, ISO 8601-like format -- '%cI': committer date, strict ISO 8601 format -- '%d': ref names, like the --decorate option of linkgit:git-log[1] -- '%D': ref names without the " (", ")" wrapping. -- '%S': ref name given on the command line by which the commit was reached - (like `git log --source`), only works with `git log` -- '%e': encoding -- '%s': subject -- '%f': sanitized subject line, suitable for a filename -- '%b': body -- '%B': raw body (unwrapped subject and body) +- Placeholders that expand to a single literal character: +'%n':: newline +'%%':: a raw '%' +'%x00':: print a byte from a hex code + +- Placeholders that affect formatting of later placeholders: +'%Cred':: switch color to red +'%Cgreen':: switch color to green +'%Cblue':: switch color to blue +'%Creset':: reset color +'%C(...)':: color specification, as described under Values in the + "CONFIGURATION FILE" section of linkgit:git-config[1]. By + default, colors are shown only when enabled for log output + (by `color.diff`, `color.ui`, or `--color`, and respecting + the `auto` settings of the former if we are going to a + terminal). `%C(auto,...)` is accepted as a historical + synonym for the default (e.g., `%C(auto,red)`). Specifying + `%C(always,...)` will show the colors even when color is + not otherwise enabled (though consider just using + `--color=always` to enable color for the whole output, + including this format and anything else git might color). + `auto` alone (i.e. `%C(auto)`) will turn on auto coloring + on the next placeholders until the color is switched + again. +'%m':: left (`<`), right (`>`) or boundary (`-`) mark +'%w([[,[,]]])':: switch line wrapping, like the -w option of + linkgit:git-shortlog[1]. +'%<([,trunc|ltrunc|mtrunc])':: make the next placeholder take at + least N columns, padding spaces on + the right if necessary. Optionally + truncate at the beginning (ltrunc), + the middle (mtrunc) or the end + (trunc) if the output is longer than + N columns. Note that truncating + only works correctly with N >= 2. +'%<|()':: make the next placeholder take at least until Nth + columns, padding spaces on the right if necessary +'%>()', '%>|()':: similar to '%<()', '%<|()' respectively, + but padding spaces on the left +'%>>()', '%>>|()':: similar to '%>()', '%>|()' + respectively, except that if the next + placeholder takes more spaces than given and + there are spaces on its left, use those + spaces +'%><()', '%><|()':: similar to '%<()', '%<|()' + respectively, but padding both sides + (i.e. the text is centered) + +- Placeholders that expand to information extracted from the commit: +'%H':: commit hash +'%h':: abbreviated commit hash +'%T':: tree hash +'%t':: abbreviated tree hash +'%P':: parent hashes +'%p':: abbreviated parent hashes +'%an':: author name +'%aN':: author name (respecting .mailmap, see linkgit:git-shortlog[1] + or linkgit:git-blame[1]) +'%ae':: author email +'%aE':: author email (respecting .mailmap, see linkgit:git-shortlog[1] + or linkgit:git-blame[1]) +'%ad':: author date (format respects --date= option) +'%aD':: author date, RFC2822 style +'%ar':: author date, relative +'%at':: author date, UNIX timestamp +'%ai':: author date, ISO 8601-like format +'%aI':: author date, strict ISO 8601 format +'%cn':: committer name +'%cN':: committer name (respecting .mailmap, see + linkgit:git-shortlog[1] or linkgit:git-blame[1]) +'%ce':: committer email +'%cE':: committer email (respecting .mailmap, see + linkgit:git-shortlog[1] or linkgit:git-blame[1]) +'%cd':: committer date (format respects --date= option) +'%cD':: committer date, RFC2822 style +'%cr':: committer date, relative +'%ct':: committer date, UNIX timestamp +'%ci':: committer date, ISO 8601-like format +'%cI':: committer date, strict ISO 8601 format +'%d':: ref names, like the --decorate option of linkgit:git-log[1] +'%D':: ref names without the " (", ")" wrapping. +'%S':: ref name given on the command line by which the commit was reached + (like `git log --source`), only works with `git log` +'%e':: encoding +'%s':: subject +'%f':: sanitized subject line, suitable for a filename +'%b':: body +'%B':: raw body (unwrapped subject and body) ifndef::git-rev-list[] -- '%N': commit notes +'%N':: commit notes endif::git-rev-list[] -- '%GG': raw verification message from GPG for a signed commit -- '%G?': show "G" for a good (valid) signature, - "B" for a bad signature, - "U" for a good signature with unknown validity, - "X" for a good signature that has expired, - "Y" for a good signature made by an expired key, - "R" for a good signature made by a revoked key, - "E" if the signature cannot be checked (e.g. missing key) - and "N" for no signature -- '%GS': show the name of the signer for a signed commit -- '%GK': show the key used to sign a signed commit -- '%GF': show the fingerprint of the key used to sign a signed commit -- '%GP': show the fingerprint of the primary key whose subkey was used - to sign a signed commit -- '%gD': reflog selector, e.g., `refs/stash@{1}` or - `refs/stash@{2 minutes ago`}; the format follows the rules described - for the `-g` option. The portion before the `@` is the refname as - given on the command line (so `git log -g refs/heads/master` would - yield `refs/heads/master@{0}`). -- '%gd': shortened reflog selector; same as `%gD`, but the refname - portion is shortened for human readability (so `refs/heads/master` - becomes just `master`). -- '%gn': reflog identity name -- '%gN': reflog identity name (respecting .mailmap, see - linkgit:git-shortlog[1] or linkgit:git-blame[1]) -- '%ge': reflog identity email -- '%gE': reflog identity email (respecting .mailmap, see - linkgit:git-shortlog[1] or linkgit:git-blame[1]) -- '%gs': reflog subject -- '%Cred': switch color to red -- '%Cgreen': switch color to green -- '%Cblue': switch color to blue -- '%Creset': reset color -- '%C(...)': color specification, as described under Values in the - "CONFIGURATION FILE" section of linkgit:git-config[1]. - By default, colors are shown only when enabled for log output (by - `color.diff`, `color.ui`, or `--color`, and respecting the `auto` - settings of the former if we are going to a terminal). `%C(auto,...)` - is accepted as a historical synonym for the default (e.g., - `%C(auto,red)`). Specifying `%C(always,...)` will show the colors - even when color is not otherwise enabled (though consider - just using `--color=always` to enable color for the whole output, - including this format and anything else git might color). `auto` - alone (i.e. `%C(auto)`) will turn on auto coloring on the next - placeholders until the color is switched again. -- '%m': left (`<`), right (`>`) or boundary (`-`) mark -- '%n': newline -- '%%': a raw '%' -- '%x00': print a byte from a hex code -- '%w([[,[,]]])': switch line wrapping, like the -w option of - linkgit:git-shortlog[1]. -- '%<([,trunc|ltrunc|mtrunc])': make the next placeholder take at - least N columns, padding spaces on the right if necessary. - Optionally truncate at the beginning (ltrunc), the middle (mtrunc) - or the end (trunc) if the output is longer than N columns. - Note that truncating only works correctly with N >= 2. -- '%<|()': make the next placeholder take at least until Nth - columns, padding spaces on the right if necessary -- '%>()', '%>|()': similar to '%<()', '%<|()' - respectively, but padding spaces on the left -- '%>>()', '%>>|()': similar to '%>()', '%>|()' - respectively, except that if the next placeholder takes more spaces - than given and there are spaces on its left, use those spaces -- '%><()', '%><|()': similar to '%<()', '%<|()' - respectively, but padding both sides (i.e. the text is centered) -- %(trailers[:options]): display the trailers of the body as interpreted - by linkgit:git-interpret-trailers[1]. The `trailers` string may be - followed by a colon and zero or more comma-separated options. If the - `only` option is given, omit non-trailer lines from the trailer block. - If the `unfold` option is given, behave as if interpret-trailer's - `--unfold` option was given. E.g., `%(trailers:only,unfold)` to do - both. +'%GG':: raw verification message from GPG for a signed commit +'%G?':: show "G" for a good (valid) signature, + "B" for a bad signature, + "U" for a good signature with unknown validity, + "X" for a good signature that has expired, + "Y" for a good signature made by an expired key, + "R" for a good signature made by a revoked key, + "E" if the signature cannot be checked (e.g. missing key) + and "N" for no signature +'%GS':: show the name of the signer for a signed commit +'%GK':: show the key used to sign a signed commit +'%GF':: show the fingerprint of the key used to sign a signed commit +'%GP':: show the fingerprint of the primary key whose subkey was used + to sign a signed commit +'%gD':: reflog selector, e.g., `refs/stash@{1}` or `refs/stash@{2 + minutes ago`}; the format follows the rules described for the + `-g` option. The portion before the `@` is the refname as + given on the command line (so `git log -g refs/heads/master` + would yield `refs/heads/master@{0}`). +'%gd':: shortened reflog selector; same as `%gD`, but the refname + portion is shortened for human readability (so + `refs/heads/master` becomes just `master`). +'%gn':: reflog identity name +'%gN':: reflog identity name (respecting .mailmap, see + linkgit:git-shortlog[1] or linkgit:git-blame[1]) +'%ge':: reflog identity email +'%gE':: reflog identity email (respecting .mailmap, see + linkgit:git-shortlog[1] or linkgit:git-blame[1]) +'%gs':: reflog subject +'%(trailers[:options])':: display the trailers of the body as + interpreted by + linkgit:git-interpret-trailers[1]. The + `trailers` string may be followed by a colon + and zero or more comma-separated options: +** 'key=': only show trailers with specified key. Matching is done + case-insensitively and trailing colon is optional. If option is + given multiple times trailer lines matching any of the keys are + shown. This option automatically enables the `only` option so that + non-trailer lines in the trailer block are hidden. If that is not + desired it can be disabled with `only=false`. E.g., + `%(trailers:key=Reviewed-by)` shows trailer lines with key + `Reviewed-by`. +** 'only[=val]': select whether non-trailer lines from the trailer + block should be included. The `only` keyword may optionally be + followed by an equal sign and one of `true`, `on`, `yes` to omit or + `false`, `off`, `no` to show the non-trailer lines. If option is + given without value it is enabled. If given multiple times the last + value is used. +** 'separator=': specify a separator inserted between trailer + lines. When this option is not given each trailer line is + terminated with a line feed character. The string SEP may contain + the literal formatting codes described above. To use comma as + separator one must use `%x2C` as it would otherwise be parsed as + next option. If separator option is given multiple times only the + last one is used. E.g., `%(trailers:key=Ticket,separator=%x2C )` + shows all trailer lines whose key is "Ticket" separated by a comma + and a space. +** 'unfold[=val]': make it behave as if interpret-trailer's `--unfold` + option was given. In same way as to for `only` it can be followed + by an equal sign and explicit value. E.g., + `%(trailers:only,unfold=true)` unfolds and shows all trailer lines. +** 'valueonly[=val]': skip over the key part of the trailer line and only + show the value part. Also this optionally allows explicit value. NOTE: Some placeholders may depend on other options given to the revision traversal engine. For example, the `%g*` reflog options will diff --git a/pretty.c b/pretty.c index 0ab45d10d7..d2995b13ed 100644 --- a/pretty.c +++ b/pretty.c @@ -1057,13 +1057,26 @@ static size_t parse_padding_placeholder(struct strbuf *sb, return 0; } -static int match_placeholder_arg(const char *to_parse, const char *candidate, - const char **end) +static int match_placeholder_arg_value(const char *to_parse, const char *candidate, + const char **end, const char **valuestart, + size_t *valuelen) { const char *p; if (!(skip_prefix(to_parse, candidate, &p))) return 0; + if (valuestart) { + if (*p == '=') { + *valuestart = p + 1; + *valuelen = strcspn(*valuestart, ",)"); + p = *valuestart + *valuelen; + } else { + if (*p != ',' && *p != ')') + return 0; + *valuestart = NULL; + *valuelen = 0; + } + } if (*p == ',') { *end = p + 1; return 1; @@ -1075,6 +1088,47 @@ static int match_placeholder_arg(const char *to_parse, const char *candidate, return 0; } +static int match_placeholder_bool_arg(const char *to_parse, const char *candidate, + const char **end, int *val) +{ + const char *argval; + char *strval; + size_t arglen; + int v; + + if (!match_placeholder_arg_value(to_parse, candidate, end, &argval, &arglen)) + return 0; + + if (!argval) { + *val = 1; + return 1; + } + + strval = xstrndup(argval, arglen); + v = git_parse_maybe_bool(strval); + free(strval); + + if (v == -1) + return 0; + + *val = v; + + return 1; +} + +static int format_trailer_match_cb(const struct strbuf *key, void *ud) +{ + const struct string_list *list = ud; + const struct string_list_item *item; + + for_each_string_list_item (item, list) { + if (key->len == (uintptr_t)item->util && + !strncasecmp(item->string, key->buf, key->len)) + return 1; + } + return 0; +} + static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ const char *placeholder, void *context) @@ -1084,10 +1138,14 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ const char *msg = c->message; struct commit_list *p; const char *arg; - int ch; + size_t res; char **slot; /* these are independent of the commit */ + res = strbuf_expand_literal_cb(sb, placeholder, NULL); + if (res) + return res; + switch (placeholder[0]) { case 'C': if (starts_with(placeholder + 1, "(auto)")) { @@ -1106,16 +1164,6 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ */ return ret; } - case 'n': /* newline */ - strbuf_addch(sb, '\n'); - return 1; - case 'x': - /* %x00 == NUL, %x0a == LF, etc. */ - ch = hex2chr(placeholder + 1); - if (ch < 0) - return 0; - strbuf_addch(sb, ch); - return 3; case 'w': if (placeholder[1] == '(') { unsigned long width = 0, indent1 = 0, indent2 = 0; @@ -1322,24 +1370,53 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ if (skip_prefix(placeholder, "(trailers", &arg)) { struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT; + struct string_list filter_list = STRING_LIST_INIT_NODUP; + struct strbuf sepbuf = STRBUF_INIT; + size_t ret = 0; opts.no_divider = 1; if (*arg == ':') { arg++; for (;;) { - if (match_placeholder_arg(arg, "only", &arg)) + const char *argval; + size_t arglen; + + if (match_placeholder_arg_value(arg, "key", &arg, &argval, &arglen)) { + uintptr_t len = arglen; + + if (!argval) + goto trailer_out; + + if (len && argval[len - 1] == ':') + len--; + string_list_append(&filter_list, argval)->util = (char *)len; + + opts.filter = format_trailer_match_cb; + opts.filter_data = &filter_list; opts.only_trailers = 1; - else if (match_placeholder_arg(arg, "unfold", &arg)) - opts.unfold = 1; - else + } else if (match_placeholder_arg_value(arg, "separator", &arg, &argval, &arglen)) { + char *fmt; + + strbuf_reset(&sepbuf); + fmt = xstrndup(argval, arglen); + strbuf_expand(&sepbuf, fmt, strbuf_expand_literal_cb, NULL); + free(fmt); + opts.separator = &sepbuf; + } else if (!match_placeholder_bool_arg(arg, "only", &arg, &opts.only_trailers) && + !match_placeholder_bool_arg(arg, "unfold", &arg, &opts.unfold) && + !match_placeholder_bool_arg(arg, "valueonly", &arg, &opts.value_only)) break; } } if (*arg == ')') { format_trailers_from_commit(sb, msg + c->subject_off, &opts); - return arg - placeholder + 1; + ret = arg - placeholder + 1; } + trailer_out: + string_list_clear(&filter_list, 0); + strbuf_release(&sepbuf); + return ret; } return 0; /* unknown placeholder */ diff --git a/strbuf.c b/strbuf.c index f6a6cf78b9..78eecd29f7 100644 --- a/strbuf.c +++ b/strbuf.c @@ -380,6 +380,27 @@ void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, } } +size_t strbuf_expand_literal_cb(struct strbuf *sb, + const char *placeholder, + void *context) +{ + int ch; + + switch (placeholder[0]) { + case 'n': /* newline */ + strbuf_addch(sb, '\n'); + return 1; + case 'x': + /* %x00 == NUL, %x0a == LF, etc. */ + ch = hex2chr(placeholder + 1); + if (ch < 0) + return 0; + strbuf_addch(sb, ch); + return 3; + } + return 0; +} + size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context) { diff --git a/strbuf.h b/strbuf.h index fc40873b65..52e44c9ab8 100644 --- a/strbuf.h +++ b/strbuf.h @@ -320,6 +320,14 @@ void strbuf_expand(struct strbuf *sb, expand_fn_t fn, void *context); +/** + * Used as callback for `strbuf_expand` to only expand literals + * (i.e. %n and %xNN). The context argument is ignored. + */ +size_t strbuf_expand_literal_cb(struct strbuf *sb, + const char *placeholder, + void *context); + /** * Used as callback for `strbuf_expand()`, expects an array of * struct strbuf_expand_dict_entry as context, i.e. pairs of diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 7df8c3d4ec..f42a69faa2 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -578,6 +578,24 @@ test_expect_success '%(trailers:only) shows only "key: value" trailers' ' test_cmp expect actual ' +test_expect_success '%(trailers:only=yes) shows only "key: value" trailers' ' + git log --no-walk --pretty=format:"%(trailers:only=yes)" >actual && + grep -v patch.description expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:only=no) shows all trailers' ' + git log --no-walk --pretty=format:"%(trailers:only=no)" >actual && + cat trailers >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:only=no,only=true) shows only "key: value" trailers' ' + git log --no-walk --pretty=format:"%(trailers:only=yes)" >actual && + grep -v patch.description expect && + test_cmp expect actual +' + test_expect_success '%(trailers:unfold) unfolds trailers' ' git log --no-walk --pretty="%(trailers:unfold)" >actual && { @@ -598,6 +616,105 @@ test_expect_success ':only and :unfold work together' ' test_cmp expect actual ' +test_expect_success 'pretty format %(trailers:key=foo) shows that trailer' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by)" >actual && + echo "Acked-by: A U Thor " >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo) is case insensitive' ' + git log --no-walk --pretty="format:%(trailers:key=AcKed-bY)" >actual && + echo "Acked-by: A U Thor " >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo:) trailing colon also works' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by:)" >actual && + echo "Acked-by: A U Thor " >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo) multiple keys' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by:,key=Signed-off-By)" >actual && + grep -v patch.description expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=nonexistant) becomes empty' ' + git log --no-walk --pretty="x%(trailers:key=Nacked-by)x" >actual && + echo "xx" >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=foo) handles multiple lines even if folded' ' + git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by)" >actual && + grep -v patch.description expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=foo,unfold) properly unfolds' ' + git log --no-walk --pretty="format:%(trailers:key=Signed-Off-by,unfold)" >actual && + unfold expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:key=foo,only=no) also includes nontrailer lines' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by,only=no)" >actual && + { + echo "Acked-by: A U Thor " && + grep patch.description expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key) without value is error' ' + git log --no-walk --pretty="tformat:%(trailers:key)" >actual && + echo "%(trailers:key)" >expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:key=foo,valueonly) shows only value' ' + git log --no-walk --pretty="format:%(trailers:key=Acked-by,valueonly)" >actual && + echo "A U Thor " >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers:separator) changes separator' ' + git log --no-walk --pretty=format:"X%(trailers:separator=%x00,unfold)X" >actual && + printf "XSigned-off-by: A U Thor \0Acked-by: A U Thor \0[ v2 updated patch description ]\0Signed-off-by: A U Thor X" >expect && + test_cmp expect actual +' + +test_expect_success 'pretty format %(trailers) combining separator/key/valueonly' ' + git commit --allow-empty -F - <<-\EOF && + Important fix + + The fix is explained here + + Closes: #1234 + EOF + + git commit --allow-empty -F - <<-\EOF && + Another fix + + The fix is explained here + + Closes: #567 + Closes: #890 + EOF + + git commit --allow-empty -F - <<-\EOF && + Does not close any tickets + EOF + + git log --pretty="%s% (trailers:separator=%x2c%x20,key=Closes,valueonly)" HEAD~3.. >actual && + test_write_lines \ + "Does not close any tickets" \ + "Another fix #567, #890" \ + "Important fix #1234" >expect && + test_cmp expect actual +' + test_expect_success 'trailer parsing not fooled by --- line' ' git commit --allow-empty -F - <<-\EOF && this is the subject diff --git a/trailer.c b/trailer.c index 0796f326b3..0c414f2fed 100644 --- a/trailer.c +++ b/trailer.c @@ -1129,10 +1129,11 @@ static void format_trailer_info(struct strbuf *out, const struct trailer_info *info, const struct process_trailer_options *opts) { + size_t origlen = out->len; size_t i; /* If we want the whole block untouched, we can take the fast path. */ - if (!opts->only_trailers && !opts->unfold) { + if (!opts->only_trailers && !opts->unfold && !opts->filter && !opts->separator) { strbuf_add(out, info->trailer_start, info->trailer_end - info->trailer_start); return; @@ -1147,15 +1148,29 @@ static void format_trailer_info(struct strbuf *out, struct strbuf val = STRBUF_INIT; parse_trailer(&tok, &val, NULL, trailer, separator_pos); - if (opts->unfold) - unfold_value(&val); + if (!opts->filter || opts->filter(&tok, opts->filter_data)) { + if (opts->unfold) + unfold_value(&val); - strbuf_addf(out, "%s: %s\n", tok.buf, val.buf); + if (opts->separator && out->len != origlen) + strbuf_addbuf(out, opts->separator); + if (!opts->value_only) + strbuf_addf(out, "%s: ", tok.buf); + strbuf_addbuf(out, &val); + if (!opts->separator) + strbuf_addch(out, '\n'); + } strbuf_release(&tok); strbuf_release(&val); } else if (!opts->only_trailers) { + if (opts->separator && out->len != origlen) { + strbuf_addbuf(out, opts->separator); + } strbuf_addstr(out, trailer); + if (opts->separator) { + strbuf_rtrim(out); + } } } diff --git a/trailer.h b/trailer.h index b997739649..203acf4ee1 100644 --- a/trailer.h +++ b/trailer.h @@ -72,6 +72,10 @@ struct process_trailer_options { int only_input; int unfold; int no_divider; + int value_only; + const struct strbuf *separator; + int (*filter)(const struct strbuf *, void *); + void *filter_data; }; #define PROCESS_TRAILER_OPTIONS_INIT {0}