summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-16 09:15:53 -0700
committerJunio C Hamano <gitster@pobox.com>2016-03-30 11:25:35 -0700
commit7cc13c717b52d3539e76f087d747f96d0d24a914 (patch)
tree1553f952b73abe8b904f6991e8f16eb8c34ba8dd
parent594730e980521310d88006d91f3f14ef5eff1e2b (diff)
downloadgit-7cc13c717b52d3539e76f087d747f96d0d24a914.tar.gz
pretty: expand tabs in indented logs to make things line up properly
A commit log message sometimes tries to line things up using tabs, assuming fixed-width font with the standard 8-place tab settings. Viewing such a commit however does not work well in "git log", as we indent the lines by prefixing 4 spaces in front of them. This should all line up: Column 1 Column 2 -------- -------- A B ABCD EFGH SPACES Instead of Tabs Even with multi-byte UTF8 characters: Column 1 Column 2 -------- -------- Ä B åäö 100 A Møøse once bit my sister.. Tab-expand the lines in "git log --expand-tabs" output before prefixing 4 spaces. This is based on the patch by Linus Torvalds, but at this step, we require an explicit command line option to enable the behaviour. Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--Documentation/pretty-options.txt5
-rw-r--r--commit.h1
-rw-r--r--log-tree.c1
-rw-r--r--pretty.c71
-rw-r--r--revision.c2
-rw-r--r--revision.h1
6 files changed, 79 insertions, 2 deletions
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 4b659ac1a6..d820653784 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -42,6 +42,11 @@ people using 80-column terminals.
verbatim; this means that invalid sequences in the original
commit may be copied to the output.
+--expand-tabs::
+ Perform a tab expansion (replace each tab with enough spaces
+ to fill to the next display column that is multiple of 8)
+ in the log message before showing it in the output.
+
ifndef::git-rev-list[]
--notes[=<ref>]::
Show the notes (see linkgit:git-notes[1]) that annotate the
diff --git a/commit.h b/commit.h
index 5d58be0017..a7ef682b5a 100644
--- a/commit.h
+++ b/commit.h
@@ -147,6 +147,7 @@ struct pretty_print_context {
int preserve_subject;
struct date_mode date_mode;
unsigned date_mode_explicit:1;
+ unsigned expand_tabs_in_log:1;
int need_8bit_cte;
char *notes_message;
struct reflog_walk_info *reflog_info;
diff --git a/log-tree.c b/log-tree.c
index 60f983934d..78a5381d0e 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -683,6 +683,7 @@ void show_log(struct rev_info *opt)
ctx.fmt = opt->commit_format;
ctx.mailmap = opt->mailmap;
ctx.color = opt->diffopt.use_color;
+ ctx.expand_tabs_in_log = opt->expand_tabs_in_log;
ctx.output_encoding = get_log_output_encoding();
if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
ctx.from_ident = &opt->from_ident;
diff --git a/pretty.c b/pretty.c
index 92b2870a7e..c8b075d91b 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1629,6 +1629,72 @@ void pp_title_line(struct pretty_print_context *pp,
strbuf_release(&title);
}
+static int pp_utf8_width(const char *start, const char *end)
+{
+ int width = 0;
+ size_t remain = end - start;
+
+ while (remain) {
+ int n = utf8_width(&start, &remain);
+ if (n < 0 || !start)
+ return -1;
+ width += n;
+ }
+ return width;
+}
+
+static void strbuf_add_tabexpand(struct strbuf *sb,
+ const char *line, int linelen)
+{
+ const char *tab;
+
+ while ((tab = memchr(line, '\t', linelen)) != NULL) {
+ int width = pp_utf8_width(line, tab);
+
+ /*
+ * If it wasn't well-formed utf8, or it
+ * had characters with badly defined
+ * width (control characters etc), just
+ * give up on trying to align things.
+ */
+ if (width < 0)
+ break;
+
+ /* Output the data .. */
+ strbuf_add(sb, line, tab - line);
+
+ /* .. and the de-tabified tab */
+ strbuf_addchars(sb, ' ', 8 - (width % 8));
+
+ /* Skip over the printed part .. */
+ linelen -= tab + 1 - line;
+ line = tab + 1;
+ }
+
+ /*
+ * Print out everything after the last tab without
+ * worrying about width - there's nothing more to
+ * align.
+ */
+ strbuf_add(sb, line, linelen);
+}
+
+/*
+ * pp_handle_indent() prints out the intendation, and
+ * the whole line (without the final newline), after
+ * de-tabifying.
+ */
+static void pp_handle_indent(struct pretty_print_context *pp,
+ struct strbuf *sb, int indent,
+ const char *line, int linelen)
+{
+ strbuf_addchars(sb, ' ', indent);
+ if (pp->expand_tabs_in_log)
+ strbuf_add_tabexpand(sb, line, linelen);
+ else
+ strbuf_add(sb, line, linelen);
+}
+
void pp_remainder(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
@@ -1653,8 +1719,9 @@ void pp_remainder(struct pretty_print_context *pp,
strbuf_grow(sb, linelen + indent + 20);
if (indent)
- strbuf_addchars(sb, ' ', indent);
- strbuf_add(sb, line, linelen);
+ pp_handle_indent(pp, sb, indent, line, linelen);
+ else
+ strbuf_add(sb, line, linelen);
strbuf_addch(sb, '\n');
}
}
diff --git a/revision.c b/revision.c
index df56fcea0e..e662230ff1 100644
--- a/revision.c
+++ b/revision.c
@@ -1915,6 +1915,8 @@ 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, "--expand-tabs")) {
+ revs->expand_tabs_in_log = 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 23857c0ed1..40797535fa 100644
--- a/revision.h
+++ b/revision.h
@@ -133,6 +133,7 @@ struct rev_info {
show_notes_given:1,
show_signature:1,
pretty_given:1,
+ expand_tabs_in_log:1,
abbrev_commit:1,
abbrev_commit_given:1,
zero_commit:1,