Merge branch 'maint'
[gitweb.git] / pretty.c
index 16bfb86cd3ce6d6b471cdc313114563ca78837dc..8beafa08d3927e943a94279f5d776d6a45c673c5 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -3,41 +3,51 @@
 #include "utf8.h"
 #include "diff.h"
 #include "revision.h"
-
-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 },
-       { "format:",    7,      CMIT_FMT_USERFORMAT},
-};
+#include "string-list.h"
+#include "mailmap.h"
+#include "log-tree.h"
 
 static char *user_format;
 
-enum cmit_fmt get_commit_format(const char *arg)
+void get_commit_format(const char *arg, struct rev_info *rev)
 {
        int i;
-
-       if (!arg || !*arg)
-               return CMIT_FMT_DEFAULT;
-       if (*arg == '=')
-               arg++;
-       if (!prefixcmp(arg, "format:")) {
+       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 },
+       };
+
+       rev->use_terminator = 0;
+       if (!arg || !*arg) {
+               rev->commit_format = CMIT_FMT_DEFAULT;
+               return;
+       }
+       if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
+               const char *cp = strchr(arg, ':') + 1;
                free(user_format);
-               user_format = xstrdup(arg + 7);
-               return CMIT_FMT_USERFORMAT;
+               user_format = xstrdup(cp);
+               if (arg[0] == 't')
+                       rev->use_terminator = 1;
+               rev->commit_format = CMIT_FMT_USERFORMAT;
+               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)))
-                       return cmt_fmts[i].v;
+                   !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;
+               }
        }
 
        die("invalid --pretty format: %s", arg);
@@ -281,8 +291,27 @@ static char *logmsg_reencode(const struct commit *commit,
        return out;
 }
 
+static int mailmap_name(struct strbuf *sb, const char *email)
+{
+       static struct string_list *mail_map;
+       char buffer[1024];
+
+       if (!mail_map) {
+               mail_map = xcalloc(1, sizeof(*mail_map));
+               read_mailmap(mail_map, ".mailmap", NULL);
+       }
+
+       if (!mail_map->nr)
+               return -1;
+
+       if (!map_email(mail_map, email, buffer, sizeof(buffer)))
+               return -1;
+       strbuf_addstr(sb, buffer);
+       return 0;
+}
+
 static size_t format_person_part(struct strbuf *sb, char part,
-                               const char *msg, int len)
+                                const char *msg, int len, enum date_mode dmode)
 {
        /* currently all placeholders have same length */
        const int placeholder_len = 2;
@@ -302,10 +331,12 @@ static size_t format_person_part(struct strbuf *sb, char part,
        if (end >= len - 2)
                goto skip;
 
-       if (part == 'n') {      /* name */
+       if (part == 'n' || part == 'N') {       /* name */
                while (end > 0 && isspace(msg[end - 1]))
                        end--;
-               strbuf_add(sb, msg, end);
+               if (part != 'N' || !msg[end] || !msg[end + 1] ||
+                   mailmap_name(sb, msg + end + 2) < 0)
+                       strbuf_add(sb, msg, end);
                return placeholder_len;
        }
        start = ++end; /* save email start position */
@@ -347,7 +378,7 @@ static size_t format_person_part(struct strbuf *sb, char part,
 
        switch (part) {
        case 'd':       /* date */
-               strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL));
+               strbuf_addstr(sb, show_date(date, tz, dmode));
                return placeholder_len;
        case 'D':       /* date, RFC2822 style */
                strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
@@ -379,6 +410,7 @@ struct chunk {
 
 struct format_commit_context {
        const struct commit *commit;
+       enum date_mode dmode;
 
        /* These offsets are relative to the start of the commit message. */
        int commit_header_parsed;
@@ -450,6 +482,23 @@ static void parse_commit_header(struct format_commit_context *context)
        context->commit_header_parsed = 1;
 }
 
+static void format_decoration(struct strbuf *sb, const struct commit *commit)
+{
+       struct name_decoration *d;
+       const char *prefix = " (";
+
+       load_ref_decorations();
+       d = lookup_decoration(&name_decoration, &commit->object);
+       while (d) {
+               strbuf_addstr(sb, prefix);
+               prefix = ", ";
+               strbuf_addstr(sb, d->name);
+               d = d->next;
+       }
+       if (prefix[0] == ',')
+               strbuf_addch(sb, ')');
+}
+
 static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                                void *context)
 {
@@ -457,6 +506,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        const struct commit *commit = c->commit;
        const char *msg = commit->buffer;
        struct commit_list *p;
+       int h1, h2;
 
        /* these are independent of the commit */
        switch (placeholder[0]) {
@@ -478,6 +528,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 'n':               /* newline */
                strbuf_addch(sb, '\n');
                return 1;
+       case 'x':
+               /* %x00 == NUL, %x0a == LF, etc. */
+               if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
+                   h1 <= 16 &&
+                   0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
+                   h2 <= 16) {
+                       strbuf_addch(sb, (h1<<4)|h2);
+                       return 3;
+               } else
+                       return 0;
        }
 
        /* these depend on the commit */
@@ -531,6 +591,9 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                                 ? '<'
                                 : '>');
                return 1;
+       case 'd':
+               format_decoration(sb, commit);
+               return 1;
        }
 
        /* For the rest we have to parse the commit header. */
@@ -543,10 +606,12 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                return 1;
        case 'a':       /* author ... */
                return format_person_part(sb, placeholder[1],
-                                  msg + c->author.off, c->author.len);
+                                  msg + c->author.off, c->author.len,
+                                  c->dmode);
        case 'c':       /* committer ... */
                return format_person_part(sb, placeholder[1],
-                                  msg + c->committer.off, c->committer.len);
+                                  msg + c->committer.off, c->committer.len,
+                                  c->dmode);
        case 'e':       /* encoding */
                strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
                return 1;
@@ -558,12 +623,14 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
 }
 
 void format_commit_message(const struct commit *commit,
-                           const void *format, struct strbuf *sb)
+                          const void *format, struct strbuf *sb,
+                          enum date_mode dmode)
 {
        struct format_commit_context context;
 
        memset(&context, 0, sizeof(context));
        context.commit = commit;
+       context.dmode = dmode;
        strbuf_expand(sb, format, format_commit_item, &context);
 }
 
@@ -729,7 +796,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
        const char *encoding;
 
        if (fmt == CMIT_FMT_USERFORMAT) {
-               format_commit_message(commit, user_format, sb);
+               format_commit_message(commit, user_format, sb, dmode);
                return;
        }