summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar Nguyễn Thái Ngọc Duy <pclouds@gmail.com>2013-04-19 09:08:51 +1000
committerLibravatar Junio C Hamano <gitster@pobox.com>2013-04-18 16:28:29 -0700
commita7f01c6b4ddf9f2f6bdcb23fc7afb56695807cba (patch)
treebbd2ecfc44a0e3349d2e419f379e653a008dc00f
parentpretty: support padding placeholders, %< %> and %>< (diff)
downloadtgif-a7f01c6b4ddf9f2f6bdcb23fc7afb56695807cba.tar.xz
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>
-rw-r--r--Documentation/pretty-formats.txt7
-rw-r--r--pretty.c51
-rwxr-xr-xt/t4205-log-pretty-formats.sh39
-rw-r--r--utf8.c46
-rw-r--r--utf8.h2
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([<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>)'
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,