aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2024-06-04 23:35:29 +0800
committerGitHub <noreply@github.com>2024-06-04 15:35:29 +0000
commitbd80225ec3688cfa89767cc352835d8d5093f764 (patch)
treeca5622482acb9b59c1c453d09feee0b981d0d034
parentfcc061ae4435f251d14a6750a0f5713800dca637 (diff)
downloadgitea-bd80225ec3688cfa89767cc352835d8d5093f764.tar.gz
gitea-bd80225ec3688cfa89767cc352835d8d5093f764.zip
Make blockquote attention recognize more syntaxes (#31240)
Fix #31214
-rw-r--r--modules/markup/markdown/markdown_test.go6
-rw-r--r--modules/markup/markdown/math/block_parser.go10
-rw-r--r--modules/markup/markdown/transform_blockquote.go89
3 files changed, 86 insertions, 19 deletions
diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go
index b4a7efa8dd..8c41ec12e3 100644
--- a/modules/markup/markdown/markdown_test.go
+++ b/modules/markup/markdown/markdown_test.go
@@ -1019,4 +1019,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>")
}
diff --git a/modules/markup/markdown/math/block_parser.go b/modules/markup/markdown/math/block_parser.go
index 7f714d7239..37f6caf11c 100644
--- a/modules/markup/markdown/math/block_parser.go
+++ b/modules/markup/markdown/math/block_parser.go
@@ -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
}
diff --git a/modules/markup/markdown/transform_blockquote.go b/modules/markup/markdown/transform_blockquote.go
index 933f0e5c59..d2dc025052 100644
--- a/modules/markup/markdown/transform_blockquote.go
+++ b/modules/markup/markdown/transform_blockquote.go
@@ -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)
}