Skip to content

Commit c2b67b3

Browse files
committed
fix
1 parent 5bc030e commit c2b67b3

File tree

7 files changed

+88
-86
lines changed

7 files changed

+88
-86
lines changed

modules/markup/markdown/markdown_math_test.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import (
1212
"github.com/stretchr/testify/assert"
1313
)
1414

15+
const nl = "\n"
16+
1517
func TestMathRender(t *testing.T) {
16-
const nl = "\n"
1718
testcases := []struct {
1819
testcase string
1920
expected string
@@ -86,6 +87,18 @@ func TestMathRender(t *testing.T) {
8687
`$\text{$b$}$`,
8788
`<p><code class="language-math">\text{$b$}</code></p>` + nl,
8889
},
90+
{
91+
"a$`b`$c",
92+
`<p>a<code class="language-math">b</code>c</p>` + nl,
93+
},
94+
{
95+
"a $`b`$ c",
96+
`<p>a <code class="language-math">b</code> c</p>` + nl,
97+
},
98+
{
99+
"a$``b``$c x$```y```$z",
100+
`<p>a<code class="language-math">b</code>c x<code class="language-math">y</code>z</p>` + nl,
101+
},
89102
}
90103

91104
for _, test := range testcases {
@@ -215,6 +228,11 @@ x
215228
</ol>
216229
`,
217230
},
231+
{
232+
"inline-broken",
233+
`\[x]`,
234+
`<p>[x]</p>` + nl,
235+
},
218236
}
219237

220238
for _, test := range testcases {

modules/markup/markdown/math/block_parser.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ import (
1717
type blockParser struct {
1818
parseDollars bool
1919
endBytesDollars []byte
20-
endBytesBracket []byte
20+
endBytesSquare []byte
2121
}
2222

2323
// NewBlockParser creates a new math BlockParser
2424
func NewBlockParser(parseDollarBlocks bool) parser.BlockParser {
2525
return &blockParser{
2626
parseDollars: parseDollarBlocks,
2727
endBytesDollars: []byte{'$', '$'},
28-
endBytesBracket: []byte{'\\', ']'},
28+
endBytesSquare: []byte{'\\', ']'},
2929
}
3030
}
3131

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

5555
// Now we need to check if the ending block is on the segment...
56-
endBytes := giteaUtil.Iif(dollars, b.endBytesDollars, b.endBytesBracket)
56+
endBytes := giteaUtil.Iif(dollars, b.endBytesDollars, b.endBytesSquare)
5757
idx := bytes.Index(line[pos+2:], endBytes)
5858
if idx >= 0 {
5959
// for case $$ ... $$ any other text
@@ -68,6 +68,13 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
6868
node.Closed = true
6969
node.Inline = true
7070
return node, parser.Close | parser.NoChildren
71+
} else {
72+
// for case "\[ ... ]" (no close marker on the same line)
73+
for i := pos + 2 + idx + 2; i < len(line); i++ {
74+
if line[i] != ' ' && line[i] != '\n' {
75+
return nil, parser.NoChildren
76+
}
77+
}
7178
}
7279

7380
segment.Start += pos + 2
@@ -85,7 +92,7 @@ func (b *blockParser) Continue(node ast.Node, reader text.Reader, pc parser.Cont
8592
line, segment := reader.PeekLine()
8693
w, pos := util.IndentWidth(line, reader.LineOffset())
8794
if w < 4 {
88-
endBytes := giteaUtil.Iif(block.Dollars, b.endBytesDollars, b.endBytesBracket)
95+
endBytes := giteaUtil.Iif(block.Dollars, b.endBytesDollars, b.endBytesSquare)
8996
if bytes.HasPrefix(line[pos:], endBytes) && util.IsBlank(line[pos+len(endBytes):]) {
9097
if util.IsBlank(line[pos+len(endBytes):]) {
9198
newline := giteaUtil.Iif(line[len(line)-1] != '\n', 0, 1)

modules/markup/markdown/math/inline_block_node.go

-31
This file was deleted.

modules/markup/markdown/math/inline_node.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"github.com/yuin/goldmark/util"
99
)
1010

11-
// Inline represents inline math e.g. $...$ or \(...\)
11+
// Inline struct represents inline math e.g. $...$ or \(...\)
1212
type Inline struct {
1313
ast.BaseInline
1414
}

modules/markup/markdown/math/inline_parser.go

+51-39
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,25 @@ import (
1212
)
1313

1414
type inlineParser struct {
15-
start []byte
16-
end []byte
15+
trigger []byte
16+
endBytesSingleDollar []byte
17+
endBytesDoubleDollar []byte
18+
endBytesBracket []byte
1719
}
1820

1921
var defaultInlineDollarParser = &inlineParser{
20-
start: []byte{'$'},
21-
end: []byte{'$'},
22-
}
23-
24-
var defaultDualDollarParser = &inlineParser{
25-
start: []byte{'$', '$'},
26-
end: []byte{'$', '$'},
22+
trigger: []byte{'$'},
23+
endBytesSingleDollar: []byte{'$'},
24+
endBytesDoubleDollar: []byte{'$', '$'},
2725
}
2826

2927
func NewInlineDollarParser() parser.InlineParser {
3028
return defaultInlineDollarParser
3129
}
3230

33-
func NewInlineDualDollarParser() parser.InlineParser {
34-
return defaultDualDollarParser
35-
}
36-
3731
var defaultInlineBracketParser = &inlineParser{
38-
start: []byte{'\\', '('},
39-
end: []byte{'\\', ')'},
32+
trigger: []byte{'\\', '('},
33+
endBytesBracket: []byte{'\\', ')'},
4034
}
4135

4236
func NewInlineBracketParser() parser.InlineParser {
@@ -45,7 +39,7 @@ func NewInlineBracketParser() parser.InlineParser {
4539

4640
// Trigger triggers this parser on $ or \
4741
func (parser *inlineParser) Trigger() []byte {
48-
return parser.start
42+
return parser.trigger
4943
}
5044

5145
func isPunctuation(b byte) bool {
@@ -64,33 +58,60 @@ func isAlphanumeric(b byte) bool {
6458
func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
6559
line, _ := block.PeekLine()
6660

67-
if !bytes.HasPrefix(line, parser.start) {
61+
if !bytes.HasPrefix(line, parser.trigger) {
6862
// We'll catch this one on the next time round
6963
return nil
7064
}
7165

72-
precedingCharacter := block.PrecendingCharacter()
73-
if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) {
74-
// need to exclude things like `a$` from being considered a start
75-
return nil
66+
var startMarkLen int
67+
var stopMark []byte
68+
checkSurrounding := true
69+
if line[0] == '$' {
70+
startMarkLen = 1
71+
stopMark = parser.endBytesSingleDollar
72+
if len(line) > 1 {
73+
if line[1] == '$' {
74+
startMarkLen = 2
75+
stopMark = parser.endBytesDoubleDollar
76+
} else if line[1] == '`' {
77+
pos := 1
78+
for ; pos < len(line) && line[pos] == '`'; pos++ {
79+
}
80+
startMarkLen = pos
81+
stopMark = bytes.Repeat([]byte{'`'}, pos)
82+
stopMark[len(stopMark)-1] = '$'
83+
checkSurrounding = false
84+
}
85+
}
86+
} else {
87+
startMarkLen = 2
88+
stopMark = parser.endBytesBracket
89+
}
90+
91+
if checkSurrounding {
92+
precedingCharacter := block.PrecendingCharacter()
93+
if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) {
94+
// need to exclude things like `a$` from being considered a start
95+
return nil
96+
}
7697
}
7798

7899
// move the opener marker point at the start of the text
79-
opener := len(parser.start)
100+
opener := startMarkLen
80101

81102
// Now look for an ending line
82103
depth := 0
83104
ender := -1
84105
for i := opener; i < len(line); i++ {
85-
if depth == 0 && bytes.HasPrefix(line[i:], parser.end) {
106+
if depth == 0 && bytes.HasPrefix(line[i:], stopMark) {
86107
succeedingCharacter := byte(0)
87-
if i+len(parser.end) < len(line) {
88-
succeedingCharacter = line[i+len(parser.end)]
108+
if i+len(stopMark) < len(line) {
109+
succeedingCharacter = line[i+len(stopMark)]
89110
}
90111
// check valid ending character
91112
isValidEndingChar := isPunctuation(succeedingCharacter) || isBracket(succeedingCharacter) ||
92113
succeedingCharacter == ' ' || succeedingCharacter == '\n' || succeedingCharacter == 0
93-
if !isValidEndingChar {
114+
if checkSurrounding && !isValidEndingChar {
94115
break
95116
}
96117
ender = i
@@ -112,21 +133,12 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
112133

113134
block.Advance(opener)
114135
_, pos := block.Position()
115-
var node ast.Node
116-
if parser == defaultDualDollarParser {
117-
node = NewInlineBlock()
118-
} else {
119-
node = NewInline()
120-
}
136+
node := NewInline()
137+
121138
segment := pos.WithStop(pos.Start + ender - opener)
122139
node.AppendChild(node, ast.NewRawTextSegment(segment))
123-
block.Advance(ender - opener + len(parser.end))
124-
125-
if parser == defaultDualDollarParser {
126-
trimBlock(&(node.(*InlineBlock)).Inline, block)
127-
} else {
128-
trimBlock(node.(*Inline), block)
129-
}
140+
block.Advance(ender - opener + len(stopMark))
141+
trimBlock(node, block)
130142
return node
131143
}
132144

modules/markup/markdown/math/inline_renderer.go

-1
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,4 @@ func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Nod
5050
// RegisterFuncs registers the renderer for inline math nodes
5151
func (r *InlineRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
5252
reg.Register(KindInline, r.renderInline)
53-
reg.Register(KindInlineBlock, r.renderInline)
5453
}

modules/markup/markdown/math/math.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,16 @@ func (e *Extension) Extend(m goldmark.Markdown) {
6363
return
6464
}
6565

66-
m.Parser().AddOptions(parser.WithBlockParsers(
67-
util.Prioritized(NewBlockParser(e.parseDollarBlock), 701),
68-
))
69-
70-
inlines := []util.PrioritizedValue{
71-
util.Prioritized(NewInlineBracketParser(), 501),
72-
}
66+
inlines := []util.PrioritizedValue{util.Prioritized(NewInlineBracketParser(), 501)}
7367
if e.parseDollarInline {
74-
inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 503),
75-
util.Prioritized(NewInlineDualDollarParser(), 502))
68+
inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 502))
7669
}
7770
m.Parser().AddOptions(parser.WithInlineParsers(inlines...))
7871

72+
m.Parser().AddOptions(parser.WithBlockParsers(
73+
util.Prioritized(NewBlockParser(e.parseDollarBlock), 701),
74+
))
75+
7976
m.Renderer().AddOptions(renderer.WithNodeRenderers(
8077
util.Prioritized(NewBlockRenderer(e.renderInternal), 501),
8178
util.Prioritized(NewInlineRenderer(e.renderInternal), 502),

0 commit comments

Comments
 (0)