Either %<, %> or %<> standing before a placeholder specifies how many
columns (at least as the placeholder can exceed it) it takes. Each
differs on how spaces are padded:

  %< pads on the right (aka left alignment)
  %> pads on the left (aka right alignment)
  %>< pads both ways equally (aka centered)

The (<N>) follows them, e.g. `%<(100)', to specify the number of
columns the next placeholder takes.

However, if '|' stands before (<N>), e.g. `%>|(100)', then the number
of columns is calculated so that it reaches the Nth column on screen.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 Documentation/pretty-formats.txt |   4 ++
 pretty.c                         | 113 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index c706556..49d29ab 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -152,6 +152,10 @@ The placeholders are:
 - '%x00': print a byte from a hex code
 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
+- '%<(<N>)': make the next placeholder take at least N columns, padding spaces 
on the right if necessary
+- '%<|(<N>)': make the next placeholder take at least until Nth columns, 
padding spaces on the right if necessary
+- '%>(<N>)', '%>|(<N>)': similar to '%<(<N<)', '%<|(<N<)' respectively, but 
padding spaces on the left
+- '%><(<N>)', '%><|(<N>)': similar to '%<(<N<)', '%<|(<N<)' respectively, but 
padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
 revision traversal engine. For example, the `%g*` reflog options will
diff --git a/pretty.c b/pretty.c
index f3275a7..d169673 100644
--- a/pretty.c
+++ b/pretty.c
@@ -617,12 +617,20 @@ struct chunk {
        size_t len;
 };
 
+enum flush_type {
+       no_flush,
+       flush_right,
+       flush_left,
+       flush_both
+};
+
 struct format_commit_context {
        const struct commit *commit;
        const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
        unsigned commit_signature_parsed:1;
+       enum flush_type flush_type;
        struct {
                char *gpg_output;
                char good_bad;
@@ -631,6 +639,7 @@ struct format_commit_context {
        char *message;
        size_t width, indent1, indent2;
        unsigned use_color;
+       int padding;
 
        /* These offsets are relative to the start of the commit message. */
        struct chunk author;
@@ -916,6 +925,52 @@ static size_t parse_color_placeholder(struct strbuf *sb,
        return 0;
 }
 
+static size_t parse_padding_placeholder(struct strbuf *sb,
+                                       const char *placeholder,
+                                       struct format_commit_context *c)
+{
+       const char *ch = placeholder;
+       enum flush_type flush_type;
+       int to_column = 0;
+
+       switch (*ch++) {
+       case '<':
+               flush_type = flush_right;
+               break;
+       case '>':
+               if (*ch == '<') {
+                       flush_type = flush_both;
+                       ch++;
+               } else
+                       flush_type = flush_left;
+               break;
+       default:
+               return 0;
+       }
+
+       /* the next value means "wide enough to that column" */
+       if (*ch == '|') {
+               to_column = 1;
+               ch++;
+       }
+
+       if (*ch == '(') {
+               const char *start = ch + 1;
+               const char *end = strchr(start, ')');
+               char *next;
+               int width;
+               if (!end || end == start)
+                       return 0;
+               width = strtoul(start, &next, 10);
+               if (next == start || width == 0)
+                       return 0;
+               c->padding = to_column ? -width : width;
+               c->flush_type = flush_type;
+               return end - placeholder + 1;
+       }
+       return 0;
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                                const char *placeholder,
                                void *context)
@@ -967,6 +1022,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in 
UTF-8 */
                        return end - placeholder + 1;
                } else
                        return 0;
+
+       case '<':
+       case '>':
+               return parse_padding_placeholder(sb, placeholder, c);
        }
 
        /* these depend on the commit */
@@ -1122,6 +1181,55 @@ static size_t format_commit_one(struct strbuf *sb, /* in 
UTF-8 */
        return 0;       /* unknown placeholder */
 }
 
+static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
+                                   const char *placeholder,
+                                   struct format_commit_context *c)
+{
+       struct strbuf local_sb = STRBUF_INIT;
+       int consumed, len, padding = c->padding;
+       if (padding < 0) {
+               const char *start = strrchr(sb->buf, '\n');
+               int occupied;
+               if (!start)
+                       start = sb->buf;
+               occupied = utf8_strnwidth(start, -1, 1);
+               padding = (-padding) - occupied;
+       }
+       consumed = format_commit_one(&local_sb, placeholder, c);
+       len = utf8_strnwidth(local_sb.buf, -1, 1);
+       if (len > padding)
+               strbuf_addstr(sb, local_sb.buf);
+       else {
+               int sb_len = sb->len, offset;
+               switch (c->flush_type) {
+               case flush_left:
+                       offset = padding - len;
+                       break;
+               case flush_right:
+                       offset = 0;
+                       break;
+               case flush_both:
+                       offset = (padding - len) / 2;
+                       break;
+               case no_flush: /* to make gcc happy */
+                       break;
+               }
+               /*
+                * we calculate padding in columns, now
+                * convert it back to chars
+                */
+               padding = padding - len + local_sb.len;
+               strbuf_grow(sb, padding);
+               strbuf_setlen(sb, sb_len + padding);
+               memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+               memcpy(sb->buf + sb_len + offset, local_sb.buf,
+                      local_sb.len);
+       }
+       strbuf_release(&local_sb);
+       c->flush_type = no_flush;
+       return consumed;
+}
+
 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
                                 const char *placeholder,
                                 void *context)
@@ -1153,7 +1261,10 @@ static size_t format_commit_item(struct strbuf *sb, /* 
in UTF-8 */
                placeholder++;
 
        orig_len = sb->len;
-       consumed = format_commit_one(sb, placeholder, context);
+       if (c->flush_type != no_flush)
+               consumed = format_and_pad_commit(sb, placeholder, context);
+       else
+               consumed = format_commit_one(sb, placeholder, context);
        if (c->use_color)
                c->use_color--;
        if (magic == NO_MAGIC)
-- 
1.7.12.1.406.g6ab07c4

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to