From 4a04682e491b5697979e921c3a5ed9ae933d9406 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 17 Jan 2017 17:13:23 +0000 Subject: [PATCH] =?UTF-8?q?Text=20formatting=20rework=20Rewrote=20main=20w?= =?UTF-8?q?rapping=20loop.=20Now=20uses=20iterators=20instead=20of=20indic?= =?UTF-8?q?es=20and=20intermediate=20strings.=20Differentiates=20between?= =?UTF-8?q?=20chars=20to=20wrap=20before,=20after=20or=20instead=20of.=20D?= =?UTF-8?q?oesn=E2=80=99t=20preserve=20trailing=20newlines.=20Wraps=20or?= =?UTF-8?q?=20more=20characters.=20Dropped=20support=20for=20using=20tab?= =?UTF-8?q?=20character=20as=20an=20indent=20setting=20control=20char.=20H?= =?UTF-8?q?opefully=20avoids=20all=20the=20undefined=20behaviour=20and=20o?= =?UTF-8?q?ther=20bugs=20of=20the=20previous=20implementation.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/external/tbc_text_format.h | 105 ++++++------ .../Baselines/console.std.approved.txt | 6 +- .../Baselines/console.sw.approved.txt | 153 +++++++++++++---- .../SelfTest/Baselines/junit.sw.approved.txt | 6 +- .../SelfTest/Baselines/xml.sw.approved.txt | 159 ++++++++++++++---- projects/SelfTest/TestMain.cpp | 26 ++- 6 files changed, 325 insertions(+), 130 deletions(-) diff --git a/include/external/tbc_text_format.h b/include/external/tbc_text_format.h index a63d6a14..a239b088 100644 --- a/include/external/tbc_text_format.h +++ b/include/external/tbc_text_format.h @@ -37,19 +37,16 @@ namespace Tbc { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), - width( consoleWidth-1 ), - tabChar( '\t' ) + width( consoleWidth-1 ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos }; class Text { @@ -57,63 +54,74 @@ namespace Tbc { Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; + const std::string wrappableBeforeChars = "[({<\t"; + const std::string wrappableAfterChars = "])}>-,./|\\"; + const std::string wrappableInsteadOfChars = " \n\r"; + std::string indent = _attr.initialIndent != std::string::npos + ? std::string( _attr.initialIndent, ' ' ) + : std::string( _attr.indent, ' ' ); + + typedef std::string::const_iterator iterator; + iterator it = _str.begin(); + const iterator strEnd = _str.end(); + + while( it != strEnd ) { - while( !remainder.empty() ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); + + std::string suffix; + std::size_t width = (std::min)( static_cast( strEnd-it ), _attr.width-static_cast( indent.size() ) ); + iterator itEnd = it+width; + iterator itNext = _str.end(); + + iterator itNewLine = std::find( it, itEnd, '\n' ); + if( itNewLine != itEnd ) + itEnd = itNewLine; + + if( itEnd != strEnd ) { + bool foundWrapPoint = false; + for( iterator findIt = itEnd; !foundWrapPoint & findIt >= it; --findIt ) { + + if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { + itEnd = findIt+1; + itNext = findIt+1; + foundWrapPoint = true; + } + else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { + itEnd = findIt; + itNext = findIt; + foundWrapPoint = true; + } + else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { + itNext = findIt+1; + itEnd = findIt; + foundWrapPoint = true; + } + } + if( !foundWrapPoint ) { + // No good wrap char, so we'll break mid word and add a hyphen + --itEnd; + itNext = itEnd; + suffix = "-"; } else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; + while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) + --itEnd; } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; } + lines.push_back( indent + std::string( it, itEnd ) + suffix ); + + if( indent.size() != _attr.indent ) + indent = std::string( _attr.indent, ' ' ); + it = itNext; } } - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } + typedef std::vector::const_iterator const_iterator; @@ -138,6 +146,7 @@ namespace Tbc { return _stream; } + private: std::string str; TextAttributes attr; diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 12dc52ee..f5c53cd6 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -584,11 +584,11 @@ MiscTests.cpp:: FAILED: CHECK( s1 == s2 ) with expansion: "if ($b == 10) { - $a= 20; + $a = 20; }" == "if ($b == 10) { - $a = 20; + $a = 20; } " @@ -831,5 +831,5 @@ with expansion: =============================================================================== test cases: 159 | 115 passed | 42 failed | 2 failed as expected -assertions: 909 | 813 passed | 78 failed | 18 failed as expected +assertions: 915 | 819 passed | 78 failed | 18 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index ab488d3b..4ac83ca2 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -2932,13 +2932,9 @@ TestMain.cpp: TestMain.cpp:: PASSED: - CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" ) + CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef" ) with expansion: - "abcdef - " - == - "abcdef - " + "abcdef" == "abcdef" TestMain.cpp:: PASSED: @@ -2948,13 +2944,19 @@ with expansion: TestMain.cpp:: PASSED: - CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" ) + CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" ) with expansion: - "abcdef - " + "abcdef" == "abcdef" + +TestMain.cpp:: +PASSED: + CHECK( Text( "abcdef\n", TextAttributes().setWidth( 5 ) ).toString() == "abcd-\nef" ) +with expansion: + "abcd- + ef" == - "abcdef - " + "abcd- + ef" ------------------------------------------------------------------------------- Long strings can be wrapped @@ -3024,24 +3026,107 @@ with expansion: ------------------------------------------------------------------------------- Long strings can be wrapped - With tabs + With wrap-before/ after characters + No wrapping ------------------------------------------------------------------------------- TestMain.cpp: ............................................................................... TestMain.cpp:: PASSED: - CHECK( Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six" ) + CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString ) with expansion: - "one two three - four - five - six" + "one,two(three) " == - "one two three - four - five - six" + "one,two(three) " + +TestMain.cpp:: +PASSED: + CHECK( Text( testString, TextAttributes().setWidth( 24 ) ).toString() == testString ) +with expansion: + "one,two(three) " + == + "one,two(three) " + +------------------------------------------------------------------------------- +Long strings can be wrapped + With wrap-before/ after characters + Wrap before +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( Text( testString, TextAttributes().setWidth( 11 ) ).toString() == "one,two\n(three)\n" ) +with expansion: + "one,two + (three) + " + == + "one,two + (three) + " + +------------------------------------------------------------------------------- +Long strings can be wrapped + With wrap-before/ after characters + Wrap after +------------------------------------------------------------------------------- +TestMain.cpp: +............................................................................... + +TestMain.cpp:: +PASSED: + CHECK( Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one,\ntwo\n(thre-\ne)\n" ) +with expansion: + "one, + two + (thre- + e) + " + == + "one, + two + (thre- + e) + " + +TestMain.cpp:: +PASSED: + CHECK( Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one,\ntwo\n(thr-\nee)\n" ) +with expansion: + "one, + two + (thr- + ee) + " + == + "one, + two + (thr- + ee) + " + +TestMain.cpp:: +PASSED: + CHECK( Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one,\ntwo\n(th-\nree)\n" ) +with expansion: + "one, + two + (th- + ree) + " + == + "one, + two + (th- + ree) + " ------------------------------------------------------------------------------- Long text is truncted @@ -6458,11 +6543,11 @@ MiscTests.cpp:: FAILED: CHECK( s1 == s2 ) with expansion: "if ($b == 10) { - $a= 20; + $a = 20; }" == "if ($b == 10) { - $a = 20; + $a = 20; } " @@ -6478,36 +6563,32 @@ PASSED: CHECK_THAT( what, Contains( "[@zzz]" ) ) with expansion: "error: tag alias, "[@zzz]" already registered. - First seen at file:2 - Redefined at file:10" contains: " - [@zzz]" + First seen at file:2 + Redefined at file:10" contains: "[@zzz]" TagAliasTests.cpp:: PASSED: CHECK_THAT( what, Contains( "file" ) ) with expansion: "error: tag alias, "[@zzz]" already registered. - First seen at file:2 - Redefined at file:10" contains: - "file" + First seen at file:2 + Redefined at file:10" contains: "file" TagAliasTests.cpp:: PASSED: CHECK_THAT( what, Contains( "2" ) ) with expansion: "error: tag alias, "[@zzz]" already registered. - First seen at file:2 - Redefined at file:10" contains: - "2" + First seen at file:2 + Redefined at file:10" contains: "2" TagAliasTests.cpp:: PASSED: CHECK_THAT( what, Contains( "10" ) ) with expansion: "error: tag alias, "[@zzz]" already registered. - First seen at file:2 - Redefined at file:10" contains: - "10" + First seen at file:2 + Redefined at file:10" contains: "10" ------------------------------------------------------------------------------- Tag alias can be registered against tag patterns @@ -8972,5 +9053,5 @@ PASSED: =============================================================================== test cases: 159 | 114 passed | 43 failed | 2 failed as expected -assertions: 911 | 813 passed | 80 failed | 18 failed as expected +assertions: 917 | 819 passed | 80 failed | 18 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 3b7345ed..43b808a2 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,6 +1,6 @@ - + @@ -242,7 +242,9 @@ ConditionTests.cpp: - + + + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index c09629e1..33989783 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -2987,14 +2987,10 @@ three four"
- Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" + Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef" - "abcdef -" -== -"abcdef -" + "abcdef" == "abcdef" @@ -3007,19 +3003,27 @@ three four" - Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" + Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" - "abcdef -" -== -"abcdef -" + "abcdef" == "abcdef" - + + + Text( "abcdef\n", TextAttributes().setWidth( 5 ) ).toString() == "abcd-\nef" + + + "abcd- +ef" +== +"abcd- +ef" + + +
- +
@@ -3091,25 +3095,116 @@ four"
-
- - - Text( testString, TextAttributes().setWidth( 15 ) ).toString() == "one two three\n four\n five\n six" - - - "one two three - four - five - six" +
+
+ + + Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString + + + "one,two(three) <here>" == -"one two three - four - five - six" - - +"one,two(three) <here>" + + + + + Text( testString, TextAttributes().setWidth( 24 ) ).toString() == testString + + + "one,two(three) <here>" +== +"one,two(three) <here>" + + + +
+ +
+
+
+ + + Text( testString, TextAttributes().setWidth( 11 ) ).toString() == "one,two\n(three)\n<here>" + + + "one,two +(three) +<here>" +== +"one,two +(three) +<here>" + + + +
+
+
+ + + Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one,\ntwo\n(thre-\ne)\n<here>" + + + "one, +two +(thre- +e) +<here>" +== +"one, +two +(thre- +e) +<here>" + + + + + Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one,\ntwo\n(thr-\nee)\n<her-\ne>" + + + "one, +two +(thr- +ee) +<her- +e>" +== +"one, +two +(thr- +ee) +<her- +e>" + + + + + Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one,\ntwo\n(th-\nree)\n<he-\nre>" + + + "one, +two +(th- +ree) +<he- +re>" +== +"one, +two +(th- +ree) +<he- +re>" + + + +
+ +
@@ -9432,7 +9527,7 @@ there"
- + - + diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index 16af2f67..db506688 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -299,9 +299,10 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) { CHECK( Text( testString, TextAttributes().setWidth( 10 ) ).toString() == testString ); } SECTION( "Trailing newline" , "" ) { - CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef\n" ); + CHECK( Text( "abcdef\n", TextAttributes().setWidth( 10 ) ).toString() == "abcdef" ); CHECK( Text( "abcdef", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" ); - CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef\n" ); + CHECK( Text( "abcdef\n", TextAttributes().setWidth( 6 ) ).toString() == "abcdef" ); + CHECK( Text( "abcdef\n", TextAttributes().setWidth( 5 ) ).toString() == "abcd-\nef" ); } SECTION( "Wrapped once", "" ) { CHECK( Text( testString, TextAttributes().setWidth( 9 ) ).toString() == "one two\nthree\nfour" ); @@ -313,16 +314,23 @@ TEST_CASE( "Long strings can be wrapped", "[wrap]" ) { } } - SECTION( "With tabs", "" ) { + SECTION( "With wrap-before/ after characters", "" ) { + std::string testString = "one,two(three) "; - // guide: 1234567890123456789 - std::string testString = "one two \tthree four five six"; - - CHECK( Text( testString, TextAttributes().setWidth( 15 ) ).toString() - == "one two three\n four\n five\n six" ); + SECTION( "No wrapping", "" ) { + CHECK( Text( testString, TextAttributes().setWidth( 80 ) ).toString() == testString ); + CHECK( Text( testString, TextAttributes().setWidth( 24 ) ).toString() == testString ); + } + SECTION( "Wrap before", "" ) { + CHECK( Text( testString, TextAttributes().setWidth( 11 ) ).toString() == "one,two\n(three)\n" ); + } + SECTION( "Wrap after", "" ) { + CHECK( Text( testString, TextAttributes().setWidth( 6 ) ).toString() == "one,\ntwo\n(thre-\ne)\n" ); + CHECK( Text( testString, TextAttributes().setWidth( 5 ) ).toString() == "one,\ntwo\n(thr-\nee)\n" ); + CHECK( Text( testString, TextAttributes().setWidth( 4 ) ).toString() == "one,\ntwo\n(th-\nree)\n" ); + } } - } using namespace Catch;