...
1 package parser
2
3 import (
4 "github.com/yuin/goldmark/ast"
5 "github.com/yuin/goldmark/text"
6 "github.com/yuin/goldmark/util"
7 )
8
9 type codeBlockParser struct {
10 }
11
12
13 var defaultCodeBlockParser = &codeBlockParser{}
14
15
16
17 func NewCodeBlockParser() BlockParser {
18 return defaultCodeBlockParser
19 }
20
21 func (b *codeBlockParser) Trigger() []byte {
22 return nil
23 }
24
25 func (b *codeBlockParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) {
26 line, segment := reader.PeekLine()
27 pos, padding := util.IndentPosition(line, reader.LineOffset(), 4)
28 if pos < 0 || util.IsBlank(line) {
29 return nil, NoChildren
30 }
31 node := ast.NewCodeBlock()
32 reader.AdvanceAndSetPadding(pos, padding)
33 _, segment = reader.PeekLine()
34
35 if segment.Padding != 0 {
36 preserveLeadingTabInCodeBlock(&segment, reader, 0)
37 }
38 node.Lines().Append(segment)
39 reader.Advance(segment.Len() - 1)
40 return node, NoChildren
41
42 }
43
44 func (b *codeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context) State {
45 line, segment := reader.PeekLine()
46 if util.IsBlank(line) {
47 node.Lines().Append(segment.TrimLeftSpaceWidth(4, reader.Source()))
48 return Continue | NoChildren
49 }
50 pos, padding := util.IndentPosition(line, reader.LineOffset(), 4)
51 if pos < 0 {
52 return Close
53 }
54 reader.AdvanceAndSetPadding(pos, padding)
55 _, segment = reader.PeekLine()
56
57
58 if segment.Padding != 0 {
59 preserveLeadingTabInCodeBlock(&segment, reader, 0)
60 }
61
62 node.Lines().Append(segment)
63 reader.Advance(segment.Len() - 1)
64 return Continue | NoChildren
65 }
66
67 func (b *codeBlockParser) Close(node ast.Node, reader text.Reader, pc Context) {
68
69 lines := node.Lines()
70 length := lines.Len() - 1
71 source := reader.Source()
72 for length >= 0 {
73 line := lines.At(length)
74 if util.IsBlank(line.Value(source)) {
75 length--
76 } else {
77 break
78 }
79 }
80 lines.SetSliced(0, length+1)
81 }
82
83 func (b *codeBlockParser) CanInterruptParagraph() bool {
84 return false
85 }
86
87 func (b *codeBlockParser) CanAcceptIndentedLine() bool {
88 return true
89 }
90
91 func preserveLeadingTabInCodeBlock(segment *text.Segment, reader text.Reader, indent int) {
92 offsetWithPadding := reader.LineOffset() + indent
93 sl, ss := reader.Position()
94 reader.SetPosition(sl, text.NewSegment(ss.Start-1, ss.Stop))
95 if offsetWithPadding == reader.LineOffset() {
96 segment.Padding = 0
97 segment.Start--
98 }
99 reader.SetPosition(sl, ss)
100 }
101
View as plain text