]> git.ipfire.org Git - thirdparty/git.git/blobdiff - pretty.c
Merge branch 'bl/pretty-shorthand-config-fix'
[thirdparty/git.git] / pretty.c
index 558622cf2bd351596b87ab1410f818ea688cbd07..2faf651d3ef2afc237bb755c9c535d9bd9b60295 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1,8 +1,13 @@
-#include "cache.h"
+#include "git-compat-util.h"
 #include "config.h"
 #include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
 #include "utf8.h"
 #include "diff.h"
+#include "pager.h"
 #include "revision.h"
 #include "string-list.h"
 #include "mailmap.h"
@@ -13,6 +18,7 @@
 #include "gpg-interface.h"
 #include "trailer.h"
 #include "run-command.h"
+#include "object-name.h"
 
 /*
  * The limit for formatting directives, which enable the caller to append
@@ -51,6 +57,7 @@ static void save_user_format(struct rev_info *rev, const char *cp, int is_tforma
 }
 
 static int git_pretty_formats_config(const char *var, const char *value,
+                                    const struct config_context *ctx UNUSED,
                                     void *cb UNUSED)
 {
        struct cmt_fmt_map *commit_format = NULL;
@@ -719,7 +726,7 @@ const char *repo_logmsg_reencode(struct repository *r,
                 * Otherwise, we still want to munge the encoding header in the
                 * result, which will be done by modifying the buffer. If we
                 * are using a fresh copy, we can reuse it. But if we are using
-                * the cached copy from get_commit_buffer, we need to duplicate it
+                * the cached copy from repo_get_commit_buffer, we need to duplicate it
                 * to avoid munging the cached copy.
                 */
                if (msg == get_cached_commit_buffer(r, commit, NULL))
@@ -1245,6 +1252,27 @@ static int format_trailer_match_cb(const struct strbuf *key, void *ud)
        return 0;
 }
 
+static struct strbuf *expand_string_arg(struct strbuf *sb,
+                                       const char *argval, size_t arglen)
+{
+       char *fmt = xstrndup(argval, arglen);
+       const char *format = fmt;
+
+       strbuf_reset(sb);
+       while (strbuf_expand_step(sb, &format)) {
+               size_t len;
+
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(sb, '%');
+               else if ((len = strbuf_expand_literal(sb, format)))
+                       format += len;
+               else
+                       strbuf_addch(sb, '%');
+       }
+       free(fmt);
+       return sb;
+}
+
 int format_set_trailers_options(struct process_trailer_options *opts,
                                struct string_list *filter_list,
                                struct strbuf *sepbuf,
@@ -1273,21 +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)) {
-                       char *fmt;
-
-                       strbuf_reset(sepbuf);
-                       fmt = xstrndup(argval, arglen);
-                       strbuf_expand(sepbuf, fmt, strbuf_expand_literal_cb, NULL);
-                       free(fmt);
-                       opts->separator = sepbuf;
+                       opts->separator = expand_string_arg(sepbuf, argval, arglen);
                } else if (match_placeholder_arg_value(*arg, "key_value_separator", arg, &argval, &arglen)) {
-                       char *fmt;
-
-                       strbuf_reset(kvsepbuf);
-                       fmt = xstrndup(argval, arglen);
-                       strbuf_expand(kvsepbuf, fmt, strbuf_expand_literal_cb, NULL);
-                       free(fmt);
-                       opts->key_value_separator = kvsepbuf;
+                       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) &&
@@ -1368,6 +1384,44 @@ 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) ||
+              parse_decoration_option(arg, "pointer", &opts->pointer) ||
+              parse_decoration_option(arg, "tag", &opts->tag))
+               ;
+}
+
+static void free_decoration_options(const struct decoration_options *opts)
+{
+       free(opts->prefix);
+       free(opts->suffix);
+       free(opts->separator);
+       free(opts->pointer);
+       free(opts->tag);
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                                const char *placeholder,
                                void *context)
@@ -1381,7 +1435,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
        char **slot;
 
        /* these are independent of the commit */
-       res = strbuf_expand_literal_cb(sb, placeholder, NULL);
+       res = strbuf_expand_literal(sb, placeholder);
        if (res)
                return res;
 
@@ -1521,11 +1575,18 @@ 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, NULL);
                return 1;
        case 'D':
-               format_decorations_extended(sb, commit, c->auto_color, "", ", ", "");
-               return 1;
+               {
+                       const struct decoration_options opts = {
+                               .prefix = "",
+                               .suffix = ""
+                       };
+
+                       format_decorations(sb, commit, c->auto_color, &opts);
+                       return 1;
+               }
        case 'S':               /* tag/branch like --source */
                if (!(c->pretty_ctx->rev && c->pretty_ctx->rev->sources))
                        return 0;
@@ -1622,6 +1683,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 =
@@ -1681,7 +1759,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                                goto trailer_out;
                }
                if (*arg == ')') {
-                       format_trailers_from_commit(sb, msg + c->subject_off, &opts);
+                       format_trailers_from_commit(&opts, msg + c->subject_off, sb);
                        ret = arg - placeholder + 1;
                }
        trailer_out:
@@ -1799,7 +1877,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
 
 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
                                 const char *placeholder,
-                                void *context)
+                                struct format_commit_context *context)
 {
        size_t consumed, orig_len;
        enum {
@@ -1838,10 +1916,10 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
        }
 
        orig_len = sb->len;
-       if (((struct format_commit_context *)context)->flush_type != no_flush)
-               consumed = format_and_pad_commit(sb, placeholder, context);
-       else
+       if (context->flush_type == no_flush)
                consumed = format_commit_one(sb, placeholder, context);
+       else
+               consumed = format_and_pad_commit(sb, placeholder, context);
        if (magic == NO_MAGIC)
                return consumed;
 
@@ -1857,40 +1935,38 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
        return consumed + 1;
 }
 
-static size_t userformat_want_item(struct strbuf *sb, const char *placeholder,
-                                  void *context)
-{
-       struct userformat_want *w = context;
-
-       if (*placeholder == '+' || *placeholder == '-' || *placeholder == ' ')
-               placeholder++;
-
-       switch (*placeholder) {
-       case 'N':
-               w->notes = 1;
-               break;
-       case 'S':
-               w->source = 1;
-               break;
-       case 'd':
-       case 'D':
-               w->decorate = 1;
-               break;
-       }
-       return 0;
-}
-
 void userformat_find_requirements(const char *fmt, struct userformat_want *w)
 {
-       struct strbuf dummy = STRBUF_INIT;
-
        if (!fmt) {
                if (!user_format)
                        return;
                fmt = user_format;
        }
-       strbuf_expand(&dummy, fmt, userformat_want_item, w);
-       strbuf_release(&dummy);
+       while ((fmt = strchr(fmt, '%'))) {
+               fmt++;
+               if (skip_prefix(fmt, "%", &fmt))
+                       continue;
+
+               if (*fmt == '+' || *fmt == '-' || *fmt == ' ')
+                       fmt++;
+
+               switch (*fmt) {
+               case 'N':
+                       w->notes = 1;
+                       break;
+               case 'S':
+                       w->source = 1;
+                       break;
+               case 'd':
+               case 'D':
+                       w->decorate = 1;
+                       break;
+               case '(':
+                       if (starts_with(fmt + 1, "decorate"))
+                               w->decorate = 1;
+                       break;
+               }
+       }
 }
 
 void repo_format_commit_message(struct repository *r,
@@ -1907,7 +1983,16 @@ void repo_format_commit_message(struct repository *r,
        const char *output_enc = pretty_ctx->output_encoding;
        const char *utf8 = "UTF-8";
 
-       strbuf_expand(sb, format, format_commit_item, &context);
+       while (strbuf_expand_step(sb, &format)) {
+               size_t len;
+
+               if (skip_prefix(format, "%", &format))
+                       strbuf_addch(sb, '%');
+               else if ((len = format_commit_item(sb, format, &context)))
+                       format += len;
+               else
+                       strbuf_addch(sb, '%');
+       }
        rewrap_message_tail(sb, &context, 0, 0, 0);
 
        /*
@@ -1992,11 +2077,11 @@ static void pp_header(struct pretty_print_context *pp,
        }
 }
 
-void pp_title_line(struct pretty_print_context *pp,
-                  const char **msg_p,
-                  struct strbuf *sb,
-                  const char *encoding,
-                  int need_8bit_cte)
+void pp_email_subject(struct pretty_print_context *pp,
+                     const char **msg_p,
+                     struct strbuf *sb,
+                     const char *encoding,
+                     int need_8bit_cte)
 {
        static const int max_length = 78; /* per rfc2047 */
        struct strbuf title;
@@ -2006,19 +2091,14 @@ void pp_title_line(struct pretty_print_context *pp,
                                pp->preserve_subject ? "\n" : " ");
 
        strbuf_grow(sb, title.len + 1024);
-       if (pp->print_email_subject) {
-               if (pp->rev)
-                       fmt_output_email_subject(sb, pp->rev);
-               if (pp->encode_email_headers &&
-                   needs_rfc2047_encoding(title.buf, title.len))
-                       add_rfc2047(sb, title.buf, title.len,
-                                               encoding, RFC2047_SUBJECT);
-               else
-                       strbuf_add_wrapped_bytes(sb, title.buf, title.len,
+       fmt_output_email_subject(sb, pp->rev);
+       if (pp->encode_email_headers &&
+           needs_rfc2047_encoding(title.buf, title.len))
+               add_rfc2047(sb, title.buf, title.len,
+                           encoding, RFC2047_SUBJECT);
+       else
+               strbuf_add_wrapped_bytes(sb, title.buf, title.len,
                                         -last_line_length(sb), 1, max_length);
-       } else {
-               strbuf_addbuf(sb, &title);
-       }
        strbuf_addch(sb, '\n');
 
        if (need_8bit_cte == 0) {
@@ -2041,9 +2121,8 @@ void pp_title_line(struct pretty_print_context *pp,
        if (pp->after_subject) {
                strbuf_addstr(sb, pp->after_subject);
        }
-       if (cmit_fmt_is_mail(pp->fmt)) {
-               strbuf_addch(sb, '\n');
-       }
+
+       strbuf_addch(sb, '\n');
 
        if (pp->in_body_headers.nr) {
                int i;
@@ -2199,12 +2278,14 @@ void pretty_print_commit(struct pretty_print_context *pp,
        int need_8bit_cte = pp->need_8bit_cte;
 
        if (pp->fmt == CMIT_FMT_USERFORMAT) {
-               format_commit_message(commit, user_format, sb, pp);
+               repo_format_commit_message(the_repository, commit,
+                                          user_format, sb, pp);
                return;
        }
 
        encoding = get_log_output_encoding();
-       msg = reencoded = logmsg_reencode(commit, NULL, encoding);
+       msg = reencoded = repo_logmsg_reencode(the_repository, commit, NULL,
+                                              encoding);
 
        if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
                indent = 0;
@@ -2233,7 +2314,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
        }
 
        pp_header(pp, encoding, commit, &msg, sb);
-       if (pp->fmt != CMIT_FMT_ONELINE && !pp->print_email_subject) {
+       if (pp->fmt != CMIT_FMT_ONELINE && !cmit_fmt_is_mail(pp->fmt)) {
                strbuf_addch(sb, '\n');
        }
 
@@ -2241,8 +2322,11 @@ void pretty_print_commit(struct pretty_print_context *pp,
        msg = skip_blank_lines(msg);
 
        /* These formats treat the title line specially. */
-       if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
-               pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
+       if (pp->fmt == CMIT_FMT_ONELINE) {
+               msg = format_subject(sb, msg, " ");
+               strbuf_addch(sb, '\n');
+       } else if (cmit_fmt_is_mail(pp->fmt))
+               pp_email_subject(pp, &msg, sb, encoding, need_8bit_cte);
 
        beginning_of_body = sb->len;
        if (pp->fmt != CMIT_FMT_ONELINE)
@@ -2261,7 +2345,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
        if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
                strbuf_addch(sb, '\n');
 
-       unuse_commit_buffer(commit, reencoded);
+       repo_unuse_commit_buffer(the_repository, commit, reencoded);
 }
 
 void pp_commit_easy(enum cmit_fmt fmt, const struct commit *commit,