Skip to content

Commit 3c4a062

Browse files
authored
Refactor markdown render (#32736)
and add some tests
1 parent b32f0cd commit 3c4a062

File tree

5 files changed

+100
-31
lines changed

5 files changed

+100
-31
lines changed

modules/markup/markdown/markdown_math_test.go

+70-6
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func TestMathRender(t *testing.T) {
6868
},
6969
{
7070
"$$a$$",
71-
`<pre class="code-block is-loading"><code class="chroma language-math display">a</code></pre>` + nl,
71+
`<code class="chroma language-math display">a</code>` + nl,
7272
},
7373
{
7474
"$$a$$ test",
@@ -79,9 +79,13 @@ func TestMathRender(t *testing.T) {
7979
`<p>test <code class="language-math display is-loading">a</code></p>` + nl,
8080
},
8181
{
82-
"foo $x=\\$$ bar",
82+
`foo $x=\$$ bar`,
8383
`<p>foo <code class="language-math is-loading">x=\$</code> bar</p>` + nl,
8484
},
85+
{
86+
`$\text{$b$}$`,
87+
`<p><code class="language-math is-loading">\text{$b$}</code></p>` + nl,
88+
},
8589
}
8690

8791
for _, test := range testcases {
@@ -121,34 +125,94 @@ func TestMathRenderBlockIndent(t *testing.T) {
121125
`<pre class="code-block is-loading"><code class="chroma language-math display">
122126
\alpha
123127
</code></pre>
128+
`,
129+
},
130+
{
131+
"indent-2-mismatch",
132+
`
133+
\[
134+
a
135+
b
136+
c
137+
d
138+
\]
139+
`,
140+
`<pre class="code-block is-loading"><code class="chroma language-math display">
141+
a
142+
b
143+
c
144+
d
145+
</code></pre>
124146
`,
125147
},
126148
{
127149
"indent-2",
128150
`
129151
\[
130-
\alpha
152+
a
153+
b
154+
c
131155
\]
132156
`,
133157
`<pre class="code-block is-loading"><code class="chroma language-math display">
134-
\alpha
158+
a
159+
b
160+
c
135161
</code></pre>
136162
`,
137163
},
138164
{
139165
"indent-0-oneline",
140166
`$$ x $$
141167
foo`,
142-
`<pre class="code-block is-loading"><code class="chroma language-math display"> x </code></pre>
168+
`<code class="chroma language-math display"> x </code>
143169
<p>foo</p>
144170
`,
145171
},
146172
{
147173
"indent-3-oneline",
148174
` $$ x $$<SPACE>
149175
foo`,
150-
`<pre class="code-block is-loading"><code class="chroma language-math display"> x </code></pre>
176+
`<code class="chroma language-math display"> x </code>
151177
<p>foo</p>
178+
`,
179+
},
180+
{
181+
"quote-block",
182+
`
183+
> \[
184+
> a
185+
> \]
186+
> \[
187+
> b
188+
> \]
189+
`,
190+
`<blockquote>
191+
<pre class="code-block is-loading"><code class="chroma language-math display">
192+
a
193+
</code></pre>
194+
<pre class="code-block is-loading"><code class="chroma language-math display">
195+
b
196+
</code></pre>
197+
</blockquote>
198+
`,
199+
},
200+
{
201+
"list-block",
202+
`
203+
1. a
204+
\[
205+
x
206+
\]
207+
2. b`,
208+
`<ol>
209+
<li>a
210+
<pre class="code-block is-loading"><code class="chroma language-math display">
211+
x
212+
</code></pre>
213+
</li>
214+
<li>b</li>
215+
</ol>
152216
`,
153217
},
154218
}

modules/markup/markdown/math/block_node.go

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type Block struct {
1111
Dollars bool
1212
Indent int
1313
Closed bool
14+
Inline bool
1415
}
1516

1617
// KindBlock is the node kind for math blocks

modules/markup/markdown/math/block_parser.go

+18-22
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,26 @@ package math
66
import (
77
"bytes"
88

9+
giteaUtil "code.gitea.io/gitea/modules/util"
10+
911
"github.com/yuin/goldmark/ast"
1012
"github.com/yuin/goldmark/parser"
1113
"github.com/yuin/goldmark/text"
1214
"github.com/yuin/goldmark/util"
1315
)
1416

1517
type blockParser struct {
16-
parseDollars bool
18+
parseDollars bool
19+
endBytesDollars []byte
20+
endBytesBracket []byte
1721
}
1822

1923
// NewBlockParser creates a new math BlockParser
2024
func NewBlockParser(parseDollarBlocks bool) parser.BlockParser {
2125
return &blockParser{
22-
parseDollars: parseDollarBlocks,
26+
parseDollars: parseDollarBlocks,
27+
endBytesDollars: []byte{'$', '$'},
28+
endBytesBracket: []byte{'\\', ']'},
2329
}
2430
}
2531

@@ -47,10 +53,7 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
4753
node := NewBlock(dollars, pos)
4854

4955
// Now we need to check if the ending block is on the segment...
50-
endBytes := []byte{'\\', ']'}
51-
if dollars {
52-
endBytes = []byte{'$', '$'}
53-
}
56+
endBytes := giteaUtil.Iif(dollars, b.endBytesDollars, b.endBytesBracket)
5457
idx := bytes.Index(line[pos+2:], endBytes)
5558
if idx >= 0 {
5659
// for case $$ ... $$ any other text
@@ -63,6 +66,7 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
6366
segment.Stop = segment.Start + idx
6467
node.Lines().Append(segment)
6568
node.Closed = true
69+
node.Inline = true
6670
return node, parser.Close | parser.NoChildren
6771
}
6872

@@ -79,27 +83,19 @@ func (b *blockParser) Continue(node ast.Node, reader text.Reader, pc parser.Cont
7983
}
8084

8185
line, segment := reader.PeekLine()
82-
w, pos := util.IndentWidth(line, 0)
86+
w, pos := util.IndentWidth(line, reader.LineOffset())
8387
if w < 4 {
84-
if block.Dollars {
85-
i := pos
86-
for ; i < len(line) && line[i] == '$'; i++ {
87-
}
88-
length := i - pos
89-
if length >= 2 && util.IsBlank(line[i:]) {
90-
reader.Advance(segment.Stop - segment.Start - segment.Padding)
91-
block.Closed = true
88+
endBytes := giteaUtil.Iif(block.Dollars, b.endBytesDollars, b.endBytesBracket)
89+
if bytes.HasPrefix(line[pos:], endBytes) && util.IsBlank(line[pos+len(endBytes):]) {
90+
if util.IsBlank(line[pos+len(endBytes):]) {
91+
newline := giteaUtil.Iif(line[len(line)-1] != '\n', 0, 1)
92+
reader.Advance(segment.Stop - segment.Start - newline + segment.Padding)
9293
return parser.Close
9394
}
94-
} else if len(line[pos:]) > 1 && line[pos] == '\\' && line[pos+1] == ']' && util.IsBlank(line[pos+2:]) {
95-
reader.Advance(segment.Stop - segment.Start - segment.Padding)
96-
block.Closed = true
97-
return parser.Close
9895
}
9996
}
100-
101-
pos, padding := util.IndentPosition(line, 0, block.Indent)
102-
seg := text.NewSegmentPadding(segment.Start+pos, segment.Stop, padding)
97+
start := segment.Start + giteaUtil.Iif(pos > block.Indent, block.Indent, pos)
98+
seg := text.NewSegmentPadding(start, segment.Stop, segment.Padding)
10399
node.Lines().Append(seg)
104100
return parser.Continue | parser.NoChildren
105101
}

modules/markup/markdown/math/block_renderer.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package math
55

66
import (
77
"code.gitea.io/gitea/modules/markup/internal"
8+
giteaUtil "code.gitea.io/gitea/modules/util"
89

910
gast "github.com/yuin/goldmark/ast"
1011
"github.com/yuin/goldmark/renderer"
@@ -37,10 +38,11 @@ func (r *BlockRenderer) writeLines(w util.BufWriter, source []byte, n gast.Node)
3738
func (r *BlockRenderer) renderBlock(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) {
3839
n := node.(*Block)
3940
if entering {
40-
_ = r.renderInternal.FormatWithSafeAttrs(w, `<pre class="code-block is-loading"><code class="chroma language-math display">`)
41+
code := giteaUtil.Iif(n.Inline, "", `<pre class="code-block is-loading">`) + `<code class="chroma language-math display">`
42+
_ = r.renderInternal.FormatWithSafeAttrs(w, code)
4143
r.writeLines(w, source, n)
4244
} else {
43-
_, _ = w.WriteString(`</code></pre>` + "\n")
45+
_, _ = w.WriteString(`</code>` + giteaUtil.Iif(n.Inline, "", `</pre>`) + "\n")
4446
}
4547
return gast.WalkContinue, nil
4648
}

modules/markup/markdown/math/inline_parser.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
7979
opener := len(parser.start)
8080

8181
// Now look for an ending line
82+
depth := 0
8283
ender := -1
8384
for i := opener; i < len(line); i++ {
84-
if bytes.HasPrefix(line[i:], parser.end) {
85+
if depth == 0 && bytes.HasPrefix(line[i:], parser.end) {
8586
succeedingCharacter := byte(0)
8687
if i+len(parser.end) < len(line) {
8788
succeedingCharacter = line[i+len(parser.end)]
@@ -99,6 +100,11 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
99100
i++
100101
continue
101102
}
103+
if line[i] == '{' {
104+
depth++
105+
} else if line[i] == '}' {
106+
depth--
107+
}
102108
}
103109
if ender == -1 {
104110
return nil

0 commit comments

Comments
 (0)