Skip to content

Commit 1c1c2d3

Browse files
GiteaBotwxiaoguang
andauthored
Make blockquote attention recognize more syntaxes (#31240) (#31250)
Backport #31240 by wxiaoguang Fix #31214 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
1 parent 082600a commit 1c1c2d3

File tree

3 files changed

+86
-19
lines changed

3 files changed

+86
-19
lines changed

modules/markup/markdown/markdown_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -1010,4 +1010,10 @@ func TestAttention(t *testing.T) {
10101010
test(`> [!important]`, renderAttention("important", "octicon-report")+"\n</blockquote>")
10111011
test(`> [!warning]`, renderAttention("warning", "octicon-alert")+"\n</blockquote>")
10121012
test(`> [!caution]`, renderAttention("caution", "octicon-stop")+"\n</blockquote>")
1013+
1014+
// escaped by mdformat
1015+
test(`> \[!NOTE\]`, renderAttention("note", "octicon-info")+"\n</blockquote>")
1016+
1017+
// legacy GitHub style
1018+
test(`> **warning**`, renderAttention("warning", "octicon-alert")+"\n</blockquote>")
10131019
}

modules/markup/markdown/math/block_parser.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,16 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
3131
return nil, parser.NoChildren
3232
}
3333

34-
dollars := false
34+
var dollars bool
3535
if b.parseDollars && line[pos] == '$' && line[pos+1] == '$' {
3636
dollars = true
37-
} else if line[pos] != '\\' || line[pos+1] != '[' {
37+
} else if line[pos] == '\\' && line[pos+1] == '[' {
38+
if len(line[pos:]) >= 3 && line[pos+2] == '!' && bytes.Contains(line[pos:], []byte(`\]`)) {
39+
// do not process escaped attention block: "> \[!NOTE\]"
40+
return nil, parser.NoChildren
41+
}
42+
dollars = false
43+
} else {
3844
return nil, parser.NoChildren
3945
}
4046

modules/markup/markdown/transform_blockquote.go

+72-17
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
"golang.org/x/text/language"
1616
)
1717

18-
// renderAttention renders a quote marked with i.e. "> **Note**" or "> **Warning**" with a corresponding svg
18+
// renderAttention renders a quote marked with i.e. "> **Note**" or "> [!Warning]" with a corresponding svg
1919
func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
2020
if entering {
2121
n := node.(*Attention)
@@ -37,38 +37,93 @@ func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast
3737
return ast.WalkContinue, nil
3838
}
3939

40-
func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Reader) (ast.WalkStatus, error) {
41-
// We only want attention blockquotes when the AST looks like:
42-
// > Text("[") Text("!TYPE") Text("]")
40+
func (g *ASTTransformer) extractBlockquoteAttentionEmphasis(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
41+
if firstParagraph.ChildCount() < 1 {
42+
return "", nil
43+
}
44+
node1, ok := firstParagraph.FirstChild().(*ast.Emphasis)
45+
if !ok {
46+
return "", nil
47+
}
48+
val1 := string(node1.Text(reader.Source()))
49+
attentionType := strings.ToLower(val1)
50+
if g.attentionTypes.Contains(attentionType) {
51+
return attentionType, []ast.Node{node1}
52+
}
53+
return "", nil
54+
}
4355

44-
// grab these nodes and make sure we adhere to the attention blockquote structure
45-
firstParagraph := v.FirstChild()
46-
g.applyElementDir(firstParagraph)
56+
func (g *ASTTransformer) extractBlockquoteAttention2(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
57+
if firstParagraph.ChildCount() < 2 {
58+
return "", nil
59+
}
60+
node1, ok := firstParagraph.FirstChild().(*ast.Text)
61+
if !ok {
62+
return "", nil
63+
}
64+
node2, ok := node1.NextSibling().(*ast.Text)
65+
if !ok {
66+
return "", nil
67+
}
68+
val1 := string(node1.Segment.Value(reader.Source()))
69+
val2 := string(node2.Segment.Value(reader.Source()))
70+
if strings.HasPrefix(val1, `\[!`) && val2 == `\]` {
71+
attentionType := strings.ToLower(val1[3:])
72+
if g.attentionTypes.Contains(attentionType) {
73+
return attentionType, []ast.Node{node1, node2}
74+
}
75+
}
76+
return "", nil
77+
}
78+
79+
func (g *ASTTransformer) extractBlockquoteAttention3(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
4780
if firstParagraph.ChildCount() < 3 {
48-
return ast.WalkContinue, nil
81+
return "", nil
4982
}
5083
node1, ok := firstParagraph.FirstChild().(*ast.Text)
5184
if !ok {
52-
return ast.WalkContinue, nil
85+
return "", nil
5386
}
5487
node2, ok := node1.NextSibling().(*ast.Text)
5588
if !ok {
56-
return ast.WalkContinue, nil
89+
return "", nil
5790
}
5891
node3, ok := node2.NextSibling().(*ast.Text)
5992
if !ok {
60-
return ast.WalkContinue, nil
93+
return "", nil
6194
}
6295
val1 := string(node1.Segment.Value(reader.Source()))
6396
val2 := string(node2.Segment.Value(reader.Source()))
6497
val3 := string(node3.Segment.Value(reader.Source()))
6598
if val1 != "[" || val3 != "]" || !strings.HasPrefix(val2, "!") {
66-
return ast.WalkContinue, nil
99+
return "", nil
67100
}
68101

69-
// grab attention type from markdown source
70102
attentionType := strings.ToLower(val2[1:])
71-
if !g.attentionTypes.Contains(attentionType) {
103+
if g.attentionTypes.Contains(attentionType) {
104+
return attentionType, []ast.Node{node1, node2, node3}
105+
}
106+
return "", nil
107+
}
108+
109+
func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Reader) (ast.WalkStatus, error) {
110+
// We only want attention blockquotes when the AST looks like:
111+
// > Text("[") Text("!TYPE") Text("]")
112+
// > Text("\[!TYPE") TEXT("\]")
113+
// > Text("**TYPE**")
114+
115+
// grab these nodes and make sure we adhere to the attention blockquote structure
116+
firstParagraph := v.FirstChild()
117+
g.applyElementDir(firstParagraph)
118+
119+
attentionType, processedNodes := g.extractBlockquoteAttentionEmphasis(firstParagraph, reader)
120+
if attentionType == "" {
121+
attentionType, processedNodes = g.extractBlockquoteAttention2(firstParagraph, reader)
122+
}
123+
if attentionType == "" {
124+
attentionType, processedNodes = g.extractBlockquoteAttention3(firstParagraph, reader)
125+
}
126+
if attentionType == "" {
72127
return ast.WalkContinue, nil
73128
}
74129

@@ -88,9 +143,9 @@ func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Read
88143
attentionParagraph.AppendChild(attentionParagraph, NewAttention(attentionType))
89144
attentionParagraph.AppendChild(attentionParagraph, emphasis)
90145
firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph)
91-
firstParagraph.RemoveChild(firstParagraph, node1)
92-
firstParagraph.RemoveChild(firstParagraph, node2)
93-
firstParagraph.RemoveChild(firstParagraph, node3)
146+
for _, processed := range processedNodes {
147+
firstParagraph.RemoveChild(firstParagraph, processed)
148+
}
94149
if firstParagraph.ChildCount() == 0 {
95150
firstParagraph.Parent().RemoveChild(firstParagraph.Parent(), firstParagraph)
96151
}

0 commit comments

Comments
 (0)