pretty: support truncating in %>, %< and %><
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Thu, 18 Apr 2013 23:08:51 +0000 (09:08 +1000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 18 Apr 2013 23:28:29 +0000 (16:28 -0700)
%>(N,trunc) truncates the right part after N columns and replace the
last two letters with "..". ltrunc does the same on the left. mtrunc
cuts the middle out.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/pretty-formats.txt
pretty.c
t/t4205-log-pretty-formats.sh
utf8.c
utf8.h
index e2345d229047f0defecaee87b49ea829ce48d093..d3450bf96fb9385bfaae2c1048c4c44dda3a1052 100644 (file)
@@ -164,8 +164,11 @@ 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>[,trunc|ltrunc|mtrunc])': make the next placeholder take at
+  least N columns, padding spaces on the right if necessary.
+  Optionally truncate at the beginning (ltrunc), the middle (mtrunc)
+  or the end (trunc) if the output is longer than N columns.
+  Note that truncating only works correctly with N >= 2.
 - '%<|(<N>)': make the next placeholder take at least until Nth
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
index b50ebf575501fb9f2c6b3c1a6463e0c22210cf0a..f7c6442e711d07cb8941a6a2b5d9f7f8b9b7ea2d 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -776,6 +776,13 @@ enum flush_type {
        flush_both
 };
 
+enum trunc_type {
+       trunc_none,
+       trunc_left,
+       trunc_middle,
+       trunc_right
+};
+
 struct format_commit_context {
        const struct commit *commit;
        const struct pretty_print_context *pretty_ctx;
@@ -783,6 +790,7 @@ struct format_commit_context {
        unsigned commit_message_parsed:1;
        struct signature_check signature_check;
        enum flush_type flush_type;
+       enum trunc_type truncate;
        char *message;
        char *commit_encoding;
        size_t width, indent1, indent2;
@@ -1033,7 +1041,7 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
 
        if (*ch == '(') {
                const char *start = ch + 1;
-               const char *end = strchr(start, ')');
+               const char *end = start + strcspn(start, ",)");
                char *next;
                int width;
                if (!end || end == start)
@@ -1043,6 +1051,23 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
                        return 0;
                c->padding = to_column ? -width : width;
                c->flush_type = flush_type;
+
+               if (*end == ',') {
+                       start = end + 1;
+                       end = strchr(start, ')');
+                       if (!end || end == start)
+                               return 0;
+                       if (!prefixcmp(start, "trunc)"))
+                               c->truncate = trunc_right;
+                       else if (!prefixcmp(start, "ltrunc)"))
+                               c->truncate = trunc_left;
+                       else if (!prefixcmp(start, "mtrunc)"))
+                               c->truncate = trunc_middle;
+                       else
+                               return 0;
+               } else
+                       c->truncate = trunc_none;
+
                return end - placeholder + 1;
        }
        return 0;
@@ -1309,9 +1334,29 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
                total_consumed++;
        }
        len = utf8_strnwidth(local_sb.buf, -1, 1);
-       if (len > padding)
+       if (len > padding) {
+               switch (c->truncate) {
+               case trunc_left:
+                       strbuf_utf8_replace(&local_sb,
+                                           0, len - (padding - 2),
+                                           "..");
+                       break;
+               case trunc_middle:
+                       strbuf_utf8_replace(&local_sb,
+                                           padding / 2 - 1,
+                                           len - (padding - 2),
+                                           "..");
+                       break;
+               case trunc_right:
+                       strbuf_utf8_replace(&local_sb,
+                                           padding - 2, len - (padding - 2),
+                                           "..");
+                       break;
+               case trunc_none:
+                       break;
+               }
                strbuf_addstr(sb, local_sb.buf);
-       else {
+       else {
                int sb_len = sb->len, offset = 0;
                if (c->flush_type == flush_left)
                        offset = padding - len;
index 88f24279851db9d0deee0b364d14d1ee18b77f50..b8685b97f99e568e88c4add70b8f2841ec742267 100755 (executable)
@@ -143,6 +143,45 @@ EOF
        test_cmp expected actual
 '
 
+test_expect_success 'left alignment formatting with trunc' '
+       git log --pretty="format:%<(10,trunc)%s" >actual &&
+       # complete the incomplete line at the end
+       echo >>actual &&
+       qz_to_tab_space <<\EOF >expected &&
+message ..
+message ..
+add bar  Z
+initial  Z
+EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with ltrunc' '
+       git log --pretty="format:%<(10,ltrunc)%s" >actual &&
+       # complete the incomplete line at the end
+       echo >>actual &&
+       qz_to_tab_space <<\EOF >expected &&
+..sage two
+..sage one
+add bar  Z
+initial  Z
+EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with mtrunc' '
+       git log --pretty="format:%<(10,mtrunc)%s" >actual &&
+       # complete the incomplete line at the end
+       echo >>actual &&
+       qz_to_tab_space <<\EOF >expected &&
+mess.. two
+mess.. one
+add bar  Z
+initial  Z
+EOF
+       test_cmp expected actual
+'
+
 test_expect_success 'right alignment formatting' '
        git log --pretty="format:%>(40)%s" >actual &&
        # complete the incomplete line at the end
diff --git a/utf8.c b/utf8.c
index 7c342ff4b6eb2e8c94bb3fa5c86b77b5de9abfae..197414af4c7cd257ea46f93ea52254c231ab9a63 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -421,6 +421,52 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
        free(tmp);
 }
 
+void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
+                        const char *subst)
+{
+       struct strbuf sb_dst = STRBUF_INIT;
+       char *src = sb_src->buf;
+       char *end = src + sb_src->len;
+       char *dst;
+       int w = 0, subst_len = 0;
+
+       if (subst)
+               subst_len = strlen(subst);
+       strbuf_grow(&sb_dst, sb_src->len + subst_len);
+       dst = sb_dst.buf;
+
+       while (src < end) {
+               char *old;
+               size_t n;
+
+               while ((n = display_mode_esc_sequence_len(src))) {
+                       memcpy(dst, src, n);
+                       src += n;
+                       dst += n;
+               }
+
+               old = src;
+               n = utf8_width((const char**)&src, NULL);
+               if (!src)       /* broken utf-8, do nothing */
+                       return;
+               if (n && w >= pos && w < pos + width) {
+                       if (subst) {
+                               memcpy(dst, subst, subst_len);
+                               dst += subst_len;
+                               subst = NULL;
+                       }
+                       w += n;
+                       continue;
+               }
+               memcpy(dst, old, src - old);
+               dst += src - old;
+               w += n;
+       }
+       strbuf_setlen(&sb_dst, dst - sb_dst.buf);
+       strbuf_attach(sb_src, strbuf_detach(&sb_dst, NULL),
+                     sb_dst.len, sb_dst.alloc);
+}
+
 int is_encoding_utf8(const char *name)
 {
        if (!name)
diff --git a/utf8.h b/utf8.h
index a43ef9ae74e1aa9199c9abe0c033d180f4aededf..edde8ee189398f8d6fb8dcd53e5c6da9d0a67884 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -15,6 +15,8 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
                const char *text, int indent, int indent2, int width);
 void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
                             int indent, int indent2, int width);
+void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
+                        const char *subst);
 
 #ifndef NO_ICONV
 char *reencode_string_iconv(const char *in, size_t insz,