git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 00/12] Layout control placeholders for pretty format
@ 2013-03-16  2:24 Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
                   ` (12 more replies)
  0 siblings, 13 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This series was ejected out of pu some time ago due to gcc warnings. I
did not have time to look at it (and it worked ok for me so it was not
a pressing matter). This re-roll should fix that.

For demonstration, try

git log --pretty='format:%C(auto)%h %<(80,trunc)%s%>>(10,ltrunc)%C(auto)%d%>(15,mtrunc)% an'

Nguyễn Thái Ngọc Duy (12):
  pretty-formats.txt: wrap long lines
  pretty: share code between format_decoration and show_decorations
  utf8.c: move display_mode_esc_sequence_len() for use by other functions
  utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  pretty: save commit encoding from logmsg_reencode if the caller needs it
  pretty: get the correct encoding for --pretty:format=%e
  utf8: keep NULs in reencode_string()
  pretty: two phase conversion for non utf-8 commits
  pretty: add %C(auto) for auto-coloring on the next placeholder
  pretty: support padding placeholders, %< %> and %><
  pretty: support truncating in %>, %< and %><
  pretty: support %>> that steal trailing spaces

 Documentation/pretty-formats.txt |  34 ++++-
 builtin/blame.c                  |   2 +-
 builtin/commit.c                 |   2 +-
 builtin/fast-export.c            |   3 +-
 builtin/mailinfo.c               |   3 +-
 commit.h                         |   1 +
 compat/precompose_utf8.c         |   2 +-
 log-tree.c                       |  60 +++++----
 log-tree.h                       |   3 +
 notes.c                          |   4 +-
 pretty.c                         | 282 ++++++++++++++++++++++++++++++++++-----
 revision.c                       |   2 +-
 sequencer.c                      |   5 +-
 t/t4207-log-decoration-colors.sh |   8 +-
 t/t6006-rev-list-format.sh       |  12 +-
 utf8.c                           | 104 +++++++++++----
 utf8.h                           |  14 +-
 17 files changed, 434 insertions(+), 107 deletions(-)

-- 
1.8.2.83.gc99314b

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH 01/12] pretty-formats.txt: wrap long lines
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 02/12] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 105f18a..66345d1 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -106,18 +106,22 @@ The placeholders are:
 - '%P': parent hashes
 - '%p': abbreviated parent hashes
 - '%an': author name
-- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1]
+  or linkgit:git-blame[1])
 - '%ae': author email
-- '%aE': author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aE': author email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ad': author date (format respects --date= option)
 - '%aD': author date, RFC2822 style
 - '%ar': author date, relative
 - '%at': author date, UNIX timestamp
 - '%ai': author date, ISO 8601 format
 - '%cn': committer name
-- '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cN': committer name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ce': committer email
-- '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cE': committer email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%cd': committer date
 - '%cD': committer date, RFC2822 style
 - '%cr': committer date, relative
@@ -136,9 +140,11 @@ The placeholders are:
 - '%gD': reflog selector, e.g., `refs/stash@{1}`
 - '%gd': shortened reflog selector, e.g., `stash@{1}`
 - '%gn': reflog identity name
-- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gN': reflog identity name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ge': reflog identity email
-- '%gE': reflog identity email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gE': reflog identity email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%gs': reflog subject
 - '%Cred': switch color to red
 - '%Cgreen': switch color to green
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 02/12] pretty: share code between format_decoration and show_decorations
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This also adds color support to format_decoration()

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 log-tree.c                       | 60 +++++++++++++++++++++++++---------------
 log-tree.h                       |  3 ++
 pretty.c                         | 19 +------------
 t/t4207-log-decoration-colors.sh |  8 +++---
 4 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/log-tree.c b/log-tree.c
index 5dc45c4..7467a1d 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -174,36 +174,50 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 	}
 }
 
-void show_decorations(struct rev_info *opt, struct commit *commit)
+void format_decoration(struct strbuf *sb,
+		       const struct commit *commit,
+		       int use_color)
 {
-	const char *prefix;
-	struct name_decoration *decoration;
+	const char *prefix = " (";
+	struct name_decoration *d;
 	const char *color_commit =
-		diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
+		diff_get_color(use_color, DIFF_COMMIT);
 	const char *color_reset =
-		decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
+		decorate_get_color(use_color, DECORATION_NONE);
+
+	load_ref_decorations(DECORATE_SHORT_REFS);
+	d = lookup_decoration(&name_decoration, &commit->object);
+	if (!d)
+		return;
+	while (d) {
+		strbuf_addstr(sb, color_commit);
+		strbuf_addstr(sb, prefix);
+		strbuf_addstr(sb, decorate_get_color(use_color, d->type));
+		if (d->type == DECORATION_REF_TAG)
+			strbuf_addstr(sb, "tag: ");
+		strbuf_addstr(sb, d->name);
+		strbuf_addstr(sb, color_reset);
+		prefix = ", ";
+		d = d->next;
+	}
+	if (prefix[0] == ',') {
+		strbuf_addstr(sb, color_commit);
+		strbuf_addch(sb, ')');
+		strbuf_addstr(sb, color_reset);
+	}
+}
+
+void show_decorations(struct rev_info *opt, struct commit *commit)
+{
+	struct strbuf sb = STRBUF_INIT;
 
 	if (opt->show_source && commit->util)
 		printf("\t%s", (char *) commit->util);
 	if (!opt->show_decorations)
 		return;
-	decoration = lookup_decoration(&name_decoration, &commit->object);
-	if (!decoration)
-		return;
-	prefix = " (";
-	while (decoration) {
-		printf("%s", prefix);
-		fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
-		      stdout);
-		if (decoration->type == DECORATION_REF_TAG)
-			fputs("tag: ", stdout);
-		printf("%s", decoration->name);
-		fputs(color_reset, stdout);
-		fputs(color_commit, stdout);
-		prefix = ", ";
-		decoration = decoration->next;
-	}
-	putchar(')');
+	format_decoration(&sb, commit, opt->diffopt.use_color);
+	fputs(sb.buf, stdout);
+	strbuf_release(&sb);
 }
 
 /*
@@ -625,8 +639,8 @@ void show_log(struct rev_info *opt)
 			printf(" (from %s)",
 			       find_unique_abbrev(parent->object.sha1,
 						  abbrev_commit));
+		fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
 		show_decorations(opt, commit);
-		printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
 		if (opt->commit_format == CMIT_FMT_ONELINE) {
 			putchar(' ');
 		} else {
diff --git a/log-tree.h b/log-tree.h
index 9140f48..e6a2da5 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -13,6 +13,9 @@ int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 int log_tree_opt_parse(struct rev_info *, const char **, int);
 void show_log(struct rev_info *opt);
+void format_decoration(struct strbuf *sb,
+		       const struct commit *commit,
+		       int use_color);
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 			     const char **subject_p,
diff --git a/pretty.c b/pretty.c
index eae57ad..79784be 100644
--- a/pretty.c
+++ b/pretty.c
@@ -898,23 +898,6 @@ static void parse_commit_message(struct format_commit_context *c)
 	c->commit_message_parsed = 1;
 }
 
-static void format_decoration(struct strbuf *sb, const struct commit *commit)
-{
-	struct name_decoration *d;
-	const char *prefix = " (";
-
-	load_ref_decorations(DECORATE_SHORT_REFS);
-	d = lookup_decoration(&name_decoration, &commit->object);
-	while (d) {
-		strbuf_addstr(sb, prefix);
-		prefix = ", ";
-		strbuf_addstr(sb, d->name);
-		d = d->next;
-	}
-	if (prefix[0] == ',')
-		strbuf_addch(sb, ')');
-}
-
 static void strbuf_wrap(struct strbuf *sb, size_t pos,
 			size_t width, size_t indent1, size_t indent2)
 {
@@ -1146,7 +1129,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 		strbuf_addstr(sb, get_revision_mark(NULL, commit));
 		return 1;
 	case 'd':
-		format_decoration(sb, commit);
+		format_decoration(sb, commit, 0);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index bbde31b..925f577 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -44,15 +44,15 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
  ${c_tag}tag: v1.0${c_reset}${c_commit},\
  ${c_tag}tag: B${c_reset}${c_commit},\
  ${c_branch}master${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\
  ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
  On master: Changes to A.t
-${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
 EOF
 
 # We want log to show all, but the second parent to refs/stash is irrelevant
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 02/12] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/utf8.c b/utf8.c
index 1087870..82c2ddf 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,6 +9,20 @@ struct interval {
   int last;
 };
 
+static size_t display_mode_esc_sequence_len(const char *s)
+{
+	const char *p = s;
+	if (*p++ != '\033')
+		return 0;
+	if (*p++ != '[')
+		return 0;
+	while (isdigit(*p) || *p == ';')
+		p++;
+	if (*p++ != 'm')
+		return 0;
+	return p - s;
+}
+
 /* auxiliary function for binary search in interval table */
 static int bisearch(ucs_char_t ucs, const struct interval *table, int max)
 {
@@ -303,20 +317,6 @@ static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
 	}
 }
 
-static size_t display_mode_esc_sequence_len(const char *s)
-{
-	const char *p = s;
-	if (*p++ != '\033')
-		return 0;
-	if (*p++ != '[')
-		return 0;
-	while (isdigit(*p) || *p == ';')
-		p++;
-	if (*p++ != 'm')
-		return 0;
-	return p - s;
-}
-
 /*
  * Wrap the text, if necessary. The variable indent is the indent for the
  * first line, indent2 is the indent for all other lines.
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 20 ++++++++++++++------
 utf8.h |  1 +
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/utf8.c b/utf8.c
index 82c2ddf..38322a1 100644
--- a/utf8.c
+++ b/utf8.c
@@ -266,18 +266,26 @@ int utf8_width(const char **start, size_t *remainder_p)
  * string, assuming that the string is utf8.  Returns strlen() instead
  * if the string does not look like a valid utf8 string.
  */
-int utf8_strwidth(const char *string)
+int utf8_strnwidth(const char *string, int len, int skip_ansi)
 {
 	int width = 0;
 	const char *orig = string;
 
-	while (1) {
-		if (!string)
-			return strlen(orig);
-		if (!*string)
-			return width;
+	if (len == -1)
+		len = strlen(string);
+	while (string && string < orig + len) {
+		int skip;
+		while (skip_ansi &&
+		       (skip = display_mode_esc_sequence_len(string)))
+			string += skip;
 		width += utf8_width(&string, NULL);
 	}
+	return string ? width : len;
+}
+
+int utf8_strwidth(const char *string)
+{
+	return utf8_strnwidth(string, -1, 0);
 }
 
 int is_utf8(const char *text)
diff --git a/utf8.h b/utf8.h
index 501b2bd..a556932 100644
--- a/utf8.h
+++ b/utf8.h
@@ -4,6 +4,7 @@
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
 int utf8_width(const char **start, size_t *remainder_p);
+int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
 int is_utf8(const char *text);
 int is_encoding_utf8(const char *name);
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (3 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-17  8:57   ` Eric Sunshine
  2013-03-16  2:24 ` [PATCH 06/12] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

The commit encoding is parsed by logmsg_reencode, there's no need for
the caller to re-parse it again. The reencoded message now have the
new encoding, not the original one. The caller would need to read
commit object again before parsing.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/blame.c  |  2 +-
 builtin/commit.c |  2 +-
 commit.h         |  1 +
 pretty.c         | 16 ++++++++++++----
 revision.c       |  2 +-
 5 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/builtin/blame.c b/builtin/blame.c
index 86100e9..104a948 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1425,7 +1425,7 @@ static void get_commit_info(struct commit *commit,
 	commit_info_init(ret);
 
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 	get_ac_line(message, "\nauthor ",
 		    &ret->author, &ret->author_mail,
 		    &ret->author_time, &ret->author_tz);
diff --git a/builtin/commit.c b/builtin/commit.c
index 3348aa1..beead44 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -953,7 +953,7 @@ static const char *read_commit_message(const char *name)
 	if (!commit)
 		die(_("could not lookup commit %s"), name);
 	out_enc = get_commit_output_encoding();
-	return logmsg_reencode(commit, out_enc);
+	return logmsg_reencode(commit, NULL, out_enc);
 }
 
 static int parse_and_validate_options(int argc, const char *argv[],
diff --git a/commit.h b/commit.h
index 4138bb4..085349a 100644
--- a/commit.h
+++ b/commit.h
@@ -100,6 +100,7 @@ struct userformat_want {
 extern int has_non_ascii(const char *text);
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern char *logmsg_reencode(const struct commit *commit,
+			     char **commit_encoding,
 			     const char *output_encoding);
 extern void logmsg_free(char *msg, const struct commit *commit);
 extern void get_commit_format(const char *arg, struct rev_info *);
diff --git a/pretty.c b/pretty.c
index 79784be..ab5d70f 100644
--- a/pretty.c
+++ b/pretty.c
@@ -584,6 +584,7 @@ static char *replace_encoding_header(char *buf, const char *encoding)
 }
 
 char *logmsg_reencode(const struct commit *commit,
+		      char **commit_encoding,
 		      const char *output_encoding)
 {
 	static const char *utf8 = "UTF-8";
@@ -605,9 +606,15 @@ char *logmsg_reencode(const struct commit *commit,
 			    sha1_to_hex(commit->object.sha1), typename(type));
 	}
 
-	if (!output_encoding || !*output_encoding)
+	if (!output_encoding || !*output_encoding) {
+		if (commit_encoding)
+			*commit_encoding =
+				get_header(commit, msg, "encoding");
 		return msg;
+	}
 	encoding = get_header(commit, msg, "encoding");
+	if (commit_encoding)
+		*commit_encoding = encoding;
 	use_encoding = encoding ? encoding : utf8;
 	if (same_encoding(use_encoding, output_encoding)) {
 		/*
@@ -648,7 +655,8 @@ char *logmsg_reencode(const struct commit *commit,
 	if (out)
 		out = replace_encoding_header(out, output_encoding);
 
-	free(encoding);
+	if (!commit_encoding)
+		free(encoding);
 	/*
 	 * If the re-encoding failed, out might be NULL here; in that
 	 * case we just return the commit message verbatim.
@@ -1313,7 +1321,7 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, output_enc);
+	context.message = logmsg_reencode(commit, NULL, output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
@@ -1476,7 +1484,7 @@ void pretty_print_commit(const struct pretty_print_context *pp,
 	}
 
 	encoding = get_log_output_encoding();
-	msg = reencoded = logmsg_reencode(commit, encoding);
+	msg = reencoded = logmsg_reencode(commit, NULL, encoding);
 
 	if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
 		indent = 0;
diff --git a/revision.c b/revision.c
index ef60205..c6ff560 100644
--- a/revision.c
+++ b/revision.c
@@ -2290,7 +2290,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 	 * in it.
 	 */
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 
 	/* Copy the commit to temporary if we are using "fake" headers */
 	if (buf.len)
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 06/12] pretty: get the correct encoding for --pretty:format=%e
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (4 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 07/12] utf8: keep NULs in reencode_string() Nguyễn Thái Ngọc Duy
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

parse_commit_header() provides the commit encoding for '%e' and it
reads it from the re-encoded message, which contains the new encoding,
not the original one in the commit object.

Get the commit encoding from logmsg_reencode() instead.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/pretty.c b/pretty.c
index ab5d70f..e2241e5 100644
--- a/pretty.c
+++ b/pretty.c
@@ -771,12 +771,12 @@ struct format_commit_context {
 		char *signer;
 	} signature;
 	char *message;
+	char *commit_encoding;
 	size_t width, indent1, indent2;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
 	struct chunk committer;
-	struct chunk encoding;
 	size_t message_off;
 	size_t subject_off;
 	size_t body_off;
@@ -823,9 +823,6 @@ static void parse_commit_header(struct format_commit_context *context)
 		} else if (!prefixcmp(msg + i, "committer ")) {
 			context->committer.off = i + 10;
 			context->committer.len = eol - i - 10;
-		} else if (!prefixcmp(msg + i, "encoding ")) {
-			context->encoding.off = i + 9;
-			context->encoding.len = eol - i - 9;
 		}
 		i = eol;
 	}
@@ -1210,7 +1207,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 				   msg + c->committer.off, c->committer.len,
 				   c->pretty_ctx->date_mode);
 	case 'e':	/* encoding */
-		strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
+		if (c->commit_encoding)
+			strbuf_addstr(sb, c->commit_encoding);
 		return 1;
 	case 'B':	/* raw body */
 		/* message_off is always left at the initial newline */
@@ -1321,11 +1319,14 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, NULL, output_enc);
+	context.message = logmsg_reencode(commit,
+					  &context.commit_encoding,
+					  output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature.gpg_output);
 	free(context.signature.signer);
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 07/12] utf8: keep NULs in reencode_string()
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (5 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 06/12] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 08/12] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

reencode_string() will be used in the next patch for re-encoding
pretty output, which can contain NULs.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/fast-export.c    |  3 ++-
 builtin/mailinfo.c       |  3 ++-
 compat/precompose_utf8.c |  2 +-
 notes.c                  |  4 +++-
 pretty.c                 |  3 ++-
 sequencer.c              |  5 +++--
 utf8.c                   | 10 +++++++---
 utf8.h                   | 10 +++++++---
 8 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 77dffd1..7ba9f3b 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -316,7 +316,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
 
 	mark_next_object(&commit->object);
 	if (!is_encoding_utf8(encoding))
-		reencoded = reencode_string(message, "UTF-8", encoding);
+		reencoded = reencode_string(message, strlen(message),
+					    "UTF-8", encoding, NULL);
 	if (!commit->parents)
 		printf("reset %s\n", (const char*)commit->util);
 	printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s",
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 24a772d..129e7dc 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -486,7 +486,8 @@ static void convert_to_utf8(struct strbuf *line, const char *charset)
 
 	if (same_encoding(metainfo_charset, charset))
 		return;
-	out = reencode_string(line->buf, metainfo_charset, charset);
+	out = reencode_string(line->buf, line->len,
+			      metainfo_charset, charset, NULL);
 	if (!out)
 		die("cannot convert from %s to %s",
 		    charset, metainfo_charset);
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 8cf5955..d9203d0 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -78,7 +78,7 @@ void precompose_argv(int argc, const char **argv)
 		size_t namelen;
 		oldarg = argv[i];
 		if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
-			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
+			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
 			if (newarg)
 				argv[i] = newarg;
 		}
diff --git a/notes.c b/notes.c
index f63fd57..4ae3b25 100644
--- a/notes.c
+++ b/notes.c
@@ -1222,7 +1222,9 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
 
 	if (output_encoding && *output_encoding &&
 	    !is_encoding_utf8(output_encoding)) {
-		char *reencoded = reencode_string(msg, output_encoding, utf8);
+		char *reencoded = reencode_string(msg, strlen(msg),
+						  output_encoding, utf8,
+						  NULL);
 		if (reencoded) {
 			free(msg);
 			msg = reencoded;
diff --git a/pretty.c b/pretty.c
index e2241e5..092dd1d 100644
--- a/pretty.c
+++ b/pretty.c
@@ -643,7 +643,8 @@ char *logmsg_reencode(const struct commit *commit,
 		 * this point, we are done with msg. If we allocated a fresh
 		 * copy, we can free it.
 		 */
-		out = reencode_string(msg, output_encoding, use_encoding);
+		out = reencode_string(msg, strlen(msg),
+				      output_encoding, use_encoding, NULL);
 		if (out && msg != commit->buffer)
 			free(msg);
 	}
diff --git a/sequencer.c b/sequencer.c
index aef5e8a..bf15531 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -61,8 +61,9 @@ static int get_message(struct commit *commit, struct commit_message *out)
 	out->reencoded_message = NULL;
 	out->message = commit->buffer;
 	if (same_encoding(encoding, git_commit_encoding))
-		out->reencoded_message = reencode_string(commit->buffer,
-					git_commit_encoding, encoding);
+		out->reencoded_message =
+			reencode_string(commit->buffer, strlen(commit->buffer),
+					git_commit_encoding, encoding, NULL);
 	if (out->reencoded_message)
 		out->message = out->reencoded_message;
 
diff --git a/utf8.c b/utf8.c
index 38322a1..9d98043 100644
--- a/utf8.c
+++ b/utf8.c
@@ -468,7 +468,7 @@ int utf8_fprintf(FILE *stream, const char *format, ...)
 #else
 	typedef char * iconv_ibp;
 #endif
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv, int *outsz_p)
 {
 	size_t outsz, outalloc;
 	char *out, *outpos;
@@ -502,13 +502,17 @@ char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
 		}
 		else {
 			*outpos = '\0';
+			if (outsz_p)
+				*outsz_p = outpos - out;
 			break;
 		}
 	}
 	return out;
 }
 
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+char *reencode_string(const char *in, int insz,
+		      const char *out_encoding, const char *in_encoding,
+		      int *outsz)
 {
 	iconv_t conv;
 	char *out;
@@ -518,7 +522,7 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
 	conv = iconv_open(out_encoding, in_encoding);
 	if (conv == (iconv_t) -1)
 		return NULL;
-	out = reencode_string_iconv(in, strlen(in), conv);
+	out = reencode_string_iconv(in, insz, conv, outsz);
 	iconv_close(conv);
 	return out;
 }
diff --git a/utf8.h b/utf8.h
index a556932..99db3e0 100644
--- a/utf8.h
+++ b/utf8.h
@@ -17,10 +17,14 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
 
 #ifndef NO_ICONV
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
+char *reencode_string_iconv(const char *in, size_t insz,
+			    iconv_t conv, int *outsz);
+char *reencode_string(const char *in, int insz,
+		      const char *out_encoding,
+		      const char *in_encoding,
+		      int *outsz);
 #else
-#define reencode_string(a,b,c) NULL
+#define reencode_string(a,b,c,d) NULL
 #endif
 
 #endif
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 08/12] pretty: two phase conversion for non utf-8 commits
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (6 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 07/12] utf8: keep NULs in reencode_string() Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  2:24 ` [PATCH 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 4644 bytes --]

Always assume format_commit_item() takes an utf-8 string for string
handling simplicity (we can handle utf-8 strings, but can't with other
encodings).

If commit message is in non-utf8, or output encoding is not, then the
commit is first converted to utf-8, processed, then output converted
to output encoding. This of course only works with encodings that are
compatible with Unicode.

This also fixes the iso8859-1 test in t6006. It's supposed to create
an iso8859-1 commit, but the commit content in t6006 is in UTF-8.
t6006 is now converted back in UTF-8 (the downside is we can't put
utf-8 strings there anymore).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c                   | 24 ++++++++++++++++++++++--
 t/t6006-rev-list-format.sh | 12 ++++++------
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/pretty.c b/pretty.c
index 092dd1d..3f4809a 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1003,7 +1003,8 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
-static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
+				const char *placeholder,
 				void *context)
 {
 	struct format_commit_context *c = context;
@@ -1235,7 +1236,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 	return 0;	/* unknown placeholder */
 }
 
-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
+				 const char *placeholder,
 				 void *context)
 {
 	int consumed;
@@ -1315,6 +1317,7 @@ void format_commit_message(const struct commit *commit,
 {
 	struct format_commit_context context;
 	const char *output_enc = pretty_ctx->output_encoding;
+	const char *utf8 = "UTF-8";
 
 	memset(&context, 0, sizeof(context));
 	context.commit = commit;
@@ -1327,6 +1330,23 @@ void format_commit_message(const struct commit *commit,
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	if (output_enc) {
+		if (same_encoding(utf8, output_enc))
+			output_enc = NULL;
+	} else {
+		if (context.commit_encoding &&
+		    !same_encoding(context.commit_encoding, utf8))
+			output_enc = context.commit_encoding;
+	}
+
+	if (output_enc) {
+		int outsz;
+		char *out = reencode_string(sb->buf, sb->len,
+					    output_enc, utf8, &outsz);
+		if (out)
+			strbuf_attach(sb, out, outsz, outsz + 1);
+	}
+
 	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature.gpg_output);
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 3fc3b74..0393c9f 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -184,7 +184,7 @@ Test printing of complex bodies
 
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 EOF
 test_expect_success 'setup complex body' '
 git config i18n.commitencoding iso8859-1 &&
@@ -192,14 +192,14 @@ git config i18n.commitencoding iso8859-1 &&
 '
 
 test_format complex-encoding %e <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 iso8859-1
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_format complex-subject %s <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 Test printing of complex bodies
 commit 131a310eb913d107dd3c09a65d1651175898735d
 changed foo
@@ -208,17 +208,17 @@ added foo
 EOF
 
 test_format complex-body %b <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_expect_success '%x00 shows NUL' '
-	echo  >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+	echo  >expect commit 1ed88da4a5b5ed8c449114ac131efc62178734c3 &&
 	echo >>expect fooQbar &&
 	git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
 	nul_to_q <actual.nul >actual &&
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (7 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 08/12] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-17  8:59   ` Eric Sunshine
  2013-03-16  2:24 ` [PATCH 10/12] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is not simply convenient over $C(auto,xxx). Some placeholders
(actually only one, %d) do multi coloring and we can't emit a multiple
colors with %C(auto,xxx).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  3 ++-
 pretty.c                         | 15 +++++++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 66345d1..8734224 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -154,7 +154,8 @@ The placeholders are:
   adding `auto,` at the beginning will emit color only when colors are
   enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
   respecting the `auto` settings of the former if we are going to a
-  terminal)
+  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
+  on the following placeholder.
 - '%m': left, right or boundary mark
 - '%n': newline
 - '%%': a raw '%'
diff --git a/pretty.c b/pretty.c
index 3f4809a..c333fd6 100644
--- a/pretty.c
+++ b/pretty.c
@@ -774,6 +774,7 @@ struct format_commit_context {
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
+	int auto_color;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -1011,7 +1012,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	const struct commit *commit = c->commit;
 	const char *msg = c->message;
 	struct commit_list *p;
-	int h1, h2;
+	int h1, h2, use_color;
 
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
@@ -1023,6 +1024,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 
 			if (!end)
 				return 0;
+			if (!prefixcmp(begin, "auto)")) {
+				c->auto_color = 1;
+				return end - placeholder + 1;
+			}
 			if (!prefixcmp(begin, "auto,")) {
 				if (!want_color(c->pretty_ctx->color))
 					return end - placeholder + 1;
@@ -1090,16 +1095,22 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	/* these depend on the commit */
 	if (!commit->object.parsed)
 		parse_object(commit->object.sha1);
+	use_color = c->auto_color;
+	c->auto_color = 0;
 
 	switch (placeholder[0]) {
 	case 'H':		/* commit hash */
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_COMMIT));
 		strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_RESET));
 		return 1;
 	case 'h':		/* abbreviated commit hash */
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_COMMIT));
 		if (add_again(sb, &c->abbrev_commit_hash))
 			return 1;
 		strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
 						     c->pretty_ctx->abbrev));
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_RESET));
 		c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
 		return 1;
 	case 'T':		/* tree hash */
@@ -1136,7 +1147,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 		strbuf_addstr(sb, get_revision_mark(NULL, commit));
 		return 1;
 	case 'd':
-		format_decoration(sb, commit, 0);
+		format_decoration(sb, commit, use_color);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 10/12] pretty: support padding placeholders, %< %> and %><
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (8 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-17  9:03   ` Eric Sunshine
  2013-03-16  2:24 ` [PATCH 11/12] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Either %<, %> or %<> standing before a placeholder specifies how many
columns (at least as the placeholder can exceed it) it takes. Each
differs on how spaces are padded:

  %< pads on the right (aka left alignment)
  %> pads on the left (aka right alignment)
  %>< pads both ways equally (aka centered)

The (<N>) follows them, e.g. `%<(100)', to specify the number of
columns the next placeholder takes.

However, if '|' stands before (<N>), e.g. `%>|(100)', then the number
of columns is calculated so that it reaches the Nth column on screen.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |   8 +++
 pretty.c                         | 117 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 8734224..87ca2c4 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -162,6 +162,14 @@ The placeholders are:
 - '%x00': print a byte from a hex code
 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
+- '%<(<N>)': make the next placeholder take at least N columns,
+  padding spaces on the right if necessary
+- '%<|(<N>)': make the next placeholder take at least until Nth
+  columns, padding spaces on the right if necessary
+- '%>(<N>)', '%>|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
+  respectively, but padding spaces on the left
+- '%><(<N>)', '%><|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
+  respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
 revision traversal engine. For example, the `%g*` reflog options will
diff --git a/pretty.c b/pretty.c
index c333fd6..233d69c 100644
--- a/pretty.c
+++ b/pretty.c
@@ -760,12 +760,20 @@ struct chunk {
 	size_t len;
 };
 
+enum flush_type {
+	no_flush,
+	flush_right,
+	flush_left,
+	flush_both
+};
+
 struct format_commit_context {
 	const struct commit *commit;
 	const struct pretty_print_context *pretty_ctx;
 	unsigned commit_header_parsed:1;
 	unsigned commit_message_parsed:1;
 	unsigned commit_signature_parsed:1;
+	enum flush_type flush_type;
 	struct {
 		char *gpg_output;
 		char good_bad;
@@ -775,6 +783,7 @@ struct format_commit_context {
 	char *commit_encoding;
 	size_t width, indent1, indent2;
 	int auto_color;
+	int padding;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -1004,6 +1013,52 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
+static size_t parse_padding_placeholder(struct strbuf *sb,
+					const char *placeholder,
+					struct format_commit_context *c)
+{
+	const char *ch = placeholder;
+	enum flush_type flush_type;
+	int to_column = 0;
+
+	switch (*ch++) {
+	case '<':
+		flush_type = flush_right;
+		break;
+	case '>':
+		if (*ch == '<') {
+			flush_type = flush_both;
+			ch++;
+		} else
+			flush_type = flush_left;
+		break;
+	default:
+		return 0;
+	}
+
+	/* the next value means "wide enough to that column" */
+	if (*ch == '|') {
+		to_column = 1;
+		ch++;
+	}
+
+	if (*ch == '(') {
+		const char *start = ch + 1;
+		const char *end = strchr(start, ')');
+		char *next;
+		int width;
+		if (!end || end == start)
+			return 0;
+		width = strtoul(start, &next, 10);
+		if (next == start || width == 0)
+			return 0;
+		c->padding = to_column ? -width : width;
+		c->flush_type = flush_type;
+		return end - placeholder + 1;
+	}
+	return 0;
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 				const char *placeholder,
 				void *context)
@@ -1090,6 +1145,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 			return end - placeholder + 1;
 		} else
 			return 0;
+
+	case '<':
+	case '>':
+		return parse_padding_placeholder(sb, placeholder, c);
 	}
 
 	/* these depend on the commit */
@@ -1247,6 +1306,59 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	return 0;	/* unknown placeholder */
 }
 
+static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
+				    const char *placeholder,
+				    struct format_commit_context *c)
+{
+	struct strbuf local_sb = STRBUF_INIT;
+	int total_consumed = 0, len, padding = c->padding;
+	if (padding < 0) {
+		const char *start = strrchr(sb->buf, '\n');
+		int occupied;
+		if (!start)
+			start = sb->buf;
+		occupied = utf8_strnwidth(start, -1, 1);
+		padding = (-padding) - occupied;
+	}
+	while (1) {
+		int modifier = *placeholder == 'C';
+		int consumed = format_commit_one(&local_sb, placeholder, c);
+		total_consumed += consumed;
+
+		if (!modifier)
+			break;
+
+		placeholder += consumed;
+		if (*placeholder != '%')
+			break;
+		placeholder++;
+		total_consumed++;
+	}
+	len = utf8_strnwidth(local_sb.buf, -1, 1);
+	if (len > padding)
+		strbuf_addstr(sb, local_sb.buf);
+	else {
+		int sb_len = sb->len, offset = 0;
+		if (c->flush_type == flush_left)
+			offset = padding - len;
+		else if (c->flush_type == flush_both)
+			offset = (padding - len) / 2;
+		/*
+		 * we calculate padding in columns, now
+		 * convert it back to chars
+		 */
+		padding = padding - len + local_sb.len;
+		strbuf_grow(sb, padding);
+		strbuf_setlen(sb, sb_len + padding);
+		memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+		memcpy(sb->buf + sb_len + offset, local_sb.buf,
+		       local_sb.len);
+	}
+	strbuf_release(&local_sb);
+	c->flush_type = no_flush;
+	return total_consumed;
+}
+
 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 				 const char *placeholder,
 				 void *context)
@@ -1277,7 +1389,10 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 		placeholder++;
 
 	orig_len = sb->len;
-	consumed = format_commit_one(sb, placeholder, context);
+	if (((struct format_commit_context *)context)->flush_type != no_flush)
+		consumed = format_and_pad_commit(sb, placeholder, context);
+	else
+		consumed = format_commit_one(sb, placeholder, context);
 	if (magic == NO_MAGIC)
 		return consumed;
 
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 11/12] pretty: support truncating in %>, %< and %><
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (9 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 10/12] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-16  9:04   ` Paul Campbell
  2013-03-16  2:24 ` [PATCH 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, 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 <pclouds@gmail.com>
---
 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([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
-- '%<(<N>)': make the next placeholder take at least N columns,
-  padding spaces on the right if necessary
+- '%<(<N>[,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.
 - '%<|(<N>)': make the next placeholder take at least until Nth
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
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 {
 		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;
+			}
+			w += n;
+			continue;
+		}
+		memcpy(dst, old, src - old);
+		dst += src - old;
+		w += n;
+	}
+	strbuf_setlen(&sb_dst, dst - sb_dst.buf);
+	strbuf_attach(sb_src, strbuf_detach(&sb_dst, NULL),
+		      sb_dst.len, sb_dst.alloc);
+}
+
 int is_encoding_utf8(const char *name)
 {
 	if (!name)
diff --git a/utf8.h b/utf8.h
index 99db3e0..faf2f91 100644
--- a/utf8.h
+++ b/utf8.h
@@ -15,6 +15,8 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
 		const char *text, int indent, int indent2, int width);
 void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
+void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
+			 const char *subst);
 
 #ifndef NO_ICONV
 char *reencode_string_iconv(const char *in, size_t insz,
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH 12/12] pretty: support %>> that steal trailing spaces
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (10 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 11/12] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
@ 2013-03-16  2:24 ` Nguyễn Thái Ngọc Duy
  2013-03-17  9:06   ` Eric Sunshine
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-16  2:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is pretty useful in `%<(100)%s%Cred%>(20)% an' where %s does not
use up all 100 columns and %an needs more than 20 columns. By
replacing %>(20) with %>>(20), %an can steal spaces from %s.

%>> understands escape sequences, so %Cred does not stop it from
stealing spaces in %<(100).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  5 ++++-
 pretty.c                         | 34 ++++++++++++++++++++++++++++++++++
 utf8.c                           |  2 +-
 utf8.h                           |  1 +
 4 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 17f82f4..036c14a 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -170,7 +170,10 @@ The placeholders are:
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
   respectively, but padding spaces on the left
-- '%><(<N>)', '%><|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
+- '%>>(<N>)', '%>>|(<N>)': similar to '%>(<N<)', '%>|(<N<)'
+  respectively, except that if the next placeholder takes more spaces
+  than given and there are spaces on its left, use those spaces
+- '%><(<N>)', '%><|(<N>)': similar to '% <(<N<)', '%<|(<N<)'
   respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
diff --git a/pretty.c b/pretty.c
index 29384b5..892274d 100644
--- a/pretty.c
+++ b/pretty.c
@@ -764,6 +764,7 @@ enum flush_type {
 	no_flush,
 	flush_right,
 	flush_left,
+	flush_left_and_steal,
 	flush_both
 };
 
@@ -1037,6 +1038,9 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
 		if (*ch == '<') {
 			flush_type = flush_both;
 			ch++;
+		} else if (*ch == '>') {
+			flush_type = flush_left_and_steal;
+			ch++;
 		} else
 			flush_type = flush_left;
 		break;
@@ -1360,6 +1364,36 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
 		total_consumed++;
 	}
 	len = utf8_strnwidth(local_sb.buf, -1, 1);
+
+	if (c->flush_type == flush_left_and_steal) {
+		const char *ch = sb->buf + sb->len - 1;
+		while (len > padding && ch > sb->buf) {
+			const char *p;
+			if (*ch == ' ') {
+				ch--;
+				padding++;
+				continue;
+			}
+			/* check for trailing ansi sequences */
+			if (*ch != 'm')
+				break;
+			p = ch - 1;
+			while (ch - p < 10 && *p != '\033')
+				p--;
+			if (*p != '\033' ||
+			    ch + 1 - p != display_mode_esc_sequence_len(p))
+				break;
+			/*
+			 * got a good ansi sequence, put it back to
+			 * local_sb as we're cutting sb
+			 */
+			strbuf_insert(&local_sb, 0, p, ch + 1 - p);
+			ch = p - 1;
+		}
+		strbuf_setlen(sb, ch + 1 - sb->buf);
+		c->flush_type = flush_left;
+	}
+
 	if (len > padding) {
 		switch (c->truncate) {
 		case trunc_left:
diff --git a/utf8.c b/utf8.c
index 766df80..414ae49 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,7 +9,7 @@ struct interval {
   int last;
 };
 
-static size_t display_mode_esc_sequence_len(const char *s)
+size_t display_mode_esc_sequence_len(const char *s)
 {
 	const char *p = s;
 	if (*p++ != '\033')
diff --git a/utf8.h b/utf8.h
index faf2f91..e913edb 100644
--- a/utf8.h
+++ b/utf8.h
@@ -3,6 +3,7 @@
 
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
+size_t display_mode_esc_sequence_len(const char *s);
 int utf8_width(const char **start, size_t *remainder_p);
 int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* Re: [PATCH 11/12] pretty: support truncating in %>, %< and %><
  2013-03-16  2:24 ` [PATCH 11/12] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
@ 2013-03-16  9:04   ` Paul Campbell
  0 siblings, 0 replies; 83+ messages in thread
From: Paul Campbell @ 2013-03-16  9:04 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano

On Sat, Mar 16, 2013 at 2:24 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> 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 <pclouds@gmail.com>
> ---

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([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
>    linkgit:git-shortlog[1].
> -- '%<(<N>)': make the next placeholder take at least N columns,
> -  padding spaces on the right if necessary
> +- '%<(<N>[,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.
>  - '%<|(<N>)': make the next placeholder take at least until Nth
>    columns, padding spaces on the right if necessary
>  - '%>(<N>)', '%>|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
> 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 {
>                 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;
> +                       }
> +                       w += n;
> +                       continue;
> +               }
> +               memcpy(dst, old, src - old);
> +               dst += src - old;
> +               w += n;
> +       }
> +       strbuf_setlen(&sb_dst, dst - sb_dst.buf);
> +       strbuf_attach(sb_src, strbuf_detach(&sb_dst, NULL),
> +                     sb_dst.len, sb_dst.alloc);
> +}
> +
>  int is_encoding_utf8(const char *name)
>  {
>         if (!name)
> diff --git a/utf8.h b/utf8.h
> index 99db3e0..faf2f91 100644
> --- a/utf8.h
> +++ b/utf8.h
> @@ -15,6 +15,8 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
>                 const char *text, int indent, int indent2, int width);
>  void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
>                              int indent, int indent2, int width);
> +void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
> +                        const char *subst);
>
>  #ifndef NO_ICONV
>  char *reencode_string_iconv(const char *in, size_t insz,
> --
> 1.8.2.83.gc99314b
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Paul [W] Campbell

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it
  2013-03-16  2:24 ` [PATCH 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
@ 2013-03-17  8:57   ` Eric Sunshine
  0 siblings, 0 replies; 83+ messages in thread
From: Eric Sunshine @ 2013-03-17  8:57 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano

On Fri, Mar 15, 2013 at 10:24 PM, Nguyễn Thái Ngọc Duy
<pclouds@gmail.com> wrote:
> The commit encoding is parsed by logmsg_reencode, there's no need for
> the caller to re-parse it again. The reencoded message now have the

s/have/has/

> new encoding, not the original one. The caller would need to read
> commit object again before parsing.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder
  2013-03-16  2:24 ` [PATCH 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
@ 2013-03-17  8:59   ` Eric Sunshine
  0 siblings, 0 replies; 83+ messages in thread
From: Eric Sunshine @ 2013-03-17  8:59 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano

On Fri, Mar 15, 2013 at 10:24 PM, Nguyễn Thái Ngọc Duy
<pclouds@gmail.com> wrote:
> This is not simply convenient over $C(auto,xxx). Some placeholders

s/\$/%/

> (actually only one, %d) do multi coloring and we can't emit a multiple
> colors with %C(auto,xxx).
>
> diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
> index 66345d1..8734224 100644
> --- a/Documentation/pretty-formats.txt
> +++ b/Documentation/pretty-formats.txt
> @@ -154,7 +154,8 @@ The placeholders are:
>    adding `auto,` at the beginning will emit color only when colors are
>    enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
>    respecting the `auto` settings of the former if we are going to a
> -  terminal)
> +  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring

s/auto coloring/auto-coloring/

> +  on the following placeholder.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 10/12] pretty: support padding placeholders, %< %> and %><
  2013-03-16  2:24 ` [PATCH 10/12] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
@ 2013-03-17  9:03   ` Eric Sunshine
  0 siblings, 0 replies; 83+ messages in thread
From: Eric Sunshine @ 2013-03-17  9:03 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano

On Fri, Mar 15, 2013 at 10:24 PM, Nguyễn Thái Ngọc Duy
<pclouds@gmail.com> wrote:
> Either %<, %> or %<> standing before a placeholder specifies how many

s/%<>/%></

> diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
> index 8734224..87ca2c4 100644
> --- a/Documentation/pretty-formats.txt
> +++ b/Documentation/pretty-formats.txt
> @@ -162,6 +162,14 @@ The placeholders are:
>  - '%x00': print a byte from a hex code
>  - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
>    linkgit:git-shortlog[1].
> +- '%<(<N>)': make the next placeholder take at least N columns,
> +  padding spaces on the right if necessary
> +- '%<|(<N>)': make the next placeholder take at least until Nth
> +  columns, padding spaces on the right if necessary
> +- '%>(<N>)', '%>|(<N>)': similar to '%<(<N<)', '%<|(<N<)'

s/<N</<N>/g

> +  respectively, but padding spaces on the left
> +- '%><(<N>)', '%><|(<N>)': similar to '%<(<N<)', '%<|(<N<)'

Ditto: s/<N</<N>/g

> +  respectively, but padding both sides (i.e. the text is centered)

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 12/12] pretty: support %>> that steal trailing spaces
  2013-03-16  2:24 ` [PATCH 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
@ 2013-03-17  9:06   ` Eric Sunshine
  2013-03-30  9:31     ` Duy Nguyen
  0 siblings, 1 reply; 83+ messages in thread
From: Eric Sunshine @ 2013-03-17  9:06 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano

On Fri, Mar 15, 2013 at 10:24 PM, Nguyễn Thái Ngọc Duy
<pclouds@gmail.com> wrote:
> This is pretty useful in `%<(100)%s%Cred%>(20)% an' where %s does not

s/% an/%an/

> use up all 100 columns and %an needs more than 20 columns. By
> replacing %>(20) with %>>(20), %an can steal spaces from %s.
>
> diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
> index 17f82f4..036c14a 100644
> --- a/Documentation/pretty-formats.txt
> +++ b/Documentation/pretty-formats.txt
> @@ -170,7 +170,10 @@ The placeholders are:
>    columns, padding spaces on the right if necessary
>  - '%>(<N>)', '%>|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
>    respectively, but padding spaces on the left
> -- '%><(<N>)', '%><|(<N>)': similar to '%<(<N<)', '%<|(<N<)'
> +- '%>>(<N>)', '%>>|(<N>)': similar to '%>(<N<)', '%>|(<N<)'

s/<N</<N>/g

> +  respectively, except that if the next placeholder takes more spaces
> +  than given and there are spaces on its left, use those spaces
> +- '%><(<N>)', '%><|(<N>)': similar to '% <(<N<)', '%<|(<N<)'

Ditto: s/<N</<N>/g

>    respectively, but padding both sides (i.e. the text is centered)

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH 12/12] pretty: support %>> that steal trailing spaces
  2013-03-17  9:06   ` Eric Sunshine
@ 2013-03-30  9:31     ` Duy Nguyen
  0 siblings, 0 replies; 83+ messages in thread
From: Duy Nguyen @ 2013-03-30  9:31 UTC (permalink / raw
  To: Eric Sunshine; +Cc: Git Mailing List, Junio C Hamano

On Sun, Mar 17, 2013 at 4:06 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Fri, Mar 15, 2013 at 10:24 PM, Nguyễn Thái Ngọc Duy
> <pclouds@gmail.com> wrote:
>> This is pretty useful in `%<(100)%s%Cred%>(20)% an' where %s does not
>
> s/% an/%an/

No. The space after '%' is intentional. And thanks for proofreading in
all my patches.
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH v2 00/12] Layout control placeholders for pretty format
  2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                   ` (11 preceding siblings ...)
  2013-03-16  2:24 ` [PATCH 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35 ` Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
                     ` (12 more replies)
  12 siblings, 13 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

The only difference in v2 is typo fixes (mostly in commit messages,
but some in pretty-formats.txt). Also resend as a reminder to Junio if
he forgot to pick it up.

Nguyễn Thái Ngọc Duy (12):
  pretty-formats.txt: wrap long lines
  pretty: share code between format_decoration and show_decorations
  utf8.c: move display_mode_esc_sequence_len() for use by other
    functions
  utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  pretty: save commit encoding from logmsg_reencode if the caller needs
    it
  pretty: get the correct encoding for --pretty:format=%e
  utf8: keep NULs in reencode_string()
  pretty: two phase conversion for non utf-8 commits
  pretty: add %C(auto) for auto-coloring on the next placeholder
  pretty: support padding placeholders, %< %> and %><
  pretty: support truncating in %>, %< and %><
  pretty: support %>> that steal trailing spaces

 Documentation/pretty-formats.txt |  34 ++++-
 builtin/blame.c                  |   2 +-
 builtin/commit.c                 |   2 +-
 builtin/fast-export.c            |   3 +-
 builtin/mailinfo.c               |   3 +-
 commit.h                         |   1 +
 compat/precompose_utf8.c         |   2 +-
 log-tree.c                       |  60 +++++----
 log-tree.h                       |   3 +
 notes.c                          |   4 +-
 pretty.c                         | 282 ++++++++++++++++++++++++++++++++++-----
 revision.c                       |   2 +-
 sequencer.c                      |   5 +-
 t/t4207-log-decoration-colors.sh |   8 +-
 t/t6006-rev-list-format.sh       |  12 +-
 utf8.c                           | 104 +++++++++++----
 utf8.h                           |  14 +-
 17 files changed, 434 insertions(+), 107 deletions(-)

-- 
1.8.2.83.gc99314b

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH v2 01/12] pretty-formats.txt: wrap long lines
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 105f18a..66345d1 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -106,18 +106,22 @@ The placeholders are:
 - '%P': parent hashes
 - '%p': abbreviated parent hashes
 - '%an': author name
-- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1]
+  or linkgit:git-blame[1])
 - '%ae': author email
-- '%aE': author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aE': author email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ad': author date (format respects --date= option)
 - '%aD': author date, RFC2822 style
 - '%ar': author date, relative
 - '%at': author date, UNIX timestamp
 - '%ai': author date, ISO 8601 format
 - '%cn': committer name
-- '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cN': committer name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ce': committer email
-- '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cE': committer email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%cd': committer date
 - '%cD': committer date, RFC2822 style
 - '%cr': committer date, relative
@@ -136,9 +140,11 @@ The placeholders are:
 - '%gD': reflog selector, e.g., `refs/stash@{1}`
 - '%gd': shortened reflog selector, e.g., `stash@{1}`
 - '%gn': reflog identity name
-- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gN': reflog identity name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ge': reflog identity email
-- '%gE': reflog identity email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gE': reflog identity email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%gs': reflog subject
 - '%Cred': switch color to red
 - '%Cgreen': switch color to green
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-04-01 17:53     ` Junio C Hamano
  2013-03-30  9:35   ` [PATCH v2 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
                     ` (10 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This also adds color support to format_decoration()

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 log-tree.c                       | 60 +++++++++++++++++++++++++---------------
 log-tree.h                       |  3 ++
 pretty.c                         | 19 +------------
 t/t4207-log-decoration-colors.sh |  8 +++---
 4 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/log-tree.c b/log-tree.c
index 5dc45c4..7467a1d 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -174,36 +174,50 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 	}
 }
 
-void show_decorations(struct rev_info *opt, struct commit *commit)
+void format_decoration(struct strbuf *sb,
+		       const struct commit *commit,
+		       int use_color)
 {
-	const char *prefix;
-	struct name_decoration *decoration;
+	const char *prefix = " (";
+	struct name_decoration *d;
 	const char *color_commit =
-		diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
+		diff_get_color(use_color, DIFF_COMMIT);
 	const char *color_reset =
-		decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
+		decorate_get_color(use_color, DECORATION_NONE);
+
+	load_ref_decorations(DECORATE_SHORT_REFS);
+	d = lookup_decoration(&name_decoration, &commit->object);
+	if (!d)
+		return;
+	while (d) {
+		strbuf_addstr(sb, color_commit);
+		strbuf_addstr(sb, prefix);
+		strbuf_addstr(sb, decorate_get_color(use_color, d->type));
+		if (d->type == DECORATION_REF_TAG)
+			strbuf_addstr(sb, "tag: ");
+		strbuf_addstr(sb, d->name);
+		strbuf_addstr(sb, color_reset);
+		prefix = ", ";
+		d = d->next;
+	}
+	if (prefix[0] == ',') {
+		strbuf_addstr(sb, color_commit);
+		strbuf_addch(sb, ')');
+		strbuf_addstr(sb, color_reset);
+	}
+}
+
+void show_decorations(struct rev_info *opt, struct commit *commit)
+{
+	struct strbuf sb = STRBUF_INIT;
 
 	if (opt->show_source && commit->util)
 		printf("\t%s", (char *) commit->util);
 	if (!opt->show_decorations)
 		return;
-	decoration = lookup_decoration(&name_decoration, &commit->object);
-	if (!decoration)
-		return;
-	prefix = " (";
-	while (decoration) {
-		printf("%s", prefix);
-		fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
-		      stdout);
-		if (decoration->type == DECORATION_REF_TAG)
-			fputs("tag: ", stdout);
-		printf("%s", decoration->name);
-		fputs(color_reset, stdout);
-		fputs(color_commit, stdout);
-		prefix = ", ";
-		decoration = decoration->next;
-	}
-	putchar(')');
+	format_decoration(&sb, commit, opt->diffopt.use_color);
+	fputs(sb.buf, stdout);
+	strbuf_release(&sb);
 }
 
 /*
@@ -625,8 +639,8 @@ void show_log(struct rev_info *opt)
 			printf(" (from %s)",
 			       find_unique_abbrev(parent->object.sha1,
 						  abbrev_commit));
+		fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
 		show_decorations(opt, commit);
-		printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
 		if (opt->commit_format == CMIT_FMT_ONELINE) {
 			putchar(' ');
 		} else {
diff --git a/log-tree.h b/log-tree.h
index 9140f48..e6a2da5 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -13,6 +13,9 @@ int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 int log_tree_opt_parse(struct rev_info *, const char **, int);
 void show_log(struct rev_info *opt);
+void format_decoration(struct strbuf *sb,
+		       const struct commit *commit,
+		       int use_color);
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 			     const char **subject_p,
diff --git a/pretty.c b/pretty.c
index eae57ad..79784be 100644
--- a/pretty.c
+++ b/pretty.c
@@ -898,23 +898,6 @@ static void parse_commit_message(struct format_commit_context *c)
 	c->commit_message_parsed = 1;
 }
 
-static void format_decoration(struct strbuf *sb, const struct commit *commit)
-{
-	struct name_decoration *d;
-	const char *prefix = " (";
-
-	load_ref_decorations(DECORATE_SHORT_REFS);
-	d = lookup_decoration(&name_decoration, &commit->object);
-	while (d) {
-		strbuf_addstr(sb, prefix);
-		prefix = ", ";
-		strbuf_addstr(sb, d->name);
-		d = d->next;
-	}
-	if (prefix[0] == ',')
-		strbuf_addch(sb, ')');
-}
-
 static void strbuf_wrap(struct strbuf *sb, size_t pos,
 			size_t width, size_t indent1, size_t indent2)
 {
@@ -1146,7 +1129,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 		strbuf_addstr(sb, get_revision_mark(NULL, commit));
 		return 1;
 	case 'd':
-		format_decoration(sb, commit);
+		format_decoration(sb, commit, 0);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index bbde31b..925f577 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -44,15 +44,15 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
  ${c_tag}tag: v1.0${c_reset}${c_commit},\
  ${c_tag}tag: B${c_reset}${c_commit},\
  ${c_branch}master${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\
  ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
  On master: Changes to A.t
-${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
 EOF
 
 # We want log to show all, but the second parent to refs/stash is irrelevant
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
                     ` (9 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/utf8.c b/utf8.c
index 1087870..82c2ddf 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,6 +9,20 @@ struct interval {
   int last;
 };
 
+static size_t display_mode_esc_sequence_len(const char *s)
+{
+	const char *p = s;
+	if (*p++ != '\033')
+		return 0;
+	if (*p++ != '[')
+		return 0;
+	while (isdigit(*p) || *p == ';')
+		p++;
+	if (*p++ != 'm')
+		return 0;
+	return p - s;
+}
+
 /* auxiliary function for binary search in interval table */
 static int bisearch(ucs_char_t ucs, const struct interval *table, int max)
 {
@@ -303,20 +317,6 @@ static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
 	}
 }
 
-static size_t display_mode_esc_sequence_len(const char *s)
-{
-	const char *p = s;
-	if (*p++ != '\033')
-		return 0;
-	if (*p++ != '[')
-		return 0;
-	while (isdigit(*p) || *p == ';')
-		p++;
-	if (*p++ != 'm')
-		return 0;
-	return p - s;
-}
-
 /*
  * Wrap the text, if necessary. The variable indent is the indent for the
  * first line, indent2 is the indent for all other lines.
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (2 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-04-01 18:04     ` Junio C Hamano
  2013-03-30  9:35   ` [PATCH v2 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
                     ` (8 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 20 ++++++++++++++------
 utf8.h |  1 +
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/utf8.c b/utf8.c
index 82c2ddf..38322a1 100644
--- a/utf8.c
+++ b/utf8.c
@@ -266,18 +266,26 @@ int utf8_width(const char **start, size_t *remainder_p)
  * string, assuming that the string is utf8.  Returns strlen() instead
  * if the string does not look like a valid utf8 string.
  */
-int utf8_strwidth(const char *string)
+int utf8_strnwidth(const char *string, int len, int skip_ansi)
 {
 	int width = 0;
 	const char *orig = string;
 
-	while (1) {
-		if (!string)
-			return strlen(orig);
-		if (!*string)
-			return width;
+	if (len == -1)
+		len = strlen(string);
+	while (string && string < orig + len) {
+		int skip;
+		while (skip_ansi &&
+		       (skip = display_mode_esc_sequence_len(string)))
+			string += skip;
 		width += utf8_width(&string, NULL);
 	}
+	return string ? width : len;
+}
+
+int utf8_strwidth(const char *string)
+{
+	return utf8_strnwidth(string, -1, 0);
 }
 
 int is_utf8(const char *text)
diff --git a/utf8.h b/utf8.h
index 501b2bd..a556932 100644
--- a/utf8.h
+++ b/utf8.h
@@ -4,6 +4,7 @@
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
 int utf8_width(const char **start, size_t *remainder_p);
+int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
 int is_utf8(const char *text);
 int is_encoding_utf8(const char *name);
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (3 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-04-01 18:10     ` Junio C Hamano
  2013-03-30  9:35   ` [PATCH v2 06/12] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
                     ` (7 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

The commit encoding is parsed by logmsg_reencode, there's no need for
the caller to re-parse it again. The reencoded message now has the new
encoding, not the original one. The caller would need to read commit
object again before parsing.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/blame.c  |  2 +-
 builtin/commit.c |  2 +-
 commit.h         |  1 +
 pretty.c         | 16 ++++++++++++----
 revision.c       |  2 +-
 5 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/builtin/blame.c b/builtin/blame.c
index 86100e9..104a948 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1425,7 +1425,7 @@ static void get_commit_info(struct commit *commit,
 	commit_info_init(ret);
 
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 	get_ac_line(message, "\nauthor ",
 		    &ret->author, &ret->author_mail,
 		    &ret->author_time, &ret->author_tz);
diff --git a/builtin/commit.c b/builtin/commit.c
index 3348aa1..beead44 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -953,7 +953,7 @@ static const char *read_commit_message(const char *name)
 	if (!commit)
 		die(_("could not lookup commit %s"), name);
 	out_enc = get_commit_output_encoding();
-	return logmsg_reencode(commit, out_enc);
+	return logmsg_reencode(commit, NULL, out_enc);
 }
 
 static int parse_and_validate_options(int argc, const char *argv[],
diff --git a/commit.h b/commit.h
index 4138bb4..085349a 100644
--- a/commit.h
+++ b/commit.h
@@ -100,6 +100,7 @@ struct userformat_want {
 extern int has_non_ascii(const char *text);
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern char *logmsg_reencode(const struct commit *commit,
+			     char **commit_encoding,
 			     const char *output_encoding);
 extern void logmsg_free(char *msg, const struct commit *commit);
 extern void get_commit_format(const char *arg, struct rev_info *);
diff --git a/pretty.c b/pretty.c
index 79784be..ab5d70f 100644
--- a/pretty.c
+++ b/pretty.c
@@ -584,6 +584,7 @@ static char *replace_encoding_header(char *buf, const char *encoding)
 }
 
 char *logmsg_reencode(const struct commit *commit,
+		      char **commit_encoding,
 		      const char *output_encoding)
 {
 	static const char *utf8 = "UTF-8";
@@ -605,9 +606,15 @@ char *logmsg_reencode(const struct commit *commit,
 			    sha1_to_hex(commit->object.sha1), typename(type));
 	}
 
-	if (!output_encoding || !*output_encoding)
+	if (!output_encoding || !*output_encoding) {
+		if (commit_encoding)
+			*commit_encoding =
+				get_header(commit, msg, "encoding");
 		return msg;
+	}
 	encoding = get_header(commit, msg, "encoding");
+	if (commit_encoding)
+		*commit_encoding = encoding;
 	use_encoding = encoding ? encoding : utf8;
 	if (same_encoding(use_encoding, output_encoding)) {
 		/*
@@ -648,7 +655,8 @@ char *logmsg_reencode(const struct commit *commit,
 	if (out)
 		out = replace_encoding_header(out, output_encoding);
 
-	free(encoding);
+	if (!commit_encoding)
+		free(encoding);
 	/*
 	 * If the re-encoding failed, out might be NULL here; in that
 	 * case we just return the commit message verbatim.
@@ -1313,7 +1321,7 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, output_enc);
+	context.message = logmsg_reencode(commit, NULL, output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
@@ -1476,7 +1484,7 @@ void pretty_print_commit(const struct pretty_print_context *pp,
 	}
 
 	encoding = get_log_output_encoding();
-	msg = reencoded = logmsg_reencode(commit, encoding);
+	msg = reencoded = logmsg_reencode(commit, NULL, encoding);
 
 	if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
 		indent = 0;
diff --git a/revision.c b/revision.c
index ef60205..c6ff560 100644
--- a/revision.c
+++ b/revision.c
@@ -2290,7 +2290,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 	 * in it.
 	 */
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 
 	/* Copy the commit to temporary if we are using "fake" headers */
 	if (buf.len)
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 06/12] pretty: get the correct encoding for --pretty:format=%e
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (4 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 07/12] utf8: keep NULs in reencode_string() Nguyễn Thái Ngọc Duy
                     ` (6 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

parse_commit_header() provides the commit encoding for '%e' and it
reads it from the re-encoded message, which contains the new encoding,
not the original one in the commit object.

Get the commit encoding from logmsg_reencode() instead.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/pretty.c b/pretty.c
index ab5d70f..e2241e5 100644
--- a/pretty.c
+++ b/pretty.c
@@ -771,12 +771,12 @@ struct format_commit_context {
 		char *signer;
 	} signature;
 	char *message;
+	char *commit_encoding;
 	size_t width, indent1, indent2;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
 	struct chunk committer;
-	struct chunk encoding;
 	size_t message_off;
 	size_t subject_off;
 	size_t body_off;
@@ -823,9 +823,6 @@ static void parse_commit_header(struct format_commit_context *context)
 		} else if (!prefixcmp(msg + i, "committer ")) {
 			context->committer.off = i + 10;
 			context->committer.len = eol - i - 10;
-		} else if (!prefixcmp(msg + i, "encoding ")) {
-			context->encoding.off = i + 9;
-			context->encoding.len = eol - i - 9;
 		}
 		i = eol;
 	}
@@ -1210,7 +1207,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 				   msg + c->committer.off, c->committer.len,
 				   c->pretty_ctx->date_mode);
 	case 'e':	/* encoding */
-		strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
+		if (c->commit_encoding)
+			strbuf_addstr(sb, c->commit_encoding);
 		return 1;
 	case 'B':	/* raw body */
 		/* message_off is always left at the initial newline */
@@ -1321,11 +1319,14 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, NULL, output_enc);
+	context.message = logmsg_reencode(commit,
+					  &context.commit_encoding,
+					  output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature.gpg_output);
 	free(context.signature.signer);
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 07/12] utf8: keep NULs in reencode_string()
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (5 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 06/12] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-03-30 17:06     ` Torsten Bögershausen
  2013-03-30  9:35   ` [PATCH v2 08/12] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
                     ` (5 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

reencode_string() will be used in the next patch for re-encoding
pretty output, which can contain NULs.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/fast-export.c    |  3 ++-
 builtin/mailinfo.c       |  3 ++-
 compat/precompose_utf8.c |  2 +-
 notes.c                  |  4 +++-
 pretty.c                 |  3 ++-
 sequencer.c              |  5 +++--
 utf8.c                   | 10 +++++++---
 utf8.h                   | 10 +++++++---
 8 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 77dffd1..7ba9f3b 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -316,7 +316,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
 
 	mark_next_object(&commit->object);
 	if (!is_encoding_utf8(encoding))
-		reencoded = reencode_string(message, "UTF-8", encoding);
+		reencoded = reencode_string(message, strlen(message),
+					    "UTF-8", encoding, NULL);
 	if (!commit->parents)
 		printf("reset %s\n", (const char*)commit->util);
 	printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s",
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 24a772d..129e7dc 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -486,7 +486,8 @@ static void convert_to_utf8(struct strbuf *line, const char *charset)
 
 	if (same_encoding(metainfo_charset, charset))
 		return;
-	out = reencode_string(line->buf, metainfo_charset, charset);
+	out = reencode_string(line->buf, line->len,
+			      metainfo_charset, charset, NULL);
 	if (!out)
 		die("cannot convert from %s to %s",
 		    charset, metainfo_charset);
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 8cf5955..d9203d0 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -78,7 +78,7 @@ void precompose_argv(int argc, const char **argv)
 		size_t namelen;
 		oldarg = argv[i];
 		if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
-			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
+			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
 			if (newarg)
 				argv[i] = newarg;
 		}
diff --git a/notes.c b/notes.c
index f63fd57..4ae3b25 100644
--- a/notes.c
+++ b/notes.c
@@ -1222,7 +1222,9 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
 
 	if (output_encoding && *output_encoding &&
 	    !is_encoding_utf8(output_encoding)) {
-		char *reencoded = reencode_string(msg, output_encoding, utf8);
+		char *reencoded = reencode_string(msg, strlen(msg),
+						  output_encoding, utf8,
+						  NULL);
 		if (reencoded) {
 			free(msg);
 			msg = reencoded;
diff --git a/pretty.c b/pretty.c
index e2241e5..092dd1d 100644
--- a/pretty.c
+++ b/pretty.c
@@ -643,7 +643,8 @@ char *logmsg_reencode(const struct commit *commit,
 		 * this point, we are done with msg. If we allocated a fresh
 		 * copy, we can free it.
 		 */
-		out = reencode_string(msg, output_encoding, use_encoding);
+		out = reencode_string(msg, strlen(msg),
+				      output_encoding, use_encoding, NULL);
 		if (out && msg != commit->buffer)
 			free(msg);
 	}
diff --git a/sequencer.c b/sequencer.c
index aef5e8a..bf15531 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -61,8 +61,9 @@ static int get_message(struct commit *commit, struct commit_message *out)
 	out->reencoded_message = NULL;
 	out->message = commit->buffer;
 	if (same_encoding(encoding, git_commit_encoding))
-		out->reencoded_message = reencode_string(commit->buffer,
-					git_commit_encoding, encoding);
+		out->reencoded_message =
+			reencode_string(commit->buffer, strlen(commit->buffer),
+					git_commit_encoding, encoding, NULL);
 	if (out->reencoded_message)
 		out->message = out->reencoded_message;
 
diff --git a/utf8.c b/utf8.c
index 38322a1..9d98043 100644
--- a/utf8.c
+++ b/utf8.c
@@ -468,7 +468,7 @@ int utf8_fprintf(FILE *stream, const char *format, ...)
 #else
 	typedef char * iconv_ibp;
 #endif
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv, int *outsz_p)
 {
 	size_t outsz, outalloc;
 	char *out, *outpos;
@@ -502,13 +502,17 @@ char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
 		}
 		else {
 			*outpos = '\0';
+			if (outsz_p)
+				*outsz_p = outpos - out;
 			break;
 		}
 	}
 	return out;
 }
 
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+char *reencode_string(const char *in, int insz,
+		      const char *out_encoding, const char *in_encoding,
+		      int *outsz)
 {
 	iconv_t conv;
 	char *out;
@@ -518,7 +522,7 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
 	conv = iconv_open(out_encoding, in_encoding);
 	if (conv == (iconv_t) -1)
 		return NULL;
-	out = reencode_string_iconv(in, strlen(in), conv);
+	out = reencode_string_iconv(in, insz, conv, outsz);
 	iconv_close(conv);
 	return out;
 }
diff --git a/utf8.h b/utf8.h
index a556932..99db3e0 100644
--- a/utf8.h
+++ b/utf8.h
@@ -17,10 +17,14 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
 
 #ifndef NO_ICONV
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
+char *reencode_string_iconv(const char *in, size_t insz,
+			    iconv_t conv, int *outsz);
+char *reencode_string(const char *in, int insz,
+		      const char *out_encoding,
+		      const char *in_encoding,
+		      int *outsz);
 #else
-#define reencode_string(a,b,c) NULL
+#define reencode_string(a,b,c,d) NULL
 #endif
 
 #endif
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 08/12] pretty: two phase conversion for non utf-8 commits
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (6 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 07/12] utf8: keep NULs in reencode_string() Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 4644 bytes --]

Always assume format_commit_item() takes an utf-8 string for string
handling simplicity (we can handle utf-8 strings, but can't with other
encodings).

If commit message is in non-utf8, or output encoding is not, then the
commit is first converted to utf-8, processed, then output converted
to output encoding. This of course only works with encodings that are
compatible with Unicode.

This also fixes the iso8859-1 test in t6006. It's supposed to create
an iso8859-1 commit, but the commit content in t6006 is in UTF-8.
t6006 is now converted back in UTF-8 (the downside is we can't put
utf-8 strings there anymore).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c                   | 24 ++++++++++++++++++++++--
 t/t6006-rev-list-format.sh | 12 ++++++------
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/pretty.c b/pretty.c
index 092dd1d..3f4809a 100644
--- a/pretty.c
+++ b/pretty.c
@@ -1003,7 +1003,8 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
-static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
+				const char *placeholder,
 				void *context)
 {
 	struct format_commit_context *c = context;
@@ -1235,7 +1236,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 	return 0;	/* unknown placeholder */
 }
 
-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
+				 const char *placeholder,
 				 void *context)
 {
 	int consumed;
@@ -1315,6 +1317,7 @@ void format_commit_message(const struct commit *commit,
 {
 	struct format_commit_context context;
 	const char *output_enc = pretty_ctx->output_encoding;
+	const char *utf8 = "UTF-8";
 
 	memset(&context, 0, sizeof(context));
 	context.commit = commit;
@@ -1327,6 +1330,23 @@ void format_commit_message(const struct commit *commit,
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	if (output_enc) {
+		if (same_encoding(utf8, output_enc))
+			output_enc = NULL;
+	} else {
+		if (context.commit_encoding &&
+		    !same_encoding(context.commit_encoding, utf8))
+			output_enc = context.commit_encoding;
+	}
+
+	if (output_enc) {
+		int outsz;
+		char *out = reencode_string(sb->buf, sb->len,
+					    output_enc, utf8, &outsz);
+		if (out)
+			strbuf_attach(sb, out, outsz, outsz + 1);
+	}
+
 	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature.gpg_output);
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 3fc3b74..0393c9f 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -184,7 +184,7 @@ Test printing of complex bodies
 
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 EOF
 test_expect_success 'setup complex body' '
 git config i18n.commitencoding iso8859-1 &&
@@ -192,14 +192,14 @@ git config i18n.commitencoding iso8859-1 &&
 '
 
 test_format complex-encoding %e <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 iso8859-1
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_format complex-subject %s <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 Test printing of complex bodies
 commit 131a310eb913d107dd3c09a65d1651175898735d
 changed foo
@@ -208,17 +208,17 @@ added foo
 EOF
 
 test_format complex-body %b <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_expect_success '%x00 shows NUL' '
-	echo  >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+	echo  >expect commit 1ed88da4a5b5ed8c449114ac131efc62178734c3 &&
 	echo >>expect fooQbar &&
 	git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
 	nul_to_q <actual.nul >actual &&
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (7 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 08/12] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-04-01 18:26     ` Junio C Hamano
  2013-03-30  9:35   ` [PATCH v2 10/12] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
                     ` (3 subsequent siblings)
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is not simply convenient over %C(auto,xxx). Some placeholders
(actually only one, %d) do multi coloring and we can't emit a multiple
colors with %C(auto,xxx).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  3 ++-
 pretty.c                         | 15 +++++++++++++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 66345d1..8734224 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -154,7 +154,8 @@ The placeholders are:
   adding `auto,` at the beginning will emit color only when colors are
   enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
   respecting the `auto` settings of the former if we are going to a
-  terminal)
+  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
+  on the following placeholder.
 - '%m': left, right or boundary mark
 - '%n': newline
 - '%%': a raw '%'
diff --git a/pretty.c b/pretty.c
index 3f4809a..c333fd6 100644
--- a/pretty.c
+++ b/pretty.c
@@ -774,6 +774,7 @@ struct format_commit_context {
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
+	int auto_color;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -1011,7 +1012,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	const struct commit *commit = c->commit;
 	const char *msg = c->message;
 	struct commit_list *p;
-	int h1, h2;
+	int h1, h2, use_color;
 
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
@@ -1023,6 +1024,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 
 			if (!end)
 				return 0;
+			if (!prefixcmp(begin, "auto)")) {
+				c->auto_color = 1;
+				return end - placeholder + 1;
+			}
 			if (!prefixcmp(begin, "auto,")) {
 				if (!want_color(c->pretty_ctx->color))
 					return end - placeholder + 1;
@@ -1090,16 +1095,22 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	/* these depend on the commit */
 	if (!commit->object.parsed)
 		parse_object(commit->object.sha1);
+	use_color = c->auto_color;
+	c->auto_color = 0;
 
 	switch (placeholder[0]) {
 	case 'H':		/* commit hash */
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_COMMIT));
 		strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_RESET));
 		return 1;
 	case 'h':		/* abbreviated commit hash */
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_COMMIT));
 		if (add_again(sb, &c->abbrev_commit_hash))
 			return 1;
 		strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
 						     c->pretty_ctx->abbrev));
+		strbuf_addstr(sb, diff_get_color(use_color, DIFF_RESET));
 		c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
 		return 1;
 	case 'T':		/* tree hash */
@@ -1136,7 +1147,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 		strbuf_addstr(sb, get_revision_mark(NULL, commit));
 		return 1;
 	case 'd':
-		format_decoration(sb, commit, 0);
+		format_decoration(sb, commit, use_color);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 10/12] pretty: support padding placeholders, %< %> and %><
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (8 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 11/12] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
                     ` (2 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Either %<, %> or %>< standing before a placeholder specifies how many
columns (at least as the placeholder can exceed it) it takes. Each
differs on how spaces are padded:

  %< pads on the right (aka left alignment)
  %> pads on the left (aka right alignment)
  %>< pads both ways equally (aka centered)

The (<N>) follows them, e.g. `%<(100)', to specify the number of
columns the next placeholder takes.

However, if '|' stands before (<N>), e.g. `%>|(100)', then the number
of columns is calculated so that it reaches the Nth column on screen.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |   8 +++
 pretty.c                         | 117 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 8734224..0ab1233 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -162,6 +162,14 @@ The placeholders are:
 - '%x00': print a byte from a hex code
 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
+- '%<(<N>)': make the next placeholder take at least N columns,
+  padding spaces on the right if necessary
+- '%<|(<N>)': make the next placeholder take at least until Nth
+  columns, padding spaces on the right if necessary
+- '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+  respectively, but padding spaces on the left
+- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+  respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
 revision traversal engine. For example, the `%g*` reflog options will
diff --git a/pretty.c b/pretty.c
index c333fd6..233d69c 100644
--- a/pretty.c
+++ b/pretty.c
@@ -760,12 +760,20 @@ struct chunk {
 	size_t len;
 };
 
+enum flush_type {
+	no_flush,
+	flush_right,
+	flush_left,
+	flush_both
+};
+
 struct format_commit_context {
 	const struct commit *commit;
 	const struct pretty_print_context *pretty_ctx;
 	unsigned commit_header_parsed:1;
 	unsigned commit_message_parsed:1;
 	unsigned commit_signature_parsed:1;
+	enum flush_type flush_type;
 	struct {
 		char *gpg_output;
 		char good_bad;
@@ -775,6 +783,7 @@ struct format_commit_context {
 	char *commit_encoding;
 	size_t width, indent1, indent2;
 	int auto_color;
+	int padding;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -1004,6 +1013,52 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
+static size_t parse_padding_placeholder(struct strbuf *sb,
+					const char *placeholder,
+					struct format_commit_context *c)
+{
+	const char *ch = placeholder;
+	enum flush_type flush_type;
+	int to_column = 0;
+
+	switch (*ch++) {
+	case '<':
+		flush_type = flush_right;
+		break;
+	case '>':
+		if (*ch == '<') {
+			flush_type = flush_both;
+			ch++;
+		} else
+			flush_type = flush_left;
+		break;
+	default:
+		return 0;
+	}
+
+	/* the next value means "wide enough to that column" */
+	if (*ch == '|') {
+		to_column = 1;
+		ch++;
+	}
+
+	if (*ch == '(') {
+		const char *start = ch + 1;
+		const char *end = strchr(start, ')');
+		char *next;
+		int width;
+		if (!end || end == start)
+			return 0;
+		width = strtoul(start, &next, 10);
+		if (next == start || width == 0)
+			return 0;
+		c->padding = to_column ? -width : width;
+		c->flush_type = flush_type;
+		return end - placeholder + 1;
+	}
+	return 0;
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 				const char *placeholder,
 				void *context)
@@ -1090,6 +1145,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 			return end - placeholder + 1;
 		} else
 			return 0;
+
+	case '<':
+	case '>':
+		return parse_padding_placeholder(sb, placeholder, c);
 	}
 
 	/* these depend on the commit */
@@ -1247,6 +1306,59 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	return 0;	/* unknown placeholder */
 }
 
+static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
+				    const char *placeholder,
+				    struct format_commit_context *c)
+{
+	struct strbuf local_sb = STRBUF_INIT;
+	int total_consumed = 0, len, padding = c->padding;
+	if (padding < 0) {
+		const char *start = strrchr(sb->buf, '\n');
+		int occupied;
+		if (!start)
+			start = sb->buf;
+		occupied = utf8_strnwidth(start, -1, 1);
+		padding = (-padding) - occupied;
+	}
+	while (1) {
+		int modifier = *placeholder == 'C';
+		int consumed = format_commit_one(&local_sb, placeholder, c);
+		total_consumed += consumed;
+
+		if (!modifier)
+			break;
+
+		placeholder += consumed;
+		if (*placeholder != '%')
+			break;
+		placeholder++;
+		total_consumed++;
+	}
+	len = utf8_strnwidth(local_sb.buf, -1, 1);
+	if (len > padding)
+		strbuf_addstr(sb, local_sb.buf);
+	else {
+		int sb_len = sb->len, offset = 0;
+		if (c->flush_type == flush_left)
+			offset = padding - len;
+		else if (c->flush_type == flush_both)
+			offset = (padding - len) / 2;
+		/*
+		 * we calculate padding in columns, now
+		 * convert it back to chars
+		 */
+		padding = padding - len + local_sb.len;
+		strbuf_grow(sb, padding);
+		strbuf_setlen(sb, sb_len + padding);
+		memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+		memcpy(sb->buf + sb_len + offset, local_sb.buf,
+		       local_sb.len);
+	}
+	strbuf_release(&local_sb);
+	c->flush_type = no_flush;
+	return total_consumed;
+}
+
 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 				 const char *placeholder,
 				 void *context)
@@ -1277,7 +1389,10 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 		placeholder++;
 
 	orig_len = sb->len;
-	consumed = format_commit_one(sb, placeholder, context);
+	if (((struct format_commit_context *)context)->flush_type != no_flush)
+		consumed = format_and_pad_commit(sb, placeholder, context);
+	else
+		consumed = format_commit_one(sb, placeholder, context);
 	if (magic == NO_MAGIC)
 		return consumed;
 
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 11/12] pretty: support truncating in %>, %< and %><
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (9 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 10/12] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-03-30  9:35   ` [PATCH v2 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

%>(N,trunc) truncates the right 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 <pclouds@gmail.com>
---
 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 0ab1233..f2df941 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([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
-- '%<(<N>)': make the next placeholder take at least N columns,
-  padding spaces on the right if necessary
+- '%<(<N>[,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.
 - '%<|(<N>)': make the next placeholder take at least until Nth
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
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 {
 		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;
+			}
+			w += n;
+			continue;
+		}
+		memcpy(dst, old, src - old);
+		dst += src - old;
+		w += n;
+	}
+	strbuf_setlen(&sb_dst, dst - sb_dst.buf);
+	strbuf_attach(sb_src, strbuf_detach(&sb_dst, NULL),
+		      sb_dst.len, sb_dst.alloc);
+}
+
 int is_encoding_utf8(const char *name)
 {
 	if (!name)
diff --git a/utf8.h b/utf8.h
index 99db3e0..faf2f91 100644
--- a/utf8.h
+++ b/utf8.h
@@ -15,6 +15,8 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
 		const char *text, int indent, int indent2, int width);
 void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
+void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
+			 const char *subst);
 
 #ifndef NO_ICONV
 char *reencode_string_iconv(const char *in, size_t insz,
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v2 12/12] pretty: support %>> that steal trailing spaces
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (10 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 11/12] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
@ 2013-03-30  9:35   ` Nguyễn Thái Ngọc Duy
  2013-04-01 18:39     ` Junio C Hamano
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
  12 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-03-30  9:35 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is pretty useful in `%<(100)%s%Cred%>(20)% an' where %s does not
use up all 100 columns and %an needs more than 20 columns. By
replacing %>(20) with %>>(20), %an can steal spaces from %s.

%>> understands escape sequences, so %Cred does not stop it from
stealing spaces in %<(100).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  5 ++++-
 pretty.c                         | 34 ++++++++++++++++++++++++++++++++++
 utf8.c                           |  2 +-
 utf8.h                           |  1 +
 4 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index f2df941..73ae4d6 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -170,7 +170,10 @@ The placeholders are:
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
   respectively, but padding spaces on the left
-- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+- '%>>(<N>)', '%>>|(<N>)': similar to '%>(<N>)', '%>|(<N>)'
+  respectively, except that if the next placeholder takes more spaces
+  than given and there are spaces on its left, use those spaces
+- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
   respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
diff --git a/pretty.c b/pretty.c
index 29384b5..892274d 100644
--- a/pretty.c
+++ b/pretty.c
@@ -764,6 +764,7 @@ enum flush_type {
 	no_flush,
 	flush_right,
 	flush_left,
+	flush_left_and_steal,
 	flush_both
 };
 
@@ -1037,6 +1038,9 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
 		if (*ch == '<') {
 			flush_type = flush_both;
 			ch++;
+		} else if (*ch == '>') {
+			flush_type = flush_left_and_steal;
+			ch++;
 		} else
 			flush_type = flush_left;
 		break;
@@ -1360,6 +1364,36 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
 		total_consumed++;
 	}
 	len = utf8_strnwidth(local_sb.buf, -1, 1);
+
+	if (c->flush_type == flush_left_and_steal) {
+		const char *ch = sb->buf + sb->len - 1;
+		while (len > padding && ch > sb->buf) {
+			const char *p;
+			if (*ch == ' ') {
+				ch--;
+				padding++;
+				continue;
+			}
+			/* check for trailing ansi sequences */
+			if (*ch != 'm')
+				break;
+			p = ch - 1;
+			while (ch - p < 10 && *p != '\033')
+				p--;
+			if (*p != '\033' ||
+			    ch + 1 - p != display_mode_esc_sequence_len(p))
+				break;
+			/*
+			 * got a good ansi sequence, put it back to
+			 * local_sb as we're cutting sb
+			 */
+			strbuf_insert(&local_sb, 0, p, ch + 1 - p);
+			ch = p - 1;
+		}
+		strbuf_setlen(sb, ch + 1 - sb->buf);
+		c->flush_type = flush_left;
+	}
+
 	if (len > padding) {
 		switch (c->truncate) {
 		case trunc_left:
diff --git a/utf8.c b/utf8.c
index 766df80..414ae49 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,7 +9,7 @@ struct interval {
   int last;
 };
 
-static size_t display_mode_esc_sequence_len(const char *s)
+size_t display_mode_esc_sequence_len(const char *s)
 {
 	const char *p = s;
 	if (*p++ != '\033')
diff --git a/utf8.h b/utf8.h
index faf2f91..e913edb 100644
--- a/utf8.h
+++ b/utf8.h
@@ -3,6 +3,7 @@
 
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
+size_t display_mode_esc_sequence_len(const char *s);
 int utf8_width(const char **start, size_t *remainder_p);
 int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
-- 
1.8.2.83.gc99314b

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 07/12] utf8: keep NULs in reencode_string()
  2013-03-30  9:35   ` [PATCH v2 07/12] utf8: keep NULs in reencode_string() Nguyễn Thái Ngọc Duy
@ 2013-03-30 17:06     ` Torsten Bögershausen
  2013-03-31  0:23       ` Duy Nguyen
  0 siblings, 1 reply; 83+ messages in thread
From: Torsten Bögershausen @ 2013-03-30 17:06 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Junio C Hamano,
	"tbo >> Torsten Bögershausen"

On 30.03.13 10:35, Nguyễn Thái Ngọc Duy wrote:
[...]
The short version of a review:
Would it make sense to leave  reencode_string() as it is,
and add a new function reencode_string_len()

+char *reencode_string_len(const char *in, int insz,
+		      const char *out_encoding, const char *in_encoding,
+		      int *outsz)

And I didn't manage to apply the patch on master (631bc94e67383b66da190550866566f09d32)
is there a specific commitID it should be applied on ?

/Torsten




> pretty output, which can contain NULs.
> -		reencoded = reencode_string(message, "UTF-8", encoding);
> +		reencoded = reencode_string(message, strlen(message),
> +					    "UTF-8", encoding, NULL);

> -	out = reencode_string(line->buf, metainfo_charset, charset);
> +	out = reencode_string(line->buf, line->len,
> +			      metainfo_charset, charset, NULL);

> -			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
> +			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
> -		char *reencoded = reencode_string(msg, output_encoding, utf8);

> +		char *reencoded = reencode_string(msg, strlen(msg),
> +						  output_encoding, utf8,
> +						  NULL);

> -		out = reencode_string(msg, output_encoding, use_encoding);
> +		out = reencode_string(msg, strlen(msg),
> +				      output_encoding, use_encoding, NULL);

> -		out->reencoded_message = reencode_string(commit->buffer,
> -					git_commit_encoding, encoding);
> +		out->reencoded_message =
> +			reencode_string(commit->buffer, strlen(commit->buffer),
> +					git_commit_encoding, encoding, NULL);

>  
> +char *reencode_string_len(const char *in, int insz,
> +		      const char *out_encoding, const char *in_encoding,
> +		      int *outsz)
>  

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 07/12] utf8: keep NULs in reencode_string()
  2013-03-30 17:06     ` Torsten Bögershausen
@ 2013-03-31  0:23       ` Duy Nguyen
  0 siblings, 0 replies; 83+ messages in thread
From: Duy Nguyen @ 2013-03-31  0:23 UTC (permalink / raw
  To: Torsten Bögershausen; +Cc: Git Mailing List, Junio C Hamano

On Sun, Mar 31, 2013 at 12:06 AM, Torsten Bögershausen <tboegi@web.de> wrote:
> On 30.03.13 10:35, Nguyễn Thái Ngọc Duy wrote:
> [...]
> The short version of a review:
> Would it make sense to leave  reencode_string() as it is,
> and add a new function reencode_string_len()

Hmm.. yeah.

> +char *reencode_string_len(const char *in, int insz,
> +                     const char *out_encoding, const char *in_encoding,
> +                     int *outsz)
>
> And I didn't manage to apply the patch on master (631bc94e67383b66da190550866566f09d32)
> is there a specific commitID it should be applied on ?

v1.8.2

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations
  2013-03-30  9:35   ` [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
@ 2013-04-01 17:53     ` Junio C Hamano
  2013-04-05  7:57       ` Jakub Narębski
  2013-04-12 23:34       ` Duy Nguyen
  0 siblings, 2 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-01 17:53 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> This also adds color support to format_decoration()
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  log-tree.c                       | 60 +++++++++++++++++++++++++---------------
>  log-tree.h                       |  3 ++
>  pretty.c                         | 19 +------------
>  t/t4207-log-decoration-colors.sh |  8 +++---
>  4 files changed, 45 insertions(+), 45 deletions(-)
>
> diff --git a/log-tree.c b/log-tree.c
> index 5dc45c4..7467a1d 100644
> --- a/log-tree.c
> +++ b/log-tree.c
> @@ -174,36 +174,50 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
>  	}
>  }
>  
> -void show_decorations(struct rev_info *opt, struct commit *commit)
> +void format_decoration(struct strbuf *sb,
> +		       const struct commit *commit,
> +		       int use_color)
>  {
> -	const char *prefix;
> -	struct name_decoration *decoration;
> +	const char *prefix = " (";
> +	struct name_decoration *d;

This renaming of variable from decoration to d seems to make the
patched result unnecessarily different from the original in
show_decorations, making it harder to compare.  Intentional?

>  	const char *color_commit =
> -		diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
> +		diff_get_color(use_color, DIFF_COMMIT);
>  	const char *color_reset =
> -		decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
> +		decorate_get_color(use_color, DECORATION_NONE);
> +
> +	load_ref_decorations(DECORATE_SHORT_REFS);

In cmd_log_init_finish(), we have loaded decorations with specified
decoration_style already.  Why is this needed (and with a hardcoded
style that may be different from what the user specified)?

> +	d = lookup_decoration(&name_decoration, &commit->object);
> +	if (!d)
> +		return;
> +	while (d) {
> +		strbuf_addstr(sb, color_commit);
> +		strbuf_addstr(sb, prefix);
> +		strbuf_addstr(sb, decorate_get_color(use_color, d->type));
> +		if (d->type == DECORATION_REF_TAG)
> +			strbuf_addstr(sb, "tag: ");
> +		strbuf_addstr(sb, d->name);
> +		strbuf_addstr(sb, color_reset);
> +		prefix = ", ";
> +		d = d->next;
> +	}
> +	if (prefix[0] == ',') {
> +		strbuf_addstr(sb, color_commit);
> +		strbuf_addch(sb, ')');
> +		strbuf_addstr(sb, color_reset);
> +	}

Was this change to conditionally close ' (' mentioned in the log
message?  It is in line with the version taken from pretty.c, and I
think it may be an improvement, but I do not think the check is
necessary in the context of this function.  You will never see
prefix[0] != ',' after the loop, because "while (d)" above runs at
least once; otherwise the "if (!d) return" would have returned from
the function early, no?

> +}
> +
> +void show_decorations(struct rev_info *opt, struct commit *commit)
> +{
> +	struct strbuf sb = STRBUF_INIT;
>  
>  	if (opt->show_source && commit->util)
>  		printf("\t%s", (char *) commit->util);
>  	if (!opt->show_decorations)
>  		return;
> -	decoration = lookup_decoration(&name_decoration, &commit->object);
> -	if (!decoration)
> -		return;
> -	prefix = " (";
> -	while (decoration) {
> -		printf("%s", prefix);
> -		fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
> -		      stdout);
> -		if (decoration->type == DECORATION_REF_TAG)
> -			fputs("tag: ", stdout);
> -		printf("%s", decoration->name);
> -		fputs(color_reset, stdout);
> -		fputs(color_commit, stdout);
> -		prefix = ", ";
> -		decoration = decoration->next;
> -	}
> -	putchar(')');
> +	format_decoration(&sb, commit, opt->diffopt.use_color);
> +	fputs(sb.buf, stdout);
> +	strbuf_release(&sb);
>  }
>  
>  /*
> @@ -625,8 +639,8 @@ void show_log(struct rev_info *opt)
>  			printf(" (from %s)",
>  			       find_unique_abbrev(parent->object.sha1,
>  						  abbrev_commit));
> +		fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
>  		show_decorations(opt, commit);
> -		printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));

We used to show and then reset.  I can see the updated
show_decorations() to format_decoration() callchain always reset at
the end, so the loss of the final reset here is very sane, but is
there a need to reset beforehand?  What is the calling convention
for the updated show_decorations()?  The caller should make sure
there is no funny colors in effect before calling, and the caller
can rest assured that there is no funny colors when the function
returns?

> diff --git a/log-tree.h b/log-tree.h
> index 9140f48..e6a2da5 100644
> --- a/log-tree.h
> +++ b/log-tree.h
> @@ -13,6 +13,9 @@ int log_tree_diff_flush(struct rev_info *);
>  int log_tree_commit(struct rev_info *, struct commit *);
>  int log_tree_opt_parse(struct rev_info *, const char **, int);
>  void show_log(struct rev_info *opt);
> +void format_decoration(struct strbuf *sb,
> +		       const struct commit *commit,
> +		       int use_color);

I think you can fit these on a single line, especially if you drop
the unused variable names (they help when there are more than one
parameter of the same type to document the order of the arguments,
but that does not apply here).  That would help people who run
"grep" on the header files without using CTAGS/ETAGS.

Wouldn't it be "format_decorations()", or does it handle only one?

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  2013-03-30  9:35   ` [PATCH v2 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
@ 2013-04-01 18:04     ` Junio C Hamano
  0 siblings, 0 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-01 18:04 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  utf8.c | 20 ++++++++++++++------
>  utf8.h |  1 +
>  2 files changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/utf8.c b/utf8.c
> index 82c2ddf..38322a1 100644
> --- a/utf8.c
> +++ b/utf8.c
> @@ -266,18 +266,26 @@ int utf8_width(const char **start, size_t *remainder_p)
>   * string, assuming that the string is utf8.  Returns strlen() instead
>   * if the string does not look like a valid utf8 string.
>   */
> -int utf8_strwidth(const char *string)
> +int utf8_strnwidth(const char *string, int len, int skip_ansi)
>  {
>  	int width = 0;
>  	const char *orig = string;
>  
> -	while (1) {
> -		if (!string)
> -			return strlen(orig);
> -		if (!*string)
> -			return width;
> +	if (len == -1)
> +		len = strlen(string);
> +	while (string && string < orig + len) {
> +		int skip;
> +		while (skip_ansi &&
> +		       (skip = display_mode_esc_sequence_len(string)))

We prefer to avoid assignment in conditionals; please write the
second as something like:

	((var = func(...)) != 0)

to clarify that it is not a misspelled comparison.

> +			string += skip;
>  		width += utf8_width(&string, NULL);
>  	}
> +	return string ? width : len;
> +}
> +
> +int utf8_strwidth(const char *string)
> +{
> +	return utf8_strnwidth(string, -1, 0);
>  }
>  
>  int is_utf8(const char *text)
> diff --git a/utf8.h b/utf8.h
> index 501b2bd..a556932 100644
> --- a/utf8.h
> +++ b/utf8.h
> @@ -4,6 +4,7 @@
>  typedef unsigned int ucs_char_t;  /* assuming 32bit int */
>  
>  int utf8_width(const char **start, size_t *remainder_p);
> +int utf8_strnwidth(const char *string, int len, int skip_ansi);
>  int utf8_strwidth(const char *string);
>  int is_utf8(const char *text);
>  int is_encoding_utf8(const char *name);

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it
  2013-03-30  9:35   ` [PATCH v2 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
@ 2013-04-01 18:10     ` Junio C Hamano
  0 siblings, 0 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-01 18:10 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> The commit encoding is parsed by logmsg_reencode, there's no need for
> the caller to re-parse it again. The reencoded message now has the new
> encoding, not the original one. The caller would need to read commit
> object again before parsing.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---

This and 06/12 look like a fix independent from the remainder of the
series.  Can they be moved a lot earlier in the series?

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder
  2013-03-30  9:35   ` [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
@ 2013-04-01 18:26     ` Junio C Hamano
  2013-04-05  2:21       ` Duy Nguyen
  0 siblings, 1 reply; 83+ messages in thread
From: Junio C Hamano @ 2013-04-01 18:26 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> This is not simply convenient over %C(auto,xxx). Some placeholders
> (actually only one, %d) do multi coloring and we can't emit a multiple
> colors with %C(auto,xxx).
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  Documentation/pretty-formats.txt |  3 ++-
>  pretty.c                         | 15 +++++++++++++--
>  2 files changed, 15 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
> index 66345d1..8734224 100644
> --- a/Documentation/pretty-formats.txt
> +++ b/Documentation/pretty-formats.txt
> @@ -154,7 +154,8 @@ The placeholders are:
>    adding `auto,` at the beginning will emit color only when colors are
>    enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
>    respecting the `auto` settings of the former if we are going to a
> -  terminal)
> +  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
> +  on the following placeholder.
>  - '%m': left, right or boundary mark
>  - '%n': newline
>  - '%%': a raw '%'

I like this at the conceptual level.

If you say "%C(auto)%C(red)Text%C(auto)%C(reset)", does it do the
right thing when the output is not capable of color?

I am a bit worried if the placement of the "grab c->auto_color to
decide if we paint for this round and reset it" is optimial and will
stay optimal as we enhance format_commit_one() later.  Is there a
reason why we do not do that at the beginning of the function,
before "these are independent of the commit" comment?

Side note.  Should the new field called "auto_color_next" or
something?

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 12/12] pretty: support %>> that steal trailing spaces
  2013-03-30  9:35   ` [PATCH v2 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
@ 2013-04-01 18:39     ` Junio C Hamano
  0 siblings, 0 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-01 18:39 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

The last three patches are a lot of fun.  It would be nice to have
some test vectors for them.

Thanks.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder
  2013-04-01 18:26     ` Junio C Hamano
@ 2013-04-05  2:21       ` Duy Nguyen
  2013-04-05 17:13         ` Junio C Hamano
  0 siblings, 1 reply; 83+ messages in thread
From: Duy Nguyen @ 2013-04-05  2:21 UTC (permalink / raw
  To: Junio C Hamano; +Cc: Git Mailing List

On Tue, Apr 2, 2013 at 5:26 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>
>> This is not simply convenient over %C(auto,xxx). Some placeholders
>> (actually only one, %d) do multi coloring and we can't emit a multiple
>> colors with %C(auto,xxx).
>>
>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
>> ---
>>  Documentation/pretty-formats.txt |  3 ++-
>>  pretty.c                         | 15 +++++++++++++--
>>  2 files changed, 15 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
>> index 66345d1..8734224 100644
>> --- a/Documentation/pretty-formats.txt
>> +++ b/Documentation/pretty-formats.txt
>> @@ -154,7 +154,8 @@ The placeholders are:
>>    adding `auto,` at the beginning will emit color only when colors are
>>    enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
>>    respecting the `auto` settings of the former if we are going to a
>> -  terminal)
>> +  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
>> +  on the following placeholder.
>>  - '%m': left, right or boundary mark
>>  - '%n': newline
>>  - '%%': a raw '%'
>
> I like this at the conceptual level.
>
> If you say "%C(auto)%C(red)Text%C(auto)%C(reset)", does it do the
> right thing when the output is not capable of color?

The above should have written "will turn on auto coloring on the
following _textual_ placeholder". I didn't intend %C(auto) to be
followed by %C(color) as it's already covered by %C(auto,red). But of
course we could make it work too.

> I am a bit worried if the placement of the "grab c->auto_color to
> decide if we paint for this round and reset it" is optimial and will
> stay optimal as we enhance format_commit_one() later.  Is there a
> reason why we do not do that at the beginning of the function,
> before "these are independent of the commit" comment?

No reason. Will move.

> Side note.  Should the new field called "auto_color_next" or
> something?

Yep, sounds better than my variable name.
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations
  2013-04-01 17:53     ` Junio C Hamano
@ 2013-04-05  7:57       ` Jakub Narębski
  2013-04-12 23:36         ` Duy Nguyen
  2013-04-12 23:34       ` Duy Nguyen
  1 sibling, 1 reply; 83+ messages in thread
From: Jakub Narębski @ 2013-04-05  7:57 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Junio C Hamano wrote:
> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

>> diff --git a/log-tree.h b/log-tree.h
>> index 9140f48..e6a2da5 100644
>> --- a/log-tree.h
>> +++ b/log-tree.h
>> @@ -13,6 +13,9 @@ int log_tree_diff_flush(struct rev_info *);
>>  int log_tree_commit(struct rev_info *, struct commit *);
>>  int log_tree_opt_parse(struct rev_info *, const char **, int);
>>  void show_log(struct rev_info *opt);
>> +void format_decoration(struct strbuf *sb,
>> +		       const struct commit *commit,
>> +		       int use_color);
> 
> I think you can fit these on a single line, especially if you drop
> the unused variable names (they help when there are more than one
> parameter of the same type to document the order of the arguments,
> but that does not apply here).  That would help people who run
> "grep" on the header files without using CTAGS/ETAGS.

Well, I think "int use_color" should be left with variable name,
don't you think?

-- 
Jakub Narębski

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder
  2013-04-05  2:21       ` Duy Nguyen
@ 2013-04-05 17:13         ` Junio C Hamano
  2013-04-15  9:54           ` Duy Nguyen
  0 siblings, 1 reply; 83+ messages in thread
From: Junio C Hamano @ 2013-04-05 17:13 UTC (permalink / raw
  To: Duy Nguyen; +Cc: Git Mailing List

Duy Nguyen <pclouds@gmail.com> writes:

> The above should have written "will turn on auto coloring on the
> following _textual_ placeholder". I didn't intend %C(auto) to be
> followed by %C(color) as it's already covered by %C(auto,red). But of
> course we could make it work too.

You are right that there is no need to say "%C(auto)%C(red)", it is
"%C(auto,red)", but that misses the point.

If %C(auto) applies to some %<placeholder> but not to some others,
the user needs to learn which %<placeholder> will eat the "auto" (so
it no longer applies to the next one) and which one will not even
look at "auto" (so the next %<placeholder> is affected by the auto,
i.e. making the effect of auto skip a %<placeholder>).  If the rule
were "%C(auto) applies to -next- placeholder", then the user does
not have to worry about which ones are what you call textual and
which ones are not (and there is no textual placeholder defined in
the glossary).

That would make it harder to learn. It would be much easier to
explain if you said "%C(auto) affects the next %-placeholder and
then resets".

I wonder if "Everything after %C(auto) will not be coloured if the
output is not going to the terminal.", i.e. not resetting once
colouring decision is made, makes more sense, though...

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations
  2013-04-01 17:53     ` Junio C Hamano
  2013-04-05  7:57       ` Jakub Narębski
@ 2013-04-12 23:34       ` Duy Nguyen
  1 sibling, 0 replies; 83+ messages in thread
From: Duy Nguyen @ 2013-04-12 23:34 UTC (permalink / raw
  To: Junio C Hamano; +Cc: Git Mailing List

Sorry for this late reply. I've been quite busy lately..

On Tue, Apr 2, 2013 at 4:53 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> -void show_decorations(struct rev_info *opt, struct commit *commit)
>> +void format_decoration(struct strbuf *sb,
>> +                    const struct commit *commit,
>> +                    int use_color)
>>  {
>> -     const char *prefix;
>> -     struct name_decoration *decoration;
>> +     const char *prefix = " (";
>> +     struct name_decoration *d;
>
> This renaming of variable from decoration to d seems to make the
> patched result unnecessarily different from the original in
> show_decorations, making it harder to compare.  Intentional?

I think I just happened to reuse the style of the old
format_decoration(). Will reuse the name "decoration" instead.

>>       const char *color_commit =
>> -             diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
>> +             diff_get_color(use_color, DIFF_COMMIT);
>>       const char *color_reset =
>> -             decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
>> +             decorate_get_color(use_color, DECORATION_NONE);
>> +
>> +     load_ref_decorations(DECORATE_SHORT_REFS);
>
> In cmd_log_init_finish(), we have loaded decorations with specified
> decoration_style already.  Why is this needed (and with a hardcoded
> style that may be different from what the user specified)?

legacy from pretty.c:format_decoration(). Will move it to the caller
format_commit_one.

>
>> +     d = lookup_decoration(&name_decoration, &commit->object);
>> +     if (!d)
>> +             return;
>> +     while (d) {
>> +             strbuf_addstr(sb, color_commit);
>> +             strbuf_addstr(sb, prefix);
>> +             strbuf_addstr(sb, decorate_get_color(use_color, d->type));
>> +             if (d->type == DECORATION_REF_TAG)
>> +                     strbuf_addstr(sb, "tag: ");
>> +             strbuf_addstr(sb, d->name);
>> +             strbuf_addstr(sb, color_reset);
>> +             prefix = ", ";
>> +             d = d->next;
>> +     }
>> +     if (prefix[0] == ',') {
>> +             strbuf_addstr(sb, color_commit);
>> +             strbuf_addch(sb, ')');
>> +             strbuf_addstr(sb, color_reset);
>> +     }
>
> Was this change to conditionally close ' (' mentioned in the log
> message?  It is in line with the version taken from pretty.c, and I
> think it may be an improvement, but I do not think the check is
> necessary in the context of this function.  You will never see
> prefix[0] != ',' after the loop, because "while (d)" above runs at
> least once; otherwise the "if (!d) return" would have returned from
> the function early, no?

Yes, your eyeballs have really good quality ;)

>> @@ -625,8 +639,8 @@ void show_log(struct rev_info *opt)
>>                       printf(" (from %s)",
>>                              find_unique_abbrev(parent->object.sha1,
>>                                                 abbrev_commit));
>> +             fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
>>               show_decorations(opt, commit);
>> -             printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
>
> We used to show and then reset.  I can see the updated
> show_decorations() to format_decoration() callchain always reset at
> the end, so the loss of the final reset here is very sane, but is
> there a need to reset beforehand?  What is the calling convention
> for the updated show_decorations()?  The caller should make sure
> there is no funny colors in effect before calling, and the caller
> can rest assured that there is no funny colors when the function
> returns?

I think it's a sane convention, unless we want a some background color
going through show_decorations.

>> +void format_decoration(struct strbuf *sb,
>> +                    const struct commit *commit,
>> +                    int use_color);
>
> I think you can fit these on a single line, especially if you drop
> the unused variable names (they help when there are more than one
> parameter of the same type to document the order of the arguments,
> but that does not apply here).  That would help people who run
> "grep" on the header files without using CTAGS/ETAGS.

No problem.

> Wouldn't it be "format_decorations()", or does it handle only one?

All in one, apparently. Will rename.
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations
  2013-04-05  7:57       ` Jakub Narębski
@ 2013-04-12 23:36         ` Duy Nguyen
  0 siblings, 0 replies; 83+ messages in thread
From: Duy Nguyen @ 2013-04-12 23:36 UTC (permalink / raw
  To: Jakub Narębski; +Cc: Git Mailing List, Junio C Hamano

On Fri, Apr 5, 2013 at 6:57 PM, Jakub Narębski <jnareb@gmail.com> wrote:
>>> +void format_decoration(struct strbuf *sb,
>>> +                   const struct commit *commit,
>>> +                   int use_color);
>>
>> I think you can fit these on a single line, especially if you drop
>> the unused variable names (they help when there are more than one
>> parameter of the same type to document the order of the arguments,
>> but that does not apply here).  That would help people who run
>> "grep" on the header files without using CTAGS/ETAGS.
>
> Well, I think "int use_color" should be left with variable name,
> don't you think?

I don't care too much about this. If Junio does not respond, I'll
leave the names in place (in one long line).
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder
  2013-04-05 17:13         ` Junio C Hamano
@ 2013-04-15  9:54           ` Duy Nguyen
  0 siblings, 0 replies; 83+ messages in thread
From: Duy Nguyen @ 2013-04-15  9:54 UTC (permalink / raw
  To: Junio C Hamano; +Cc: Git Mailing List

On Sat, Apr 6, 2013 at 4:13 AM, Junio C Hamano <gitster@pobox.com> wrote:
> If %C(auto) applies to some %<placeholder> but not to some others,
> the user needs to learn which %<placeholder> will eat the "auto" (so
> it no longer applies to the next one) and which one will not even
> look at "auto" (so the next %<placeholder> is affected by the auto,
> i.e. making the effect of auto skip a %<placeholder>).  If the rule
> were "%C(auto) applies to -next- placeholder", then the user does
> not have to worry about which ones are what you call textual and
> which ones are not (and there is no textual placeholder defined in
> the glossary).
>
> That would make it harder to learn. It would be much easier to
> explain if you said "%C(auto) affects the next %-placeholder and
> then resets".

So far (after this series, that is), we have two modifiers: %C(auto)
and %< (and friends). Both can be used to modify the "next"
placeholder, so either of them must learn to ignore the next
non-textual placeholder...

> I wonder if "Everything after %C(auto) will not be coloured if the
> output is not going to the terminal.", i.e. not resetting once
> colouring decision is made, makes more sense, though...

.. or we do this, which makes %< and friends the only placeholders
that care about the next one. Thanks for the idea.
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH v3 00/13] nd/pretty-formats
  2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
                     ` (11 preceding siblings ...)
  2013-03-30  9:35   ` [PATCH v2 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24   ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
                       ` (14 more replies)
  12 siblings, 15 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

I've been updating this series on and off over a long span of time, I
don't think I remember exactly what changes I've made. But basically
I think I have covered all comments from v2. The only semantics change
is %C(auto) now turns auto coloring on for all following placeholders
until another valid %C is encountered.

Nguyễn Thái Ngọc Duy (13):
  pretty: save commit encoding from logmsg_reencode if the caller needs it
  pretty: get the correct encoding for --pretty:format=%e
  pretty-formats.txt: wrap long lines
  pretty: share code between format_decoration and show_decorations
  utf8.c: move display_mode_esc_sequence_len() for use by other functions
  utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  utf8.c: add reencode_string_len() that can handle NULs in string
  pretty: two phase conversion for non utf-8 commits
  pretty: split color parsing into a separate function
  pretty: add %C(auto) for auto-coloring
  pretty: support padding placeholders, %< %> and %><
  pretty: support truncating in %>, %< and %><
  pretty: support %>> that steal trailing spaces

 Documentation/pretty-formats.txt |  35 +++-
 builtin/blame.c                  |   2 +-
 builtin/commit.c                 |   2 +-
 commit.h                         |   1 +
 compat/precompose_utf8.c         |   2 +-
 log-tree.c                       |  48 ++++--
 log-tree.h                       |   1 +
 pretty.c                         | 349 ++++++++++++++++++++++++++++++++-------
 revision.c                       |   2 +-
 t/t4205-log-pretty-formats.sh    | 179 ++++++++++++++++++++
 t/t4207-log-decoration-colors.sh |   8 +-
 t/t6006-rev-list-format.sh       |  12 +-
 utf8.c                           | 104 +++++++++---
 utf8.h                           |  23 ++-
 14 files changed, 644 insertions(+), 124 deletions(-)

-- 
1.8.2.82.gc24b958

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH v3 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 02/13] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
                       ` (13 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

The commit encoding is parsed by logmsg_reencode, there's no need for
the caller to re-parse it again. The reencoded message now has the new
encoding, not the original one. The caller would need to read commit
object again before parsing.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/blame.c  |  2 +-
 builtin/commit.c |  2 +-
 commit.h         |  1 +
 pretty.c         | 16 ++++++++++++----
 revision.c       |  2 +-
 5 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/builtin/blame.c b/builtin/blame.c
index 86100e9..104a948 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1425,7 +1425,7 @@ static void get_commit_info(struct commit *commit,
 	commit_info_init(ret);
 
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 	get_ac_line(message, "\nauthor ",
 		    &ret->author, &ret->author_mail,
 		    &ret->author_time, &ret->author_tz);
diff --git a/builtin/commit.c b/builtin/commit.c
index 4620437..d2f30d9 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -955,7 +955,7 @@ static const char *read_commit_message(const char *name)
 	if (!commit)
 		die(_("could not lookup commit %s"), name);
 	out_enc = get_commit_output_encoding();
-	return logmsg_reencode(commit, out_enc);
+	return logmsg_reencode(commit, NULL, out_enc);
 }
 
 static int parse_and_validate_options(int argc, const char *argv[],
diff --git a/commit.h b/commit.h
index 87b4b6c..ad55213 100644
--- a/commit.h
+++ b/commit.h
@@ -101,6 +101,7 @@ struct userformat_want {
 extern int has_non_ascii(const char *text);
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern char *logmsg_reencode(const struct commit *commit,
+			     char **commit_encoding,
 			     const char *output_encoding);
 extern void logmsg_free(char *msg, const struct commit *commit);
 extern void get_commit_format(const char *arg, struct rev_info *);
diff --git a/pretty.c b/pretty.c
index d3a82d2..c361b9b 100644
--- a/pretty.c
+++ b/pretty.c
@@ -594,6 +594,7 @@ static char *replace_encoding_header(char *buf, const char *encoding)
 }
 
 char *logmsg_reencode(const struct commit *commit,
+		      char **commit_encoding,
 		      const char *output_encoding)
 {
 	static const char *utf8 = "UTF-8";
@@ -615,9 +616,15 @@ char *logmsg_reencode(const struct commit *commit,
 			    sha1_to_hex(commit->object.sha1), typename(type));
 	}
 
-	if (!output_encoding || !*output_encoding)
+	if (!output_encoding || !*output_encoding) {
+		if (commit_encoding)
+			*commit_encoding =
+				get_header(commit, msg, "encoding");
 		return msg;
+	}
 	encoding = get_header(commit, msg, "encoding");
+	if (commit_encoding)
+		*commit_encoding = encoding;
 	use_encoding = encoding ? encoding : utf8;
 	if (same_encoding(use_encoding, output_encoding)) {
 		/*
@@ -658,7 +665,8 @@ char *logmsg_reencode(const struct commit *commit,
 	if (out)
 		out = replace_encoding_header(out, output_encoding);
 
-	free(encoding);
+	if (!commit_encoding)
+		free(encoding);
 	/*
 	 * If the re-encoding failed, out might be NULL here; in that
 	 * case we just return the commit message verbatim.
@@ -1288,7 +1296,7 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, output_enc);
+	context.message = logmsg_reencode(commit, NULL, output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
@@ -1451,7 +1459,7 @@ void pretty_print_commit(const struct pretty_print_context *pp,
 	}
 
 	encoding = get_log_output_encoding();
-	msg = reencoded = logmsg_reencode(commit, encoding);
+	msg = reencoded = logmsg_reencode(commit, NULL, encoding);
 
 	if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
 		indent = 0;
diff --git a/revision.c b/revision.c
index 71e62d8..2e77397 100644
--- a/revision.c
+++ b/revision.c
@@ -2314,7 +2314,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 	 * in it.
 	 */
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 
 	/* Copy the commit to temporary if we are using "fake" headers */
 	if (buf.len)
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 02/13] pretty: get the correct encoding for --pretty:format=%e
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 03/13] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
                       ` (12 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

parse_commit_header() provides the commit encoding for '%e' and it
reads it from the re-encoded message, which contains the new encoding,
not the original one in the commit object. This never happens because
--pretty=format:xxx never respects i18n.logoutputencoding. But that's
a different story.

Get the commit encoding from logmsg_reencode() instead.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/pretty.c b/pretty.c
index c361b9b..e59688b 100644
--- a/pretty.c
+++ b/pretty.c
@@ -776,12 +776,12 @@ struct format_commit_context {
 	unsigned commit_message_parsed:1;
 	struct signature_check signature_check;
 	char *message;
+	char *commit_encoding;
 	size_t width, indent1, indent2;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
 	struct chunk committer;
-	struct chunk encoding;
 	size_t message_off;
 	size_t subject_off;
 	size_t body_off;
@@ -828,9 +828,6 @@ static void parse_commit_header(struct format_commit_context *context)
 		} else if (!prefixcmp(msg + i, "committer ")) {
 			context->committer.off = i + 10;
 			context->committer.len = eol - i - 10;
-		} else if (!prefixcmp(msg + i, "encoding ")) {
-			context->encoding.off = i + 9;
-			context->encoding.len = eol - i - 9;
 		}
 		i = eol;
 	}
@@ -1185,7 +1182,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 				   msg + c->committer.off, c->committer.len,
 				   c->pretty_ctx->date_mode);
 	case 'e':	/* encoding */
-		strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
+		if (c->commit_encoding)
+			strbuf_addstr(sb, c->commit_encoding);
 		return 1;
 	case 'B':	/* raw body */
 		/* message_off is always left at the initial newline */
@@ -1296,11 +1294,14 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, NULL, output_enc);
+	context.message = logmsg_reencode(commit,
+					  &context.commit_encoding,
+					  output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature_check.gpg_output);
 	free(context.signature_check.signer);
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 03/13] pretty-formats.txt: wrap long lines
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 02/13] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 04/13] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
                       ` (11 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index afac703..6bde67e 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -106,18 +106,22 @@ The placeholders are:
 - '%P': parent hashes
 - '%p': abbreviated parent hashes
 - '%an': author name
-- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1]
+  or linkgit:git-blame[1])
 - '%ae': author email
-- '%aE': author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aE': author email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ad': author date (format respects --date= option)
 - '%aD': author date, RFC2822 style
 - '%ar': author date, relative
 - '%at': author date, UNIX timestamp
 - '%ai': author date, ISO 8601 format
 - '%cn': committer name
-- '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cN': committer name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ce': committer email
-- '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cE': committer email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%cd': committer date
 - '%cD': committer date, RFC2822 style
 - '%cr': committer date, relative
@@ -138,9 +142,11 @@ The placeholders are:
 - '%gD': reflog selector, e.g., `refs/stash@{1}`
 - '%gd': shortened reflog selector, e.g., `stash@{1}`
 - '%gn': reflog identity name
-- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gN': reflog identity name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ge': reflog identity email
-- '%gE': reflog identity email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gE': reflog identity email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%gs': reflog subject
 - '%Cred': switch color to red
 - '%Cgreen': switch color to green
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 04/13] pretty: share code between format_decoration and show_decorations
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (2 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 03/13] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
                       ` (10 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This also adds color support to format_decorations()

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 log-tree.c                       | 48 ++++++++++++++++++++++++++--------------
 log-tree.h                       |  1 +
 pretty.c                         | 20 ++---------------
 t/t4207-log-decoration-colors.sh |  8 +++----
 4 files changed, 39 insertions(+), 38 deletions(-)

diff --git a/log-tree.c b/log-tree.c
index 7cc7d59..1946e9c 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -175,36 +175,52 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 	}
 }
 
-void show_decorations(struct rev_info *opt, struct commit *commit)
+/*
+ * The caller makes sure there is no funny color before
+ * calling. format_decorations makes sure the same after return.
+ */
+void format_decorations(struct strbuf *sb,
+			const struct commit *commit,
+			int use_color)
 {
 	const char *prefix;
 	struct name_decoration *decoration;
 	const char *color_commit =
-		diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
+		diff_get_color(use_color, DIFF_COMMIT);
 	const char *color_reset =
-		decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
+		decorate_get_color(use_color, DECORATION_NONE);
 
-	if (opt->show_source && commit->util)
-		printf("\t%s", (char *) commit->util);
-	if (!opt->show_decorations)
-		return;
 	decoration = lookup_decoration(&name_decoration, &commit->object);
 	if (!decoration)
 		return;
 	prefix = " (";
 	while (decoration) {
-		printf("%s", prefix);
-		fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
-		      stdout);
+		strbuf_addstr(sb, color_commit);
+		strbuf_addstr(sb, prefix);
+		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
 		if (decoration->type == DECORATION_REF_TAG)
-			fputs("tag: ", stdout);
-		printf("%s", decoration->name);
-		fputs(color_reset, stdout);
-		fputs(color_commit, stdout);
+			strbuf_addstr(sb, "tag: ");
+		strbuf_addstr(sb, decoration->name);
+		strbuf_addstr(sb, color_reset);
 		prefix = ", ";
 		decoration = decoration->next;
 	}
-	putchar(')');
+	strbuf_addstr(sb, color_commit);
+	strbuf_addch(sb, ')');
+	strbuf_addstr(sb, color_reset);
+}
+
+void show_decorations(struct rev_info *opt, struct commit *commit)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	if (opt->show_source && commit->util)
+		printf("\t%s", (char *) commit->util);
+	if (!opt->show_decorations)
+		return;
+	format_decorations(&sb, commit, opt->diffopt.use_color);
+	fputs(sb.buf, stdout);
+	strbuf_release(&sb);
 }
 
 static unsigned int digits_in_number(unsigned int number)
@@ -540,8 +556,8 @@ void show_log(struct rev_info *opt)
 			printf(" (from %s)",
 			       find_unique_abbrev(parent->object.sha1,
 						  abbrev_commit));
+		fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
 		show_decorations(opt, commit);
-		printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
 		if (opt->commit_format == CMIT_FMT_ONELINE) {
 			putchar(' ');
 		} else {
diff --git a/log-tree.h b/log-tree.h
index 9140f48..d6ecd4d 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -13,6 +13,7 @@ int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 int log_tree_opt_parse(struct rev_info *, const char **, int);
 void show_log(struct rev_info *opt);
+void format_decorations(struct strbuf *sb, const struct commit *commit, int use_color);
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 			     const char **subject_p,
diff --git a/pretty.c b/pretty.c
index e59688b..e0f93ba 100644
--- a/pretty.c
+++ b/pretty.c
@@ -908,23 +908,6 @@ static void parse_commit_message(struct format_commit_context *c)
 	c->commit_message_parsed = 1;
 }
 
-static void format_decoration(struct strbuf *sb, const struct commit *commit)
-{
-	struct name_decoration *d;
-	const char *prefix = " (";
-
-	load_ref_decorations(DECORATE_SHORT_REFS);
-	d = lookup_decoration(&name_decoration, &commit->object);
-	while (d) {
-		strbuf_addstr(sb, prefix);
-		prefix = ", ";
-		strbuf_addstr(sb, d->name);
-		d = d->next;
-	}
-	if (prefix[0] == ',')
-		strbuf_addch(sb, ')');
-}
-
 static void strbuf_wrap(struct strbuf *sb, size_t pos,
 			size_t width, size_t indent1, size_t indent2)
 {
@@ -1103,7 +1086,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 		strbuf_addstr(sb, get_revision_mark(NULL, commit));
 		return 1;
 	case 'd':
-		format_decoration(sb, commit);
+		load_ref_decorations(DECORATE_SHORT_REFS);
+		format_decorations(sb, commit, 0);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index bbde31b..925f577 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -44,15 +44,15 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
  ${c_tag}tag: v1.0${c_reset}${c_commit},\
  ${c_tag}tag: B${c_reset}${c_commit},\
  ${c_branch}master${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\
  ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
  On master: Changes to A.t
-${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
 EOF
 
 # We want log to show all, but the second parent to refs/stash is irrelevant
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (3 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 04/13] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
                       ` (9 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/utf8.c b/utf8.c
index 7f64857..6ed93c3 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,6 +9,20 @@ struct interval {
   int last;
 };
 
+static size_t display_mode_esc_sequence_len(const char *s)
+{
+	const char *p = s;
+	if (*p++ != '\033')
+		return 0;
+	if (*p++ != '[')
+		return 0;
+	while (isdigit(*p) || *p == ';')
+		p++;
+	if (*p++ != 'm')
+		return 0;
+	return p - s;
+}
+
 /* auxiliary function for binary search in interval table */
 static int bisearch(ucs_char_t ucs, const struct interval *table, int max)
 {
@@ -303,20 +317,6 @@ static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
 	}
 }
 
-static size_t display_mode_esc_sequence_len(const char *s)
-{
-	const char *p = s;
-	if (*p++ != '\033')
-		return 0;
-	if (*p++ != '[')
-		return 0;
-	while (isdigit(*p) || *p == ';')
-		p++;
-	if (*p++ != 'm')
-		return 0;
-	return p - s;
-}
-
 /*
  * Wrap the text, if necessary. The variable indent is the indent for the
  * first line, indent2 is the indent for all other lines.
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (4 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
                       ` (8 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 20 ++++++++++++++------
 utf8.h |  1 +
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/utf8.c b/utf8.c
index 6ed93c3..9df087f 100644
--- a/utf8.c
+++ b/utf8.c
@@ -266,18 +266,26 @@ int utf8_width(const char **start, size_t *remainder_p)
  * string, assuming that the string is utf8.  Returns strlen() instead
  * if the string does not look like a valid utf8 string.
  */
-int utf8_strwidth(const char *string)
+int utf8_strnwidth(const char *string, int len, int skip_ansi)
 {
 	int width = 0;
 	const char *orig = string;
 
-	while (1) {
-		if (!string)
-			return strlen(orig);
-		if (!*string)
-			return width;
+	if (len == -1)
+		len = strlen(string);
+	while (string && string < orig + len) {
+		int skip;
+		while (skip_ansi &&
+		       (skip = display_mode_esc_sequence_len(string)))
+			string += skip;
 		width += utf8_width(&string, NULL);
 	}
+	return string ? width : len;
+}
+
+int utf8_strwidth(const char *string)
+{
+	return utf8_strnwidth(string, -1, 0);
 }
 
 int is_utf8(const char *text)
diff --git a/utf8.h b/utf8.h
index 1f8ecad..d3da96f 100644
--- a/utf8.h
+++ b/utf8.h
@@ -4,6 +4,7 @@
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
 int utf8_width(const char **start, size_t *remainder_p);
+int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
 int is_utf8(const char *text);
 int is_encoding_utf8(const char *name);
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (5 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:30       ` Duy Nguyen
  2013-04-18 17:25       ` Junio C Hamano
  2013-04-16  8:24     ` [PATCH v3 08/13] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
                       ` (7 subsequent siblings)
  14 siblings, 2 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 compat/precompose_utf8.c |  2 +-
 utf8.c                   | 10 +++++++---
 utf8.h                   | 19 ++++++++++++++++---
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 8cf5955..d9203d0 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -78,7 +78,7 @@ void precompose_argv(int argc, const char **argv)
 		size_t namelen;
 		oldarg = argv[i];
 		if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
-			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
+			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
 			if (newarg)
 				argv[i] = newarg;
 		}
diff --git a/utf8.c b/utf8.c
index 9df087f..ac630bc 100644
--- a/utf8.c
+++ b/utf8.c
@@ -468,7 +468,7 @@ int utf8_fprintf(FILE *stream, const char *format, ...)
 #else
 	typedef char * iconv_ibp;
 #endif
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv, int *outsz_p)
 {
 	size_t outsz, outalloc;
 	char *out, *outpos;
@@ -502,13 +502,17 @@ char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
 		}
 		else {
 			*outpos = '\0';
+			if (outsz_p)
+				*outsz_p = outpos - out;
 			break;
 		}
 	}
 	return out;
 }
 
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+char *reencode_string_len(const char *in, int insz,
+			  const char *out_encoding, const char *in_encoding,
+			  int *outsz)
 {
 	iconv_t conv;
 	char *out;
@@ -534,7 +538,7 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
 			return NULL;
 	}
 
-	out = reencode_string_iconv(in, strlen(in), conv);
+	out = reencode_string_iconv(in, insz, conv, outsz);
 	iconv_close(conv);
 	return out;
 }
diff --git a/utf8.h b/utf8.h
index d3da96f..a43ef9a 100644
--- a/utf8.h
+++ b/utf8.h
@@ -17,12 +17,25 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
 
 #ifndef NO_ICONV
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
+char *reencode_string_iconv(const char *in, size_t insz,
+			    iconv_t conv, int *outsz);
+char *reencode_string_len(const char *in, int insz,
+			  const char *out_encoding,
+			  const char *in_encoding,
+			  int *outsz);
 #else
-#define reencode_string(a,b,c) NULL
+#define reencode_string_len(a,b,c,d,e) NULL
 #endif
 
+static inline char *reencode_string(const char *in,
+				    const char *out_encoding,
+				    const char *in_encoding)
+{
+	return reencode_string_len(in, strlen(in),
+				   out_encoding, in_encoding,
+				   NULL);
+}
+
 int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
 
 #endif
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 08/13] pretty: two phase conversion for non utf-8 commits
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (6 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 09/13] pretty: split color parsing into a separate function Nguyễn Thái Ngọc Duy
                       ` (6 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 4649 bytes --]

Always assume format_commit_item() takes an utf-8 string for string
handling simplicity (we can handle utf-8 strings, but can't with other
encodings).

If commit message is in non-utf8, or output encoding is not, then the
commit is first converted to utf-8, processed, then output converted
to output encoding. This of course only works with encodings that are
compatible with Unicode.

This also fixes the iso8859-1 test in t6006. It's supposed to create
an iso8859-1 commit, but the commit content in t6006 is in UTF-8.
t6006 is now converted back in UTF-8 (the downside is we can't put
utf-8 strings there anymore).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c                   | 24 ++++++++++++++++++++++--
 t/t6006-rev-list-format.sh | 12 ++++++------
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/pretty.c b/pretty.c
index e0f93ba..5947275 100644
--- a/pretty.c
+++ b/pretty.c
@@ -954,7 +954,8 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
-static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
+				const char *placeholder,
 				void *context)
 {
 	struct format_commit_context *c = context;
@@ -1193,7 +1194,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 	return 0;	/* unknown placeholder */
 }
 
-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
+				 const char *placeholder,
 				 void *context)
 {
 	int consumed;
@@ -1273,6 +1275,7 @@ void format_commit_message(const struct commit *commit,
 {
 	struct format_commit_context context;
 	const char *output_enc = pretty_ctx->output_encoding;
+	const char *utf8 = "UTF-8";
 
 	memset(&context, 0, sizeof(context));
 	context.commit = commit;
@@ -1285,6 +1288,23 @@ void format_commit_message(const struct commit *commit,
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	if (output_enc) {
+		if (same_encoding(utf8, output_enc))
+			output_enc = NULL;
+	} else {
+		if (context.commit_encoding &&
+		    !same_encoding(context.commit_encoding, utf8))
+			output_enc = context.commit_encoding;
+	}
+
+	if (output_enc) {
+		int outsz;
+		char *out = reencode_string_len(sb->buf, sb->len,
+						output_enc, utf8, &outsz);
+		if (out)
+			strbuf_attach(sb, out, outsz, outsz + 1);
+	}
+
 	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature_check.gpg_output);
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 3fc3b74..0393c9f 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -184,7 +184,7 @@ Test printing of complex bodies
 
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 EOF
 test_expect_success 'setup complex body' '
 git config i18n.commitencoding iso8859-1 &&
@@ -192,14 +192,14 @@ git config i18n.commitencoding iso8859-1 &&
 '
 
 test_format complex-encoding %e <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 iso8859-1
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_format complex-subject %s <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 Test printing of complex bodies
 commit 131a310eb913d107dd3c09a65d1651175898735d
 changed foo
@@ -208,17 +208,17 @@ added foo
 EOF
 
 test_format complex-body %b <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_expect_success '%x00 shows NUL' '
-	echo  >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+	echo  >expect commit 1ed88da4a5b5ed8c449114ac131efc62178734c3 &&
 	echo >>expect fooQbar &&
 	git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
 	nul_to_q <actual.nul >actual &&
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 09/13] pretty: split color parsing into a separate function
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (7 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 08/13] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:24     ` [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
                       ` (5 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c | 71 +++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 39 insertions(+), 32 deletions(-)

diff --git a/pretty.c b/pretty.c
index 5947275..e0413e3 100644
--- a/pretty.c
+++ b/pretty.c
@@ -954,6 +954,44 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
+static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
+			  const char *placeholder,
+			  struct format_commit_context *c)
+{
+	if (placeholder[1] == '(') {
+		const char *begin = placeholder + 2;
+		const char *end = strchr(begin, ')');
+		char color[COLOR_MAXLEN];
+
+		if (!end)
+			return 0;
+		if (!prefixcmp(begin, "auto,")) {
+			if (!want_color(c->pretty_ctx->color))
+				return end - placeholder + 1;
+			begin += 5;
+		}
+		color_parse_mem(begin,
+				end - begin,
+				"--pretty format", color);
+		strbuf_addstr(sb, color);
+		return end - placeholder + 1;
+	}
+	if (!prefixcmp(placeholder + 1, "red")) {
+		strbuf_addstr(sb, GIT_COLOR_RED);
+		return 4;
+	} else if (!prefixcmp(placeholder + 1, "green")) {
+		strbuf_addstr(sb, GIT_COLOR_GREEN);
+		return 6;
+	} else if (!prefixcmp(placeholder + 1, "blue")) {
+		strbuf_addstr(sb, GIT_COLOR_BLUE);
+		return 5;
+	} else if (!prefixcmp(placeholder + 1, "reset")) {
+		strbuf_addstr(sb, GIT_COLOR_RESET);
+		return 6;
+	} else
+		return 0;
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 				const char *placeholder,
 				void *context)
@@ -967,38 +1005,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
 	case 'C':
-		if (placeholder[1] == '(') {
-			const char *begin = placeholder + 2;
-			const char *end = strchr(begin, ')');
-			char color[COLOR_MAXLEN];
-
-			if (!end)
-				return 0;
-			if (!prefixcmp(begin, "auto,")) {
-				if (!want_color(c->pretty_ctx->color))
-					return end - placeholder + 1;
-				begin += 5;
-			}
-			color_parse_mem(begin,
-					end - begin,
-					"--pretty format", color);
-			strbuf_addstr(sb, color);
-			return end - placeholder + 1;
-		}
-		if (!prefixcmp(placeholder + 1, "red")) {
-			strbuf_addstr(sb, GIT_COLOR_RED);
-			return 4;
-		} else if (!prefixcmp(placeholder + 1, "green")) {
-			strbuf_addstr(sb, GIT_COLOR_GREEN);
-			return 6;
-		} else if (!prefixcmp(placeholder + 1, "blue")) {
-			strbuf_addstr(sb, GIT_COLOR_BLUE);
-			return 5;
-		} else if (!prefixcmp(placeholder + 1, "reset")) {
-			strbuf_addstr(sb, GIT_COLOR_RESET);
-			return 6;
-		} else
-			return 0;
+		return parse_color(sb, placeholder, c);
 	case 'n':		/* newline */
 		strbuf_addch(sb, '\n');
 		return 1;
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (8 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 09/13] pretty: split color parsing into a separate function Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:24     ` Nguyễn Thái Ngọc Duy
  2013-04-16 21:33       ` Junio C Hamano
  2013-04-16 21:37       ` Junio C Hamano
  2013-04-16  8:25     ` [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
                       ` (4 subsequent siblings)
  14 siblings, 2 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:24 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is not simply convenient over %C(auto,xxx). Some placeholders
(actually only one, %d) do multi coloring and we can't emit a multiple
colors with %C(auto,xxx).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  3 ++-
 pretty.c                         | 17 +++++++++++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 6bde67e..bad627a 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -156,7 +156,8 @@ The placeholders are:
   adding `auto,` at the beginning will emit color only when colors are
   enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
   respecting the `auto` settings of the former if we are going to a
-  terminal)
+  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
+  on the next placeholders until the color is switched again.
 - '%m': left, right or boundary mark
 - '%n': newline
 - '%%': a raw '%'
diff --git a/pretty.c b/pretty.c
index e0413e3..f385176 100644
--- a/pretty.c
+++ b/pretty.c
@@ -778,6 +778,7 @@ struct format_commit_context {
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
+	int auto_color_next;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -1005,7 +1006,15 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
 	case 'C':
-		return parse_color(sb, placeholder, c);
+		if (!prefixcmp(placeholder + 1, "(auto)")) {
+			c->auto_color_next = 1;
+			return 7;
+		} else {
+			int ret = parse_color(sb, placeholder, c);
+			if (ret)
+				c->auto_color_next = 0;
+			return ret;
+		}
 	case 'n':		/* newline */
 		strbuf_addch(sb, '\n');
 		return 1;
@@ -1051,13 +1060,17 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 
 	switch (placeholder[0]) {
 	case 'H':		/* commit hash */
+		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_COMMIT));
 		strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
+		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_RESET));
 		return 1;
 	case 'h':		/* abbreviated commit hash */
+		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_COMMIT));
 		if (add_again(sb, &c->abbrev_commit_hash))
 			return 1;
 		strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
 						     c->pretty_ctx->abbrev));
+		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_RESET));
 		c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
 		return 1;
 	case 'T':		/* tree hash */
@@ -1095,7 +1108,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 		return 1;
 	case 'd':
 		load_ref_decorations(DECORATE_SHORT_REFS);
-		format_decorations(sb, commit, 0);
+		format_decorations(sb, commit, c->auto_color_next);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %><
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (9 preceding siblings ...)
  2013-04-16  8:24     ` [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:25     ` Nguyễn Thái Ngọc Duy
  2013-04-16 20:41       ` Junio C Hamano
  2013-04-16  8:25     ` [PATCH v3 12/13] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
                       ` (3 subsequent siblings)
  14 siblings, 1 reply; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Either %<, %> or %>< standing before a placeholder specifies how many
columns (at least as the placeholder can exceed it) it takes. Each
differs on how spaces are padded:

  %< pads on the right (aka left alignment)
  %> pads on the left (aka right alignment)
  %>< pads both ways equally (aka centered)

The (<N>) follows them, e.g. `%<(100)', to specify the number of
columns the next placeholder takes.

However, if '|' stands before (<N>), e.g. `%>|(100)', then the number
of columns is calculated so that it reaches the Nth column on screen.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |   8 +++
 pretty.c                         | 117 +++++++++++++++++++++++++++++++++++-
 t/t4205-log-pretty-formats.sh    | 126 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 250 insertions(+), 1 deletion(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index bad627a..e2345d2 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -164,6 +164,14 @@ The placeholders are:
 - '%x00': print a byte from a hex code
 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
+- '%<(<N>)': make the next placeholder take at least N columns,
+  padding spaces on the right if necessary
+- '%<|(<N>)': make the next placeholder take at least until Nth
+  columns, padding spaces on the right if necessary
+- '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+  respectively, but padding spaces on the left
+- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+  respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
 revision traversal engine. For example, the `%g*` reflog options will
diff --git a/pretty.c b/pretty.c
index f385176..7debfb2 100644
--- a/pretty.c
+++ b/pretty.c
@@ -769,16 +769,25 @@ struct chunk {
 	size_t len;
 };
 
+enum flush_type {
+	no_flush,
+	flush_right,
+	flush_left,
+	flush_both
+};
+
 struct format_commit_context {
 	const struct commit *commit;
 	const struct pretty_print_context *pretty_ctx;
 	unsigned commit_header_parsed:1;
 	unsigned commit_message_parsed:1;
 	struct signature_check signature_check;
+	enum flush_type flush_type;
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
 	int auto_color_next;
+	int padding;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -993,6 +1002,52 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
 		return 0;
 }
 
+static size_t parse_padding_placeholder(struct strbuf *sb,
+					const char *placeholder,
+					struct format_commit_context *c)
+{
+	const char *ch = placeholder;
+	enum flush_type flush_type;
+	int to_column = 0;
+
+	switch (*ch++) {
+	case '<':
+		flush_type = flush_right;
+		break;
+	case '>':
+		if (*ch == '<') {
+			flush_type = flush_both;
+			ch++;
+		} else
+			flush_type = flush_left;
+		break;
+	default:
+		return 0;
+	}
+
+	/* the next value means "wide enough to that column" */
+	if (*ch == '|') {
+		to_column = 1;
+		ch++;
+	}
+
+	if (*ch == '(') {
+		const char *start = ch + 1;
+		const char *end = strchr(start, ')');
+		char *next;
+		int width;
+		if (!end || end == start)
+			return 0;
+		width = strtoul(start, &next, 10);
+		if (next == start || width == 0)
+			return 0;
+		c->padding = to_column ? -width : width;
+		c->flush_type = flush_type;
+		return end - placeholder + 1;
+	}
+	return 0;
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 				const char *placeholder,
 				void *context)
@@ -1052,6 +1107,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 			return end - placeholder + 1;
 		} else
 			return 0;
+
+	case '<':
+	case '>':
+		return parse_padding_placeholder(sb, placeholder, c);
 	}
 
 	/* these depend on the commit */
@@ -1214,6 +1273,59 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	return 0;	/* unknown placeholder */
 }
 
+static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
+				    const char *placeholder,
+				    struct format_commit_context *c)
+{
+	struct strbuf local_sb = STRBUF_INIT;
+	int total_consumed = 0, len, padding = c->padding;
+	if (padding < 0) {
+		const char *start = strrchr(sb->buf, '\n');
+		int occupied;
+		if (!start)
+			start = sb->buf;
+		occupied = utf8_strnwidth(start, -1, 1);
+		padding = (-padding) - occupied;
+	}
+	while (1) {
+		int modifier = *placeholder == 'C';
+		int consumed = format_commit_one(&local_sb, placeholder, c);
+		total_consumed += consumed;
+
+		if (!modifier)
+			break;
+
+		placeholder += consumed;
+		if (*placeholder != '%')
+			break;
+		placeholder++;
+		total_consumed++;
+	}
+	len = utf8_strnwidth(local_sb.buf, -1, 1);
+	if (len > padding)
+		strbuf_addstr(sb, local_sb.buf);
+	else {
+		int sb_len = sb->len, offset = 0;
+		if (c->flush_type == flush_left)
+			offset = padding - len;
+		else if (c->flush_type == flush_both)
+			offset = (padding - len) / 2;
+		/*
+		 * we calculate padding in columns, now
+		 * convert it back to chars
+		 */
+		padding = padding - len + local_sb.len;
+		strbuf_grow(sb, padding);
+		strbuf_setlen(sb, sb_len + padding);
+		memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+		memcpy(sb->buf + sb_len + offset, local_sb.buf,
+		       local_sb.len);
+	}
+	strbuf_release(&local_sb);
+	c->flush_type = no_flush;
+	return total_consumed;
+}
+
 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 				 const char *placeholder,
 				 void *context)
@@ -1244,7 +1356,10 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 		placeholder++;
 
 	orig_len = sb->len;
-	consumed = format_commit_one(sb, placeholder, context);
+	if (((struct format_commit_context *)context)->flush_type != no_flush)
+		consumed = format_and_pad_commit(sb, placeholder, context);
+	else
+		consumed = format_commit_one(sb, placeholder, context);
 	if (magic == NO_MAGIC)
 		return consumed;
 
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 98a43d4..e9d7c2c 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -99,4 +99,130 @@ test_expect_failure 'NUL termination with --stat' '
 	test_i18ncmp expected actual
 '
 
+test_expect_success 'setup more commits' '
+	test_commit "message one" one one message-one &&
+	test_commit "message two" two two message-two
+'
+
+delete_trailing_dollar() {
+	sed 's/\$$//'
+}
+
+test_expect_success 'left alignment formatting' '
+	git log --pretty="format:%<(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+message two                             $
+message one                             $
+add bar                                 $
+initial                                 $
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting at the nth column' '
+	git log --pretty="format:%h %<|(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+fa33ab1 message two                     $
+7cd6c63 message one                     $
+1711bf9 add bar                         $
+af20c06 initial                         $
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with no padding' '
+	git log --pretty="format:%<(1)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF >expected &&
+message two
+message one
+add bar
+initial
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting' '
+	git log --pretty="format:%>(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+                             message two$
+                             message one$
+                                 add bar$
+                                 initial$
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting at the nth column' '
+	git log --pretty="format:%h %>|(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+fa33ab1                      message two$
+7cd6c63                      message one$
+1711bf9                          add bar$
+af20c06                          initial$
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting with no padding' '
+	git log --pretty="format:%>(1)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF >expected &&
+message two
+message one
+add bar
+initial
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting' '
+	git log --pretty="format:%><(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+              message two               $
+              message one               $
+                add bar                 $
+                initial                 $
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting at the nth column' '
+	git log --pretty="format:%h %><|(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+fa33ab1           message two           $
+7cd6c63           message one           $
+1711bf9             add bar             $
+af20c06             initial             $
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting with no padding' '
+	git log --pretty="format:%><(1)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF >expected &&
+message two
+message one
+add bar
+initial
+EOF
+	test_cmp expected actual
+'
+
 test_done
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 12/13] pretty: support truncating in %>, %< and %><
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (10 preceding siblings ...)
  2013-04-16  8:25     ` [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:25     ` Nguyễn Thái Ngọc Duy
  2013-04-16  8:25     ` [PATCH v3 13/13] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
                       ` (2 subsequent siblings)
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

%>(N,trunc) truncates the right 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 <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  7 ++++--
 pretty.c                         | 51 +++++++++++++++++++++++++++++++++++++---
 t/t4205-log-pretty-formats.sh    | 39 ++++++++++++++++++++++++++++++
 utf8.c                           | 46 ++++++++++++++++++++++++++++++++++++
 utf8.h                           |  2 ++
 5 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index e2345d2..d3450bf 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -164,8 +164,11 @@ The placeholders are:
 - '%x00': print a byte from a hex code
 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
-- '%<(<N>)': make the next placeholder take at least N columns,
-  padding spaces on the right if necessary
+- '%<(<N>[,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.
+  Note that truncating only works correctly with N >= 2.
 - '%<|(<N>)': make the next placeholder take at least until Nth
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
diff --git a/pretty.c b/pretty.c
index 7debfb2..a6c029c 100644
--- a/pretty.c
+++ b/pretty.c
@@ -776,6 +776,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;
@@ -783,6 +790,7 @@ struct format_commit_context {
 	unsigned commit_message_parsed:1;
 	struct signature_check signature_check;
 	enum flush_type flush_type;
+	enum trunc_type truncate;
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
@@ -1033,7 +1041,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)
@@ -1043,6 +1051,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;
@@ -1302,9 +1327,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/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index e9d7c2c..d1e9677 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -147,6 +147,45 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success 'left alignment formatting with trunc' '
+	git log --pretty="format:%<(10,trunc)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+message ..$
+message ..$
+add bar   $
+initial   $
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with ltrunc' '
+	git log --pretty="format:%<(10,ltrunc)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+..sage two$
+..sage one$
+add bar   $
+initial   $
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with mtrunc' '
+	git log --pretty="format:%<(10,mtrunc)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+mess.. two$
+mess.. one$
+add bar   $
+initial   $
+EOF
+	test_cmp expected actual
+'
+
 test_expect_success 'right alignment formatting' '
 	git log --pretty="format:%>(40)%s" >actual &&
 	# complete the incomplete line at the end
diff --git a/utf8.c b/utf8.c
index ac630bc..0428e76 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;
+			}
+			w += n;
+			continue;
+		}
+		memcpy(dst, old, src - old);
+		dst += src - old;
+		w += n;
+	}
+	strbuf_setlen(&sb_dst, dst - sb_dst.buf);
+	strbuf_attach(sb_src, strbuf_detach(&sb_dst, NULL),
+		      sb_dst.len, sb_dst.alloc);
+}
+
 int is_encoding_utf8(const char *name)
 {
 	if (!name)
diff --git a/utf8.h b/utf8.h
index a43ef9a..edde8ee 100644
--- a/utf8.h
+++ b/utf8.h
@@ -15,6 +15,8 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
 		const char *text, int indent, int indent2, int width);
 void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
+void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
+			 const char *subst);
 
 #ifndef NO_ICONV
 char *reencode_string_iconv(const char *in, size_t insz,
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v3 13/13] pretty: support %>> that steal trailing spaces
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (11 preceding siblings ...)
  2013-04-16  8:25     ` [PATCH v3 12/13] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:25     ` Nguyễn Thái Ngọc Duy
       [not found]     ` <516D57BD.7080208@web.de>
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
  14 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-16  8:25 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is pretty useful in `%<(100)%s%Cred%>(20)% an' where %s does not
use up all 100 columns and %an needs more than 20 columns. By
replacing %>(20) with %>>(20), %an can steal spaces from %s.

%>> understands escape sequences, so %Cred does not stop it from
stealing spaces in %<(100).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  5 ++++-
 pretty.c                         | 34 ++++++++++++++++++++++++++++++++++
 t/t4205-log-pretty-formats.sh    | 14 ++++++++++++++
 utf8.c                           |  2 +-
 utf8.h                           |  1 +
 5 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index d3450bf..c96ff41 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -173,7 +173,10 @@ The placeholders are:
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
   respectively, but padding spaces on the left
-- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+- '%>>(<N>)', '%>>|(<N>)': similar to '%>(<N>)', '%>|(<N>)'
+  respectively, except that if the next placeholder takes more spaces
+  than given and there are spaces on its left, use those spaces
+- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
   respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
diff --git a/pretty.c b/pretty.c
index a6c029c..306ba08 100644
--- a/pretty.c
+++ b/pretty.c
@@ -773,6 +773,7 @@ enum flush_type {
 	no_flush,
 	flush_right,
 	flush_left,
+	flush_left_and_steal,
 	flush_both
 };
 
@@ -1026,6 +1027,9 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
 		if (*ch == '<') {
 			flush_type = flush_both;
 			ch++;
+		} else if (*ch == '>') {
+			flush_type = flush_left_and_steal;
+			ch++;
 		} else
 			flush_type = flush_left;
 		break;
@@ -1327,6 +1331,36 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
 		total_consumed++;
 	}
 	len = utf8_strnwidth(local_sb.buf, -1, 1);
+
+	if (c->flush_type == flush_left_and_steal) {
+		const char *ch = sb->buf + sb->len - 1;
+		while (len > padding && ch > sb->buf) {
+			const char *p;
+			if (*ch == ' ') {
+				ch--;
+				padding++;
+				continue;
+			}
+			/* check for trailing ansi sequences */
+			if (*ch != 'm')
+				break;
+			p = ch - 1;
+			while (ch - p < 10 && *p != '\033')
+				p--;
+			if (*p != '\033' ||
+			    ch + 1 - p != display_mode_esc_sequence_len(p))
+				break;
+			/*
+			 * got a good ansi sequence, put it back to
+			 * local_sb as we're cutting sb
+			 */
+			strbuf_insert(&local_sb, 0, p, ch + 1 - p);
+			ch = p - 1;
+		}
+		strbuf_setlen(sb, ch + 1 - sb->buf);
+		c->flush_type = flush_left;
+	}
+
 	if (len > padding) {
 		switch (c->truncate) {
 		case trunc_left:
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index d1e9677..d006f76 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -264,4 +264,18 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success 'left/right alignment formatting with stealing' '
+	git commit --amend -m short --author "long long long <long@me.com>" &&
+	git log --pretty="format:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF | delete_trailing_dollar >expected &&
+short long  long long$
+message ..   A U Thor$
+add bar      A U Thor$
+initial      A U Thor$
+EOF
+	test_cmp expected actual
+'
+
 test_done
diff --git a/utf8.c b/utf8.c
index 0428e76..76e5c04 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,7 +9,7 @@ struct interval {
   int last;
 };
 
-static size_t display_mode_esc_sequence_len(const char *s)
+size_t display_mode_esc_sequence_len(const char *s)
 {
 	const char *p = s;
 	if (*p++ != '\033')
diff --git a/utf8.h b/utf8.h
index edde8ee..32a7bfb 100644
--- a/utf8.h
+++ b/utf8.h
@@ -3,6 +3,7 @@
 
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
+size_t display_mode_esc_sequence_len(const char *s);
 int utf8_width(const char **start, size_t *remainder_p);
 int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string
  2013-04-16  8:24     ` [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
@ 2013-04-16  8:30       ` Duy Nguyen
  2013-04-18 17:25       ` Junio C Hamano
  1 sibling, 0 replies; 83+ messages in thread
From: Duy Nguyen @ 2013-04-16  8:30 UTC (permalink / raw
  To: Git Mailing List, Torsten Bögershausen
  Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Torsten,

I can't compile compat/precomposed_utf8.c on linux even though I make
some changes there. Can you check if I break something? I'm pretty
sure I don't, but just in case.

On Tue, Apr 16, 2013 at 6:24 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  compat/precompose_utf8.c |  2 +-
>  utf8.c                   | 10 +++++++---
>  utf8.h                   | 19 ++++++++++++++++---
>  3 files changed, 24 insertions(+), 7 deletions(-)
>
> diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
> index 8cf5955..d9203d0 100644
> --- a/compat/precompose_utf8.c
> +++ b/compat/precompose_utf8.c
> @@ -78,7 +78,7 @@ void precompose_argv(int argc, const char **argv)
>                 size_t namelen;
>                 oldarg = argv[i];
>                 if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
> -                       newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
> +                       newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
>                         if (newarg)
>                                 argv[i] = newarg;
>                 }
> diff --git a/utf8.c b/utf8.c
> index 9df087f..ac630bc 100644
> --- a/utf8.c
> +++ b/utf8.c
> @@ -468,7 +468,7 @@ int utf8_fprintf(FILE *stream, const char *format, ...)
>  #else
>         typedef char * iconv_ibp;
>  #endif
> -char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
> +char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv, int *outsz_p)
>  {
>         size_t outsz, outalloc;
>         char *out, *outpos;
> @@ -502,13 +502,17 @@ char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
>                 }
>                 else {
>                         *outpos = '\0';
> +                       if (outsz_p)
> +                               *outsz_p = outpos - out;
>                         break;
>                 }
>         }
>         return out;
>  }
>
> -char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
> +char *reencode_string_len(const char *in, int insz,
> +                         const char *out_encoding, const char *in_encoding,
> +                         int *outsz)
>  {
>         iconv_t conv;
>         char *out;
> @@ -534,7 +538,7 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
>                         return NULL;
>         }
>
> -       out = reencode_string_iconv(in, strlen(in), conv);
> +       out = reencode_string_iconv(in, insz, conv, outsz);
>         iconv_close(conv);
>         return out;
>  }
> diff --git a/utf8.h b/utf8.h
> index d3da96f..a43ef9a 100644
> --- a/utf8.h
> +++ b/utf8.h
> @@ -17,12 +17,25 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
>                              int indent, int indent2, int width);
>
>  #ifndef NO_ICONV
> -char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
> -char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
> +char *reencode_string_iconv(const char *in, size_t insz,
> +                           iconv_t conv, int *outsz);
> +char *reencode_string_len(const char *in, int insz,
> +                         const char *out_encoding,
> +                         const char *in_encoding,
> +                         int *outsz);
>  #else
> -#define reencode_string(a,b,c) NULL
> +#define reencode_string_len(a,b,c,d,e) NULL
>  #endif
>
> +static inline char *reencode_string(const char *in,
> +                                   const char *out_encoding,
> +                                   const char *in_encoding)
> +{
> +       return reencode_string_len(in, strlen(in),
> +                                  out_encoding, in_encoding,
> +                                  NULL);
> +}
> +
>  int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
>
>  #endif
> --
> 1.8.2.82.gc24b958
>
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 00/13] nd/pretty-formats
       [not found]     ` <516D57BD.7080208@web.de>
@ 2013-04-16 14:47       ` Torsten Bögershausen
  0 siblings, 0 replies; 83+ messages in thread
From: Torsten Bögershausen @ 2013-04-16 14:47 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano

The short version:
all applied, compiled and test OK.

Possible minor nits from apply:
applying: pretty: support padding placeholders, %< %> and %><
/Users/tb/projects/git/tb.duy/.git/rebase-apply/patch:253: indent with spaces.
                             message two$
/Users/tb/projects/git/tb.duy/.git/rebase-apply/patch:254: indent with spaces.
                             message one$
/Users/tb/projects/git/tb.duy/.git/rebase-apply/patch:255: indent with spaces.
                                 add bar$
/Users/tb/projects/git/tb.duy/.git/rebase-apply/patch:256: indent with spaces.
                                 initial$
/Users/tb/projects/git/tb.duy/.git/rebase-apply/patch:292: indent with spaces.
              message two               $
warning: squelched 3 whitespace errors
=========================
And a possible micronit: what happened to that?

On Sun, Mar 31, 2013 at 12:06 AM, Torsten Bögershausen <tboegi@web.de> wrote:

> On 30.03.13 10:35, Nguyễn Thái Ngọc Duy wrote:
> [...]
> The short version of a review:
> Would it make sense to leave  reencode_string() as it is,
> and add a new function reencode_string_len()

Hmm.. yeah.

/Torsten

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %><
  2013-04-16  8:25     ` [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
@ 2013-04-16 20:41       ` Junio C Hamano
  2013-04-16 20:43         ` Junio C Hamano
  2013-04-17  9:45         ` Duy Nguyen
  0 siblings, 2 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-16 20:41 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> +delete_trailing_dollar() {
> +	sed 's/\$$//'
> +}

This is what we have qz_to_tab_space for, isn't it?  With it, you
can not just avoid "trailing whitespace", but also "indent with
spaces", like this:

Q         message thousand    Z

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %><
  2013-04-16 20:41       ` Junio C Hamano
@ 2013-04-16 20:43         ` Junio C Hamano
  2013-04-17  9:45         ` Duy Nguyen
  1 sibling, 0 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-16 20:43 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Junio C Hamano <gitster@pobox.com> writes:

> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>
>> +delete_trailing_dollar() {
>> +	sed 's/\$$//'
>> +}
>
> This is what we have qz_to_tab_space for, isn't it?  With it, you
> can not just avoid "trailing whitespace", but also "indent with
> spaces", like this:
>
> Q         message thousand    Z

Sorry, the above needs s/Q/Z/;

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring
  2013-04-16  8:24     ` [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
@ 2013-04-16 21:33       ` Junio C Hamano
  2013-04-17  9:55         ` Duy Nguyen
  2013-04-16 21:37       ` Junio C Hamano
  1 sibling, 1 reply; 83+ messages in thread
From: Junio C Hamano @ 2013-04-16 21:33 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> This is not simply convenient over %C(auto,xxx). Some placeholders
> (actually only one, %d) do multi coloring and we can't emit a multiple
> colors with %C(auto,xxx).
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  Documentation/pretty-formats.txt |  3 ++-
>  pretty.c                         | 17 +++++++++++++++--
>  2 files changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
> index 6bde67e..bad627a 100644
> --- a/Documentation/pretty-formats.txt
> +++ b/Documentation/pretty-formats.txt
> @@ -156,7 +156,8 @@ The placeholders are:
>    adding `auto,` at the beginning will emit color only when colors are
>    enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
>    respecting the `auto` settings of the former if we are going to a
> -  terminal)
> +  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
> +  on the next placeholders until the color is switched again.
>  - '%m': left, right or boundary mark
>  - '%n': newline
>  - '%%': a raw '%'

Good addition.

In the previous round, it used to be "%C(auto)" was remembered in
this field to color the _next_ one, and the momorized value was
toggled off.  As the field no longer toggles automatically once it
is used, perhaps it should simply be called "auto_color" without
"next", though?

I can locally tweak that before queuing if you think it is better.

> diff --git a/pretty.c b/pretty.c
> index e0413e3..f385176 100644
> --- a/pretty.c
> +++ b/pretty.c
> @@ -778,6 +778,7 @@ struct format_commit_context {
>  	char *message;
>  	char *commit_encoding;
>  	size_t width, indent1, indent2;
> +	int auto_color_next;
>  
>  	/* These offsets are relative to the start of the commit message. */
>  	struct chunk author;
> @@ -1005,7 +1006,15 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
>  	/* these are independent of the commit */
>  	switch (placeholder[0]) {
>  	case 'C':
> -		return parse_color(sb, placeholder, c);
> +		if (!prefixcmp(placeholder + 1, "(auto)")) {
> +			c->auto_color_next = 1;
> +			return 7;
> +		} else {
> +			int ret = parse_color(sb, placeholder, c);
> +			if (ret)
> +				c->auto_color_next = 0;
> +			return ret;
> +		}

This is to handle a corrupt input, e.g. "%C(auto)%Cbleu%H" where
(perhaps deprecated) "%Cblue" is misspelled, and parse_color()
returns 0 without consuming any byte.

Does it make sense not to turn auto off in such a case?  Otherwise
the above would become

	if (!prefixcmp(placeholder + 1, "(auto)")) {
        	c->auto_color_next = 1;
                return 7; /* consumed 7 bytes, "C(auto)" */
	}
        c->auto_color_next = 0;
        return parse_color(sb, placeholder, c);

which may be simpler.  When we see %C, previous %C(auto) is
cancelled.

>  	case 'n':		/* newline */
>  		strbuf_addch(sb, '\n');
>  		return 1;
> @@ -1051,13 +1060,17 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
>  
>  	switch (placeholder[0]) {
>  	case 'H':		/* commit hash */
> +		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_COMMIT));
>  		strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
> +		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_RESET));
>  		return 1;

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring
  2013-04-16  8:24     ` [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
  2013-04-16 21:33       ` Junio C Hamano
@ 2013-04-16 21:37       ` Junio C Hamano
  1 sibling, 0 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-16 21:37 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

>  	case 'h':		/* abbreviated commit hash */
> +		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_COMMIT));
>  		if (add_again(sb, &c->abbrev_commit_hash))
>  			return 1;

Doesn't this early return mess things up?

>  		strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
>  						     c->pretty_ctx->abbrev));
> +		strbuf_addstr(sb, diff_get_color(c->auto_color_next, DIFF_RESET));
>  		c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
>  		return 1;

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %><
  2013-04-16 20:41       ` Junio C Hamano
  2013-04-16 20:43         ` Junio C Hamano
@ 2013-04-17  9:45         ` Duy Nguyen
  1 sibling, 0 replies; 83+ messages in thread
From: Duy Nguyen @ 2013-04-17  9:45 UTC (permalink / raw
  To: Junio C Hamano; +Cc: Git Mailing List

On Wed, Apr 17, 2013 at 6:41 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>
>> +delete_trailing_dollar() {
>> +     sed 's/\$$//'
>> +}
>
> This is what we have qz_to_tab_space for, isn't it?

Thanks! I looked for something like this, but my eyes focused on
similar sed line and forgot the "tr"
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring
  2013-04-16 21:33       ` Junio C Hamano
@ 2013-04-17  9:55         ` Duy Nguyen
  2013-04-17 15:28           ` Junio C Hamano
  0 siblings, 1 reply; 83+ messages in thread
From: Duy Nguyen @ 2013-04-17  9:55 UTC (permalink / raw
  To: Junio C Hamano; +Cc: Git Mailing List

On Wed, Apr 17, 2013 at 7:33 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> @@ -1005,7 +1006,15 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
>>       /* these are independent of the commit */
>>       switch (placeholder[0]) {
>>       case 'C':
>> -             return parse_color(sb, placeholder, c);
>> +             if (!prefixcmp(placeholder + 1, "(auto)")) {
>> +                     c->auto_color_next = 1;
>> +                     return 7;
>> +             } else {
>> +                     int ret = parse_color(sb, placeholder, c);
>> +                     if (ret)
>> +                             c->auto_color_next = 0;
>> +                     return ret;
>> +             }
>
> This is to handle a corrupt input, e.g. "%C(auto)%Cbleu%H" where
> (perhaps deprecated) "%Cblue" is misspelled, and parse_color()
> returns 0 without consuming any byte.
>
> Does it make sense not to turn auto off in such a case?

We don't have any mechanism to report invalid %C. Instead we let them
through as literals. If they are literals, they should not have any
side effects. So I think it makes sense not to turn off things.

> Otherwise the above would become
>
>         if (!prefixcmp(placeholder + 1, "(auto)")) {
>                 c->auto_color_next = 1;
>                 return 7; /* consumed 7 bytes, "C(auto)" */
>         }
>         c->auto_color_next = 0;
>         return parse_color(sb, placeholder, c);
>
> which may be simpler.  When we see %C, previous %C(auto) is
> cancelled.

If we do this, maybe we could show invalid %C with blinking. Quite
catchy and might make the user wonder why. Of course it won't work
without coloring. But who would add %C in that case.
--
Duy

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring
  2013-04-17  9:55         ` Duy Nguyen
@ 2013-04-17 15:28           ` Junio C Hamano
  0 siblings, 0 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-17 15:28 UTC (permalink / raw
  To: Duy Nguyen; +Cc: Git Mailing List

Duy Nguyen <pclouds@gmail.com> writes:

>> This is to handle a corrupt input, e.g. "%C(auto)%Cbleu%H" where
>> (perhaps deprecated) "%Cblue" is misspelled, and parse_color()
>> returns 0 without consuming any byte.
>>
>> Does it make sense not to turn auto off in such a case?
>
> We don't have any mechanism to report invalid %C. Instead we let them
> through as literals. If they are literals, they should not have any
> side effects. So I think it makes sense not to turn off things.

Oh, you are right.  Thanks for a dose of sanity.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* Re: [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string
  2013-04-16  8:24     ` [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
  2013-04-16  8:30       ` Duy Nguyen
@ 2013-04-18 17:25       ` Junio C Hamano
  1 sibling, 0 replies; 83+ messages in thread
From: Junio C Hamano @ 2013-04-18 17:25 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> diff --git a/utf8.h b/utf8.h
> index d3da96f..a43ef9a 100644
> --- a/utf8.h
> +++ b/utf8.h
> @@ -17,12 +17,25 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
>  			     int indent, int indent2, int width);
>  
>  #ifndef NO_ICONV
> -char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
> -char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
> +char *reencode_string_iconv(const char *in, size_t insz,
> +			    iconv_t conv, int *outsz);
> +char *reencode_string_len(const char *in, int insz,
> +			  const char *out_encoding,
> +			  const char *in_encoding,
> +			  int *outsz);
>  #else
> -#define reencode_string(a,b,c) NULL
> +#define reencode_string_len(a,b,c,d,e) NULL
>  #endif
>  
> +static inline char *reencode_string(const char *in,
> +				    const char *out_encoding,
> +				    const char *in_encoding)
> +{
> +	return reencode_string_len(in, strlen(in),
> +				   out_encoding, in_encoding,
> +				   NULL);
> +}
> +
>  int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
>  
>  #endif

Nicely done.

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH v4 00/13] nd/pretty-formats
  2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
                       ` (13 preceding siblings ...)
       [not found]     ` <516D57BD.7080208@web.de>
@ 2013-04-18 23:08     ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
                         ` (12 more replies)
  14 siblings, 13 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

v4 fixes comments from v3, mainly in the auto-coloring patch, and uses
qz_to_tab_space for changes in t4205. It also fixes a coding style
issue in 06/13, spotted in v2 but I missed it in v3.

Nguyễn Thái Ngọc Duy (13):
  pretty: save commit encoding from logmsg_reencode if the caller needs it
  pretty: get the correct encoding for --pretty:format=%e
  pretty-formats.txt: wrap long lines
  pretty: share code between format_decoration and show_decorations
  utf8.c: move display_mode_esc_sequence_len() for use by other functions
  utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  utf8.c: add reencode_string_len() that can handle NULs in string
  pretty: two phase conversion for non utf-8 commits
  pretty: split color parsing into a separate function
  pretty: add %C(auto) for auto-coloring
  pretty: support padding placeholders, %< %> and %><
  pretty: support truncating in %>, %< and %><
  pretty: support %>> that steal trailing spaces

 Documentation/pretty-formats.txt |  35 +++-
 builtin/blame.c                  |   2 +-
 builtin/commit.c                 |   2 +-
 commit.h                         |   1 +
 compat/precompose_utf8.c         |   2 +-
 log-tree.c                       |  48 ++++--
 log-tree.h                       |   1 +
 pretty.c                         | 358 ++++++++++++++++++++++++++++++++-------
 revision.c                       |   2 +-
 t/t4205-log-pretty-formats.sh    | 175 +++++++++++++++++++
 t/t4207-log-decoration-colors.sh |   8 +-
 t/t6006-rev-list-format.sh       |  12 +-
 utf8.c                           | 104 +++++++++---
 utf8.h                           |  23 ++-
 14 files changed, 648 insertions(+), 125 deletions(-)

-- 
1.8.2.82.gc24b958

^ permalink raw reply	[flat|nested] 83+ messages in thread

* [PATCH v4 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 02/13] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
                         ` (11 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

The commit encoding is parsed by logmsg_reencode, there's no need for
the caller to re-parse it again. The reencoded message now has the new
encoding, not the original one. The caller would need to read commit
object again before parsing.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/blame.c  |  2 +-
 builtin/commit.c |  2 +-
 commit.h         |  1 +
 pretty.c         | 16 ++++++++++++----
 revision.c       |  2 +-
 5 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/builtin/blame.c b/builtin/blame.c
index 86100e9..104a948 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1425,7 +1425,7 @@ static void get_commit_info(struct commit *commit,
 	commit_info_init(ret);
 
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 	get_ac_line(message, "\nauthor ",
 		    &ret->author, &ret->author_mail,
 		    &ret->author_time, &ret->author_tz);
diff --git a/builtin/commit.c b/builtin/commit.c
index 4620437..d2f30d9 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -955,7 +955,7 @@ static const char *read_commit_message(const char *name)
 	if (!commit)
 		die(_("could not lookup commit %s"), name);
 	out_enc = get_commit_output_encoding();
-	return logmsg_reencode(commit, out_enc);
+	return logmsg_reencode(commit, NULL, out_enc);
 }
 
 static int parse_and_validate_options(int argc, const char *argv[],
diff --git a/commit.h b/commit.h
index 87b4b6c..ad55213 100644
--- a/commit.h
+++ b/commit.h
@@ -101,6 +101,7 @@ struct userformat_want {
 extern int has_non_ascii(const char *text);
 struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
 extern char *logmsg_reencode(const struct commit *commit,
+			     char **commit_encoding,
 			     const char *output_encoding);
 extern void logmsg_free(char *msg, const struct commit *commit);
 extern void get_commit_format(const char *arg, struct rev_info *);
diff --git a/pretty.c b/pretty.c
index d3a82d2..c361b9b 100644
--- a/pretty.c
+++ b/pretty.c
@@ -594,6 +594,7 @@ static char *replace_encoding_header(char *buf, const char *encoding)
 }
 
 char *logmsg_reencode(const struct commit *commit,
+		      char **commit_encoding,
 		      const char *output_encoding)
 {
 	static const char *utf8 = "UTF-8";
@@ -615,9 +616,15 @@ char *logmsg_reencode(const struct commit *commit,
 			    sha1_to_hex(commit->object.sha1), typename(type));
 	}
 
-	if (!output_encoding || !*output_encoding)
+	if (!output_encoding || !*output_encoding) {
+		if (commit_encoding)
+			*commit_encoding =
+				get_header(commit, msg, "encoding");
 		return msg;
+	}
 	encoding = get_header(commit, msg, "encoding");
+	if (commit_encoding)
+		*commit_encoding = encoding;
 	use_encoding = encoding ? encoding : utf8;
 	if (same_encoding(use_encoding, output_encoding)) {
 		/*
@@ -658,7 +665,8 @@ char *logmsg_reencode(const struct commit *commit,
 	if (out)
 		out = replace_encoding_header(out, output_encoding);
 
-	free(encoding);
+	if (!commit_encoding)
+		free(encoding);
 	/*
 	 * If the re-encoding failed, out might be NULL here; in that
 	 * case we just return the commit message verbatim.
@@ -1288,7 +1296,7 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, output_enc);
+	context.message = logmsg_reencode(commit, NULL, output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
@@ -1451,7 +1459,7 @@ void pretty_print_commit(const struct pretty_print_context *pp,
 	}
 
 	encoding = get_log_output_encoding();
-	msg = reencoded = logmsg_reencode(commit, encoding);
+	msg = reencoded = logmsg_reencode(commit, NULL, encoding);
 
 	if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
 		indent = 0;
diff --git a/revision.c b/revision.c
index 71e62d8..2e77397 100644
--- a/revision.c
+++ b/revision.c
@@ -2314,7 +2314,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 	 * in it.
 	 */
 	encoding = get_log_output_encoding();
-	message = logmsg_reencode(commit, encoding);
+	message = logmsg_reencode(commit, NULL, encoding);
 
 	/* Copy the commit to temporary if we are using "fake" headers */
 	if (buf.len)
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 02/13] pretty: get the correct encoding for --pretty:format=%e
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 03/13] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
                         ` (10 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

parse_commit_header() provides the commit encoding for '%e' and it
reads it from the re-encoded message, which contains the new encoding,
not the original one in the commit object. This never happens because
--pretty=format:xxx never respects i18n.logoutputencoding. But that's
a different story.

Get the commit encoding from logmsg_reencode() instead.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/pretty.c b/pretty.c
index c361b9b..e59688b 100644
--- a/pretty.c
+++ b/pretty.c
@@ -776,12 +776,12 @@ struct format_commit_context {
 	unsigned commit_message_parsed:1;
 	struct signature_check signature_check;
 	char *message;
+	char *commit_encoding;
 	size_t width, indent1, indent2;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
 	struct chunk committer;
-	struct chunk encoding;
 	size_t message_off;
 	size_t subject_off;
 	size_t body_off;
@@ -828,9 +828,6 @@ static void parse_commit_header(struct format_commit_context *context)
 		} else if (!prefixcmp(msg + i, "committer ")) {
 			context->committer.off = i + 10;
 			context->committer.len = eol - i - 10;
-		} else if (!prefixcmp(msg + i, "encoding ")) {
-			context->encoding.off = i + 9;
-			context->encoding.len = eol - i - 9;
 		}
 		i = eol;
 	}
@@ -1185,7 +1182,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 				   msg + c->committer.off, c->committer.len,
 				   c->pretty_ctx->date_mode);
 	case 'e':	/* encoding */
-		strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
+		if (c->commit_encoding)
+			strbuf_addstr(sb, c->commit_encoding);
 		return 1;
 	case 'B':	/* raw body */
 		/* message_off is always left at the initial newline */
@@ -1296,11 +1294,14 @@ void format_commit_message(const struct commit *commit,
 	context.commit = commit;
 	context.pretty_ctx = pretty_ctx;
 	context.wrap_start = sb->len;
-	context.message = logmsg_reencode(commit, NULL, output_enc);
+	context.message = logmsg_reencode(commit,
+					  &context.commit_encoding,
+					  output_enc);
 
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature_check.gpg_output);
 	free(context.signature_check.signer);
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 03/13] pretty-formats.txt: wrap long lines
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 02/13] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 04/13] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
                         ` (9 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index afac703..6bde67e 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -106,18 +106,22 @@ The placeholders are:
 - '%P': parent hashes
 - '%p': abbreviated parent hashes
 - '%an': author name
-- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aN': author name (respecting .mailmap, see linkgit:git-shortlog[1]
+  or linkgit:git-blame[1])
 - '%ae': author email
-- '%aE': author email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%aE': author email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ad': author date (format respects --date= option)
 - '%aD': author date, RFC2822 style
 - '%ar': author date, relative
 - '%at': author date, UNIX timestamp
 - '%ai': author date, ISO 8601 format
 - '%cn': committer name
-- '%cN': committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cN': committer name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ce': committer email
-- '%cE': committer email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%cE': committer email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%cd': committer date
 - '%cD': committer date, RFC2822 style
 - '%cr': committer date, relative
@@ -138,9 +142,11 @@ The placeholders are:
 - '%gD': reflog selector, e.g., `refs/stash@{1}`
 - '%gd': shortened reflog selector, e.g., `stash@{1}`
 - '%gn': reflog identity name
-- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gN': reflog identity name (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%ge': reflog identity email
-- '%gE': reflog identity email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%gE': reflog identity email (respecting .mailmap, see
+  linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%gs': reflog subject
 - '%Cred': switch color to red
 - '%Cgreen': switch color to green
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 04/13] pretty: share code between format_decoration and show_decorations
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (2 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 03/13] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
                         ` (8 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This also adds color support to format_decorations()

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 log-tree.c                       | 48 ++++++++++++++++++++++++++--------------
 log-tree.h                       |  1 +
 pretty.c                         | 20 ++---------------
 t/t4207-log-decoration-colors.sh |  8 +++----
 4 files changed, 39 insertions(+), 38 deletions(-)

diff --git a/log-tree.c b/log-tree.c
index 7cc7d59..1946e9c 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -175,36 +175,52 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
 	}
 }
 
-void show_decorations(struct rev_info *opt, struct commit *commit)
+/*
+ * The caller makes sure there is no funny color before
+ * calling. format_decorations makes sure the same after return.
+ */
+void format_decorations(struct strbuf *sb,
+			const struct commit *commit,
+			int use_color)
 {
 	const char *prefix;
 	struct name_decoration *decoration;
 	const char *color_commit =
-		diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
+		diff_get_color(use_color, DIFF_COMMIT);
 	const char *color_reset =
-		decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
+		decorate_get_color(use_color, DECORATION_NONE);
 
-	if (opt->show_source && commit->util)
-		printf("\t%s", (char *) commit->util);
-	if (!opt->show_decorations)
-		return;
 	decoration = lookup_decoration(&name_decoration, &commit->object);
 	if (!decoration)
 		return;
 	prefix = " (";
 	while (decoration) {
-		printf("%s", prefix);
-		fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
-		      stdout);
+		strbuf_addstr(sb, color_commit);
+		strbuf_addstr(sb, prefix);
+		strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
 		if (decoration->type == DECORATION_REF_TAG)
-			fputs("tag: ", stdout);
-		printf("%s", decoration->name);
-		fputs(color_reset, stdout);
-		fputs(color_commit, stdout);
+			strbuf_addstr(sb, "tag: ");
+		strbuf_addstr(sb, decoration->name);
+		strbuf_addstr(sb, color_reset);
 		prefix = ", ";
 		decoration = decoration->next;
 	}
-	putchar(')');
+	strbuf_addstr(sb, color_commit);
+	strbuf_addch(sb, ')');
+	strbuf_addstr(sb, color_reset);
+}
+
+void show_decorations(struct rev_info *opt, struct commit *commit)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	if (opt->show_source && commit->util)
+		printf("\t%s", (char *) commit->util);
+	if (!opt->show_decorations)
+		return;
+	format_decorations(&sb, commit, opt->diffopt.use_color);
+	fputs(sb.buf, stdout);
+	strbuf_release(&sb);
 }
 
 static unsigned int digits_in_number(unsigned int number)
@@ -540,8 +556,8 @@ void show_log(struct rev_info *opt)
 			printf(" (from %s)",
 			       find_unique_abbrev(parent->object.sha1,
 						  abbrev_commit));
+		fputs(diff_get_color_opt(&opt->diffopt, DIFF_RESET), stdout);
 		show_decorations(opt, commit);
-		printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
 		if (opt->commit_format == CMIT_FMT_ONELINE) {
 			putchar(' ');
 		} else {
diff --git a/log-tree.h b/log-tree.h
index 9140f48..d6ecd4d 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -13,6 +13,7 @@ int log_tree_diff_flush(struct rev_info *);
 int log_tree_commit(struct rev_info *, struct commit *);
 int log_tree_opt_parse(struct rev_info *, const char **, int);
 void show_log(struct rev_info *opt);
+void format_decorations(struct strbuf *sb, const struct commit *commit, int use_color);
 void show_decorations(struct rev_info *opt, struct commit *commit);
 void log_write_email_headers(struct rev_info *opt, struct commit *commit,
 			     const char **subject_p,
diff --git a/pretty.c b/pretty.c
index e59688b..e0f93ba 100644
--- a/pretty.c
+++ b/pretty.c
@@ -908,23 +908,6 @@ static void parse_commit_message(struct format_commit_context *c)
 	c->commit_message_parsed = 1;
 }
 
-static void format_decoration(struct strbuf *sb, const struct commit *commit)
-{
-	struct name_decoration *d;
-	const char *prefix = " (";
-
-	load_ref_decorations(DECORATE_SHORT_REFS);
-	d = lookup_decoration(&name_decoration, &commit->object);
-	while (d) {
-		strbuf_addstr(sb, prefix);
-		prefix = ", ";
-		strbuf_addstr(sb, d->name);
-		d = d->next;
-	}
-	if (prefix[0] == ',')
-		strbuf_addch(sb, ')');
-}
-
 static void strbuf_wrap(struct strbuf *sb, size_t pos,
 			size_t width, size_t indent1, size_t indent2)
 {
@@ -1103,7 +1086,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 		strbuf_addstr(sb, get_revision_mark(NULL, commit));
 		return 1;
 	case 'd':
-		format_decoration(sb, commit);
+		load_ref_decorations(DECORATE_SHORT_REFS);
+		format_decorations(sb, commit, 0);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
diff --git a/t/t4207-log-decoration-colors.sh b/t/t4207-log-decoration-colors.sh
index bbde31b..925f577 100755
--- a/t/t4207-log-decoration-colors.sh
+++ b/t/t4207-log-decoration-colors.sh
@@ -44,15 +44,15 @@ test_expect_success setup '
 '
 
 cat >expected <<EOF
-${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_HEAD}HEAD${c_reset}${c_commit},\
  ${c_tag}tag: v1.0${c_reset}${c_commit},\
  ${c_tag}tag: B${c_reset}${c_commit},\
  ${c_branch}master${c_reset}${c_commit})${c_reset} B
-${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A1${c_reset}${c_commit},\
  ${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
-${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
  On master: Changes to A.t
-${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
+${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
 EOF
 
 # We want log to show all, but the second parent to refs/stash is irrelevant
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (3 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 04/13] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
                         ` (7 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/utf8.c b/utf8.c
index 7f64857..6ed93c3 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,6 +9,20 @@ struct interval {
   int last;
 };
 
+static size_t display_mode_esc_sequence_len(const char *s)
+{
+	const char *p = s;
+	if (*p++ != '\033')
+		return 0;
+	if (*p++ != '[')
+		return 0;
+	while (isdigit(*p) || *p == ';')
+		p++;
+	if (*p++ != 'm')
+		return 0;
+	return p - s;
+}
+
 /* auxiliary function for binary search in interval table */
 static int bisearch(ucs_char_t ucs, const struct interval *table, int max)
 {
@@ -303,20 +317,6 @@ static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
 	}
 }
 
-static size_t display_mode_esc_sequence_len(const char *s)
-{
-	const char *p = s;
-	if (*p++ != '\033')
-		return 0;
-	if (*p++ != '[')
-		return 0;
-	while (isdigit(*p) || *p == ';')
-		p++;
-	if (*p++ != 'm')
-		return 0;
-	return p - s;
-}
-
 /*
  * Wrap the text, if necessary. The variable indent is the indent for the
  * first line, indent2 is the indent for all other lines.
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (4 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
                         ` (6 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 utf8.c | 20 ++++++++++++++------
 utf8.h |  1 +
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/utf8.c b/utf8.c
index 6ed93c3..e7ba33c 100644
--- a/utf8.c
+++ b/utf8.c
@@ -266,18 +266,26 @@ int utf8_width(const char **start, size_t *remainder_p)
  * string, assuming that the string is utf8.  Returns strlen() instead
  * if the string does not look like a valid utf8 string.
  */
-int utf8_strwidth(const char *string)
+int utf8_strnwidth(const char *string, int len, int skip_ansi)
 {
 	int width = 0;
 	const char *orig = string;
 
-	while (1) {
-		if (!string)
-			return strlen(orig);
-		if (!*string)
-			return width;
+	if (len == -1)
+		len = strlen(string);
+	while (string && string < orig + len) {
+		int skip;
+		while (skip_ansi &&
+		       (skip = display_mode_esc_sequence_len(string)) != 0)
+			string += skip;
 		width += utf8_width(&string, NULL);
 	}
+	return string ? width : len;
+}
+
+int utf8_strwidth(const char *string)
+{
+	return utf8_strnwidth(string, -1, 0);
 }
 
 int is_utf8(const char *text)
diff --git a/utf8.h b/utf8.h
index 1f8ecad..d3da96f 100644
--- a/utf8.h
+++ b/utf8.h
@@ -4,6 +4,7 @@
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
 int utf8_width(const char **start, size_t *remainder_p);
+int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
 int is_utf8(const char *text);
 int is_encoding_utf8(const char *name);
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 07/13] utf8.c: add reencode_string_len() that can handle NULs in string
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (5 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 08/13] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
                         ` (5 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 compat/precompose_utf8.c |  2 +-
 utf8.c                   | 10 +++++++---
 utf8.h                   | 19 ++++++++++++++++---
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 8cf5955..d9203d0 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -78,7 +78,7 @@ void precompose_argv(int argc, const char **argv)
 		size_t namelen;
 		oldarg = argv[i];
 		if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
-			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
+			newarg = reencode_string_iconv(oldarg, namelen, ic_precompose, NULL);
 			if (newarg)
 				argv[i] = newarg;
 		}
diff --git a/utf8.c b/utf8.c
index e7ba33c..7c342ff 100644
--- a/utf8.c
+++ b/utf8.c
@@ -468,7 +468,7 @@ int utf8_fprintf(FILE *stream, const char *format, ...)
 #else
 	typedef char * iconv_ibp;
 #endif
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
+char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv, int *outsz_p)
 {
 	size_t outsz, outalloc;
 	char *out, *outpos;
@@ -502,13 +502,17 @@ char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv)
 		}
 		else {
 			*outpos = '\0';
+			if (outsz_p)
+				*outsz_p = outpos - out;
 			break;
 		}
 	}
 	return out;
 }
 
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+char *reencode_string_len(const char *in, int insz,
+			  const char *out_encoding, const char *in_encoding,
+			  int *outsz)
 {
 	iconv_t conv;
 	char *out;
@@ -534,7 +538,7 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
 			return NULL;
 	}
 
-	out = reencode_string_iconv(in, strlen(in), conv);
+	out = reencode_string_iconv(in, insz, conv, outsz);
 	iconv_close(conv);
 	return out;
 }
diff --git a/utf8.h b/utf8.h
index d3da96f..a43ef9a 100644
--- a/utf8.h
+++ b/utf8.h
@@ -17,12 +17,25 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
 
 #ifndef NO_ICONV
-char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv);
-char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
+char *reencode_string_iconv(const char *in, size_t insz,
+			    iconv_t conv, int *outsz);
+char *reencode_string_len(const char *in, int insz,
+			  const char *out_encoding,
+			  const char *in_encoding,
+			  int *outsz);
 #else
-#define reencode_string(a,b,c) NULL
+#define reencode_string_len(a,b,c,d,e) NULL
 #endif
 
+static inline char *reencode_string(const char *in,
+				    const char *out_encoding,
+				    const char *in_encoding)
+{
+	return reencode_string_len(in, strlen(in),
+				   out_encoding, in_encoding,
+				   NULL);
+}
+
 int mbs_chrlen(const char **text, size_t *remainder_p, const char *encoding);
 
 #endif
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 08/13] pretty: two phase conversion for non utf-8 commits
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (6 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 09/13] pretty: split color parsing into a separate function Nguyễn Thái Ngọc Duy
                         ` (4 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 4649 bytes --]

Always assume format_commit_item() takes an utf-8 string for string
handling simplicity (we can handle utf-8 strings, but can't with other
encodings).

If commit message is in non-utf8, or output encoding is not, then the
commit is first converted to utf-8, processed, then output converted
to output encoding. This of course only works with encodings that are
compatible with Unicode.

This also fixes the iso8859-1 test in t6006. It's supposed to create
an iso8859-1 commit, but the commit content in t6006 is in UTF-8.
t6006 is now converted back in UTF-8 (the downside is we can't put
utf-8 strings there anymore).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c                   | 24 ++++++++++++++++++++++--
 t/t6006-rev-list-format.sh | 12 ++++++------
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/pretty.c b/pretty.c
index e0f93ba..5947275 100644
--- a/pretty.c
+++ b/pretty.c
@@ -954,7 +954,8 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
-static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
+				const char *placeholder,
 				void *context)
 {
 	struct format_commit_context *c = context;
@@ -1193,7 +1194,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
 	return 0;	/* unknown placeholder */
 }
 
-static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
+static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
+				 const char *placeholder,
 				 void *context)
 {
 	int consumed;
@@ -1273,6 +1275,7 @@ void format_commit_message(const struct commit *commit,
 {
 	struct format_commit_context context;
 	const char *output_enc = pretty_ctx->output_encoding;
+	const char *utf8 = "UTF-8";
 
 	memset(&context, 0, sizeof(context));
 	context.commit = commit;
@@ -1285,6 +1288,23 @@ void format_commit_message(const struct commit *commit,
 	strbuf_expand(sb, format, format_commit_item, &context);
 	rewrap_message_tail(sb, &context, 0, 0, 0);
 
+	if (output_enc) {
+		if (same_encoding(utf8, output_enc))
+			output_enc = NULL;
+	} else {
+		if (context.commit_encoding &&
+		    !same_encoding(context.commit_encoding, utf8))
+			output_enc = context.commit_encoding;
+	}
+
+	if (output_enc) {
+		int outsz;
+		char *out = reencode_string_len(sb->buf, sb->len,
+						output_enc, utf8, &outsz);
+		if (out)
+			strbuf_attach(sb, out, outsz, outsz + 1);
+	}
+
 	free(context.commit_encoding);
 	logmsg_free(context.message, commit);
 	free(context.signature_check.gpg_output);
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 3fc3b74..0393c9f 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -184,7 +184,7 @@ Test printing of complex bodies
 
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 EOF
 test_expect_success 'setup complex body' '
 git config i18n.commitencoding iso8859-1 &&
@@ -192,14 +192,14 @@ git config i18n.commitencoding iso8859-1 &&
 '
 
 test_format complex-encoding %e <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 iso8859-1
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_format complex-subject %s <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 Test printing of complex bodies
 commit 131a310eb913d107dd3c09a65d1651175898735d
 changed foo
@@ -208,17 +208,17 @@ added foo
 EOF
 
 test_format complex-body %b <<'EOF'
-commit f58db70b055c5718631e5c61528b28b12090cdea
+commit 1ed88da4a5b5ed8c449114ac131efc62178734c3
 This commit message is much longer than the others,
 and it will be encoded in iso8859-1. We should therefore
-include an iso8859 character: ¡bueno!
+include an iso8859 character: ¡bueno!
 
 commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
 test_expect_success '%x00 shows NUL' '
-	echo  >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+	echo  >expect commit 1ed88da4a5b5ed8c449114ac131efc62178734c3 &&
 	echo >>expect fooQbar &&
 	git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
 	nul_to_q <actual.nul >actual &&
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 09/13] pretty: split color parsing into a separate function
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (7 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 08/13] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
                         ` (3 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pretty.c | 71 +++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 39 insertions(+), 32 deletions(-)

diff --git a/pretty.c b/pretty.c
index 5947275..e0413e3 100644
--- a/pretty.c
+++ b/pretty.c
@@ -954,6 +954,44 @@ static int format_reflog_person(struct strbuf *sb,
 	return format_person_part(sb, part, ident, strlen(ident), dmode);
 }
 
+static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
+			  const char *placeholder,
+			  struct format_commit_context *c)
+{
+	if (placeholder[1] == '(') {
+		const char *begin = placeholder + 2;
+		const char *end = strchr(begin, ')');
+		char color[COLOR_MAXLEN];
+
+		if (!end)
+			return 0;
+		if (!prefixcmp(begin, "auto,")) {
+			if (!want_color(c->pretty_ctx->color))
+				return end - placeholder + 1;
+			begin += 5;
+		}
+		color_parse_mem(begin,
+				end - begin,
+				"--pretty format", color);
+		strbuf_addstr(sb, color);
+		return end - placeholder + 1;
+	}
+	if (!prefixcmp(placeholder + 1, "red")) {
+		strbuf_addstr(sb, GIT_COLOR_RED);
+		return 4;
+	} else if (!prefixcmp(placeholder + 1, "green")) {
+		strbuf_addstr(sb, GIT_COLOR_GREEN);
+		return 6;
+	} else if (!prefixcmp(placeholder + 1, "blue")) {
+		strbuf_addstr(sb, GIT_COLOR_BLUE);
+		return 5;
+	} else if (!prefixcmp(placeholder + 1, "reset")) {
+		strbuf_addstr(sb, GIT_COLOR_RESET);
+		return 6;
+	} else
+		return 0;
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 				const char *placeholder,
 				void *context)
@@ -967,38 +1005,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
 	case 'C':
-		if (placeholder[1] == '(') {
-			const char *begin = placeholder + 2;
-			const char *end = strchr(begin, ')');
-			char color[COLOR_MAXLEN];
-
-			if (!end)
-				return 0;
-			if (!prefixcmp(begin, "auto,")) {
-				if (!want_color(c->pretty_ctx->color))
-					return end - placeholder + 1;
-				begin += 5;
-			}
-			color_parse_mem(begin,
-					end - begin,
-					"--pretty format", color);
-			strbuf_addstr(sb, color);
-			return end - placeholder + 1;
-		}
-		if (!prefixcmp(placeholder + 1, "red")) {
-			strbuf_addstr(sb, GIT_COLOR_RED);
-			return 4;
-		} else if (!prefixcmp(placeholder + 1, "green")) {
-			strbuf_addstr(sb, GIT_COLOR_GREEN);
-			return 6;
-		} else if (!prefixcmp(placeholder + 1, "blue")) {
-			strbuf_addstr(sb, GIT_COLOR_BLUE);
-			return 5;
-		} else if (!prefixcmp(placeholder + 1, "reset")) {
-			strbuf_addstr(sb, GIT_COLOR_RESET);
-			return 6;
-		} else
-			return 0;
+		return parse_color(sb, placeholder, c);
 	case 'n':		/* newline */
 		strbuf_addch(sb, '\n');
 		return 1;
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 10/13] pretty: add %C(auto) for auto-coloring
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (8 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 09/13] pretty: split color parsing into a separate function Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 11/13] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
                         ` (2 subsequent siblings)
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is not simply convenient over %C(auto,xxx). Some placeholders
(actually only one, %d) do multi coloring and we can't emit a multiple
colors with %C(auto,xxx).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  3 ++-
 pretty.c                         | 26 +++++++++++++++++++++++---
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 6bde67e..bad627a 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -156,7 +156,8 @@ The placeholders are:
   adding `auto,` at the beginning will emit color only when colors are
   enabled for log output (by `color.diff`, `color.ui`, or `--color`, and
   respecting the `auto` settings of the former if we are going to a
-  terminal)
+  terminal). `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
+  on the next placeholders until the color is switched again.
 - '%m': left, right or boundary mark
 - '%n': newline
 - '%%': a raw '%'
diff --git a/pretty.c b/pretty.c
index e0413e3..3612f82 100644
--- a/pretty.c
+++ b/pretty.c
@@ -778,6 +778,7 @@ struct format_commit_context {
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
+	int auto_color;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -1005,7 +1006,20 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	/* these are independent of the commit */
 	switch (placeholder[0]) {
 	case 'C':
-		return parse_color(sb, placeholder, c);
+		if (!prefixcmp(placeholder + 1, "(auto)")) {
+			c->auto_color = 1;
+			return 7; /* consumed 7 bytes, "C(auto)" */
+		} else {
+			int ret = parse_color(sb, placeholder, c);
+			if (ret)
+				c->auto_color = 0;
+			/*
+			 * Otherwise, we decided to treat %C<unknown>
+			 * as a literal string, and the previous
+			 * %C(auto) is still valid.
+			 */
+			return ret;
+		}
 	case 'n':		/* newline */
 		strbuf_addch(sb, '\n');
 		return 1;
@@ -1051,13 +1065,19 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 
 	switch (placeholder[0]) {
 	case 'H':		/* commit hash */
+		strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
 		strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
+		strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
 		return 1;
 	case 'h':		/* abbreviated commit hash */
-		if (add_again(sb, &c->abbrev_commit_hash))
+		strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
+		if (add_again(sb, &c->abbrev_commit_hash)) {
+			strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
 			return 1;
+		}
 		strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
 						     c->pretty_ctx->abbrev));
+		strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
 		c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
 		return 1;
 	case 'T':		/* tree hash */
@@ -1095,7 +1115,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 		return 1;
 	case 'd':
 		load_ref_decorations(DECORATE_SHORT_REFS);
-		format_decorations(sb, commit, 0);
+		format_decorations(sb, commit, c->auto_color);
 		return 1;
 	case 'g':		/* reflog info */
 		switch(placeholder[1]) {
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 11/13] pretty: support padding placeholders, %< %> and %><
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (9 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 12/13] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 13/13] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Either %<, %> or %>< standing before a placeholder specifies how many
columns (at least as the placeholder can exceed it) it takes. Each
differs on how spaces are padded:

  %< pads on the right (aka left alignment)
  %> pads on the left (aka right alignment)
  %>< pads both ways equally (aka centered)

The (<N>) follows them, e.g. `%<(100)', to specify the number of
columns the next placeholder takes.

However, if '|' stands before (<N>), e.g. `%>|(100)', then the number
of columns is calculated so that it reaches the Nth column on screen.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |   8 +++
 pretty.c                         | 117 ++++++++++++++++++++++++++++++++++++-
 t/t4205-log-pretty-formats.sh    | 122 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 246 insertions(+), 1 deletion(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index bad627a..e2345d2 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -164,6 +164,14 @@ The placeholders are:
 - '%x00': print a byte from a hex code
 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
+- '%<(<N>)': make the next placeholder take at least N columns,
+  padding spaces on the right if necessary
+- '%<|(<N>)': make the next placeholder take at least until Nth
+  columns, padding spaces on the right if necessary
+- '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+  respectively, but padding spaces on the left
+- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+  respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
 revision traversal engine. For example, the `%g*` reflog options will
diff --git a/pretty.c b/pretty.c
index 3612f82..b50ebf5 100644
--- a/pretty.c
+++ b/pretty.c
@@ -769,16 +769,25 @@ struct chunk {
 	size_t len;
 };
 
+enum flush_type {
+	no_flush,
+	flush_right,
+	flush_left,
+	flush_both
+};
+
 struct format_commit_context {
 	const struct commit *commit;
 	const struct pretty_print_context *pretty_ctx;
 	unsigned commit_header_parsed:1;
 	unsigned commit_message_parsed:1;
 	struct signature_check signature_check;
+	enum flush_type flush_type;
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
 	int auto_color;
+	int padding;
 
 	/* These offsets are relative to the start of the commit message. */
 	struct chunk author;
@@ -993,6 +1002,52 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
 		return 0;
 }
 
+static size_t parse_padding_placeholder(struct strbuf *sb,
+					const char *placeholder,
+					struct format_commit_context *c)
+{
+	const char *ch = placeholder;
+	enum flush_type flush_type;
+	int to_column = 0;
+
+	switch (*ch++) {
+	case '<':
+		flush_type = flush_right;
+		break;
+	case '>':
+		if (*ch == '<') {
+			flush_type = flush_both;
+			ch++;
+		} else
+			flush_type = flush_left;
+		break;
+	default:
+		return 0;
+	}
+
+	/* the next value means "wide enough to that column" */
+	if (*ch == '|') {
+		to_column = 1;
+		ch++;
+	}
+
+	if (*ch == '(') {
+		const char *start = ch + 1;
+		const char *end = strchr(start, ')');
+		char *next;
+		int width;
+		if (!end || end == start)
+			return 0;
+		width = strtoul(start, &next, 10);
+		if (next == start || width == 0)
+			return 0;
+		c->padding = to_column ? -width : width;
+		c->flush_type = flush_type;
+		return end - placeholder + 1;
+	}
+	return 0;
+}
+
 static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 				const char *placeholder,
 				void *context)
@@ -1057,6 +1112,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 			return end - placeholder + 1;
 		} else
 			return 0;
+
+	case '<':
+	case '>':
+		return parse_padding_placeholder(sb, placeholder, c);
 	}
 
 	/* these depend on the commit */
@@ -1221,6 +1280,59 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
 	return 0;	/* unknown placeholder */
 }
 
+static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
+				    const char *placeholder,
+				    struct format_commit_context *c)
+{
+	struct strbuf local_sb = STRBUF_INIT;
+	int total_consumed = 0, len, padding = c->padding;
+	if (padding < 0) {
+		const char *start = strrchr(sb->buf, '\n');
+		int occupied;
+		if (!start)
+			start = sb->buf;
+		occupied = utf8_strnwidth(start, -1, 1);
+		padding = (-padding) - occupied;
+	}
+	while (1) {
+		int modifier = *placeholder == 'C';
+		int consumed = format_commit_one(&local_sb, placeholder, c);
+		total_consumed += consumed;
+
+		if (!modifier)
+			break;
+
+		placeholder += consumed;
+		if (*placeholder != '%')
+			break;
+		placeholder++;
+		total_consumed++;
+	}
+	len = utf8_strnwidth(local_sb.buf, -1, 1);
+	if (len > padding)
+		strbuf_addstr(sb, local_sb.buf);
+	else {
+		int sb_len = sb->len, offset = 0;
+		if (c->flush_type == flush_left)
+			offset = padding - len;
+		else if (c->flush_type == flush_both)
+			offset = (padding - len) / 2;
+		/*
+		 * we calculate padding in columns, now
+		 * convert it back to chars
+		 */
+		padding = padding - len + local_sb.len;
+		strbuf_grow(sb, padding);
+		strbuf_setlen(sb, sb_len + padding);
+		memset(sb->buf + sb_len, ' ', sb->len - sb_len);
+		memcpy(sb->buf + sb_len + offset, local_sb.buf,
+		       local_sb.len);
+	}
+	strbuf_release(&local_sb);
+	c->flush_type = no_flush;
+	return total_consumed;
+}
+
 static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 				 const char *placeholder,
 				 void *context)
@@ -1251,7 +1363,10 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
 		placeholder++;
 
 	orig_len = sb->len;
-	consumed = format_commit_one(sb, placeholder, context);
+	if (((struct format_commit_context *)context)->flush_type != no_flush)
+		consumed = format_and_pad_commit(sb, placeholder, context);
+	else
+		consumed = format_commit_one(sb, placeholder, context);
 	if (magic == NO_MAGIC)
 		return consumed;
 
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 98a43d4..88f2427 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -99,4 +99,126 @@ test_expect_failure 'NUL termination with --stat' '
 	test_i18ncmp expected actual
 '
 
+test_expect_success 'setup more commits' '
+	test_commit "message one" one one message-one &&
+	test_commit "message two" two two message-two
+'
+
+test_expect_success 'left alignment formatting' '
+	git log --pretty="format:%<(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+message two                            Z
+message one                            Z
+add bar                                Z
+initial                                Z
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting at the nth column' '
+	git log --pretty="format:%h %<|(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+fa33ab1 message two                    Z
+7cd6c63 message one                    Z
+1711bf9 add bar                        Z
+af20c06 initial                        Z
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with no padding' '
+	git log --pretty="format:%<(1)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF >expected &&
+message two
+message one
+add bar
+initial
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting' '
+	git log --pretty="format:%>(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+Z                            message two
+Z                            message one
+Z                                add bar
+Z                                initial
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting at the nth column' '
+	git log --pretty="format:%h %>|(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+fa33ab1                      message two
+7cd6c63                      message one
+1711bf9                          add bar
+af20c06                          initial
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'right alignment formatting with no padding' '
+	git log --pretty="format:%>(1)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF >expected &&
+message two
+message one
+add bar
+initial
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting' '
+	git log --pretty="format:%><(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+Z             message two              Z
+Z             message one              Z
+Z               add bar                Z
+Z               initial                Z
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting at the nth column' '
+	git log --pretty="format:%h %><|(40)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+fa33ab1           message two          Z
+7cd6c63           message one          Z
+1711bf9             add bar            Z
+af20c06             initial            Z
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'center alignment formatting with no padding' '
+	git log --pretty="format:%><(1)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF >expected &&
+message two
+message one
+add bar
+initial
+EOF
+	test_cmp expected actual
+'
+
 test_done
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 12/13] pretty: support truncating in %>, %< and %><
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (10 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 11/13] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  2013-04-18 23:08       ` [PATCH v4 13/13] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

%>(N,trunc) truncates the right 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 <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  7 ++++--
 pretty.c                         | 51 +++++++++++++++++++++++++++++++++++++---
 t/t4205-log-pretty-formats.sh    | 39 ++++++++++++++++++++++++++++++
 utf8.c                           | 46 ++++++++++++++++++++++++++++++++++++
 utf8.h                           |  2 ++
 5 files changed, 140 insertions(+), 5 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index e2345d2..d3450bf 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -164,8 +164,11 @@ The placeholders are:
 - '%x00': print a byte from a hex code
 - '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
   linkgit:git-shortlog[1].
-- '%<(<N>)': make the next placeholder take at least N columns,
-  padding spaces on the right if necessary
+- '%<(<N>[,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.
+  Note that truncating only works correctly with N >= 2.
 - '%<|(<N>)': make the next placeholder take at least until Nth
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
diff --git a/pretty.c b/pretty.c
index b50ebf5..f7c6442 100644
--- a/pretty.c
+++ b/pretty.c
@@ -776,6 +776,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;
@@ -783,6 +790,7 @@ struct format_commit_context {
 	unsigned commit_message_parsed:1;
 	struct signature_check signature_check;
 	enum flush_type flush_type;
+	enum trunc_type truncate;
 	char *message;
 	char *commit_encoding;
 	size_t width, indent1, indent2;
@@ -1033,7 +1041,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)
@@ -1043,6 +1051,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;
@@ -1309,9 +1334,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/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 88f2427..b8685b9 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -143,6 +143,45 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success 'left alignment formatting with trunc' '
+	git log --pretty="format:%<(10,trunc)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+message ..
+message ..
+add bar  Z
+initial  Z
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with ltrunc' '
+	git log --pretty="format:%<(10,ltrunc)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+..sage two
+..sage one
+add bar  Z
+initial  Z
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'left alignment formatting with mtrunc' '
+	git log --pretty="format:%<(10,mtrunc)%s" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	qz_to_tab_space <<\EOF >expected &&
+mess.. two
+mess.. one
+add bar  Z
+initial  Z
+EOF
+	test_cmp expected actual
+'
+
 test_expect_success 'right alignment formatting' '
 	git log --pretty="format:%>(40)%s" >actual &&
 	# complete the incomplete line at the end
diff --git a/utf8.c b/utf8.c
index 7c342ff..197414a 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;
+			}
+			w += n;
+			continue;
+		}
+		memcpy(dst, old, src - old);
+		dst += src - old;
+		w += n;
+	}
+	strbuf_setlen(&sb_dst, dst - sb_dst.buf);
+	strbuf_attach(sb_src, strbuf_detach(&sb_dst, NULL),
+		      sb_dst.len, sb_dst.alloc);
+}
+
 int is_encoding_utf8(const char *name)
 {
 	if (!name)
diff --git a/utf8.h b/utf8.h
index a43ef9a..edde8ee 100644
--- a/utf8.h
+++ b/utf8.h
@@ -15,6 +15,8 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
 		const char *text, int indent, int indent2, int width);
 void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
 			     int indent, int indent2, int width);
+void strbuf_utf8_replace(struct strbuf *sb, int pos, int width,
+			 const char *subst);
 
 #ifndef NO_ICONV
 char *reencode_string_iconv(const char *in, size_t insz,
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

* [PATCH v4 13/13] pretty: support %>> that steal trailing spaces
  2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
                         ` (11 preceding siblings ...)
  2013-04-18 23:08       ` [PATCH v4 12/13] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
@ 2013-04-18 23:08       ` Nguyễn Thái Ngọc Duy
  12 siblings, 0 replies; 83+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-04-18 23:08 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is pretty useful in `%<(100)%s%Cred%>(20)% an' where %s does not
use up all 100 columns and %an needs more than 20 columns. By
replacing %>(20) with %>>(20), %an can steal spaces from %s.

%>> understands escape sequences, so %Cred does not stop it from
stealing spaces in %<(100).

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/pretty-formats.txt |  5 ++++-
 pretty.c                         | 34 ++++++++++++++++++++++++++++++++++
 t/t4205-log-pretty-formats.sh    | 14 ++++++++++++++
 utf8.c                           |  2 +-
 utf8.h                           |  1 +
 5 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index d3450bf..c96ff41 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -173,7 +173,10 @@ The placeholders are:
   columns, padding spaces on the right if necessary
 - '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
   respectively, but padding spaces on the left
-- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
+- '%>>(<N>)', '%>>|(<N>)': similar to '%>(<N>)', '%>|(<N>)'
+  respectively, except that if the next placeholder takes more spaces
+  than given and there are spaces on its left, use those spaces
+- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
   respectively, but padding both sides (i.e. the text is centered)
 
 NOTE: Some placeholders may depend on other options given to the
diff --git a/pretty.c b/pretty.c
index f7c6442..d59579a 100644
--- a/pretty.c
+++ b/pretty.c
@@ -773,6 +773,7 @@ enum flush_type {
 	no_flush,
 	flush_right,
 	flush_left,
+	flush_left_and_steal,
 	flush_both
 };
 
@@ -1026,6 +1027,9 @@ static size_t parse_padding_placeholder(struct strbuf *sb,
 		if (*ch == '<') {
 			flush_type = flush_both;
 			ch++;
+		} else if (*ch == '>') {
+			flush_type = flush_left_and_steal;
+			ch++;
 		} else
 			flush_type = flush_left;
 		break;
@@ -1334,6 +1338,36 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
 		total_consumed++;
 	}
 	len = utf8_strnwidth(local_sb.buf, -1, 1);
+
+	if (c->flush_type == flush_left_and_steal) {
+		const char *ch = sb->buf + sb->len - 1;
+		while (len > padding && ch > sb->buf) {
+			const char *p;
+			if (*ch == ' ') {
+				ch--;
+				padding++;
+				continue;
+			}
+			/* check for trailing ansi sequences */
+			if (*ch != 'm')
+				break;
+			p = ch - 1;
+			while (ch - p < 10 && *p != '\033')
+				p--;
+			if (*p != '\033' ||
+			    ch + 1 - p != display_mode_esc_sequence_len(p))
+				break;
+			/*
+			 * got a good ansi sequence, put it back to
+			 * local_sb as we're cutting sb
+			 */
+			strbuf_insert(&local_sb, 0, p, ch + 1 - p);
+			ch = p - 1;
+		}
+		strbuf_setlen(sb, ch + 1 - sb->buf);
+		c->flush_type = flush_left;
+	}
+
 	if (len > padding) {
 		switch (c->truncate) {
 		case trunc_left:
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index b8685b9..26fbfde 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -260,4 +260,18 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success 'left/right alignment formatting with stealing' '
+	git commit --amend -m short --author "long long long <long@me.com>" &&
+	git log --pretty="format:%<(10,trunc)%s%>>(10,ltrunc)% an" >actual &&
+	# complete the incomplete line at the end
+	echo >>actual &&
+	cat <<\EOF >expected &&
+short long  long long
+message ..   A U Thor
+add bar      A U Thor
+initial      A U Thor
+EOF
+	test_cmp expected actual
+'
+
 test_done
diff --git a/utf8.c b/utf8.c
index 197414a..b1e1303 100644
--- a/utf8.c
+++ b/utf8.c
@@ -9,7 +9,7 @@ struct interval {
   int last;
 };
 
-static size_t display_mode_esc_sequence_len(const char *s)
+size_t display_mode_esc_sequence_len(const char *s)
 {
 	const char *p = s;
 	if (*p++ != '\033')
diff --git a/utf8.h b/utf8.h
index edde8ee..32a7bfb 100644
--- a/utf8.h
+++ b/utf8.h
@@ -3,6 +3,7 @@
 
 typedef unsigned int ucs_char_t;  /* assuming 32bit int */
 
+size_t display_mode_esc_sequence_len(const char *s);
 int utf8_width(const char **start, size_t *remainder_p);
 int utf8_strnwidth(const char *string, int len, int skip_ansi);
 int utf8_strwidth(const char *string);
-- 
1.8.2.82.gc24b958

^ permalink raw reply related	[flat|nested] 83+ messages in thread

end of thread, other threads:[~2013-04-18 23:10 UTC | newest]

Thread overview: 83+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-16  2:24 [PATCH 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 02/12] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
2013-03-17  8:57   ` Eric Sunshine
2013-03-16  2:24 ` [PATCH 06/12] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 07/12] utf8: keep NULs in reencode_string() Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 08/12] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
2013-03-16  2:24 ` [PATCH 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
2013-03-17  8:59   ` Eric Sunshine
2013-03-16  2:24 ` [PATCH 10/12] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
2013-03-17  9:03   ` Eric Sunshine
2013-03-16  2:24 ` [PATCH 11/12] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
2013-03-16  9:04   ` Paul Campbell
2013-03-16  2:24 ` [PATCH 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
2013-03-17  9:06   ` Eric Sunshine
2013-03-30  9:31     ` Duy Nguyen
2013-03-30  9:35 ` [PATCH v2 00/12] Layout control placeholders for pretty format Nguyễn Thái Ngọc Duy
2013-03-30  9:35   ` [PATCH v2 01/12] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
2013-03-30  9:35   ` [PATCH v2 02/12] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
2013-04-01 17:53     ` Junio C Hamano
2013-04-05  7:57       ` Jakub Narębski
2013-04-12 23:36         ` Duy Nguyen
2013-04-12 23:34       ` Duy Nguyen
2013-03-30  9:35   ` [PATCH v2 03/12] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
2013-03-30  9:35   ` [PATCH v2 04/12] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
2013-04-01 18:04     ` Junio C Hamano
2013-03-30  9:35   ` [PATCH v2 05/12] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
2013-04-01 18:10     ` Junio C Hamano
2013-03-30  9:35   ` [PATCH v2 06/12] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
2013-03-30  9:35   ` [PATCH v2 07/12] utf8: keep NULs in reencode_string() Nguyễn Thái Ngọc Duy
2013-03-30 17:06     ` Torsten Bögershausen
2013-03-31  0:23       ` Duy Nguyen
2013-03-30  9:35   ` [PATCH v2 08/12] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
2013-03-30  9:35   ` [PATCH v2 09/12] pretty: add %C(auto) for auto-coloring on the next placeholder Nguyễn Thái Ngọc Duy
2013-04-01 18:26     ` Junio C Hamano
2013-04-05  2:21       ` Duy Nguyen
2013-04-05 17:13         ` Junio C Hamano
2013-04-15  9:54           ` Duy Nguyen
2013-03-30  9:35   ` [PATCH v2 10/12] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
2013-03-30  9:35   ` [PATCH v2 11/12] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
2013-03-30  9:35   ` [PATCH v2 12/12] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
2013-04-01 18:39     ` Junio C Hamano
2013-04-16  8:24   ` [PATCH v3 00/13] nd/pretty-formats Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 02/13] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 03/13] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 04/13] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
2013-04-16  8:30       ` Duy Nguyen
2013-04-18 17:25       ` Junio C Hamano
2013-04-16  8:24     ` [PATCH v3 08/13] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 09/13] pretty: split color parsing into a separate function Nguyễn Thái Ngọc Duy
2013-04-16  8:24     ` [PATCH v3 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
2013-04-16 21:33       ` Junio C Hamano
2013-04-17  9:55         ` Duy Nguyen
2013-04-17 15:28           ` Junio C Hamano
2013-04-16 21:37       ` Junio C Hamano
2013-04-16  8:25     ` [PATCH v3 11/13] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
2013-04-16 20:41       ` Junio C Hamano
2013-04-16 20:43         ` Junio C Hamano
2013-04-17  9:45         ` Duy Nguyen
2013-04-16  8:25     ` [PATCH v3 12/13] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
2013-04-16  8:25     ` [PATCH v3 13/13] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy
     [not found]     ` <516D57BD.7080208@web.de>
2013-04-16 14:47       ` [PATCH v3 00/13] nd/pretty-formats Torsten Bögershausen
2013-04-18 23:08     ` [PATCH v4 " Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 01/13] pretty: save commit encoding from logmsg_reencode if the caller needs it Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 02/13] pretty: get the correct encoding for --pretty:format=%e Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 03/13] pretty-formats.txt: wrap long lines Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 04/13] pretty: share code between format_decoration and show_decorations Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 05/13] utf8.c: move display_mode_esc_sequence_len() for use by other functions Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 06/13] utf8.c: add utf8_strnwidth() with the ability to skip ansi sequences Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 07/13] utf8.c: add reencode_string_len() that can handle NULs in string Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 08/13] pretty: two phase conversion for non utf-8 commits Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 09/13] pretty: split color parsing into a separate function Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 10/13] pretty: add %C(auto) for auto-coloring Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 11/13] pretty: support padding placeholders, %< %> and %>< Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 12/13] pretty: support truncating in %>, %< " Nguyễn Thái Ngọc Duy
2013-04-18 23:08       ` [PATCH v4 13/13] pretty: support %>> that steal trailing spaces Nguyễn Thái Ngọc Duy

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).