From a7f01c6b4ddf9f2f6bdcb23fc7afb56695807cba Mon Sep 17 00:00:00 2001 From: =?utf8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 19 Apr 2013 09:08:51 +1000 Subject: [PATCH] pretty: support truncating in %>, %< and %>< MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit %>(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 Signed-off-by: Junio C Hamano --- Documentation/pretty-formats.txt | 7 ++++-- pretty.c | 51 +++++++++++++++++++++++++++++++++++++--- t/t4205-log-pretty-formats.sh | 39 ++++++++++++++++++++++++++++++ utf8.c | 46 ++++++++++++++++++++++++++++++++++++ utf8.h | 2 ++ 5 files changed, 140 insertions(+), 5 deletions(-) diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index e2345d2290..d3450bf96f 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -164,8 +164,11 @@ The placeholders are: - '%x00': print a byte from a hex code - '%w([[,[,]]])': switch line wrapping, like the -w option of linkgit:git-shortlog[1]. -- '%<()': make the next placeholder take at least N columns, - padding spaces on the right if necessary +- '%<([,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. - '%<|()': make the next placeholder take at least until Nth columns, padding spaces on the right if necessary - '%>()', '%>|()': similar to '%<()', '%<|()' diff --git a/pretty.c b/pretty.c index b50ebf5755..f7c6442e71 100644 --- 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; diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 88f2427985..b8685b97f9 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -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 7c342ff4b6..197414af4c 100644 --- 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 a43ef9ae74..edde8ee189 100644 --- 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, -- 2.11.4.GIT