Skip to content

Commit cafe05b

Browse files
committed
fix
1 parent e8b54d9 commit cafe05b

File tree

7 files changed

+159
-23
lines changed

7 files changed

+159
-23
lines changed

custom/conf/app.example.ini

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,12 @@ LEVEL = Info
14341434
;;
14351435
;; Enables math inline and block detection
14361436
;ENABLE_MATH = true
1437+
;;
1438+
;; Enable delimiters for math code block detection. Set to "none" to disable all, or use comma separated list:
1439+
;; inline-dollar, inline-parentheses, block-dollar, block-square-brackets
1440+
;; Defaults to "inline-dollar,block-dollar" to follow GitHub's behavior.
1441+
;MATH_CODE_BLOCK_DETECTION =
1442+
;;
14371443

14381444
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14391445
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

modules/markup/markdown/markdown.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,11 @@ func SpecializedMarkdown(ctx *markup.RenderContext) *GlodmarkRender {
126126
highlighting.WithWrapperRenderer(r.highlightingRenderer),
127127
),
128128
math.NewExtension(&ctx.RenderInternal, math.Options{
129-
Enabled: setting.Markdown.EnableMath,
130-
ParseDollarInline: true,
131-
ParseDollarBlock: true,
132-
ParseSquareBlock: true, // TODO: this is a bad syntax "\[ ... \]", it conflicts with normal markdown escaping, it should be deprecated in the future (by some config options)
133-
// ParseBracketInline: true, // TODO: this is also a bad syntax "\( ... \)", it also conflicts, it should be deprecated in the future
129+
Enabled: setting.Markdown.EnableMath,
130+
ParseInlineDollar: setting.Markdown.MathCodeBlockOptions.ParseInlineDollar,
131+
ParseInlineParentheses: setting.Markdown.MathCodeBlockOptions.ParseInlineParentheses, // this is a bad syntax "\( ... \)", it conflicts with normal markdown escaping
132+
ParseBlockDollar: setting.Markdown.MathCodeBlockOptions.ParseBlockDollar,
133+
ParseBlockSquareBrackets: setting.Markdown.MathCodeBlockOptions.ParseBlockSquareBrackets, // this is a bad syntax "\[ ... \]", it conflicts with normal markdown escaping
134134
}),
135135
meta.Meta,
136136
),

modules/markup/markdown/markdown_math_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package markdown
55

66
import (
7+
"code.gitea.io/gitea/modules/setting"
8+
"code.gitea.io/gitea/modules/test"
79
"strings"
810
"testing"
911

@@ -15,6 +17,7 @@ import (
1517
const nl = "\n"
1618

1719
func TestMathRender(t *testing.T) {
20+
setting.Markdown.MathCodeBlockOptions = setting.MarkdownMathCodeBlockOptions{ParseInlineDollar: true, ParseInlineParentheses: true}
1821
testcases := []struct {
1922
testcase string
2023
expected string
@@ -111,6 +114,7 @@ func TestMathRender(t *testing.T) {
111114
}
112115

113116
func TestMathRenderBlockIndent(t *testing.T) {
117+
setting.Markdown.MathCodeBlockOptions = setting.MarkdownMathCodeBlockOptions{ParseBlockDollar: true, ParseBlockSquareBrackets: true}
114118
testcases := []struct {
115119
name string
116120
testcase string
@@ -243,3 +247,61 @@ x
243247
})
244248
}
245249
}
250+
251+
func TestMathRenderOptions(t *testing.T) {
252+
setting.Markdown.MathCodeBlockOptions = setting.MarkdownMathCodeBlockOptions{}
253+
defer test.MockVariableValue(&setting.Markdown.MathCodeBlockOptions)
254+
test := func(t *testing.T, expected, input string) {
255+
res, err := RenderString(markup.NewTestRenderContext(), input)
256+
assert.NoError(t, err)
257+
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(res)), "input: %s", input)
258+
}
259+
260+
// ParseInlineDollar
261+
test(t, `<p>$a$</p>`, `$a$`)
262+
setting.Markdown.MathCodeBlockOptions.ParseInlineDollar = true
263+
test(t, `<p><code class="language-math">a</code></p>`, `$a$`)
264+
265+
// ParseInlineParentheses
266+
test(t, `<p>(a)</p>`, `\(a\)`)
267+
setting.Markdown.MathCodeBlockOptions.ParseInlineParentheses = true
268+
test(t, `<p><code class="language-math">a</code></p>`, `\(a\)`)
269+
270+
// ParseBlockDollar
271+
test(t, `<p>$$
272+
a
273+
$$</p>
274+
`, `
275+
$$
276+
a
277+
$$
278+
`)
279+
setting.Markdown.MathCodeBlockOptions.ParseBlockDollar = true
280+
test(t, `<pre class="code-block is-loading"><code class="language-math display">
281+
a
282+
</code></pre>
283+
`, `
284+
$$
285+
a
286+
$$
287+
`)
288+
289+
// ParseBlockSquareBrackets
290+
test(t, `<p>[
291+
a
292+
]</p>
293+
`, `
294+
\[
295+
a
296+
\]
297+
`)
298+
setting.Markdown.MathCodeBlockOptions.ParseBlockSquareBrackets = true
299+
test(t, `<pre class="code-block is-loading"><code class="language-math display">
300+
a
301+
</code></pre>
302+
`, `
303+
\[
304+
a
305+
\]
306+
`)
307+
}

modules/markup/markdown/math/inline_parser.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type inlineParser struct {
1515
trigger []byte
1616
endBytesSingleDollar []byte
1717
endBytesDoubleDollar []byte
18-
endBytesBracket []byte
18+
endBytesParentheses []byte
1919
}
2020

2121
var defaultInlineDollarParser = &inlineParser{
@@ -28,13 +28,13 @@ func NewInlineDollarParser() parser.InlineParser {
2828
return defaultInlineDollarParser
2929
}
3030

31-
var defaultInlineBracketParser = &inlineParser{
32-
trigger: []byte{'\\', '('},
33-
endBytesBracket: []byte{'\\', ')'},
31+
var defaultInlineParenthesesParser = &inlineParser{
32+
trigger: []byte{'\\', '('},
33+
endBytesParentheses: []byte{'\\', ')'},
3434
}
3535

36-
func NewInlineBracketParser() parser.InlineParser {
37-
return defaultInlineBracketParser
36+
func NewInlineParenthesesParser() parser.InlineParser {
37+
return defaultInlineParenthesesParser
3838
}
3939

4040
// Trigger triggers this parser on $ or \
@@ -46,7 +46,7 @@ func isPunctuation(b byte) bool {
4646
return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':'
4747
}
4848

49-
func isBracket(b byte) bool {
49+
func isParenthesesClose(b byte) bool {
5050
return b == ')'
5151
}
5252

@@ -86,7 +86,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
8686
}
8787
} else {
8888
startMarkLen = 2
89-
stopMark = parser.endBytesBracket
89+
stopMark = parser.endBytesParentheses
9090
}
9191

9292
if checkSurrounding {
@@ -110,7 +110,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
110110
succeedingCharacter = line[i+len(stopMark)]
111111
}
112112
// check valid ending character
113-
isValidEndingChar := isPunctuation(succeedingCharacter) || isBracket(succeedingCharacter) ||
113+
isValidEndingChar := isPunctuation(succeedingCharacter) || isParenthesesClose(succeedingCharacter) ||
114114
succeedingCharacter == ' ' || succeedingCharacter == '\n' || succeedingCharacter == 0
115115
if checkSurrounding && !isValidEndingChar {
116116
break

modules/markup/markdown/math/math.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ import (
1414
)
1515

1616
type Options struct {
17-
Enabled bool
18-
ParseDollarInline bool
19-
ParseDollarBlock bool
20-
ParseSquareBlock bool
17+
Enabled bool
18+
ParseInlineDollar bool // inline $$ xxx $$ text
19+
ParseInlineParentheses bool // inline \( xxx \) text
20+
ParseBlockDollar bool // block $$ multiple-line $$ text
21+
ParseBlockSquareBrackets bool // block \[ multiple-line \] text
2122
}
2223

2324
// Extension is a math extension
@@ -42,16 +43,17 @@ func (e *Extension) Extend(m goldmark.Markdown) {
4243
return
4344
}
4445

45-
inlines := []util.PrioritizedValue{util.Prioritized(NewInlineBracketParser(), 501)}
46-
if e.options.ParseDollarInline {
46+
var inlines []util.PrioritizedValue
47+
if e.options.ParseInlineParentheses {
48+
inlines = append(inlines, util.Prioritized(NewInlineParenthesesParser(), 501))
49+
}
50+
if e.options.ParseInlineDollar {
4751
inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 502))
4852
}
4953
m.Parser().AddOptions(parser.WithInlineParsers(inlines...))
50-
5154
m.Parser().AddOptions(parser.WithBlockParsers(
52-
util.Prioritized(NewBlockParser(e.options.ParseDollarBlock, e.options.ParseSquareBlock), 701),
55+
util.Prioritized(NewBlockParser(e.options.ParseBlockDollar, e.options.ParseBlockSquareBrackets), 701),
5356
))
54-
5557
m.Renderer().AddOptions(renderer.WithNodeRenderers(
5658
util.Prioritized(NewBlockRenderer(e.renderInternal), 501),
5759
util.Prioritized(NewInlineRenderer(e.renderInternal), 502),

modules/setting/markup.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,22 @@ const (
2323
RenderContentModeIframe = "iframe"
2424
)
2525

26+
type MarkdownMathCodeBlockOptions struct {
27+
ParseInlineDollar bool
28+
ParseInlineParentheses bool
29+
ParseBlockDollar bool
30+
ParseBlockSquareBrackets bool
31+
}
32+
2633
// Markdown settings
2734
var Markdown = struct {
2835
EnableHardLineBreakInComments bool
2936
EnableHardLineBreakInDocuments bool
3037
CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
3138
FileExtensions []string
3239
EnableMath bool
40+
MathCodeBlockDetection []string
41+
MathCodeBlockOptions MarkdownMathCodeBlockOptions `ini:"-"`
3342
}{
3443
EnableHardLineBreakInComments: true,
3544
EnableHardLineBreakInDocuments: false,
@@ -61,6 +70,33 @@ type MarkupSanitizerRule struct {
6170
func loadMarkupFrom(rootCfg ConfigProvider) {
6271
mustMapSetting(rootCfg, "markdown", &Markdown)
6372

73+
const mathCodeNone = "none"
74+
const mathCodeInlineDollar = "inline-dollar"
75+
const mathCodeInlineParentheses = "inline-parentheses"
76+
const mathCodeBlockDollar = "block-dollar"
77+
const mathCodeBlockSquareBrackets = "block-square-brackets"
78+
if len(Markdown.MathCodeBlockDetection) == 0 {
79+
Markdown.MathCodeBlockDetection = []string{mathCodeInlineDollar, mathCodeBlockDollar}
80+
}
81+
Markdown.MathCodeBlockOptions = MarkdownMathCodeBlockOptions{}
82+
for _, s := range Markdown.MathCodeBlockDetection {
83+
switch s {
84+
case mathCodeInlineDollar:
85+
Markdown.MathCodeBlockOptions.ParseInlineDollar = true
86+
case mathCodeInlineParentheses:
87+
Markdown.MathCodeBlockOptions.ParseInlineParentheses = true
88+
case mathCodeBlockDollar:
89+
Markdown.MathCodeBlockOptions.ParseBlockDollar = true
90+
case mathCodeBlockSquareBrackets:
91+
Markdown.MathCodeBlockOptions.ParseBlockSquareBrackets = true
92+
case mathCodeNone:
93+
Markdown.MathCodeBlockOptions = MarkdownMathCodeBlockOptions{}
94+
case "":
95+
default:
96+
log.Fatal("Unknown math code block detection option: " + s)
97+
}
98+
}
99+
64100
MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000)
65101
ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10)
66102
ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, 10)

modules/setting/markup_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package setting
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestLoadMarkup(t *testing.T) {
13+
cfg, _ := NewConfigProviderFromData(``)
14+
loadMarkupFrom(cfg)
15+
assert.Equal(t, MarkdownMathCodeBlockOptions{ParseInlineDollar: true, ParseBlockDollar: true}, Markdown.MathCodeBlockOptions)
16+
17+
cfg, _ = NewConfigProviderFromData(`
18+
[markdown]
19+
MATH_CODE_BLOCK_DETECTION = none
20+
`)
21+
loadMarkupFrom(cfg)
22+
assert.Equal(t, MarkdownMathCodeBlockOptions{}, Markdown.MathCodeBlockOptions)
23+
24+
cfg, _ = NewConfigProviderFromData(`
25+
[markdown]
26+
MATH_CODE_BLOCK_DETECTION = inline-dollar, inline-parentheses, block-dollar, block-square-brackets
27+
`)
28+
loadMarkupFrom(cfg)
29+
assert.Equal(t, MarkdownMathCodeBlockOptions{ParseInlineDollar: true, ParseInlineParentheses: true, ParseBlockDollar: true, ParseBlockSquareBrackets: true}, Markdown.MathCodeBlockOptions)
30+
}

0 commit comments

Comments
 (0)