diff options
Diffstat (limited to 'pretty.c')
-rw-r--r-- | pretty.c | 132 |
1 files changed, 114 insertions, 18 deletions
@@ -16,6 +16,7 @@ static struct cmt_fmt_map { const char *name; enum cmit_fmt format; int is_tformat; + int expand_tabs_in_log; int is_alias; const char *user_format; } *commit_formats; @@ -87,13 +88,14 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c 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 } + { "raw", CMIT_FMT_RAW, 0, 0 }, + { "medium", CMIT_FMT_MEDIUM, 0, 8 }, + { "short", CMIT_FMT_SHORT, 0, 0 }, + { "email", CMIT_FMT_EMAIL, 0, 0 }, + { "mboxrd", CMIT_FMT_MBOXRD, 0, 0 }, + { "fuller", CMIT_FMT_FULLER, 0, 8 }, + { "full", CMIT_FMT_FULL, 0, 8 }, + { "oneline", CMIT_FMT_ONELINE, 1, 0 } }; commit_formats_len = ARRAY_SIZE(builtin_formats); builtin_formats_len = commit_formats_len; @@ -172,6 +174,7 @@ void get_commit_format(const char *arg, struct rev_info *rev) rev->commit_format = commit_format->format; rev->use_terminator = commit_format->is_tformat; + rev->expand_tabs_in_log_default = commit_format->expand_tabs_in_log; if (commit_format->format == CMIT_FMT_USERFORMAT) { save_user_format(rev, commit_format->user_format, commit_format->is_tformat); @@ -442,7 +445,7 @@ void pp_user_info(struct pretty_print_context *pp, if (pp->mailmap) map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen); - if (pp->fmt == CMIT_FMT_EMAIL) { + if (cmit_fmt_is_mail(pp->fmt)) { if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) { struct strbuf buf = STRBUF_INIT; @@ -492,6 +495,7 @@ void pp_user_info(struct pretty_print_context *pp, show_ident_date(&ident, &pp->date_mode)); break; case CMIT_FMT_EMAIL: + case CMIT_FMT_MBOXRD: strbuf_addf(sb, "Date: %s\n", show_ident_date(&ident, DATE_MODE(RFC2822))); break; @@ -533,7 +537,7 @@ static void add_merge_info(const struct pretty_print_context *pp, { struct commit_list *parent = commit->parents; - if ((pp->fmt == CMIT_FMT_ONELINE) || (pp->fmt == CMIT_FMT_EMAIL) || + if ((pp->fmt == CMIT_FMT_ONELINE) || (cmit_fmt_is_mail(pp->fmt)) || !parent || !parent->next) return; @@ -1020,9 +1024,15 @@ static size_t parse_padding_placeholder(struct strbuf *sb, int width; if (!end || end == start) return 0; - width = strtoul(start, &next, 10); + width = strtol(start, &next, 10); if (next == start || width == 0) return 0; + if (width < 0) { + if (to_column) + width += term_columns(); + if (width < 0) + return 0; + } c->padding = to_column ? -width : width; c->flush_type = flush_type; @@ -1061,7 +1071,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ switch (placeholder[0]) { case 'C': if (starts_with(placeholder + 1, "(auto)")) { - c->auto_color = 1; + c->auto_color = want_color(c->pretty_ctx->color); return 7; /* consumed 7 bytes, "C(auto)" */ } else { int ret = parse_color(sb, placeholder, c); @@ -1297,6 +1307,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */ if (!start) start = sb->buf; occupied = utf8_strnwidth(start, -1, 1); + occupied += c->pretty_ctx->graph_width; padding = (-padding) - occupied; } while (1) { @@ -1612,7 +1623,7 @@ void pp_title_line(struct pretty_print_context *pp, if (pp->after_subject) { strbuf_addstr(sb, pp->after_subject); } - if (pp->fmt == CMIT_FMT_EMAIL) { + if (cmit_fmt_is_mail(pp->fmt)) { strbuf_addch(sb, '\n'); } @@ -1629,6 +1640,82 @@ void pp_title_line(struct pretty_print_context *pp, strbuf_release(&title); } +static int pp_utf8_width(const char *start, const char *end) +{ + int width = 0; + size_t remain = end - start; + + while (remain) { + int n = utf8_width(&start, &remain); + if (n < 0 || !start) + return -1; + width += n; + } + return width; +} + +static void strbuf_add_tabexpand(struct strbuf *sb, int tabwidth, + const char *line, int linelen) +{ + const char *tab; + + while ((tab = memchr(line, '\t', linelen)) != NULL) { + int width = pp_utf8_width(line, tab); + + /* + * If it wasn't well-formed utf8, or it + * had characters with badly defined + * width (control characters etc), just + * give up on trying to align things. + */ + if (width < 0) + break; + + /* Output the data .. */ + strbuf_add(sb, line, tab - line); + + /* .. and the de-tabified tab */ + strbuf_addchars(sb, ' ', tabwidth - (width % tabwidth)); + + /* Skip over the printed part .. */ + linelen -= tab + 1 - line; + line = tab + 1; + } + + /* + * Print out everything after the last tab without + * worrying about width - there's nothing more to + * align. + */ + strbuf_add(sb, line, linelen); +} + +/* + * pp_handle_indent() prints out the intendation, and + * the whole line (without the final newline), after + * de-tabifying. + */ +static void pp_handle_indent(struct pretty_print_context *pp, + struct strbuf *sb, int indent, + const char *line, int linelen) +{ + strbuf_addchars(sb, ' ', indent); + if (pp->expand_tabs_in_log) + strbuf_add_tabexpand(sb, pp->expand_tabs_in_log, line, linelen); + else + strbuf_add(sb, line, linelen); +} + +static int is_mboxrd_from(const char *line, int len) +{ + /* + * a line matching /^From $/ here would only have len == 4 + * at this point because is_empty_line would've trimmed all + * trailing space + */ + return len > 4 && starts_with(line + strspn(line, ">"), "From "); +} + void pp_remainder(struct pretty_print_context *pp, const char **msg_p, struct strbuf *sb, @@ -1653,8 +1740,17 @@ void pp_remainder(struct pretty_print_context *pp, strbuf_grow(sb, linelen + indent + 20); if (indent) - strbuf_addchars(sb, ' ', indent); - strbuf_add(sb, line, linelen); + pp_handle_indent(pp, sb, indent, line, linelen); + else if (pp->expand_tabs_in_log) + strbuf_add_tabexpand(sb, pp->expand_tabs_in_log, + line, linelen); + else { + if (pp->fmt == CMIT_FMT_MBOXRD && + is_mboxrd_from(line, linelen)) + strbuf_addch(sb, '>'); + + strbuf_add(sb, line, linelen); + } strbuf_addch(sb, '\n'); } } @@ -1678,14 +1774,14 @@ void pretty_print_commit(struct pretty_print_context *pp, encoding = get_log_output_encoding(); msg = reencoded = logmsg_reencode(commit, NULL, encoding); - if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL) + if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt)) indent = 0; /* * We need to check and emit Content-type: to mark it * as 8-bit if we haven't done so. */ - if (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { + if (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { @@ -1713,7 +1809,7 @@ void pretty_print_commit(struct pretty_print_context *pp, msg = skip_empty_lines(msg); /* These formats treat the title line specially. */ - if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL) + if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt)) pp_title_line(pp, &msg, sb, encoding, need_8bit_cte); beginning_of_body = sb->len; @@ -1730,7 +1826,7 @@ void pretty_print_commit(struct pretty_print_context *pp, * format. Make sure we did not strip the blank line * between the header and the body. */ - if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) + if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); unuse_commit_buffer(commit, reencoded); |