Re: [PATCH 11/12] pretty: support truncating in %>, %< and %>

2013-03-16 Thread Paul Campbell
On Sat, Mar 16, 2013 at 2:24 AM, Nguyễn Thái Ngọc Duy  wrote:
> %>(N,trunc) truncates the righ 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 
> ---

s/righ/right/

>  Documentation/pretty-formats.txt |  6 +++--
>  pretty.c | 51 
> +---
>  utf8.c   | 46 
>  utf8.h   |  2 ++
>  4 files changed, 100 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/pretty-formats.txt 
> b/Documentation/pretty-formats.txt
> index 87ca2c4..17f82f4 100644
> --- a/Documentation/pretty-formats.txt
> +++ b/Documentation/pretty-formats.txt
> @@ -162,8 +162,10 @@ 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.
>  - '%<|()': 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 233d69c..29384b5 100644
> --- a/pretty.c
> +++ b/pretty.c
> @@ -767,6 +767,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;
> @@ -774,6 +781,7 @@ struct format_commit_context {
> unsigned commit_message_parsed:1;
> unsigned commit_signature_parsed:1;
> enum flush_type flush_type;
> +   enum trunc_type truncate;
> struct {
> char *gpg_output;
> char good_bad;
> @@ -1044,7 +1052,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)
> @@ -1054,6 +1062,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;
> @@ -1335,9 +1360,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 {
> 

[PATCH 11/12] pretty: support truncating in %>, %< and %>

2013-03-15 Thread Nguyễn Thái Ngọc Duy
%>(N,trunc) truncates the righ 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 
---
 Documentation/pretty-formats.txt |  6 +++--
 pretty.c | 51 +---
 utf8.c   | 46 
 utf8.h   |  2 ++
 4 files changed, 100 insertions(+), 5 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 87ca2c4..17f82f4 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -162,8 +162,10 @@ 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.
 - '%<|()': make the next placeholder take at least until Nth
   columns, padding spaces on the right if necessary
 - '%>()', '%>|()': similar to '%<(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;
@@ -1335,9 +1360,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/utf8.c b/utf8.c
index 9d98043..766df80 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;
+