diff mbox series

[v2] pretty: add %r format specifier for showing refs

Message ID 20230712205608.1806-1-andy.koppe@gmail.com (mailing list archive)
State New, archived
Headers show
Series [v2] pretty: add %r format specifier for showing refs | expand

Commit Message

Andy Koppe July 12, 2023, 8:56 p.m. UTC
This lists refs similarly to the %D decoration format, but separates
the refs with spaces only and omits "tag:" annotations. It's intended
primarily for color output, where tags are already distinguished by
color.

Refactor format_decorations() to take an enum decoration_format argument
that determines the prefix, separator and suffix as well as the tag
annotation.

For %d and %D, wrap the "tag:" annotation and the actual tag in separate
color controls, because otherwise the tag ends up uncolored when %w
width formatting breaks a line between the annotation and tag.

Amend t4207-log-decoration-colors.sh to reflect the added color
controls, and t4202-log.sh to test the %r format.

Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
---
CI: https://github.com/ak2/git/actions/runs/5535093717
All passed apart from unrelated errors for MacOS.

 Documentation/pretty-formats.txt |  3 +-
 log-tree.c                       | 53 ++++++++++++++++++++++----------
 log-tree.h                       | 15 ++++-----
 pretty.c                         |  7 +++--
 t/t4202-log.sh                   |  7 ++++-
 t/t4207-log-decoration-colors.sh | 32 +++++++++++--------
 6 files changed, 76 insertions(+), 41 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 3b71334459..d2ae898c79 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -221,7 +221,8 @@  The placeholders are:
 '%ch':: committer date, human style (like the `--date=human` option of
 	linkgit:git-rev-list[1])
 '%d':: ref names, like the --decorate option of linkgit:git-log[1]
-'%D':: ref names without the " (", ")" wrapping.
+'%D':: ref names without the " (", ")" wrapping
+'%r':: ref names only, separated by spaces
 '%(describe[:options])':: human-readable name, like
 			  linkgit:git-describe[1]; empty string for
 			  undescribable commits.  The `describe` string
diff --git a/log-tree.c b/log-tree.c
index f4b22a60cc..33dcb31858 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -301,14 +301,12 @@  static void show_name(struct strbuf *sb, const struct name_decoration *decoratio
 
 /*
  * The caller makes sure there is no funny color before calling.
- * format_decorations_extended makes sure the same after return.
+ * format_decorations makes sure the same after return.
  */
-void format_decorations_extended(struct strbuf *sb,
+void format_decorations(struct strbuf *sb,
 			const struct commit *commit,
 			int use_color,
-			const char *prefix,
-			const char *separator,
-			const char *suffix)
+			enum decoration_format format)
 {
 	const struct name_decoration *decoration;
 	const struct name_decoration *current_and_HEAD;
@@ -316,11 +314,18 @@  void format_decorations_extended(struct strbuf *sb,
 		diff_get_color(use_color, DIFF_COMMIT);
 	const char *color_reset =
 		decorate_get_color(use_color, DECORATION_NONE);
+	int first = 1;
 
 	decoration = get_name_decoration(&commit->object);
 	if (!decoration)
 		return;
 
+	if (format == DECO_FMT_WRAPPED) {
+		strbuf_addstr(sb, color_commit);
+		strbuf_addstr(sb, " (");
+		strbuf_addstr(sb, color_reset);
+	}
+
 	current_and_HEAD = current_pointed_by_HEAD(decoration);
 	while (decoration) {
 		/*
@@ -329,13 +334,26 @@  void format_decorations_extended(struct strbuf *sb,
 		 * appeared, skipping the entry for current.
 		 */
 		if (decoration != current_and_HEAD) {
-			strbuf_addstr(sb, color_commit);
-			strbuf_addstr(sb, prefix);
-			strbuf_addstr(sb, color_reset);
-			strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
-			if (decoration->type == DECORATION_REF_TAG)
-				strbuf_addstr(sb, "tag: ");
+			const char *color = decorate_get_color(use_color, decoration->type);
 
+			if (!first) {
+				if (format == DECO_FMT_BARE)
+					strbuf_addstr(sb, " ");
+				else {
+					strbuf_addstr(sb, color_commit);
+					strbuf_addstr(sb, ", ");
+					strbuf_addstr(sb, color_reset);
+				}
+			}
+			first = 0;
+
+			if (format != DECO_FMT_BARE &&
+			    decoration->type == DECORATION_REF_TAG) {
+				strbuf_addstr(sb, color);
+				strbuf_addstr(sb, "tag: ");
+				strbuf_addstr(sb, color_reset);
+			}
+			strbuf_addstr(sb, color);
 			show_name(sb, decoration);
 
 			if (current_and_HEAD &&
@@ -346,14 +364,15 @@  void format_decorations_extended(struct strbuf *sb,
 				show_name(sb, current_and_HEAD);
 			}
 			strbuf_addstr(sb, color_reset);
-
-			prefix = separator;
 		}
 		decoration = decoration->next;
 	}
-	strbuf_addstr(sb, color_commit);
-	strbuf_addstr(sb, suffix);
-	strbuf_addstr(sb, color_reset);
+
+	if (format == DECO_FMT_WRAPPED) {
+		strbuf_addstr(sb, color_commit);
+		strbuf_addstr(sb, ")");
+		strbuf_addstr(sb, color_reset);
+	}
 }
 
 void show_decorations(struct rev_info *opt, struct commit *commit)
@@ -368,7 +387,7 @@  void show_decorations(struct rev_info *opt, struct commit *commit)
 	}
 	if (!opt->show_decorations)
 		return;
-	format_decorations(&sb, commit, opt->diffopt.use_color);
+	format_decorations(&sb, commit, opt->diffopt.use_color, DECO_FMT_WRAPPED);
 	fputs(sb.buf, opt->diffopt.file);
 	strbuf_release(&sb);
 }
diff --git a/log-tree.h b/log-tree.h
index e7e4641cf8..345d1e80dc 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -13,17 +13,18 @@  struct decoration_filter {
 	struct string_list *exclude_ref_config_pattern;
 };
 
+enum decoration_format {
+	DECO_FMT_BARE = 0,
+	DECO_FMT_UNWRAPPED,
+	DECO_FMT_WRAPPED,
+};
+
 int parse_decorate_color_config(const char *var, const char *slot_name, const char *value);
 int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 void show_log(struct rev_info *opt);
-void format_decorations_extended(struct strbuf *sb, const struct commit *commit,
-			     int use_color,
-			     const char *prefix,
-			     const char *separator,
-			     const char *suffix);
-#define format_decorations(strbuf, commit, color) \
-			     format_decorations_extended((strbuf), (commit), (color), " (", ", ", ")")
+void format_decorations(struct strbuf *sb, const struct commit *commit,
+			int use_color, enum decoration_format format);
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 			     const char **extra_headers_p,
diff --git a/pretty.c b/pretty.c
index 0bb938021b..88b041df85 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1526,10 +1526,13 @@  static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 		strbuf_addstr(sb, get_revision_mark(NULL, commit));
 		return 1;
 	case 'd':
-		format_decorations(sb, commit, c->auto_color);
+		format_decorations(sb, commit, c->auto_color, DECO_FMT_WRAPPED);
 		return 1;
 	case 'D':
-		format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
+		format_decorations(sb, commit, c->auto_color, DECO_FMT_UNWRAPPED);
+		return 1;
+	case 'r':
+		format_decorations(sb, commit, c->auto_color, DECO_FMT_BARE);
 		return 1;
 	case 'S':		/* tag/branch like --source */
 		if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index ae73aef922..9e0871df24 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -2325,7 +2325,12 @@  test_expect_success 'log --decorate includes all levels of tag annotated tags' '
 	HEAD -> branch, tag: lightweight, tag: double-1, tag: double-0, tag: annotated
 	EOF
 	git log -1 --format="%D" >actual &&
-	test_cmp expect actual
+	test_cmp expect actual &&
+	cat >expect2 <<-\EOF &&
+	HEAD -> branch lightweight double-1 double-0 annotated
+	EOF
+	git log -1 --format="%r" >actual2 &&
+	test_cmp expect2 actual2
 '
 
 test_expect_success 'log --decorate does not include things outside filter' '
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index ded33a82e2..3a4eedc494 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -55,13 +55,15 @@  test_expect_success 'commit decorations colored correctly' '
 	cat >expect <<-EOF &&
 	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
 ${c_reset}${c_branch}main${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A1${c_reset}${c_commit}, \
 ${c_reset}${c_remoteBranch}other/main${c_reset}${c_commit})${c_reset} A1
-	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset} \
-On main: Changes to A.t
-	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_stash}refs/stash${c_reset}${c_commit})${c_reset} On main: Changes to A.t
+	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
 	EOF
 
 	git log --first-parent --no-abbrev --decorate --oneline --color=always --all >actual &&
@@ -78,10 +80,12 @@  test_expect_success 'test coloring with replace-objects' '
 	cat >expect <<-EOF &&
 	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
 ${c_reset}${c_branch}main${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: D${c_reset}${c_commit})${c_reset} D
-	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: C${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit})${c_reset} D
+	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}C${c_reset}${c_commit}, \
 ${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} B
-	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
 EOF
 
 	git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&
@@ -102,11 +106,13 @@  test_expect_success 'test coloring with grafted commit' '
 	cat >expect <<-EOF &&
 	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD -> \
 ${c_reset}${c_branch}main${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: D${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}D${c_reset}${c_commit}, \
 ${c_reset}${c_grafted}replaced${c_reset}${c_commit})${c_reset} D
-	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit}, \
-${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
-	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}v1.0${c_reset}${c_commit}, \
+${c_reset}${c_tag}tag: ${c_reset}${c_tag}B${c_reset}${c_commit})${c_reset} B
+	${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}\
+${c_tag}tag: ${c_reset}${c_tag}A${c_reset}${c_commit})${c_reset} A
 	EOF
 
 	git log --first-parent --no-abbrev --decorate --oneline --color=always HEAD >actual &&