@@ -393,6 +393,9 @@ class Scanner {
393
393
// / Pos is whitespace or a new line
394
394
bool isBlankOrBreak (StringRef::iterator Position);
395
395
396
+ // / Return true if the line is a line break, false otherwise.
397
+ bool isLineEmpty (StringRef Line);
398
+
396
399
// / Consume a single b-break[28] if it's present at the current position.
397
400
// /
398
401
// / Return false if the code unit at the current position isn't a line break.
@@ -471,6 +474,18 @@ class Scanner {
471
474
// / Scan a block scalar starting with | or >.
472
475
bool scanBlockScalar (bool IsLiteral);
473
476
477
+ // / Scan a block scalar style indicator and header.
478
+ // /
479
+ // / Note: This is distinct from scanBlockScalarHeader to mirror the fact that
480
+ // / YAML does not consider the style indicator to be a part of the header.
481
+ // /
482
+ // / Return false if an error occurred.
483
+ bool scanBlockScalarIndicators (char &StyleIndicator, char &ChompingIndicator,
484
+ unsigned &IndentIndicator, bool &IsDone);
485
+
486
+ // / Scan a style indicator in a block scalar header.
487
+ char scanBlockStyleIndicator ();
488
+
474
489
// / Scan a chomping indicator in a block scalar header.
475
490
char scanBlockChompingIndicator ();
476
491
@@ -1035,6 +1050,13 @@ bool Scanner::isBlankOrBreak(StringRef::iterator Position) {
1035
1050
*Position == ' \n ' ;
1036
1051
}
1037
1052
1053
+ bool Scanner::isLineEmpty (StringRef Line) {
1054
+ for (const auto *Position = Line.begin (); Position != Line.end (); ++Position)
1055
+ if (!isBlankOrBreak (Position))
1056
+ return false ;
1057
+ return true ;
1058
+ }
1059
+
1038
1060
bool Scanner::consumeLineBreakIfPresent () {
1039
1061
auto Next = skip_b_break (Current);
1040
1062
if (Next == Current)
@@ -1517,6 +1539,25 @@ bool Scanner::scanAliasOrAnchor(bool IsAlias) {
1517
1539
return true ;
1518
1540
}
1519
1541
1542
+ bool Scanner::scanBlockScalarIndicators (char &StyleIndicator,
1543
+ char &ChompingIndicator,
1544
+ unsigned &IndentIndicator,
1545
+ bool &IsDone) {
1546
+ StyleIndicator = scanBlockStyleIndicator ();
1547
+ if (!scanBlockScalarHeader (ChompingIndicator, IndentIndicator, IsDone))
1548
+ return false ;
1549
+ return true ;
1550
+ }
1551
+
1552
+ char Scanner::scanBlockStyleIndicator () {
1553
+ char Indicator = ' ' ;
1554
+ if (Current != End && (*Current == ' >' || *Current == ' |' )) {
1555
+ Indicator = *Current;
1556
+ skip (1 );
1557
+ }
1558
+ return Indicator;
1559
+ }
1560
+
1520
1561
char Scanner::scanBlockChompingIndicator () {
1521
1562
char Indicator = ' ' ;
1522
1563
if (Current != End && (*Current == ' +' || *Current == ' -' )) {
@@ -1655,19 +1696,19 @@ bool Scanner::scanBlockScalarIndent(unsigned BlockIndent,
1655
1696
}
1656
1697
1657
1698
bool Scanner::scanBlockScalar (bool IsLiteral) {
1658
- // Eat '|' or '>'
1659
1699
assert (*Current == ' |' || *Current == ' >' );
1660
- skip (1 );
1661
-
1700
+ char StyleIndicator;
1662
1701
char ChompingIndicator;
1663
1702
unsigned BlockIndent;
1664
1703
bool IsDone = false ;
1665
- if (!scanBlockScalarHeader (ChompingIndicator, BlockIndent, IsDone))
1704
+ if (!scanBlockScalarIndicators (StyleIndicator, ChompingIndicator, BlockIndent,
1705
+ IsDone))
1666
1706
return false ;
1667
1707
if (IsDone)
1668
1708
return true ;
1709
+ bool IsFolded = StyleIndicator == ' >' ;
1669
1710
1670
- auto Start = Current;
1711
+ const auto * Start = Current;
1671
1712
unsigned BlockExitIndent = Indent < 0 ? 0 : (unsigned )Indent;
1672
1713
unsigned LineBreaks = 0 ;
1673
1714
if (BlockIndent == 0 ) {
@@ -1688,6 +1729,22 @@ bool Scanner::scanBlockScalar(bool IsLiteral) {
1688
1729
auto LineStart = Current;
1689
1730
advanceWhile (&Scanner::skip_nb_char);
1690
1731
if (LineStart != Current) {
1732
+ if (LineBreaks && IsFolded && !Scanner::isLineEmpty (Str)) {
1733
+ // The folded style "folds" any single line break between content into a
1734
+ // single space, except when that content is "empty" (only contains
1735
+ // whitespace) in which case the line break is left as-is.
1736
+ if (LineBreaks == 1 ) {
1737
+ Str.append (LineBreaks,
1738
+ isLineEmpty (StringRef (LineStart, Current - LineStart))
1739
+ ? ' \n '
1740
+ : ' ' );
1741
+ }
1742
+ // If we saw a single line break, we are completely replacing it and so
1743
+ // want `LineBreaks == 0`. Otherwise this decrement accounts for the
1744
+ // fact that the first line break is "trimmed", only being used to
1745
+ // signal a sequence of line breaks which should not be folded.
1746
+ LineBreaks--;
1747
+ }
1691
1748
Str.append (LineBreaks, ' \n ' );
1692
1749
Str.append (StringRef (LineStart, Current - LineStart));
1693
1750
LineBreaks = 0 ;
0 commit comments