Fairly simpleminded line wrapping that makes commit messages readable if they weren’t wrapped by the committer. - Use strbuf_add_wrapped_text() to do the dirty work - Detect simple lists which begin with "+ ", "* ", or "- " and indent them appropriately (like this line) - Print lines which begin with whitespace as-is (e.g. code samples) Add --wrap[=<width>] and --no-wrap to commands that pretty-print commit messages, and add log.wrap and log.wrap.width configuration options. log.wrap defaults to never, and can be set to never/false, auto/true, or always. If auto, hijack want_color() to decide whether it’s appropriate to use line wrapping. (This is a little hacky, but as far as I can tell the conditions for auto color and auto wrapping are the same. Maybe it would make sense to rename want_color()?) log.wrap.width defaults to 80. Signed-off-by: Sidney San Martín <s@xxxxxxxxxxxx> --- I hope I’m doing this right! Consider this a first draft of the new feature I brought up a few weeks ago. Documentation/config.txt | 8 ++++ Documentation/pretty-options.txt | 14 +++++++ commit.h | 6 +++ log-tree.c | 1 + pretty.c | 71 +++++++++++++++++++++++++++++++++++++- revision.c | 10 +++++ revision.h | 3 ++ 7 files changed, 112 insertions(+), 1 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 6e63b59..b8c1a81 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1403,6 +1403,14 @@ log.showroot:: Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which normally hide the root commit will now show it. True by default. +log.wrap:: + Commit message wrapping. May be set to always, false (or never) or + auto (or true), in which case commit messages are only wrapped when + the output is to a terminal. Defaults to false. See linkgit:git-log[1]. + +log.wrap.width:: + Line width for commit message wrapping. Defaults to 80 characters. + mailmap.file:: The location of an augmenting mailmap file. The default mailmap, located in the root of the repository, is loaded diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt index 2a3dc86..7601a43 100644 --- a/Documentation/pretty-options.txt +++ b/Documentation/pretty-options.txt @@ -10,6 +10,20 @@ Note: you can specify the default pretty format in the repository configuration (see linkgit:git-config[1]). +--wrap[=<width>]:: + Word-wrap commit messages to the specified width, 80 characters + by default. Lines beginning with +, *, or - and a space, or with a + number followed by a period and a space, are interpreted as lists + and wrapped with a hanging indent. Lines beginning with whitespace + (e.g. code samples) are left as-is. ++ +Note: you can specify the default wrapping behavior in the repository +configuration (see linkgit:git-config[1]). + +--no-wrap:: + Turn off commit message wrapping. This is the default (unless + otherwise specified in the repository configuration). + --abbrev-commit:: Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix. Non default number of diff --git a/commit.h b/commit.h index 4df3978..1321666 100644 --- a/commit.h +++ b/commit.h @@ -86,6 +86,12 @@ struct pretty_print_context { int show_notes; struct reflog_walk_info *reflog_info; const char *output_encoding; + struct wrap_options { + unsigned int + width, + wrap:1, + wrap_given:1; + } wrap; }; struct userformat_want { diff --git a/log-tree.c b/log-tree.c index 319bd31..3dfa944 100644 --- a/log-tree.c +++ b/log-tree.c @@ -414,6 +414,7 @@ void show_log(struct rev_info *opt) opt->loginfo = NULL; ctx.show_notes = opt->show_notes; + ctx.wrap = opt->wrap; if (!opt->verbose_header) { graph_show_commit(opt->graph); diff --git a/pretty.c b/pretty.c index 1580299..133bc53 100644 --- a/pretty.c +++ b/pretty.c @@ -23,6 +23,10 @@ static size_t commit_formats_len; static size_t commit_formats_alloc; static struct cmt_fmt_map *find_commit_format(const char *sought); +static unsigned int wrap_configured = 0; +static unsigned int wrap = 0; +static unsigned int wrap_width = 80; + static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat) { free(user_format); @@ -172,6 +176,63 @@ void get_commit_format(const char *arg, struct rev_info *rev) } } +static int git_wrap_config(const char *name, const char *value, void *cb) +{ + wrap_configured = 1; + + if (prefixcmp(name, "log.wrap")) + return 0; + + if (name[8] == '\0') { + if (value && !strcmp(value, "always")) { + wrap = 1; + } else if (value && !strcmp(value, "never")) { + wrap = 0; + } else if (!value || !strcmp(value, "auto") || git_config_bool(name, value)) { + wrap = want_color(GIT_COLOR_AUTO); + } + } else if (name[8] == '.') { + name += 9; + if (!strcmp(name, "width")) { + wrap_width = git_config_int(name, value); + } + } + return 0; +} + +static unsigned int want_wrap(struct wrap_options options) +{ + if(!wrap_configured) + git_config(git_wrap_config, NULL); + return (options.wrap_given ? options.wrap : wrap); +} +static unsigned int get_wrap_width(struct wrap_options options) +{ + if(!wrap_configured) + git_config(git_wrap_config, NULL); + return options.width ? options.width : wrap_width; +} + +static int line_list_prefix(const char *line, int len) +{ + unsigned int numberLength = 0; + const char *pos = line; + if (len < 3) { + return 0; + } else if ((line[0] == '*' || line[0] == '+' || line[0] == '-') && line[1] == ' ') { + return 2; + } else { + while (pos - line < len && pos[0] >= '0' && pos[0] <= '9'){ + numberLength++; + pos++; + } + if (numberLength && pos - line + 1 < len && pos[0] == '.' && pos[1] == ' ') { + return numberLength + 2; + } + } + return 0; +} + /* * Generic support for pretty-printing the header */ @@ -1246,6 +1307,8 @@ void pp_remainder(const struct pretty_print_context *pp, struct strbuf *sb, int indent) { + unsigned int wrap = want_wrap(pp->wrap); + unsigned int width = get_wrap_width(pp->wrap); int first = 1; for (;;) { const char *line = *msg_p; @@ -1268,7 +1331,13 @@ void pp_remainder(const struct pretty_print_context *pp, memset(sb->buf + sb->len, ' ', indent); strbuf_setlen(sb, sb->len + indent); } - strbuf_add(sb, line, linelen); + if (wrap && linelen && line[0] != ' ' && line[0] != '\t') { + struct strbuf wrapped = STRBUF_INIT; + strbuf_add(&wrapped, line, linelen); + strbuf_add_wrapped_text(sb, wrapped.buf, 0, indent + line_list_prefix(line, linelen), width - indent); + } else { + strbuf_add(sb, line, linelen); + } strbuf_addch(sb, '\n'); } } diff --git a/revision.c b/revision.c index 8764dde..ca4b386 100644 --- a/revision.c +++ b/revision.c @@ -1465,6 +1465,16 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->verbose_header = 1; revs->pretty_given = 1; get_commit_format(arg+9, revs); + } else if (!strcmp(arg, "--wrap")) { + revs->wrap.wrap = 1; + revs->wrap.wrap_given = 1; + } else if (!prefixcmp(arg, "--wrap=")) { + revs->wrap.wrap = 1; + revs->wrap.wrap_given = 1; + revs->wrap.width = atoi(arg+7); + } else if (!prefixcmp(arg, "--no-wrap")) { + revs->wrap.wrap = 0; + revs->wrap.wrap_given = 1; } else if (!strcmp(arg, "--show-notes") || !strcmp(arg, "--notes")) { revs->show_notes = 1; revs->show_notes_given = 1; diff --git a/revision.h b/revision.h index 6aa53d1..f812685 100644 --- a/revision.h +++ b/revision.h @@ -117,6 +117,9 @@ struct rev_info { missing_newline:1, date_mode_explicit:1, preserve_subject:1; + + struct wrap_options wrap; + unsigned int disable_stdin:1; unsigned int leak_pending:1; -- 1.7.8.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html