Commit f5f96a23ee7c7774bca5c52404f819cf56c78501

Stjepan Rajko 2015-10-09T10:41:06

Fix git_commit_summary to convert newlines to spaces even after whitespace. Collapse spaces around newlines for the summary.

diff --git a/src/commit.c b/src/commit.c
index 616f947..b42f9de 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -431,22 +431,37 @@ const char *git_commit_summary(git_commit *commit)
 {
 	git_buf summary = GIT_BUF_INIT;
 	const char *msg, *space;
+	bool space_contains_newline = false;
 
 	assert(commit);
 
 	if (!commit->summary) {
 		for (msg = git_commit_message(commit), space = NULL; *msg; ++msg) {
-			if (msg[0] == '\n' && (!msg[1] || msg[1] == '\n'))
+			char next_character = msg[0];
+			/* stop processing at the end of the first paragraph */
+			if (next_character == '\n' && (!msg[1] || msg[1] == '\n'))
 				break;
-			else if (msg[0] == '\n')
-				git_buf_putc(&summary, ' ');
-			else if (git__isspace(msg[0]))
-				space = space ? space : msg;
-			else if (space) {
-				git_buf_put(&summary, space, (msg - space) + 1);
-				space = NULL;
-			} else
-				git_buf_putc(&summary, *msg);
+			/* record the beginning of contiguous whitespace runs */
+			else if (git__isspace(next_character)) {
+				if(space == NULL) {
+					space = msg;
+					space_contains_newline = false;
+				}
+				space_contains_newline |= next_character == '\n';
+			}
+			/* the next character is non-space */
+			else {
+				/* process any recorded whitespace */
+				if (space) {
+					if(space_contains_newline)
+						git_buf_putc(&summary, ' '); /* if the space contains a newline, collapse to ' ' */
+					else
+						git_buf_put(&summary, space, (msg - space)); /* otherwise copy it */
+					space = NULL;
+				}
+				/* copy the next character */
+				git_buf_putc(&summary, next_character);
+			}
 		}
 
 		commit->summary = git_buf_detach(&summary);
diff --git a/tests/commit/commit.c b/tests/commit/commit.c
index f5461cf..81aaf80 100644
--- a/tests/commit/commit.c
+++ b/tests/commit/commit.c
@@ -70,12 +70,16 @@ void test_commit_commit__summary(void)
 	assert_commit_summary("Trimmed leading&trailing newlines", "\n\nTrimmed leading&trailing newlines\n\n");
 	assert_commit_summary("First paragraph only", "\nFirst paragraph only\n\n(There are more!)");
 	assert_commit_summary("First paragraph with  unwrapped trailing\tlines", "\nFirst paragraph\nwith  unwrapped\ntrailing\tlines\n\n(Yes, unwrapped!)");
-	assert_commit_summary("\tLeading \ttabs", "\tLeading\n\ttabs\n\nis preserved");
-	assert_commit_summary(" Leading  Spaces", " Leading\n Spaces\n\nare preserved");
+	assert_commit_summary("\tLeading tabs", "\tLeading\n\ttabs\n\nare preserved"); /* tabs around newlines are collapsed down to a single space */
+	assert_commit_summary(" Leading Spaces", " Leading\n Spaces\n\nare preserved"); /* spaces around newlines are collapsed down to a single space */
 	assert_commit_summary("Trailing tabs\tare removed", "Trailing tabs\tare removed\t\t");
 	assert_commit_summary("Trailing spaces  are removed", "Trailing spaces  are removed  ");
 	assert_commit_summary("Trailing tabs", "Trailing tabs\t\n\nare removed");
 	assert_commit_summary("Trailing spaces", "Trailing spaces \n\nare removed");
+	assert_commit_summary("Newlines are replaced by spaces", "Newlines\nare\nreplaced by spaces\n");
+	assert_commit_summary("  Spaces after newlines are collapsed", "\n  Spaces after newlines\n  are\n  collapsed\n  "); /* newlines at the very beginning are ignored and not collapsed */
+	assert_commit_summary(" Spaces before newlines are collapsed", "  \nSpaces before newlines  \nare  \ncollapsed  \n");
+	assert_commit_summary(" Spaces around newlines are collapsed", "  \n  Spaces around newlines  \n  are  \n  collapsed  \n  ");
 	assert_commit_summary("", "");
 	assert_commit_summary("", " ");
 	assert_commit_summary("", "\n");
diff --git a/tests/commit/write.c b/tests/commit/write.c
index ee9eb82..176965c 100644
--- a/tests/commit/write.c
+++ b/tests/commit/write.c
@@ -8,7 +8,7 @@ static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
 static const char *root_commit_message = "This is a root commit\n\
    This is a root commit and should be the only one in this branch\n";
 static const char *root_reflog_message = "commit (initial): This is a root commit \
-   This is a root commit and should be the only one in this branch";
+This is a root commit and should be the only one in this branch";
 static char *head_old;
 static git_reference *head, *branch;
 static git_commit *commit;