diff options
Diffstat (limited to 'pretty.c')
-rw-r--r-- | pretty.c | 164 |
1 files changed, 110 insertions, 54 deletions
@@ -5,6 +5,7 @@ #include "revision.h" #include "string-list.h" #include "mailmap.h" +#include "log-tree.h" static char *user_format; @@ -180,6 +181,20 @@ static int is_empty_line(const char *line, int *len_p) return !len; } +static const char *skip_empty_lines(const char *msg) +{ + for (;;) { + int linelen = get_one_line(msg); + int ll = linelen; + if (!linelen) + break; + if (!is_empty_line(msg, &ll)) + break; + msg += linelen; + } + return msg; +} + static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb, const struct commit *commit, int abbrev) { @@ -233,7 +248,7 @@ static char *get_header(const struct commit *commit, const char *key) static char *replace_encoding_header(char *buf, const char *encoding) { - struct strbuf tmp; + struct strbuf tmp = STRBUF_INIT; size_t start, len; char *cp = buf; @@ -249,7 +264,6 @@ static char *replace_encoding_header(char *buf, const char *encoding) return buf; /* should not happen but be defensive */ len = cp + 1 - (buf + start); - strbuf_init(&tmp, 0); strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1); if (is_encoding_utf8(encoding)) { /* we have re-coded to UTF-8; drop the header */ @@ -410,13 +424,15 @@ struct chunk { struct format_commit_context { const struct commit *commit; enum date_mode dmode; + unsigned commit_header_parsed:1; + unsigned commit_message_parsed:1; /* These offsets are relative to the start of the commit message. */ - int commit_header_parsed; - struct chunk subject; struct chunk author; struct chunk committer; struct chunk encoding; + size_t message_off; + size_t subject_off; size_t body_off; /* The following ones are relative to the result struct strbuf. */ @@ -446,23 +462,14 @@ static void parse_commit_header(struct format_commit_context *context) { const char *msg = context->commit->buffer; int i; - enum { HEADER, SUBJECT, BODY } state; - for (i = 0, state = HEADER; msg[i] && state < BODY; i++) { + for (i = 0; msg[i]; i++) { int eol; for (eol = i; msg[eol] && msg[eol] != '\n'; eol++) ; /* do nothing */ - if (state == SUBJECT) { - context->subject.off = i; - context->subject.len = eol - i; - i = eol; - } if (i == eol) { - state++; - /* strip empty lines */ - while (msg[eol] == '\n' && msg[eol + 1] == '\n') - eol++; + break; } else if (!prefixcmp(msg + i, "author ")) { context->author.off = i + 7; context->author.len = eol - i - 7; @@ -474,13 +481,67 @@ static void parse_commit_header(struct format_commit_context *context) context->encoding.len = eol - i - 9; } i = eol; - if (!msg[i]) - break; } - context->body_off = i; + context->message_off = i; context->commit_header_parsed = 1; } +static const char *format_subject(struct strbuf *sb, const char *msg, + const char *line_separator) +{ + int first = 1; + + for (;;) { + const char *line = msg; + int linelen = get_one_line(line); + + msg += linelen; + if (!linelen || is_empty_line(line, &linelen)) + break; + + if (!sb) + continue; + strbuf_grow(sb, linelen + 2); + if (!first) + strbuf_addstr(sb, line_separator); + strbuf_add(sb, line, linelen); + first = 0; + } + return 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; + + msg = skip_empty_lines(msg); + c->subject_off = msg - start; + + msg = format_subject(NULL, msg, NULL); + msg = skip_empty_lines(msg); + c->body_off = msg - start; + + c->commit_message_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) { @@ -573,6 +634,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. */ @@ -580,9 +644,6 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, parse_commit_header(c); switch (placeholder[0]) { - case 's': /* subject */ - strbuf_add(sb, msg + c->subject.off, c->subject.len); - return 1; case 'a': /* author ... */ return format_person_part(sb, placeholder[1], msg + c->author.off, c->author.len, @@ -594,6 +655,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, case 'e': /* encoding */ strbuf_add(sb, msg + c->encoding.off, c->encoding.len); return 1; + } + + /* Now we need to parse the commit message. */ + if (!c->commit_message_parsed) + parse_commit_message(c); + + switch (placeholder[0]) { + case 's': /* subject */ + format_subject(sb, msg + c->subject_off, " "); + return 1; case 'b': /* body */ strbuf_addstr(sb, msg + c->body_off); return 1; @@ -684,27 +755,11 @@ void pp_title_line(enum cmit_fmt fmt, const char *encoding, int need_8bit_cte) { + const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " "; struct strbuf title; strbuf_init(&title, 80); - - for (;;) { - const char *line = *msg_p; - int linelen = get_one_line(line); - - *msg_p += linelen; - if (!linelen || is_empty_line(line, &linelen)) - break; - - strbuf_grow(&title, linelen + 2); - if (title.len) { - if (fmt == CMIT_FMT_EMAIL) { - strbuf_addch(&title, '\n'); - } - strbuf_addch(&title, ' '); - } - strbuf_add(&title, line, linelen); - } + *msg_p = format_subject(&title, *msg_p, line_separator); strbuf_grow(sb, title.len + 1024); if (subject) { @@ -763,6 +818,20 @@ void pp_remainder(enum cmit_fmt fmt, } } +char *reencode_commit_message(const struct commit *commit, const char **encoding_p) +{ + const char *encoding; + + encoding = (git_log_output_encoding + ? git_log_output_encoding + : git_commit_encoding); + if (!encoding) + encoding = "utf-8"; + 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, @@ -779,12 +848,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, return; } - encoding = (git_log_output_encoding - ? git_log_output_encoding - : git_commit_encoding); - if (!encoding) - encoding = "utf-8"; - reencoded = logmsg_reencode(commit, encoding); + reencoded = reencode_commit_message(commit, &encoding); if (reencoded) { msg = reencoded; } @@ -821,15 +885,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, } /* Skip excess blank lines at the beginning of body, if any... */ - for (;;) { - int linelen = get_one_line(msg); - int ll = linelen; - if (!linelen) - break; - if (!is_empty_line(msg, &ll)) - break; - msg += linelen; - } + msg = skip_empty_lines(msg); /* These formats treat the title line specially. */ if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) |