pretty: support truncating in %>, %< and %><

%>(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>

Nguyễn Thái Ngọc Duy committed Apr 19, 2013 at 09:08 UTC a7f01c6b4ddf9f2f6bdcb23fc7afb56695807cba
5 files changed +140 -5
Documentation/pretty-formats.txt
+5 -2
@@ -164,8 +164,11 @@ The placeholders are:
164 - '%x00': print a byte from a hex code
165 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
166 linkgit:git-shortlog[1].
167 -- '%<(<N>)': make the next placeholder take at least N columns,
168 - padding spaces on the right if necessary
167 +- '%<(<N>[,trunc|ltrunc|mtrunc])': make the next placeholder take at
168 + least N columns, padding spaces on the right if necessary.
169 + Optionally truncate at the beginning (ltrunc), the middle (mtrunc)
170 + or the end (trunc) if the output is longer than N columns.
171 + Note that truncating only works correctly with N >= 2.
172 - '%<|(<N>)': make the next placeholder take at least until Nth
173 columns, padding spaces on the right if necessary
174 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
pretty.c
+48 -3
@@ -776,6 +776,13 @@ enum flush_type {
776 flush_both
777 };
778
779 +enum trunc_type {
780 + trunc_none,
781 + trunc_left,
782 + trunc_middle,
783 + trunc_right
784 +};
785 +
786 struct format_commit_context {
787 const struct commit *commit;
788 const struct pretty_print_context *pretty_ctx;
@@ -783,6 +790,7 @@ struct format_commit_context {
790 unsigned commit_message_parsed:1;
791 struct signature_check signature_check;
792 enum flush_type flush_type;
793 + enum trunc_type truncate;
794 char *message;
795 char *commit_encoding;
796 size_t width, indent1, indent2;
@@ -1033,7 +1041,7 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
1041
1042 if (*ch == '(') {
1043 const char *start = ch + 1;
1036 - const char *end = strchr(start, ')');
1044 + const char *end = start + strcspn(start, ",)");
1045 char *next;
1046 int width;
1047 if (!end || end == start)
@@ -1043,6 +1051,23 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
1051 return 0;
1052 c->padding = to_column ? -width : width;
1053 c->flush_type = flush_type;
1054 +
1055 + if (*end == ',') {
1056 + start = end + 1;
1057 + end = strchr(start, ')');
1058 + if (!end || end == start)
1059 + return 0;
1060 + if (!prefixcmp(start, "trunc)"))
1061 + c->truncate = trunc_right;
1062 + else if (!prefixcmp(start, "ltrunc)"))
1063 + c->truncate = trunc_left;
1064 + else if (!prefixcmp(start, "mtrunc)"))
1065 + c->truncate = trunc_middle;
1066 + else
1067 + return 0;
1068 + } else
1069 + c->truncate = trunc_none;
1070 +
1071 return end - placeholder + 1;
1072 }
1073 return 0;
@@ -1309,9 +1334,29 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
1334 total_consumed++;
1335 }
1336 len = utf8_strnwidth(local_sb.buf, -1, 1);
1312 - if (len > padding)
1337 + if (len > padding) {
1338 + switch (c->truncate) {
1339 + case trunc_left:
1340 + strbuf_utf8_replace(&local_sb,
1341 + 0, len - (padding - 2),
1342 + "..");
1343 + break;
1344 + case trunc_middle:
1345 + strbuf_utf8_replace(&local_sb,
1346 + padding / 2 - 1,
1347 + len - (padding - 2),
1348 + "..");
1349 + break;
1350 + case trunc_right:
1351 + strbuf_utf8_replace(&local_sb,
1352 + padding - 2, len - (padding - 2),
1353 + "..");
1354 + break;
1355 + case trunc_none:
1356 + break;
1357 + }
1358 strbuf_addstr(sb, local_sb.buf);
1314 - else {
1359 + } else {
1360 int sb_len = sb->len, offset = 0;
1361 if (c->flush_type == flush_left)
1362 offset = padding - len;
t/t4205-log-pretty-formats.sh
+39
@@ -143,6 +143,45 @@ EOF
143 test_cmp expected actual
144 '
145
146 +test_expect_success 'left alignment formatting with trunc' '
147 + git log --pretty="format:%<(10,trunc)%s" >actual &&
148 + # complete the incomplete line at the end
149 + echo >>actual &&
150 + qz_to_tab_space <<\EOF >expected &&
151 +message ..
152 +message ..
153 +add bar Z
154 +initial Z
155 +EOF
156 + test_cmp expected actual
157 +'
158 +
159 +test_expect_success 'left alignment formatting with ltrunc' '
160 + git log --pretty="format:%<(10,ltrunc)%s" >actual &&
161 + # complete the incomplete line at the end
162 + echo >>actual &&
163 + qz_to_tab_space <<\EOF >expected &&
164 +..sage two
165 +..sage one
166 +add bar Z
167 +initial Z
168 +EOF
169 + test_cmp expected actual
170 +'
171 +
172 +test_expect_success 'left alignment formatting with mtrunc' '
173 + git log --pretty="format:%<(10,mtrunc)%s" >actual &&
174 + # complete the incomplete line at the end
175 + echo >>actual &&
176 + qz_to_tab_space <<\EOF >expected &&
177 +mess.. two
178 +mess.. one
179 +add bar Z
180 +initial Z
181 +EOF
182 + test_cmp expected actual
183 +'
184 +
185 test_expect_success 'right alignment formatting' '
186 git log --pretty="format:%>(40)%s" >actual &&
187 # complete the incomplete line at the end
utf8.c
+46
@@ -421,6 +421,52 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
421 free(tmp);
422 }
423
424 +void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
425 + const char *subst)
426 +{
427 + struct strbuf sb_dst = STRBUF_INIT;
428 + char *src = sb_src->buf;
429 + char *end = src + sb_src->len;
430 + char *dst;
431 + int w = 0, subst_len = 0;
432 +
433 + if (subst)
434 + subst_len = strlen(subst);
435 + strbuf_grow(&sb_dst, sb_src->len + subst_len);
436 + dst = sb_dst.buf;
437 +
438 + while (src < end) {
439 + char *old;
440 + size_t n;
441 +
442 + while ((n = display_mode_esc_sequence_len(src))) {
443 + memcpy(dst, src, n);
444 + src += n;
445 + dst += n;
446 + }
447 +
448 + old = src;
449 + n = utf8_width((const char**)&src, NULL);
450 + if (!src) /* broken utf-8, do nothing */
451 + return;
452 + if (n && w >= pos && w < pos + width) {
453 + if (subst) {
454 + memcpy(dst, subst, subst_len);
455 + dst += subst_len;
456 + subst = NULL;
457 + }
458 + w += n;
459 + continue;
460 + }
461 + memcpy(dst, old, src - old);
462 + dst += src - old;
463 + w += n;
464 + }
465 + strbuf_setlen(&sb_dst, dst - sb_dst.buf);
466 + strbuf_attach(sb_src, strbuf_detach(&sb_dst, NULL),
467 + sb_dst.len, sb_dst.alloc);
468 +}
469 +
470 int is_encoding_utf8(const char *name)
471 {
472 if (!name)
utf8.h
+2
@@ -15,6 +15,8 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
15 const char *text, int indent, int indent2, int width);
16 void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
17 int indent, int indent2, int width);
18 +void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
19 + const char *subst);
20
21 #ifndef NO_ICONV
22 char *reencode_string_iconv(const char *in, size_t insz,