Fix markdown preview $$ support (#31514)
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)
This commit is contained in:
parent
91745ae46f
commit
f0033051d5
@ -555,6 +555,14 @@ func TestMathBlock(t *testing.T) {
|
||||
"$a$ ($b$) [$c$] {$d$}",
|
||||
`<p><code class="language-math is-loading">a</code> (<code class="language-math is-loading">b</code>) [$c$] {$d$}</p>` + nl,
|
||||
},
|
||||
{
|
||||
"$$a$$ test",
|
||||
`<p><code class="language-math display is-loading">a</code> test</p>` + nl,
|
||||
},
|
||||
{
|
||||
"test $$a$$",
|
||||
`<p>test <code class="language-math display is-loading">a</code></p>` + nl,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testcases {
|
||||
|
@ -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
|
||||
|
31
modules/markup/markdown/math/inline_block_node.go
Normal file
31
modules/markup/markdown/math/inline_block_node.go
Normal file
@ -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{},
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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(`<code class="language-math is-loading">`)
|
||||
extraClass := ""
|
||||
if _, ok := n.(*InlineBlock); ok {
|
||||
extraClass = "display "
|
||||
}
|
||||
_, _ = w.WriteString(`<code class="language-math ` + extraClass + `is-loading">`)
|
||||
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
|
||||
segment := c.(*ast.Text).Segment
|
||||
value := util.EscapeHTML(segment.Value(source))
|
||||
@ -43,4 +47,5 @@ func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Nod
|
||||
// RegisterFuncs registers the renderer for inline math nodes
|
||||
func (r *InlineRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
|
||||
reg.Register(KindInline, r.renderInline)
|
||||
reg.Register(KindInlineBlock, r.renderInline)
|
||||
}
|
||||
|
@ -96,7 +96,8 @@ func (e *Extension) Extend(m goldmark.Markdown) {
|
||||
util.Prioritized(NewInlineBracketParser(), 501),
|
||||
}
|
||||
if e.parseDollarInline {
|
||||
inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 501))
|
||||
inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 503),
|
||||
util.Prioritized(NewInlineDualDollarParser(), 502))
|
||||
}
|
||||
m.Parser().AddOptions(parser.WithInlineParsers(inlines...))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user