Merge branch 'rs/pretty-wrap'
authorJunio C Hamano <gitster@pobox.com>
Mon, 16 Nov 2009 00:41:17 +0000 (16:41 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 16 Nov 2009 00:41:17 +0000 (16:41 -0800)
* rs/pretty-wrap:
log --format: don't ignore %w() at the start of format string
Implement wrap format %w() as if it is a mode switch

Conflicts:
pretty.c

1  2 
pretty.c
diff --combined pretty.c
index da15cf2a80d08e38b4b0bb279e378b72dbe49cc7,5e9d1f84b976c7f85e67c6af446d31e54c2388fd..2e031e62fd98c02bfa6cc558fc49aef86c03ed09
+++ b/pretty.c
@@@ -7,7 -7,6 +7,7 @@@
  #include "mailmap.h"
  #include "log-tree.h"
  #include "color.h"
 +#include "reflog-walk.h"
  
  static char *user_format;
  
@@@ -443,9 -442,10 +443,10 @@@ struct chunk 
  
  struct format_commit_context {
        const struct commit *commit;
 -      enum date_mode dmode;
 +      const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
+       size_t width, indent1, indent2;
  
        /* These offsets are relative to the start of the commit message. */
        struct chunk author;
        struct chunk abbrev_commit_hash;
        struct chunk abbrev_tree_hash;
        struct chunk abbrev_parent_hashes;
+       size_t wrap_start;
  };
  
  static int add_again(struct strbuf *sb, struct chunk *chunk)
@@@ -596,6 -597,35 +598,35 @@@ static void format_decoration(struct st
                strbuf_addch(sb, ')');
  }
  
+ static void strbuf_wrap(struct strbuf *sb, size_t pos,
+                       size_t width, size_t indent1, size_t indent2)
+ {
+       struct strbuf tmp = STRBUF_INIT;
+       if (pos)
+               strbuf_add(&tmp, sb->buf, pos);
+       strbuf_add_wrapped_text(&tmp, sb->buf + pos,
+                               (int) indent1, (int) indent2, (int) width);
+       strbuf_swap(&tmp, sb);
+       strbuf_release(&tmp);
+ }
+ static void rewrap_message_tail(struct strbuf *sb,
+                               struct format_commit_context *c,
+                               size_t new_width, size_t new_indent1,
+                               size_t new_indent2)
+ {
+       if (c->width == new_width && c->indent1 == new_indent1 &&
+           c->indent2 == new_indent2)
+               return;
+       if (c->wrap_start < sb->len)
+               strbuf_wrap(sb, c->wrap_start, c->width, c->indent1, c->indent2);
+       c->wrap_start = sb->len;
+       c->width = new_width;
+       c->indent1 = new_indent1;
+       c->indent2 = new_indent2;
+ }
  static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
                                 void *context)
  {
                        return 3;
                } else
                        return 0;
+       case 'w':
+               if (placeholder[1] == '(') {
+                       unsigned long width = 0, indent1 = 0, indent2 = 0;
+                       char *next;
+                       const char *start = placeholder + 2;
+                       const char *end = strchr(start, ')');
+                       if (!end)
+                               return 0;
+                       if (end > start) {
+                               width = strtoul(start, &next, 10);
+                               if (*next == ',') {
+                                       indent1 = strtoul(next + 1, &next, 10);
+                                       if (*next == ',') {
+                                               indent2 = strtoul(next + 1,
+                                                                &next, 10);
+                                       }
+                               }
+                               if (*next != ')')
+                                       return 0;
+                       }
+                       rewrap_message_tail(sb, c, width, indent1, indent2);
+                       return end - placeholder + 1;
+               } else
+                       return 0;
        }
  
        /* these depend on the commit */
        case 'd':
                format_decoration(sb, commit);
                return 1;
 +      case 'g':               /* reflog info */
 +              switch(placeholder[1]) {
 +              case 'd':       /* reflog selector */
 +              case 'D':
 +                      if (c->pretty_ctx->reflog_info)
 +                              get_reflog_selector(sb,
 +                                                  c->pretty_ctx->reflog_info,
 +                                                  c->pretty_ctx->date_mode,
 +                                                  (placeholder[1] == 'd'));
 +                      return 2;
 +              case 's':       /* reflog message */
 +                      if (c->pretty_ctx->reflog_info)
 +                              get_reflog_message(sb, c->pretty_ctx->reflog_info);
 +                      return 2;
 +              }
 +              return 0;       /* unknown %g placeholder */
        }
  
        /* For the rest we have to parse the commit header. */
        case 'a':       /* author ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->author.off, c->author.len,
 -                                 c->dmode);
 +                                 c->pretty_ctx->date_mode);
        case 'c':       /* committer ... */
                return format_person_part(sb, placeholder[1],
                                   msg + c->committer.off, c->committer.len,
 -                                 c->dmode);
 +                                 c->pretty_ctx->date_mode);
        case 'e':       /* encoding */
                strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
                return 1;
  
  void format_commit_message(const struct commit *commit,
                           const char *format, struct strbuf *sb,
 -                         enum date_mode dmode)
 +                         const struct pretty_print_context *pretty_ctx)
  {
        struct format_commit_context context;
  
        memset(&context, 0, sizeof(context));
        context.commit = commit;
 -      context.dmode = dmode;
 +      context.pretty_ctx = pretty_ctx;
+       context.wrap_start = sb->len;
        strbuf_expand(sb, format, format_commit_item, &context);
+       rewrap_message_tail(sb, &context, 0, 0, 0);
  }
  
  static void pp_header(enum cmit_fmt fmt,
@@@ -917,18 -957,18 +974,18 @@@ char *reencode_commit_message(const str
  }
  
  void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 -                       struct strbuf *sb, int abbrev,
 -                       const char *subject, const char *after_subject,
 -                       enum date_mode dmode, int need_8bit_cte)
 +                       struct strbuf *sb,
 +                       const struct pretty_print_context *context)
  {
        unsigned long beginning_of_body;
        int indent = 4;
        const char *msg = commit->buffer;
        char *reencoded;
        const char *encoding;
 +      int need_8bit_cte = context->need_8bit_cte;
  
        if (fmt == CMIT_FMT_USERFORMAT) {
 -              format_commit_message(commit, user_format, sb, dmode);
 +              format_commit_message(commit, user_format, sb, context);
                return;
        }
  
                }
        }
  
 -      pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
 -      if (fmt != CMIT_FMT_ONELINE && !subject) {
 +      pp_header(fmt, context->abbrev, context->date_mode, encoding,
 +                commit, &msg, sb);
 +      if (fmt != CMIT_FMT_ONELINE && !context->subject) {
                strbuf_addch(sb, '\n');
        }
  
  
        /* These formats treat the title line specially. */
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
 -              pp_title_line(fmt, &msg, sb, subject,
 -                            after_subject, encoding, need_8bit_cte);
 +              pp_title_line(fmt, &msg, sb, context->subject,
 +                            context->after_subject, encoding, need_8bit_cte);
  
        beginning_of_body = sb->len;
        if (fmt != CMIT_FMT_ONELINE)