git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 5/5] pretty: add support for separator option in %(trailers)

From
Anders Waldenborg <anders@0x63.nu>
Date
Nov 18, 2018, 11:44 UTC
Message-ID
<20181118114427.1397-6-anders@0x63.nu>
In-Reply-To
<20181118114427.1397-1-anders@0x63.nu>

By default trailer lines are terminated by linebreaks ('\n'). By specifying the new 'separator' option they will instead be separated by user provided string and have separator semantics rather than terminator semantics. The separator string can contain the literal formatting codes %n and %xNN allowing it to be things that are otherwise hard to type as %x00, or comma and end-parenthesis which would break parsing.

E.g:
 $ git log --pretty='%(trailers:key=Reviewed-by,valueonly,separator=%x00)'
Signed-off-by: Anders Waldenborg <anders@0x63.nu>
---
 Documentation/pretty-formats.txt | 13 +++++++++---
 pretty.c                         | 15 +++++++++++++
 t/t4205-log-pretty-formats.sh    | 36 ++++++++++++++++++++++++++++++++
 trailer.c                        | 15 +++++++++++--
 trailer.h                        |  1 +
 5 files changed, 75 insertions(+), 5 deletions(-)
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 8cc8c3f9f..30e238338 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -218,9 +218,16 @@ endif::git-rev-list[]
      is given multiple times only last one is used.
   ** 'valueonly': skip over the key part of the trailer and only show
      the its value part.
-  ** Examples: `%(trailers:only,unfold)` unfolds and shows all trailer
-     lines, `%(trailers:key=Reviewed-by,unfold)` unfolds and shows
-     trailer lines with key `Reviewed-by`.
+  ** 'separator=<SEP>': specifying an alternative separator than the
+     default line feed character. SEP may can contain the literal
+     formatting codes %n and %xNN allowing it to contain characters
+     that are hard to type such as %x00, or comma and end-parenthesis
+     which would break parsing. If option is given multiple times only
+     the last one is used.
+  ** Examples: `%(trailers:only,unfold,separator=%x00)` unfolds and
+     shows all trailer lines separated by NUL character,
+     `%(trailers:key=Reviewed-by,unfold)` unfolds and shows trailer
+     lines with key `Reviewed-by`.
 
 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 819c5c50a..5b22a7237 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1318,6 +1318,7 @@ 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 format_trailer_match_data filter_data;
+		struct strbuf sepbuf = STRBUF_INIT;
 		size_t ret = 0;
 
 		opts.no_divider = 1;
@@ -1348,6 +1349,19 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 					arg = end;
 					if (*arg == ',')
 						arg++;
+				} else if (skip_prefix(arg, "separator=", &arg)) {
+					size_t seplen = strcspn(arg, ",)");
+					char *fmt;
+
+					strbuf_reset(&sepbuf);
+					fmt = xstrndup(arg, seplen);
+					strbuf_expand(&sepbuf, fmt, strbuf_expand_literal_cb, NULL);
+					free(fmt);
+					opts.separator = &sepbuf;
+
+					arg += seplen;
+					if (*arg == ',')
+						arg++;
 				} else
 					break;
 			}
@@ -1356,6 +1370,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 			format_trailers_from_commit(sb, msg + c->subject_off, &opts);
 			ret = arg - placeholder + 1;
 		}
+		strbuf_release(&sepbuf);
 		return ret;
 	}
 
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 095208d6b..562b56dda 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -640,6 +640,42 @@ test_expect_success '%(trailers:key=foo,valueonly) shows only value' '
 	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 <author@example.com>\0Acked-by: A U Thor <author@example.com>\0[ v2 updated patch description ]\0Signed-off-by: A U Thor <author@example.com>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 662c7ff03..85cd2e52e 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->separator) {
 		strbuf_add(out, info->trailer_start,
 			   info->trailer_end - info->trailer_start);
 		return;
@@ -1150,16 +1151,26 @@ static void format_trailer_info(struct strbuf *out,
 			if (!opts->filter || opts->filter(&tok, opts->filter_data)) {
 				if (opts->unfold)
 					unfold_value(&val);
+
+				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);
-				strbuf_addch(out, '\n');
+				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 06d417fe9..203acf4ee 100644
--- a/trailer.h
+++ b/trailer.h
@@ -73,6 +73,7 @@ struct process_trailer_options {
 	int unfold;
 	int no_divider;
 	int value_only;
+	const struct strbuf *separator;
 	int (*filter)(const struct strbuf *, void *);
 	void *filter_data;
 };
-- 
2.17.1
Previous: Anders WaldenborgNext: Eric Sunshine
Message 30 of 69 in “pretty: Add %(trailer:X) to display single trailer”
  1. pretty: Add %(trailer:X) to display single trailerAnders Waldenborg, Oct 28, 2018
  2. Junio C HamanoOct 29, 2018
  3. Jeff KingOct 29, 2018
  4. Anders WaldenborgOct 29, 2018
  5. Jeff KingOct 31, 2018
  6. Anders WaldenborgOct 31, 2018
  7. Jeff KingNov 1, 2018
  8. 0/5 %(trailers) improvements in pretty formatAnders Waldenborg, Nov 4, 2018
  9. 1/5 pretty: single return path in %(trailers) handlingAnders Waldenborg, Nov 4, 2018
  10. 2/5 pretty: allow showing specific trailersAnders Waldenborg, Nov 4, 2018
  11. Eric SunshineNov 4, 2018
  12. Junio C HamanoNov 5, 2018
  13. Eric SunshineNov 5, 2018
  14. Anders WaldenborgNov 5, 2018
  15. Eric SunshineNov 5, 2018
  16. Junio C HamanoNov 5, 2018
  17. 3/5 pretty: add support for "nokey" option in %(trailers)Anders Waldenborg, Nov 4, 2018
  18. 4/5 pretty: extract fundamental placeholders to separate functionAnders Waldenborg, Nov 4, 2018
  19. Junio C HamanoNov 5, 2018
  20. Anders WaldenborgNov 5, 2018
  21. Junio C HamanoNov 6, 2018
  22. 5/5 pretty: add support for separator option in %(trailers)Anders Waldenborg, Nov 4, 2018
  23. Junio C HamanoNov 5, 2018
  24. Anders WaldenborgNov 5, 2018
  25. Junio C HamanoNov 6, 2018
  26. Junio C HamanoNov 5, 2018
  27. Eric SunshineNov 4, 2018
  28. Anders WaldenborgNov 5, 2018
  29. 0/5 %(trailers) improvements in pretty formatAnders Waldenborg, Nov 18, 2018
  30. 5/5 pretty: add support for separator option in %(trailers)Anders Waldenborg, Nov 18, 2018
  31. Eric SunshineNov 20, 2018
  32. 2/5 pretty: allow showing specific trailersAnders Waldenborg, Nov 18, 2018
  33. Junio C HamanoNov 20, 2018
  34. Junio C HamanoNov 20, 2018
  35. Anders WaldenborgNov 25, 2018
  36. Junio C HamanoNov 26, 2018
  37. Anders WaldenborgNov 26, 2018
  38. Junio C HamanoNov 26, 2018
  39. 3/5 pretty: add support for "valueonly" option in %(trailers)Anders Waldenborg, Nov 18, 2018
  40. Eric SunshineNov 20, 2018
  41. 1/5 pretty: single return path in %(trailers) handlingAnders Waldenborg, Nov 18, 2018
  42. 4/5 strbuf: separate callback for strbuf_expand:ing literalsAnders Waldenborg, Nov 18, 2018
  43. 0/7 %(trailers) improvements in pretty formatAnders Waldenborg, Dec 8, 2018
  44. 2/7 pretty: allow %(trailers) options with explicit valueAnders Waldenborg, Dec 8, 2018
  45. Junio C HamanoDec 10, 2018
  46. Anders WaldenborgDec 18, 2018
  47. Jeff KingJan 29, 2019
  48. Anders WaldenborgJan 29, 2019
  49. 1/7 doc: group pretty-format.txt placeholders descriptionsAnders Waldenborg, Dec 8, 2018
  50. 3/7 pretty: single return path in %(trailers) handlingAnders Waldenborg, Dec 8, 2018
  51. 5/7 pretty: add support for "valueonly" option in %(trailers)Anders Waldenborg, Dec 8, 2018
  52. 6/7 strbuf: separate callback for strbuf_expand:ing literalsAnders Waldenborg, Dec 8, 2018
  53. 7/7 pretty: add support for separator option in %(trailers)Anders Waldenborg, Dec 8, 2018
  54. 4/7 pretty: allow showing specific trailersAnders Waldenborg, Dec 8, 2018
  55. Junio C HamanoDec 10, 2018
  56. 0/7 %(trailers) improvements in pretty formatAnders Waldenborg, Jan 28, 2019
  57. 2/7 pretty: Allow %(trailers) options with explicit valueAnders Waldenborg, Jan 28, 2019
  58. Junio C HamanoJan 28, 2019
  59. Anders WaldenborgJan 29, 2019
  60. Jeff KingJan 29, 2019
  61. Anders WaldenborgJan 29, 2019
  62. 5/7 pretty: add support for "valueonly" option in %(trailers)Anders Waldenborg, Jan 28, 2019
  63. 7/7 pretty: add support for separator option in %(trailers)Anders Waldenborg, Jan 28, 2019
  64. 1/7 doc: group pretty-format.txt placeholders descriptionsAnders Waldenborg, Jan 28, 2019
  65. 6/7 strbuf: separate callback for strbuf_expand:ing literalsAnders Waldenborg, Jan 28, 2019
  66. 4/7 pretty: allow showing specific trailersAnders Waldenborg, Jan 28, 2019
  67. 3/7 pretty: single return path in %(trailers) handlingAnders Waldenborg, Jan 28, 2019
  68. Anders WaldenborgJan 31, 2019
  69. Оля ТележнаяFeb 2, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.