Make the default abbrev length configurable
[gitweb.git] / pretty.c
index e9540e46da7af16e3aa765d79a5b03a4847975df..85499347514ec3e1d62d6caa9f53b886c556e345 100644 (file)
--- a/pretty.c
+++ b/pretty.c
 #include "string-list.h"
 #include "mailmap.h"
 #include "log-tree.h"
+#include "notes.h"
 #include "color.h"
+#include "reflog-walk.h"
 
 static char *user_format;
+static struct cmt_fmt_map {
+       const char *name;
+       enum cmit_fmt format;
+       int is_tformat;
+       int is_alias;
+       const char *user_format;
+} *commit_formats;
+static size_t builtin_formats_len;
+static size_t commit_formats_len;
+static size_t commit_formats_alloc;
+static struct cmt_fmt_map *find_commit_format(const char *sought);
+
+static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
+{
+       free(user_format);
+       user_format = xstrdup(cp);
+       if (is_tformat)
+               rev->use_terminator = 1;
+       rev->commit_format = CMIT_FMT_USERFORMAT;
+}
 
-void get_commit_format(const char *arg, struct rev_info *rev)
+static int git_pretty_formats_config(const char *var, const char *value, void *cb)
 {
+       struct cmt_fmt_map *commit_format = NULL;
+       const char *name;
+       const char *fmt;
        int i;
-       static struct cmt_fmt_map {
-               const char *n;
-               size_t cmp_len;
-               enum cmit_fmt v;
-       } cmt_fmts[] = {
-               { "raw",        1,      CMIT_FMT_RAW },
-               { "medium",     1,      CMIT_FMT_MEDIUM },
-               { "short",      1,      CMIT_FMT_SHORT },
-               { "email",      1,      CMIT_FMT_EMAIL },
-               { "full",       5,      CMIT_FMT_FULL },
-               { "fuller",     5,      CMIT_FMT_FULLER },
-               { "oneline",    1,      CMIT_FMT_ONELINE },
+
+       if (prefixcmp(var, "pretty."))
+               return 0;
+
+       name = var + strlen("pretty.");
+       for (i = 0; i < builtin_formats_len; i++) {
+               if (!strcmp(commit_formats[i].name, name))
+                       return 0;
+       }
+
+       for (i = builtin_formats_len; i < commit_formats_len; i++) {
+               if (!strcmp(commit_formats[i].name, name)) {
+                       commit_format = &commit_formats[i];
+                       break;
+               }
+       }
+
+       if (!commit_format) {
+               ALLOC_GROW(commit_formats, commit_formats_len+1,
+                          commit_formats_alloc);
+               commit_format = &commit_formats[commit_formats_len];
+               memset(commit_format, 0, sizeof(*commit_format));
+               commit_formats_len++;
+       }
+
+       commit_format->name = xstrdup(name);
+       commit_format->format = CMIT_FMT_USERFORMAT;
+       git_config_string(&fmt, var, value);
+       if (!prefixcmp(fmt, "format:") || !prefixcmp(fmt, "tformat:")) {
+               commit_format->is_tformat = fmt[0] == 't';
+               fmt = strchr(fmt, ':') + 1;
+       } else if (strchr(fmt, '%'))
+               commit_format->is_tformat = 1;
+       else
+               commit_format->is_alias = 1;
+       commit_format->user_format = fmt;
+
+       return 0;
+}
+
+static void setup_commit_formats(void)
+{
+       struct cmt_fmt_map builtin_formats[] = {
+               { "raw",        CMIT_FMT_RAW,           0 },
+               { "medium",     CMIT_FMT_MEDIUM,        0 },
+               { "short",      CMIT_FMT_SHORT,         0 },
+               { "email",      CMIT_FMT_EMAIL,         0 },
+               { "fuller",     CMIT_FMT_FULLER,        0 },
+               { "full",       CMIT_FMT_FULL,          0 },
+               { "oneline",    CMIT_FMT_ONELINE,       1 }
        };
+       commit_formats_len = ARRAY_SIZE(builtin_formats);
+       builtin_formats_len = commit_formats_len;
+       ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
+       memcpy(commit_formats, builtin_formats,
+              sizeof(*builtin_formats)*ARRAY_SIZE(builtin_formats));
+
+       git_config(git_pretty_formats_config, NULL);
+}
+
+static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
+                                                       const char *original,
+                                                       int num_redirections)
+{
+       struct cmt_fmt_map *found = NULL;
+       size_t found_match_len = 0;
+       int i;
+
+       if (num_redirections >= commit_formats_len)
+               die("invalid --pretty format: "
+                   "'%s' references an alias which points to itself",
+                   original);
+
+       for (i = 0; i < commit_formats_len; i++) {
+               size_t match_len;
+
+               if (prefixcmp(commit_formats[i].name, sought))
+                       continue;
+
+               match_len = strlen(commit_formats[i].name);
+               if (found == NULL || found_match_len > match_len) {
+                       found = &commit_formats[i];
+                       found_match_len = match_len;
+               }
+       }
+
+       if (found && found->is_alias) {
+               found = find_commit_format_recursive(found->user_format,
+                                                    original,
+                                                    num_redirections+1);
+       }
+
+       return found;
+}
+
+static struct cmt_fmt_map *find_commit_format(const char *sought)
+{
+       if (!commit_formats)
+               setup_commit_formats();
+
+       return find_commit_format_recursive(sought, sought, 0);
+}
+
+void get_commit_format(const char *arg, struct rev_info *rev)
+{
+       struct cmt_fmt_map *commit_format;
 
        rev->use_terminator = 0;
        if (!arg || !*arg) {
@@ -33,25 +151,25 @@ void get_commit_format(const char *arg, struct rev_info *rev)
                return;
        }
        if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
-               const char *cp = strchr(arg, ':') + 1;
-               free(user_format);
-               user_format = xstrdup(cp);
-               if (arg[0] == 't')
-                       rev->use_terminator = 1;
-               rev->commit_format = CMIT_FMT_USERFORMAT;
+               save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
                return;
        }
-       for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
-               if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
-                   !strncmp(arg, cmt_fmts[i].n, strlen(arg))) {
-                       if (cmt_fmts[i].v == CMIT_FMT_ONELINE)
-                               rev->use_terminator = 1;
-                       rev->commit_format = cmt_fmts[i].v;
-                       return;
-               }
+
+       if (strchr(arg, '%')) {
+               save_user_format(rev, arg, 1);
+               return;
        }
 
-       die("invalid --pretty format: %s", arg);
+       commit_format = find_commit_format(arg);
+       if (!commit_format)
+               die("invalid --pretty format: %s", arg);
+
+       rev->commit_format = commit_format->format;
+       rev->use_terminator = commit_format->is_tformat;
+       if (commit_format->format == CMIT_FMT_USERFORMAT) {
+               save_user_format(rev, commit_format->user_format,
+                                commit_format->is_tformat);
+       }
 }
 
 /*
@@ -73,11 +191,23 @@ static int get_one_line(const char *msg)
 }
 
 /* High bit set, or ISO-2022-INT */
-int non_ascii(int ch)
+static int non_ascii(int ch)
 {
        return !isascii(ch) || ch == '\033';
 }
 
+int has_non_ascii(const char *s)
+{
+       int ch;
+       if (!s)
+               return 0;
+       while ((ch = *s++) != '\0') {
+               if (non_ascii(ch))
+                       return 1;
+       }
+       return 0;
+}
+
 static int is_rfc2047_special(char ch)
 {
        return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
@@ -127,7 +257,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
        int namelen;
        unsigned long time;
        int tz;
-       const char *filler = "    ";
 
        if (fmt == CMIT_FMT_ONELINE)
                return;
@@ -146,7 +275,6 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
                while (line < name_tail && isspace(name_tail[-1]))
                        name_tail--;
                display_name_length = name_tail - line;
-               filler = "";
                strbuf_addstr(sb, "From: ");
                add_rfc2047(sb, line, display_name_length, encoding);
                strbuf_add(sb, name_tail, namelen - display_name_length);
@@ -154,7 +282,7 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
        } else {
                strbuf_addf(sb, "%s: %.*s%.*s\n", what,
                              (fmt == CMIT_FMT_FULLER) ? 4 : 0,
-                             filler, namelen, line);
+                             "    ", namelen, line);
        }
        switch (fmt) {
        case CMIT_FMT_MEDIUM:
@@ -275,10 +403,10 @@ static char *replace_encoding_header(char *buf, const char *encoding)
        return strbuf_detach(&tmp, NULL);
 }
 
-static char *logmsg_reencode(const struct commit *commit,
-                            const char *output_encoding)
+char *logmsg_reencode(const struct commit *commit,
+                     const char *output_encoding)
 {
-       static const char *utf8 = "utf-8";
+       static const char *utf8 = "UTF-8";
        const char *use_encoding;
        char *encoding;
        char *out;
@@ -424,9 +552,11 @@ struct chunk {
 
 struct format_commit_context {
        const struct commit *commit;
-       enum date_mode dmode;
+       const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
+       char *message;
+       size_t width, indent1, indent2;
 
        /* These offsets are relative to the start of the commit message. */
        struct chunk author;
@@ -440,6 +570,7 @@ struct format_commit_context {
        struct chunk abbrev_commit_hash;
        struct chunk abbrev_tree_hash;
        struct chunk abbrev_parent_hashes;
+       size_t wrap_start;
 };
 
 static int add_again(struct strbuf *sb, struct chunk *chunk)
@@ -461,7 +592,7 @@ static int add_again(struct strbuf *sb, struct chunk *chunk)
 
 static void parse_commit_header(struct format_commit_context *context)
 {
-       const char *msg = context->commit->buffer;
+       const char *msg = context->message;
        int i;
 
        for (i = 0; msg[i]; i++) {
@@ -487,6 +618,40 @@ static void parse_commit_header(struct format_commit_context *context)
        context->commit_header_parsed = 1;
 }
 
+static int istitlechar(char c)
+{
+       return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+               (c >= '0' && c <= '9') || c == '.' || c == '_';
+}
+
+static void format_sanitized_subject(struct strbuf *sb, const char *msg)
+{
+       size_t trimlen;
+       size_t start_len = sb->len;
+       int space = 2;
+
+       for (; *msg && *msg != '\n'; msg++) {
+               if (istitlechar(*msg)) {
+                       if (space == 1)
+                               strbuf_addch(sb, '-');
+                       space = 0;
+                       strbuf_addch(sb, *msg);
+                       if (*msg == '.')
+                               while (*(msg+1) == '.')
+                                       msg++;
+               } else
+                       space |= 1;
+       }
+
+       /* trim any trailing '.' or '-' characters */
+       trimlen = 0;
+       while (sb->len - trimlen > start_len &&
+               (sb->buf[sb->len - 1 - trimlen] == '.'
+               || sb->buf[sb->len - 1 - trimlen] == '-'))
+               trimlen++;
+       strbuf_remove(sb, sb->len - trimlen, trimlen);
+}
+
 const char *format_subject(struct strbuf *sb, const char *msg,
                           const char *line_separator)
 {
@@ -513,8 +678,8 @@ const char *format_subject(struct strbuf *sb, const char *msg,
 
 static void parse_commit_message(struct format_commit_context *c)
 {
-       const char *msg = c->commit->buffer + c->message_off;
-       const char *start = c->commit->buffer;
+       const char *msg = c->message + c->message_off;
+       const char *start = c->message;
 
        msg = skip_empty_lines(msg);
        c->subject_off = msg - start;
@@ -531,7 +696,7 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)
        struct name_decoration *d;
        const char *prefix = " (";
 
-       load_ref_decorations();
+       load_ref_decorations(DECORATE_SHORT_REFS);
        d = lookup_decoration(&name_decoration, &commit->object);
        while (d) {
                strbuf_addstr(sb, prefix);
@@ -543,12 +708,41 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)
                strbuf_addch(sb, ')');
 }
 
-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
-                               void *context)
+static void strbuf_wrap(struct strbuf *sb, size_t pos,
+                       size_t width, size_t indent1, size_t indent2)
+{
+       struct strbuf tmp = STRBUF_INIT;
+
+       if (pos)
+               strbuf_add(&tmp, sb->buf, pos);
+       strbuf_add_wrapped_text(&tmp, sb->buf + pos,
+                               (int) indent1, (int) indent2, (int) width);
+       strbuf_swap(&tmp, sb);
+       strbuf_release(&tmp);
+}
+
+static void rewrap_message_tail(struct strbuf *sb,
+                               struct format_commit_context *c,
+                               size_t new_width, size_t new_indent1,
+                               size_t new_indent2)
+{
+       if (c->width == new_width && c->indent1 == new_indent1 &&
+           c->indent2 == new_indent2)
+               return;
+       if (c->wrap_start < sb->len)
+               strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2);
+       c->wrap_start = sb->len;
+       c->width = new_width;
+       c->indent1 = new_indent1;
+       c->indent2 = new_indent2;
+}
+
+static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
+                               void *context)
 {
        struct format_commit_context *c = context;
        const struct commit *commit = c->commit;
-       const char *msg = commit->buffer;
+       const char *msg = c->message;
        struct commit_list *p;
        int h1, h2;
 
@@ -567,16 +761,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                        return end - placeholder + 1;
                }
                if (!prefixcmp(placeholder + 1, "red")) {
-                       strbuf_addstr(sb, "\033[31m");
+                       strbuf_addstr(sb, GIT_COLOR_RED);
                        return 4;
                } else if (!prefixcmp(placeholder + 1, "green")) {
-                       strbuf_addstr(sb, "\033[32m");
+                       strbuf_addstr(sb, GIT_COLOR_GREEN);
                        return 6;
                } else if (!prefixcmp(placeholder + 1, "blue")) {
-                       strbuf_addstr(sb, "\033[34m");
+                       strbuf_addstr(sb, GIT_COLOR_BLUE);
                        return 5;
                } else if (!prefixcmp(placeholder + 1, "reset")) {
-                       strbuf_addstr(sb, "\033[m");
+                       strbuf_addstr(sb, GIT_COLOR_RESET);
                        return 6;
                } else
                        return 0;
@@ -593,6 +787,30 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                        return 3;
                } else
                        return 0;
+       case 'w':
+               if (placeholder[1] == '(') {
+                       unsigned long width = 0, indent1 = 0, indent2 = 0;
+                       char *next;
+                       const char *start = placeholder + 2;
+                       const char *end = strchr(start, ')');
+                       if (!end)
+                               return 0;
+                       if (end > start) {
+                               width = strtoul(start, &next, 10);
+                               if (*next == ',') {
+                                       indent1 = strtoul(next + 1, &next, 10);
+                                       if (*next == ',') {
+                                               indent2 = strtoul(next + 1,
+                                                                &next, 10);
+                                       }
+                               }
+                               if (*next != ')')
+                                       return 0;
+                       }
+                       rewrap_message_tail(sb, c, width, indent1, indent2);
+                       return end - placeholder + 1;
+               } else
+                       return 0;
        }
 
        /* these depend on the commit */
@@ -607,7 +825,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                if (add_again(sb, &c->abbrev_commit_hash))
                        return 1;
                strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
-                                                    DEFAULT_ABBREV));
+                                                    c->pretty_ctx->abbrev));
                c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
                return 1;
        case 'T':               /* tree hash */
@@ -617,7 +835,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                if (add_again(sb, &c->abbrev_tree_hash))
                        return 1;
                strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
-                                                    DEFAULT_ABBREV));
+                                                    c->pretty_ctx->abbrev));
                c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
                return 1;
        case 'P':               /* parent hashes */
@@ -634,7 +852,8 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                        if (p != commit->parents)
                                strbuf_addch(sb, ' ');
                        strbuf_addstr(sb, find_unique_abbrev(
-                                       p->item->object.sha1, DEFAULT_ABBREV));
+                                       p->item->object.sha1,
+                                       c->pretty_ctx->abbrev));
                }
                c->abbrev_parent_hashes.len = sb->len -
                                              c->abbrev_parent_hashes.off;
@@ -649,6 +868,29 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 'd':
                format_decoration(sb, commit);
                return 1;
+       case 'g':               /* reflog info */
+               switch(placeholder[1]) {
+               case 'd':       /* reflog selector */
+               case 'D':
+                       if (c->pretty_ctx->reflog_info)
+                               get_reflog_selector(sb,
+                                                   c->pretty_ctx->reflog_info,
+                                                   c->pretty_ctx->date_mode,
+                                                   (placeholder[1] == 'd'));
+                       return 2;
+               case 's':       /* reflog message */
+                       if (c->pretty_ctx->reflog_info)
+                               get_reflog_message(sb, c->pretty_ctx->reflog_info);
+                       return 2;
+               }
+               return 0;       /* unknown %g placeholder */
+       case 'N':
+               if (c->pretty_ctx->show_notes) {
+                       format_display_notes(commit->object.sha1, sb,
+                                   get_log_output_encoding(), 0);
+                       return 1;
+               }
+               return 0;
        }
 
        /* For the rest we have to parse the commit header. */
@@ -659,14 +901,18 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 'a':       /* author ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->author.off, c->author.len,
-                                  c->dmode);
+                                  c->pretty_ctx->date_mode);
        case 'c':       /* committer ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->committer.off, c->committer.len,
-                                  c->dmode);
+                                  c->pretty_ctx->date_mode);
        case 'e':       /* encoding */
                strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
                return 1;
+       case 'B':       /* raw body */
+               /* message_off is always left at the initial newline */
+               strbuf_addstr(sb, msg + c->message_off + 1);
+               return 1;
        }
 
        /* Now we need to parse the commit message. */
@@ -677,6 +923,9 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 's':       /* subject */
                format_subject(sb, msg + c->subject_off, " ");
                return 1;
+       case 'f':       /* sanitized subject */
+               format_sanitized_subject(sb, msg + c->subject_off);
+               return 1;
        case 'b':       /* body */
                strbuf_addstr(sb, msg + c->body_off);
                return 1;
@@ -684,16 +933,106 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        return 0;       /* unknown placeholder */
 }
 
+static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
+                                void *context)
+{
+       int consumed;
+       size_t orig_len;
+       enum {
+               NO_MAGIC,
+               ADD_LF_BEFORE_NON_EMPTY,
+               DEL_LF_BEFORE_EMPTY,
+               ADD_SP_BEFORE_NON_EMPTY
+       } magic = NO_MAGIC;
+
+       switch (placeholder[0]) {
+       case '-':
+               magic = DEL_LF_BEFORE_EMPTY;
+               break;
+       case '+':
+               magic = ADD_LF_BEFORE_NON_EMPTY;
+               break;
+       case ' ':
+               magic = ADD_SP_BEFORE_NON_EMPTY;
+               break;
+       default:
+               break;
+       }
+       if (magic != NO_MAGIC)
+               placeholder++;
+
+       orig_len = sb->len;
+       consumed = format_commit_one(sb, placeholder, context);
+       if (magic == NO_MAGIC)
+               return consumed;
+
+       if ((orig_len == sb->len) && magic == DEL_LF_BEFORE_EMPTY) {
+               while (sb->len && sb->buf[sb->len - 1] == '\n')
+                       strbuf_setlen(sb, sb->len - 1);
+       } else if (orig_len != sb->len) {
+               if (magic == ADD_LF_BEFORE_NON_EMPTY)
+                       strbuf_insert(sb, orig_len, "\n", 1);
+               else if (magic == ADD_SP_BEFORE_NON_EMPTY)
+                       strbuf_insert(sb, orig_len, " ", 1);
+       }
+       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;
+       }
+       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, user_format, userformat_want_item, w);
+       strbuf_release(&dummy);
+}
+
 void format_commit_message(const struct commit *commit,
-                          const void *format, struct strbuf *sb,
-                          enum date_mode dmode)
+                          const char *format, struct strbuf *sb,
+                          const struct pretty_print_context *pretty_ctx)
 {
        struct format_commit_context context;
+       static const char utf8[] = "UTF-8";
+       const char *enc;
+       const char *output_enc = pretty_ctx->output_encoding;
 
        memset(&context, 0, sizeof(context));
        context.commit = commit;
-       context.dmode = dmode;
+       context.pretty_ctx = pretty_ctx;
+       context.wrap_start = sb->len;
+       context.message = commit->buffer;
+       if (output_enc) {
+               enc = get_header(commit, "encoding");
+               enc = enc ? enc : utf8;
+               if (strcmp(enc, output_enc))
+                       context.message = logmsg_reencode(commit, output_enc);
+       }
+
        strbuf_expand(sb, format, format_commit_item, &context);
+       rewrap_message_tail(sb, &context, 0, 0, 0);
+
+       if (context.message != commit->buffer)
+               free(context.message);
 }
 
 static void pp_header(enum cmit_fmt fmt,
@@ -834,29 +1173,25 @@ char *reencode_commit_message(const struct commit *commit, const char **encoding
 {
        const char *encoding;
 
-       encoding = (git_log_output_encoding
-                   ? git_log_output_encoding
-                   : git_commit_encoding);
-       if (!encoding)
-               encoding = "utf-8";
+       encoding = get_log_output_encoding();
        if (encoding_p)
                *encoding_p = encoding;
        return logmsg_reencode(commit, encoding);
 }
 
 void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
-                        struct strbuf *sb, int abbrev,
-                        const char *subject, const char *after_subject,
-                        enum date_mode dmode, int need_8bit_cte)
+                        struct strbuf *sb,
+                        const struct pretty_print_context *context)
 {
        unsigned long beginning_of_body;
        int indent = 4;
        const char *msg = commit->buffer;
        char *reencoded;
        const char *encoding;
+       int need_8bit_cte = context->need_8bit_cte;
 
        if (fmt == CMIT_FMT_USERFORMAT) {
-               format_commit_message(commit, user_format, sb, dmode);
+               format_commit_message(commit, user_format, sb, context);
                return;
        }
 
@@ -891,8 +1226,9 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
                }
        }
 
-       pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
-       if (fmt != CMIT_FMT_ONELINE && !subject) {
+       pp_header(fmt, context->abbrev, context->date_mode, encoding,
+                 commit, &msg, sb);
+       if (fmt != CMIT_FMT_ONELINE && !context->subject) {
                strbuf_addch(sb, '\n');
        }
 
@@ -901,8 +1237,8 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 
        /* These formats treat the title line specially. */
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
-               pp_title_line(fmt, &msg, sb, subject,
-                             after_subject, encoding, need_8bit_cte);
+               pp_title_line(fmt, &msg, sb, context->subject,
+                             context->after_subject, encoding, need_8bit_cte);
 
        beginning_of_body = sb->len;
        if (fmt != CMIT_FMT_ONELINE)
@@ -920,5 +1256,10 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
         */
        if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
                strbuf_addch(sb, '\n');
+
+       if (context->show_notes)
+               format_display_notes(commit->object.sha1, sb, encoding,
+                                    NOTES_SHOW_HEADER | NOTES_INDENT);
+
        free(reencoded);
 }