Skip to content

Commit cc2095e

Browse files
committed
Rewrite FormatParagraph to handle newlines within input strings correctly
1 parent cddffaf commit cc2095e

File tree

2 files changed

+49
-28
lines changed

2 files changed

+49
-28
lines changed

src/test/util_tests.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -399,12 +399,27 @@ BOOST_AUTO_TEST_CASE(test_FormatParagraph)
399399
{
400400
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
401401
BOOST_CHECK_EQUAL(FormatParagraph("test", 79, 0), "test");
402-
BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), "test");
402+
BOOST_CHECK_EQUAL(FormatParagraph(" test", 79, 0), " test");
403403
BOOST_CHECK_EQUAL(FormatParagraph("test test", 79, 0), "test test");
404404
BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 0), "test\ntest");
405-
BOOST_CHECK_EQUAL(FormatParagraph("testerde test ", 4, 0), "testerde\ntest");
405+
BOOST_CHECK_EQUAL(FormatParagraph("testerde test", 4, 0), "testerde\ntest");
406406
BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test");
407-
BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string. This is a second sentence in the very long test string."), "This is a very long test string. This is a second sentence in the very long\ntest string.");
407+
408+
// Make sure we don't indent a fully-new line following a too-long line ending
409+
BOOST_CHECK_EQUAL(FormatParagraph("test test\nabc", 4, 4), "test\n test\nabc");
410+
411+
BOOST_CHECK_EQUAL(FormatParagraph("This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_returned_as_is_despite_the_length until it gets here", 79), "This_is_a_very_long_test_string_without_any_spaces_so_it_should_just_get_returned_as_is_despite_the_length\nuntil it gets here");
412+
413+
// Test wrap length is exact
414+
BOOST_CHECK_EQUAL(FormatParagraph("a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p", 79), "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\nf g h i j k l m n o p");
415+
BOOST_CHECK_EQUAL(FormatParagraph("x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p", 79), "x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\nf g h i j k l m n o p");
416+
// Indent should be included in length of lines
417+
BOOST_CHECK_EQUAL(FormatParagraph("x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg h i j k", 79, 4), "x\na b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 a b c de\n f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 a b c d e fg\n h i j k");
418+
419+
BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string. This is a second sentence in the very long test string.", 79), "This is a very long test string. This is a second sentence in the very long\ntest string.");
420+
BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string.\nThis is a second sentence in the very long test string. This is a third sentence in the very long test string.", 79), "This is a very long test string.\nThis is a second sentence in the very long test string. This is a third\nsentence in the very long test string.");
421+
BOOST_CHECK_EQUAL(FormatParagraph("This is a very long test string.\n\nThis is a second sentence in the very long test string. This is a third sentence in the very long test string.", 79), "This is a very long test string.\n\nThis is a second sentence in the very long test string. This is a third\nsentence in the very long test string.");
422+
BOOST_CHECK_EQUAL(FormatParagraph("Testing that normal newlines do not get indented.\nLike here.", 79), "Testing that normal newlines do not get indented.\nLike here.");
408423
}
409424

410425
BOOST_AUTO_TEST_CASE(test_FormatSubVersion)

src/utilstrencodings.cpp

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -478,34 +478,40 @@ bool ParseDouble(const std::string& str, double *out)
478478
std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
479479
{
480480
std::stringstream out;
481-
size_t col = 0;
482481
size_t ptr = 0;
483-
while(ptr < in.size())
482+
size_t indented = 0;
483+
while (ptr < in.size())
484484
{
485-
// Find beginning of next word
486-
ptr = in.find_first_not_of(' ', ptr);
487-
if (ptr == std::string::npos)
488-
break;
489-
// Find end of next word
490-
size_t endword = in.find_first_of(' ', ptr);
491-
if (endword == std::string::npos)
492-
endword = in.size();
493-
// Add newline and indentation if this wraps over the allowed width
494-
if (col > 0)
495-
{
496-
if ((col + endword - ptr) > width)
497-
{
498-
out << '\n';
499-
for(size_t i=0; i<indent; ++i)
500-
out << ' ';
501-
col = 0;
502-
} else
503-
out << ' ';
485+
size_t lineend = in.find_first_of('\n', ptr);
486+
if (lineend == std::string::npos) {
487+
lineend = in.size();
488+
}
489+
const size_t linelen = lineend - ptr;
490+
const size_t rem_width = width - indented;
491+
if (linelen <= rem_width) {
492+
out << in.substr(ptr, linelen + 1);
493+
ptr = lineend + 1;
494+
indented = 0;
495+
} else {
496+
size_t finalspace = in.find_last_of(" \n", ptr + rem_width);
497+
if (finalspace == std::string::npos || finalspace < ptr) {
498+
// No place to break; just include the entire word and move on
499+
finalspace = in.find_first_of("\n ", ptr);
500+
if (finalspace == std::string::npos) {
501+
// End of the string, just add it and break
502+
out << in.substr(ptr);
503+
break;
504+
}
505+
}
506+
out << in.substr(ptr, finalspace - ptr) << "\n";
507+
if (in[finalspace] == '\n') {
508+
indented = 0;
509+
} else if (indent) {
510+
out << std::string(indent, ' ');
511+
indented = indent;
512+
}
513+
ptr = finalspace + 1;
504514
}
505-
// Append word
506-
out << in.substr(ptr, endword - ptr);
507-
col += endword - ptr + 1;
508-
ptr = endword;
509515
}
510516
return out.str();
511517
}

0 commit comments

Comments
 (0)