diff --git a/_test/extra.txt b/_test/extra.txt index 5e2386f..f202b13 100644 --- a/_test/extra.txt +++ b/_test/extra.txt @@ -639,3 +639,13 @@ b //= = = = = = = = = = = = = = = = = = = = = = = =// + + +50: Spaces before a visible hard linebreak should be preserved +//- - - - - - - - -// +a \ +b +//- - - - - - - - -// +

a
+b

+//= = = = = = = = = = = = = = = = = = = = = = = =// diff --git a/parser/parser.go b/parser/parser.go index 0276bee..bac0704 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1115,6 +1115,12 @@ func (p *parser) walkBlock(block ast.Node, cb func(node ast.Node)) { cb(block) } +const ( + lineBreakHard uint8 = 1 << iota + lineBreakSoft + lineBreakVisible +) + func (p *parser) parseBlock(block text.BlockReader, parent ast.Node, pc Context) { if parent.IsRaw() { return @@ -1129,27 +1135,25 @@ func (p *parser) parseBlock(block text.BlockReader, parent ast.Node, pc Context) break } lineLength := len(line) - softLinebreak := false - hardlineBreak := false + var lineBreakFlags uint8 = 0 hasNewLine := line[lineLength-1] == '\n' if ((lineLength >= 3 && line[lineLength-2] == '\\' && line[lineLength-3] != '\\') || (lineLength == 2 && line[lineLength-2] == '\\')) && hasNewLine { // ends with \\n lineLength -= 2 - hardlineBreak = true - + lineBreakFlags |= lineBreakHard | lineBreakVisible } else if ((lineLength >= 4 && line[lineLength-3] == '\\' && line[lineLength-2] == '\r' && line[lineLength-4] != '\\') || (lineLength == 3 && line[lineLength-3] == '\\' && line[lineLength-2] == '\r')) && hasNewLine { // ends with \\r\n lineLength -= 3 - hardlineBreak = true + lineBreakFlags |= lineBreakHard | lineBreakVisible } else if lineLength >= 3 && line[lineLength-3] == ' ' && line[lineLength-2] == ' ' && hasNewLine { // ends with [space][space]\n lineLength -= 3 - hardlineBreak = true + lineBreakFlags |= lineBreakHard } else if lineLength >= 4 && line[lineLength-4] == ' ' && line[lineLength-3] == ' ' && line[lineLength-2] == '\r' && hasNewLine { // ends with [space][space]\r\n lineLength -= 4 - hardlineBreak = true + lineBreakFlags |= lineBreakHard } else if hasNewLine { // If the line ends with a newline character, but it is not a hardlineBreak, then it is a softLinebreak // If the line ends with a hardlineBreak, then it cannot end with a softLinebreak // See https://spec.commonmark.org/0.30/#soft-line-breaks - softLinebreak = true + lineBreakFlags |= lineBreakSoft } l, startPosition := block.Position() @@ -1213,11 +1217,14 @@ func (p *parser) parseBlock(block text.BlockReader, parent ast.Node, pc Context) continue } diff := startPosition.Between(currentPosition) - stop := diff.Stop - rest := diff.WithStop(stop) - text := ast.NewTextSegment(rest.TrimRightSpace(source)) - text.SetSoftLineBreak(softLinebreak) - text.SetHardLineBreak(hardlineBreak) + var text *ast.Text + if lineBreakFlags&(lineBreakHard|lineBreakVisible) == lineBreakHard|lineBreakVisible { + text = ast.NewTextSegment(diff) + } else { + text = ast.NewTextSegment(diff.TrimRightSpace(source)) + } + text.SetSoftLineBreak(lineBreakFlags&lineBreakSoft != 0) + text.SetHardLineBreak(lineBreakFlags&lineBreakHard != 0) parent.AppendChild(parent, text) block.AdvanceLine() }