Implement wrap format %w() as if it is a mode switch
I always considered line wrapping to be more similar to a colour, i.e. a state that one can change and that is applied to all following text until the next state change, except that it's always reset at the end of the format string. Here's a patch to implement this behaviour, using Dscho's strbuf_add_wrapped_text() Signed-off-by: Junio C Hamano <gitster@pobox.com>
René Scharfe committed
Oct 17, 2009 at 23:04 UTC
02edd56b84f00c1a88c5602f5608033d4bc1cbff
1 file changed
+57
pretty.c
+57
@@ -445,6 +445,7 @@ struct format_commit_context {
445
enum date_mode dmode;
446
unsigned commit_header_parsed:1;
447
unsigned commit_message_parsed:1;
448
+ size_t width, indent1, indent2;
449
450
/* These offsets are relative to the start of the commit message. */
451
struct chunk author;
@@ -458,6 +459,7 @@ struct format_commit_context {
459
struct chunk abbrev_commit_hash;
460
struct chunk abbrev_tree_hash;
461
struct chunk abbrev_parent_hashes;
462
+ size_t wrap_start;
463
};
464
465
static int add_again(struct strbuf *sb, struct chunk *chunk)
@@ -595,6 +597,35 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)
597
strbuf_addch(sb, ')');
598
}
599
600
+static void strbuf_wrap(struct strbuf *sb, size_t pos,
601
+ size_t width, size_t indent1, size_t indent2)
602
+{
603
+ struct strbuf tmp = STRBUF_INIT;
604
+
605
+ if (pos)
606
+ strbuf_add(&tmp, sb->buf, pos);
607
+ strbuf_add_wrapped_text(&tmp, sb->buf + pos,
608
+ (int) indent1, (int) indent2, (int) width);
609
+ strbuf_swap(&tmp, sb);
610
+ strbuf_release(&tmp);
611
+}
612
+
613
+static void rewrap_message_tail(struct strbuf *sb,
614
+ struct format_commit_context *c,
615
+ size_t new_width, size_t new_indent1,
616
+ size_t new_indent2)
617
+{
618
+ if (c->width == new_width && c->indent1 == new_indent1 &&
619
+ c->indent2 == new_indent2)
620
+ return;
621
+ if (c->wrap_start && c->wrap_start < sb->len)
622
+ strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2);
623
+ c->wrap_start = sb->len;
624
+ c->width = new_width;
625
+ c->indent1 = new_indent1;
626
+ c->indent2 = new_indent2;
627
+}
628
+
629
static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
630
void *context)
631
{
@@ -645,6 +676,30 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
676
return 3;
677
} else
678
return 0;
679
+ case 'w':
680
+ if (placeholder[1] == '(') {
681
+ unsigned long width = 0, indent1 = 0, indent2 = 0;
682
+ char *next;
683
+ const char *start = placeholder + 2;
684
+ const char *end = strchr(start, ')');
685
+ if (!end)
686
+ return 0;
687
+ if (end > start) {
688
+ width = strtoul(start, &next, 10);
689
+ if (*next == ',') {
690
+ indent1 = strtoul(next + 1, &next, 10);
691
+ if (*next == ',') {
692
+ indent2 = strtoul(next + 1,
693
+ &next, 10);
694
+ }
695
+ }
696
+ if (*next != ')')
697
+ return 0;
698
+ }
699
+ rewrap_message_tail(sb, c, width, indent1, indent2);
700
+ return end - placeholder + 1;
701
+ } else
702
+ return 0;
703
}
704
705
/* these depend on the commit */
@@ -748,7 +803,9 @@ void format_commit_message(const struct commit *commit,
803
memset(&context, 0, sizeof(context));
804
context.commit = commit;
805
context.dmode = dmode;
806
+ context.wrap_start = sb->len;
807
strbuf_expand(sb, format, format_commit_item, &context);
808
+ rewrap_message_tail(sb, &context, 0, 0, 0);
809
}
810
811
static void pp_header(enum cmit_fmt fmt,