And this is a for-fun patch that adds %| to right align everything after that. I'm ignoring problems with line wrapping, i18n and so on. "%C+%h %s%|%d" looks quite nice. I'm not sure how much useful it is beyond --oneline though. It looks something like this cc543b2 pretty: support placeholders %C+ and %C- (HEAD, master) da6001e pretty: share code between format_decoration and show_decorations b0576a6 Update draft release notes to 1.8.0 (origin/master, origin/HEAD) 3d7535e Merge branch 'jc/maint-log-grep-all-match' 06e211a Merge branch 'jc/make-static' 8db3865 Merge branch 'pw/p4-submit-conflicts' 3387423 Merge branch 'mv/cherry-pick-s' d71abd9 Merge branch 'nd/fetch-status-alignment' 3c7d509 Sync with 1.7.12.1 304b7d9 Git 1.7.12.1 (tag: v1.7.12.1, origin/maint) 39e2e02 Merge branch 'er/doc-fast-import-done' into maint 8ffc331 Merge branch 'jk/config-warn-on-inaccessible-paths' into maint 01f7d7f Doc: Improve shallow depth wording 8093ae8 Documentation/git-filter-branch: Move note about effect of removing commits -- 8< -- diff --git a/pretty.c b/pretty.c index b1cec71..6e96f83 100644 --- a/pretty.c +++ b/pretty.c @@ -624,6 +624,7 @@ struct format_commit_context { unsigned commit_message_parsed:1; unsigned commit_signature_parsed:1; unsigned use_color:1; + unsigned right_alignment:1; struct { char *gpg_output; char good_bad; @@ -645,6 +646,8 @@ struct format_commit_context { struct chunk abbrev_tree_hash; struct chunk abbrev_parent_hashes; size_t wrap_start; + + struct strbuf *right_sb; }; static int add_again(struct strbuf *sb, struct chunk *chunk) @@ -944,6 +947,10 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder, return end - placeholder + 1; } else return 0; + + case '|': + c->right_alignment = 1; + return 1; } /* these depend on the commit */ @@ -1099,9 +1106,44 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder, return 0; /* unknown placeholder */ } +static void right_align(struct strbuf *sb, + struct format_commit_context *c, + int flush) +{ + const char *p; + int llen, rlen, len, total = term_columns() - 1; + if (!c->right_alignment) + return; + p = strchr(c->right_sb->buf, '\n'); + if (!p && flush) + p = c->right_sb->buf + c->right_sb->len; + if (!p) + return; + + c->right_alignment = 0; + len = p - c->right_sb->buf; + if (!len) + return; + if (total > 110) + total = 110; + rlen = utf8_strnwidth(c->right_sb->buf, len); + p = strrchr(sb->buf, '\n'); + if (!p) + p = sb->buf; + else + p++; + llen = utf8_strwidth(p); + strbuf_addf(sb, "%*s", + total - llen + (len - rlen), + c->right_sb->buf); + strbuf_reset(c->right_sb); +} + static size_t format_commit_item(struct strbuf *sb, const char *placeholder, void *context) { + struct format_commit_context *c = context; + struct strbuf *real_sb; int consumed; size_t orig_len; enum { @@ -1127,10 +1169,13 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, if (magic != NO_MAGIC) placeholder++; + if (c->right_alignment && c->right_sb) { + real_sb = sb; + sb = c->right_sb; + } + 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') @@ -1141,7 +1186,13 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, else if (magic == ADD_SP_BEFORE_NON_EMPTY) strbuf_insert(sb, orig_len, " ", 1); } - return consumed + 1; + + if (real_sb) + right_align(real_sb, c, 0); + + if (magic != NO_MAGIC) + consumed++; + return consumed; } static size_t userformat_want_item(struct strbuf *sb, const char *placeholder, @@ -1180,12 +1231,14 @@ void format_commit_message(const struct commit *commit, struct format_commit_context context; static const char utf8[] = "UTF-8"; const char *output_enc = pretty_ctx->output_encoding; + struct strbuf right_sb = STRBUF_INIT; memset(&context, 0, sizeof(context)); context.commit = commit; context.pretty_ctx = pretty_ctx; context.wrap_start = sb->len; context.message = commit->buffer; + context.right_sb = &right_sb; if (output_enc) { char *enc = get_header(commit, "encoding"); if (strcmp(enc ? enc : utf8, output_enc)) { @@ -1197,8 +1250,11 @@ void format_commit_message(const struct commit *commit, } strbuf_expand(sb, format, format_commit_item, &context); + if (context.right_alignment) + right_align(sb, &context, 1); rewrap_message_tail(sb, &context, 0, 0, 0); + strbuf_release(&right_sb); if (context.message != commit->buffer) free(context.message); free(context.signature.gpg_output); diff --git a/utf8.c b/utf8.c index a544f15..68ca0b4 100644 --- a/utf8.c +++ b/utf8.c @@ -9,6 +9,20 @@ struct interval { int last; }; +static size_t display_mode_esc_sequence_len(const char *s) +{ + const char *p = s; + if (*p++ != '\033') + return 0; + if (*p++ != '[') + return 0; + while (isdigit(*p) || *p == ';') + p++; + if (*p++ != 'm') + return 0; + return p - s; +} + /* auxiliary function for binary search in interval table */ static int bisearch(ucs_char_t ucs, const struct interval *table, int max) { @@ -252,18 +266,25 @@ int utf8_width(const char **start, size_t *remainder_p) * string, assuming that the string is utf8. Returns strlen() instead * if the string does not look like a valid utf8 string. */ -int utf8_strwidth(const char *string) +int utf8_strnwidth(const char *string, int len) { int width = 0; const char *orig = string; - while (1) { - if (!string) - return strlen(orig); - if (!*string) - return width; + if (len == -1) + len = strlen(string); + while (string && string < orig + len) { + int skip; + while ((skip = display_mode_esc_sequence_len(string))) + string += skip; width += utf8_width(&string, NULL); } + return string ? width : len; +} + +int utf8_strwidth(const char *string) +{ + return utf8_strnwidth(string, -1); } int is_utf8(const char *text) @@ -303,20 +324,6 @@ static void strbuf_add_indented_text(struct strbuf *buf, const char *text, } } -static size_t display_mode_esc_sequence_len(const char *s) -{ - const char *p = s; - if (*p++ != '\033') - return 0; - if (*p++ != '[') - return 0; - while (isdigit(*p) || *p == ';') - p++; - if (*p++ != 'm') - return 0; - return p - s; -} - /* * Wrap the text, if necessary. The variable indent is the indent for the * first line, indent2 is the indent for all other lines. diff --git a/utf8.h b/utf8.h index 3c0ae76..1727405 100644 --- a/utf8.h +++ b/utf8.h @@ -4,6 +4,7 @@ typedef unsigned int ucs_char_t; /* assuming 32bit int */ int utf8_width(const char **start, size_t *remainder_p); +int utf8_strnwidth(const char *string, int len); int utf8_strwidth(const char *string); int is_utf8(const char *text); int is_encoding_utf8(const char *name); -- 8< -- -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html