]> source.dussan.org Git - gitea.git/commitdiff
Make blockquote attention recognize more syntaxes (#31240) (#31250)
authorGiteabot <teabot@gitea.io>
Tue, 4 Jun 2024 16:03:01 +0000 (00:03 +0800)
committerGitHub <noreply@github.com>
Tue, 4 Jun 2024 16:03:01 +0000 (16:03 +0000)
Backport #31240 by wxiaoguang

Fix #31214

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
modules/markup/markdown/markdown_test.go
modules/markup/markdown/math/block_parser.go
modules/markup/markdown/transform_blockquote.go

index bc6ad7fb3c737c06c93e364b08270207e2961618..cefbdbf9c2b8ef791dd659e2778251574b576432 100644 (file)
@@ -1010,4 +1010,10 @@ func TestAttention(t *testing.T) {
        test(`> [!important]`, renderAttention("important", "octicon-report")+"\n</blockquote>")
        test(`> [!warning]`, renderAttention("warning", "octicon-alert")+"\n</blockquote>")
        test(`> [!caution]`, renderAttention("caution", "octicon-stop")+"\n</blockquote>")
+
+       // escaped by mdformat
+       test(`> \[!NOTE\]`, renderAttention("note", "octicon-info")+"\n</blockquote>")
+
+       // legacy GitHub style
+       test(`> **warning**`, renderAttention("warning", "octicon-alert")+"\n</blockquote>")
 }
index 7f714d7239292da5be0ec3ad112494d87f5fa0c2..37f6caf11ce2c0fe2c02f29b690f4bbc31664b69 100644 (file)
@@ -31,10 +31,16 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
                return nil, parser.NoChildren
        }
 
-       dollars := false
+       var dollars bool
        if b.parseDollars && line[pos] == '$' && line[pos+1] == '$' {
                dollars = true
-       } else if line[pos] != '\\' || line[pos+1] != '[' {
+       } else if line[pos] == '\\' && line[pos+1] == '[' {
+               if len(line[pos:]) >= 3 && line[pos+2] == '!' && bytes.Contains(line[pos:], []byte(`\]`)) {
+                       // do not process escaped attention block: "> \[!NOTE\]"
+                       return nil, parser.NoChildren
+               }
+               dollars = false
+       } else {
                return nil, parser.NoChildren
        }
 
index 933f0e5c5938422f099d18a6b63461e18f490f65..d2dc025052d00edeb7687d4407b8b9f8cf5a1fc5 100644 (file)
@@ -15,7 +15,7 @@ import (
        "golang.org/x/text/language"
 )
 
-// renderAttention renders a quote marked with i.e. "> **Note**" or "> **Warning**" with a corresponding svg
+// renderAttention renders a quote marked with i.e. "> **Note**" or "> [!Warning]" with a corresponding svg
 func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
        if entering {
                n := node.(*Attention)
@@ -37,38 +37,93 @@ func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast
        return ast.WalkContinue, nil
 }
 
-func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Reader) (ast.WalkStatus, error) {
-       // We only want attention blockquotes when the AST looks like:
-       // > Text("[") Text("!TYPE") Text("]")
+func (g *ASTTransformer) extractBlockquoteAttentionEmphasis(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
+       if firstParagraph.ChildCount() < 1 {
+               return "", nil
+       }
+       node1, ok := firstParagraph.FirstChild().(*ast.Emphasis)
+       if !ok {
+               return "", nil
+       }
+       val1 := string(node1.Text(reader.Source()))
+       attentionType := strings.ToLower(val1)
+       if g.attentionTypes.Contains(attentionType) {
+               return attentionType, []ast.Node{node1}
+       }
+       return "", nil
+}
 
-       // grab these nodes and make sure we adhere to the attention blockquote structure
-       firstParagraph := v.FirstChild()
-       g.applyElementDir(firstParagraph)
+func (g *ASTTransformer) extractBlockquoteAttention2(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
+       if firstParagraph.ChildCount() < 2 {
+               return "", nil
+       }
+       node1, ok := firstParagraph.FirstChild().(*ast.Text)
+       if !ok {
+               return "", nil
+       }
+       node2, ok := node1.NextSibling().(*ast.Text)
+       if !ok {
+               return "", nil
+       }
+       val1 := string(node1.Segment.Value(reader.Source()))
+       val2 := string(node2.Segment.Value(reader.Source()))
+       if strings.HasPrefix(val1, `\[!`) && val2 == `\]` {
+               attentionType := strings.ToLower(val1[3:])
+               if g.attentionTypes.Contains(attentionType) {
+                       return attentionType, []ast.Node{node1, node2}
+               }
+       }
+       return "", nil
+}
+
+func (g *ASTTransformer) extractBlockquoteAttention3(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
        if firstParagraph.ChildCount() < 3 {
-               return ast.WalkContinue, nil
+               return "", nil
        }
        node1, ok := firstParagraph.FirstChild().(*ast.Text)
        if !ok {
-               return ast.WalkContinue, nil
+               return "", nil
        }
        node2, ok := node1.NextSibling().(*ast.Text)
        if !ok {
-               return ast.WalkContinue, nil
+               return "", nil
        }
        node3, ok := node2.NextSibling().(*ast.Text)
        if !ok {
-               return ast.WalkContinue, nil
+               return "", nil
        }
        val1 := string(node1.Segment.Value(reader.Source()))
        val2 := string(node2.Segment.Value(reader.Source()))
        val3 := string(node3.Segment.Value(reader.Source()))
        if val1 != "[" || val3 != "]" || !strings.HasPrefix(val2, "!") {
-               return ast.WalkContinue, nil
+               return "", nil
        }
 
-       // grab attention type from markdown source
        attentionType := strings.ToLower(val2[1:])
-       if !g.attentionTypes.Contains(attentionType) {
+       if g.attentionTypes.Contains(attentionType) {
+               return attentionType, []ast.Node{node1, node2, node3}
+       }
+       return "", nil
+}
+
+func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Reader) (ast.WalkStatus, error) {
+       // We only want attention blockquotes when the AST looks like:
+       // > Text("[") Text("!TYPE") Text("]")
+       // > Text("\[!TYPE") TEXT("\]")
+       // > Text("**TYPE**")
+
+       // grab these nodes and make sure we adhere to the attention blockquote structure
+       firstParagraph := v.FirstChild()
+       g.applyElementDir(firstParagraph)
+
+       attentionType, processedNodes := g.extractBlockquoteAttentionEmphasis(firstParagraph, reader)
+       if attentionType == "" {
+               attentionType, processedNodes = g.extractBlockquoteAttention2(firstParagraph, reader)
+       }
+       if attentionType == "" {
+               attentionType, processedNodes = g.extractBlockquoteAttention3(firstParagraph, reader)
+       }
+       if attentionType == "" {
                return ast.WalkContinue, nil
        }
 
@@ -88,9 +143,9 @@ func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Read
        attentionParagraph.AppendChild(attentionParagraph, NewAttention(attentionType))
        attentionParagraph.AppendChild(attentionParagraph, emphasis)
        firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph)
-       firstParagraph.RemoveChild(firstParagraph, node1)
-       firstParagraph.RemoveChild(firstParagraph, node2)
-       firstParagraph.RemoveChild(firstParagraph, node3)
+       for _, processed := range processedNodes {
+               firstParagraph.RemoveChild(firstParagraph, processed)
+       }
        if firstParagraph.ChildCount() == 0 {
                firstParagraph.Parent().RemoveChild(firstParagraph.Parent(), firstParagraph)
        }