pretty: add %(decorate[:<options>]) format

Add %(decorate[:<options>]) format that lists ref names similarly to the
%d format, but which allows the otherwise fixed prefix, suffix and
separator strings to be customized. Omitted options default to the
strings used in %d.

Rename expand_separator() function used to expand %x literal formatting
codes to expand_string_arg(), as it is now used on strings other than
separators.

Examples:
- %(decorate) is equivalent to %d.
- %(decorate:prefix=,suffix=) is equivalent to %D.
- %(decorate:prefix=[,suffix=],separator=%x3B) produces a list enclosed
in square brackets and separated by semicolons.

Test the format in t4205-log-pretty-formats.sh and document it in
pretty-formats.txt.

Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Andy Koppe
2023-08-20 19:50:07 +01:00
committed by Junio C Hamano
parent dcb347f837
commit a58dd835e9
3 changed files with 92 additions and 4 deletions

View File

@@ -1252,8 +1252,8 @@ static int format_trailer_match_cb(const struct strbuf *key, void *ud)
return 0;
}
static struct strbuf *expand_separator(struct strbuf *sb,
const char *argval, size_t arglen)
static struct strbuf *expand_string_arg(struct strbuf *sb,
const char *argval, size_t arglen)
{
char *fmt = xstrndup(argval, arglen);
const char *format = fmt;
@@ -1301,9 +1301,9 @@ int format_set_trailers_options(struct process_trailer_options *opts,
opts->filter_data = filter_list;
opts->only_trailers = 1;
} else if (match_placeholder_arg_value(*arg, "separator", arg, &argval, &arglen)) {
opts->separator = expand_separator(sepbuf, argval, arglen);
opts->separator = expand_string_arg(sepbuf, argval, arglen);
} else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
opts->key_value_separator = expand_separator(kvsepbuf, argval, arglen);
opts->key_value_separator = expand_string_arg(kvsepbuf, argval, arglen);
} 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, "keyonly", arg, &opts->key_only) &&
@@ -1384,6 +1384,40 @@ static size_t parse_describe_args(const char *start, struct strvec *args)
return arg - start;
}
static int parse_decoration_option(const char **arg,
const char *name,
char **opt)
{
const char *argval;
size_t arglen;
if (match_placeholder_arg_value(*arg, name, arg, &argval, &arglen)) {
struct strbuf sb = STRBUF_INIT;
expand_string_arg(&sb, argval, arglen);
*opt = strbuf_detach(&sb, NULL);
return 1;
}
return 0;
}
static void parse_decoration_options(const char **arg,
struct decoration_options *opts)
{
while (parse_decoration_option(arg, "prefix", &opts->prefix) ||
parse_decoration_option(arg, "suffix", &opts->suffix) ||
parse_decoration_option(arg, "separator", &opts->separator))
;
}
static void free_decoration_options(const struct decoration_options *opts)
{
free(opts->prefix);
free(opts->suffix);
free(opts->separator);
}
static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
const char *placeholder,
void *context)
@@ -1645,6 +1679,23 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
return 2;
}
if (skip_prefix(placeholder, "(decorate", &arg)) {
struct decoration_options opts = { NULL };
size_t ret = 0;
if (*arg == ':') {
arg++;
parse_decoration_options(&arg, &opts);
}
if (*arg == ')') {
format_decorations(sb, commit, c->auto_color, &opts);
ret = arg - placeholder + 1;
}
free_decoration_options(&opts);
return ret;
}
/* For the rest we have to parse the commit header. */
if (!c->commit_header_parsed) {
msg = c->message =