Skip to content

Commit

Permalink
pretty: support truncating in %>, %< and %><
Browse files Browse the repository at this point in the history
%>(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>
  • Loading branch information
pclouds authored and gitster committed Apr 18, 2013
1 parent a575234 commit a7f01c6
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 5 deletions.
7 changes: 5 additions & 2 deletions Documentation/pretty-formats.txt
Expand Up @@ -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>)'
Expand Down
51 changes: 48 additions & 3 deletions pretty.c
Expand Up @@ -776,13 +776,21 @@ 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;
unsigned commit_header_parsed:1;
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;
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
39 changes: 39 additions & 0 deletions t/t4205-log-pretty-formats.sh
Expand Up @@ -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
Expand Down
46 changes: 46 additions & 0 deletions utf8.c
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions utf8.h
Expand Up @@ -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,
Expand Down

0 comments on commit a7f01c6

Please sign in to comment.