1
2
3
4
5 package markdown
6
7 import (
8 "bytes"
9 "fmt"
10 "strings"
11 )
12
13 type CodeBlock struct {
14 Position
15 Fence string
16 Info string
17 Text []string
18 }
19
20 func (b *CodeBlock) PrintHTML(buf *bytes.Buffer) {
21 if buf.Len() > 0 && buf.Bytes()[buf.Len()-1] != '\n' {
22 buf.WriteString("\n")
23 }
24 buf.WriteString("<pre><code")
25 if b.Info != "" {
26
27
28
29
30
31 lang := b.Info
32 for i, c := range lang {
33 if isUnicodeSpace(c) {
34 lang = lang[:i]
35 break
36 }
37 }
38 fmt.Fprintf(buf, " class=\"language-%s\"", htmlQuoteEscaper.Replace(lang))
39 }
40 buf.WriteString(">")
41 if b.Fence == "" {
42 for len(b.Text) > 0 && trimSpaceTab(b.Text[len(b.Text)-1]) == "" {
43 b.Text = b.Text[:len(b.Text)-1]
44 }
45 }
46 for _, s := range b.Text {
47 buf.WriteString(htmlEscaper.Replace(s))
48 buf.WriteString("\n")
49 }
50 buf.WriteString("</code></pre>\n")
51 }
52
53
54
55
56
57
58
59
60
61
62 func (b *CodeBlock) printMarkdown(buf *bytes.Buffer, s mdState) {
63 prefix1 := s.prefix1
64 if prefix1 == "" {
65 prefix1 = s.prefix
66 }
67 if b.Fence == "" {
68 for i, line := range b.Text {
69
70 if i == len(b.Text)-1 && len(line) == 0 {
71 break
72 }
73
74
75
76
77
78
79
80
81 pre := s.prefix
82 if i == 0 {
83 pre = prefix1
84 }
85 fmt.Fprintf(buf, "%s%s%s\n", pre, " ", line)
86 }
87 } else {
88 fmt.Fprintf(buf, "%s%s\n", prefix1, b.Fence)
89 for _, line := range b.Text {
90 fmt.Fprintf(buf, "%s%s\n", s.prefix, line)
91 }
92 fmt.Fprintf(buf, "%s%s\n", s.prefix, b.Fence)
93 }
94 }
95
96 func newPre(p *parseState, s line) (line, bool) {
97 peek2 := s
98 if p.para() == nil && peek2.trimSpace(4, 4, false) && !peek2.isBlank() {
99 b := &preBuilder{ }
100 p.addBlock(b)
101 p.corner = p.corner || peek2.nl != '\n'
102 b.text = append(b.text, peek2.string())
103 return line{}, true
104 }
105 return s, false
106 }
107
108 func newFence(p *parseState, s line) (line, bool) {
109 var fence, info string
110 var n int
111 peek := s
112 if peek.trimFence(&fence, &info, &n) {
113 if fence[0] == '~' && info != "" {
114
115 p.corner = true
116 } else if info != "" && !isLetter(info[0]) {
117
118
119 p.corner = true
120 }
121 for _, c := range info {
122 if isUnicodeSpace(c) {
123 if c != ' ' {
124
125 p.corner = true
126 }
127 break
128 }
129 }
130
131 p.addBlock(&fenceBuilder{fence, info, n, nil})
132 return line{}, true
133 }
134 return s, false
135 }
136
137 func (s *line) trimFence(fence, info *string, n *int) bool {
138 t := *s
139 *n = 0
140 for *n < 3 && t.trimSpace(1, 1, false) {
141 *n++
142 }
143 switch c := t.peek(); c {
144 case '`', '~':
145 f := t.string()
146 n := 0
147 for i := 0; ; i++ {
148 if !t.trim(c) {
149 if i >= 3 {
150 break
151 }
152 return false
153 }
154 n++
155 }
156 txt := mdUnescaper.Replace(t.trimString())
157 if c == '`' && strings.Contains(txt, "`") {
158 return false
159 }
160 txt = trimSpaceTab(txt)
161 *info = txt
162
163 *fence = f[:n]
164 *s = line{}
165 return true
166 }
167 return false
168 }
169
170
171 type preBuilder struct {
172 indent string
173 text []string
174 }
175
176 func (c *preBuilder) extend(p *parseState, s line) (line, bool) {
177 if !s.trimSpace(4, 4, true) {
178 return s, false
179 }
180 c.text = append(c.text, s.string())
181 p.corner = p.corner || s.nl != '\n'
182 return line{}, true
183 }
184
185 func (b *preBuilder) build(p buildState) Block {
186 return &CodeBlock{p.pos(), "", "", b.text}
187 }
188
189 type fenceBuilder struct {
190 fence string
191 info string
192 n int
193 text []string
194 }
195
196 func (c *fenceBuilder) extend(p *parseState, s line) (line, bool) {
197 var fence, info string
198 var n int
199 if t := s; t.trimFence(&fence, &info, &n) && strings.HasPrefix(fence, c.fence) && info == "" {
200 return line{}, false
201 }
202 if !s.trimSpace(c.n, c.n, false) {
203 p.corner = true
204 s.trimSpace(0, c.n, false)
205 }
206 c.text = append(c.text, s.string())
207 p.corner = p.corner || s.nl != '\n'
208 return line{}, true
209 }
210
211 func (c *fenceBuilder) build(p buildState) Block {
212 return &CodeBlock{
213 p.pos(),
214 c.fence,
215 c.info,
216 c.text,
217 }
218 }
219
View as plain text