From f0033051d5ce07f5a18d2aacef6bfdca5fc69014 Mon Sep 17 00:00:00 2001
From: charles <30816317+charles7668@users.noreply.github.com>
Date: Sun, 30 Jun 2024 07:23:47 +0800
Subject: [PATCH] Fix markdown preview $$ support (#31514)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
close #31481
currently `$$A + B$$ test` will ignore text after $$ block
test text
![圖片](https://github.com/go-gitea/gitea/assets/30816317/39b2974b-c0b6-48a0-87d0-5f4a13615eed)
before fix
![圖片](https://github.com/go-gitea/gitea/assets/30816317/15469e4c-474d-4128-b46f-d6cadaafbd68)
after fix
![圖片](https://github.com/go-gitea/gitea/assets/30816317/c1025eef-177f-4ade-988f-510e7039f3f9)
github display
![圖片](https://github.com/go-gitea/gitea/assets/30816317/97cd1e10-ac94-4899-86d8-8e359ef1d694)
---
modules/markup/markdown/markdown_test.go | 8 +++++
modules/markup/markdown/math/block_parser.go | 6 ++++
.../markup/markdown/math/inline_block_node.go | 31 +++++++++++++++++++
modules/markup/markdown/math/inline_parser.go | 30 +++++++++++++++---
.../markup/markdown/math/inline_renderer.go | 7 ++++-
modules/markup/markdown/math/math.go | 3 +-
6 files changed, 79 insertions(+), 6 deletions(-)
create mode 100644 modules/markup/markdown/math/inline_block_node.go
diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go
index 1a88d5d44..671276e45 100644
--- a/modules/markup/markdown/markdown_test.go
+++ b/modules/markup/markdown/markdown_test.go
@@ -555,6 +555,14 @@ func TestMathBlock(t *testing.T) {
"$a$ ($b$) [$c$] {$d$}",
`
a
(b
) [$c$] {$d$}
` + nl,
},
+ {
+ "$$a$$ test",
+ `a
test
` + nl,
+ },
+ {
+ "test $$a$$",
+ `test a
` + nl,
+ },
}
for _, test := range testcases {
diff --git a/modules/markup/markdown/math/block_parser.go b/modules/markup/markdown/math/block_parser.go
index 37f6caf11..a23f48b63 100644
--- a/modules/markup/markdown/math/block_parser.go
+++ b/modules/markup/markdown/math/block_parser.go
@@ -53,6 +53,12 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
}
idx := bytes.Index(line[pos+2:], endBytes)
if idx >= 0 {
+ // for case $$ ... $$ any other text
+ for i := pos + idx + 4; i < len(line); i++ {
+ if line[i] != ' ' && line[i] != '\n' {
+ return nil, parser.NoChildren
+ }
+ }
segment.Stop = segment.Start + idx + 2
reader.Advance(segment.Len() - 1)
segment.Start += 2
diff --git a/modules/markup/markdown/math/inline_block_node.go b/modules/markup/markdown/math/inline_block_node.go
new file mode 100644
index 000000000..c92d0c8d8
--- /dev/null
+++ b/modules/markup/markdown/math/inline_block_node.go
@@ -0,0 +1,31 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package math
+
+import (
+ "github.com/yuin/goldmark/ast"
+)
+
+// InlineBlock represents inline math e.g. $$...$$
+type InlineBlock struct {
+ Inline
+}
+
+// InlineBlock implements InlineBlock.
+func (n *InlineBlock) InlineBlock() {}
+
+// KindInlineBlock is the kind for math inline block
+var KindInlineBlock = ast.NewNodeKind("MathInlineBlock")
+
+// Kind returns KindInlineBlock
+func (n *InlineBlock) Kind() ast.NodeKind {
+ return KindInlineBlock
+}
+
+// NewInlineBlock creates a new ast math inline block node
+func NewInlineBlock() *InlineBlock {
+ return &InlineBlock{
+ Inline{},
+ }
+}
diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go
index 614cf329a..b11195d55 100644
--- a/modules/markup/markdown/math/inline_parser.go
+++ b/modules/markup/markdown/math/inline_parser.go
@@ -21,11 +21,20 @@ var defaultInlineDollarParser = &inlineParser{
end: []byte{'$'},
}
+var defaultDualDollarParser = &inlineParser{
+ start: []byte{'$', '$'},
+ end: []byte{'$', '$'},
+}
+
// NewInlineDollarParser returns a new inline parser
func NewInlineDollarParser() parser.InlineParser {
return defaultInlineDollarParser
}
+func NewInlineDualDollarParser() parser.InlineParser {
+ return defaultDualDollarParser
+}
+
var defaultInlineBracketParser = &inlineParser{
start: []byte{'\\', '('},
end: []byte{'\\', ')'},
@@ -38,7 +47,7 @@ func NewInlineBracketParser() parser.InlineParser {
// Trigger triggers this parser on $ or \
func (parser *inlineParser) Trigger() []byte {
- return parser.start[0:1]
+ return parser.start
}
func isPunctuation(b byte) bool {
@@ -88,7 +97,11 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
break
}
suceedingCharacter := line[pos]
- if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') && !isBracket(suceedingCharacter) {
+ // check valid ending character
+ if !isPunctuation(suceedingCharacter) &&
+ !(suceedingCharacter == ' ') &&
+ !(suceedingCharacter == '\n') &&
+ !isBracket(suceedingCharacter) {
return nil
}
if line[ender-1] != '\\' {
@@ -101,12 +114,21 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
block.Advance(opener)
_, pos := block.Position()
- node := NewInline()
+ var node ast.Node
+ if parser == defaultDualDollarParser {
+ node = NewInlineBlock()
+ } else {
+ node = NewInline()
+ }
segment := pos.WithStop(pos.Start + ender - opener)
node.AppendChild(node, ast.NewRawTextSegment(segment))
block.Advance(ender - opener + len(parser.end))
- trimBlock(node, block)
+ if parser == defaultDualDollarParser {
+ trimBlock(&(node.(*InlineBlock)).Inline, block)
+ } else {
+ trimBlock(node.(*Inline), block)
+ }
return node
}
diff --git a/modules/markup/markdown/math/inline_renderer.go b/modules/markup/markdown/math/inline_renderer.go
index b4e9ade0a..96848099c 100644
--- a/modules/markup/markdown/math/inline_renderer.go
+++ b/modules/markup/markdown/math/inline_renderer.go
@@ -21,7 +21,11 @@ func NewInlineRenderer() renderer.NodeRenderer {
func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
- _, _ = w.WriteString(``)
+ extraClass := ""
+ if _, ok := n.(*InlineBlock); ok {
+ extraClass = "display "
+ }
+ _, _ = w.WriteString(`