Git development
 help / color / mirror / Atom feed
From: Andy Koppe <andy.koppe@gmail.com>
To: git@vger.kernel.org
Cc: "René Scharfe" <l.s.r@web.de>,
	"Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
	"Andy Koppe" <andy.koppe@gmail.com>
Subject: [PATCH v2] pretty: fix lost indent after newline in %w()
Date: Sat, 17 Oct 2026 09:11:50 +0100	[thread overview]
Message-ID: <20261017081150.2295695-1-andy.koppe@gmail.com> (raw)
In-Reply-To: <20261014172333.2224123-1-andy.koppe@gmail.com>

When strbuf_add_wrapped_text() meets a newline followed by a
non-alphanumeric character, it treats it as a hard line break and jumps
to the new_line label. That code was written for the case where a line
gets too long. It moves past the space where the line was broken by
setting the next line's start to 'space + isspace(*space)'.

After a hard line break, 'space' already points to the first character
of the next line. If that character is whitespace, it was wrongly
skipped, so the line lost one column of indentation. This affected
things like code examples or multi-line list items starting with "- "
and continuing with two spaces of indentation.

Fix this by skipping the space only in the line-too-long case. In the
double-newline case, skip the second newline explicitly, because that
case relied on the old skipping.

Add a test for this, and update the expected output of the "magical
wrapping directives" test in t4205. There, %+d emits a newline followed
by " (tag: ...)", and that leading space is no longer lost. With a wrap
width of 1, the space now causes an extra line break.

Document the %w placeholder properly, removing the reference to `git
shortlog -w`, which has different defaults and isn't concerned with
paragraph reflowing.

Signed-off-by: Andy Koppe <andy.koppe@gmail.com>
---
 Documentation/pretty-formats.adoc | 9 +++++++--
 t/t4202-log.sh                    | 6 ++++++
 t/t4205-log-pretty-formats.sh     | 2 +-
 utf8.c                            | 4 +++-
 4 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/Documentation/pretty-formats.adoc b/Documentation/pretty-formats.adoc
index 2ae0eb11a9..4fb0419715 100644
--- a/Documentation/pretty-formats.adoc
+++ b/Documentation/pretty-formats.adoc
@@ -169,8 +169,13 @@ The placeholders are:
 	    on the next placeholders until the color is switched
 	    again.
 ++%m++:: left (`<`), right (`>`) or boundary (`-`) mark
-++%w(++`[<w>[,<i1>[,<i2>]]]`++)++:: switch line wrapping, like the `-w` option of
-			    linkgit:git-shortlog[1].
+++%w(++`[<w>[,<i1>[,<i2>]]]`++)++:: set line wrapping and indentation.
+	    Output is word-wrapped at _<w>_ columns, with the first line
+	    indented by _<i1>_ spaces and subsequent lines indented by
+	    _<i2>_ spaces. A width of 0 disables wrapping. Omitted values
+	    default to 0, so ++%w()++ turns off both wrapping and indentation.
+	    Newlines that are followed by an ASCII letter or digit are replaced
+	    by spaces to reflow paragraphs. Existing indentation is kept.
 ++%<(++`<n>[,(trunc|ltrunc|mtrunc)]`++)++:: make the next placeholder take at
 				  least N column widths, padding spaces on
 				  the right if necessary.  Optionally
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 06552a6271..5895780e8f 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -94,6 +94,12 @@ test_expect_success 'format %w(,1,2)' '
 	test_cmp expect actual
 '
 
+test_expect_success 'format %w(11)' '
+
+	git log -2 --format="%w(11) This is%n  the %s%n  commit." > actual &&
+	test_cmp expect actual
+'
+
 cat > expect << EOF
 $(git rev-parse --short :/sixth  ) sixth
 $(git rev-parse --short :/fifth  ) fifth
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index 4be5c51489..0733f22d58 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -1139,7 +1139,7 @@ test_expect_success 'log --pretty with invalid padding format' '
 test_expect_success 'log --pretty with magical wrapping directives' '
 	commit_id=$(git commit-tree HEAD^{tree} -m "describe me") &&
 	git tag describe-me $commit_id &&
-	printf "\n(tag:\ndescribe-me)%%+w(2)" >expect &&
+	printf "\n\n(tag:\ndescribe-me)%%+w(2)" >expect &&
 	git log -1 --pretty="format:%w(1)%+d%+w(2)" $commit_id >actual &&
 	test_cmp expect actual
 '
diff --git a/utf8.c b/utf8.c
index 96460cc414..bb55bf357f 100644
--- a/utf8.c
+++ b/utf8.c
@@ -322,6 +322,7 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
 					space++;
 					if (*space == '\n') {
 						strbuf_addch(buf, '\n');
+						space++;
 						goto new_line;
 					}
 					else if (!isalnum(*space))
@@ -333,9 +334,10 @@ void strbuf_add_wrapped_text(struct strbuf *buf,
 				text++;
 			}
 			else {
+				space += isspace(*space);
 new_line:
 				strbuf_addch(buf, '\n');
-				text = bol = space + isspace(*space);
+				text = bol = space;
 				space = NULL;
 				w = indent = indent2;
 			}
-- 
2.56.0


      parent reply	other threads:[~2026-10-17  8:12 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-14 17:23 [PATCH] pretty: fix lost indent after newline in %w() Andy Koppe
2026-10-15 20:11 ` Andy Koppe
2026-10-15 20:42 ` René Scharfe
2026-10-15 20:59   ` Junio C Hamano
2026-10-17  8:26   ` Andy Koppe
2026-10-17  8:11 ` Andy Koppe [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261017081150.2295695-1-andy.koppe@gmail.com \
    --to=andy.koppe@gmail.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=git@vger.kernel.org \
    --cc=l.s.r@web.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox