mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	@@ -1019,4 +1019,10 @@ func TestAttention(t *testing.T) {
 | 
				
			|||||||
	test(`> [!important]`, renderAttention("important", "octicon-report")+"\n</blockquote>")
 | 
						test(`> [!important]`, renderAttention("important", "octicon-report")+"\n</blockquote>")
 | 
				
			||||||
	test(`> [!warning]`, renderAttention("warning", "octicon-alert")+"\n</blockquote>")
 | 
						test(`> [!warning]`, renderAttention("warning", "octicon-alert")+"\n</blockquote>")
 | 
				
			||||||
	test(`> [!caution]`, renderAttention("caution", "octicon-stop")+"\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>")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,10 +31,16 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex
 | 
				
			|||||||
		return nil, parser.NoChildren
 | 
							return nil, parser.NoChildren
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dollars := false
 | 
						var dollars bool
 | 
				
			||||||
	if b.parseDollars && line[pos] == '$' && line[pos+1] == '$' {
 | 
						if b.parseDollars && line[pos] == '$' && line[pos+1] == '$' {
 | 
				
			||||||
		dollars = true
 | 
							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
 | 
							return nil, parser.NoChildren
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ import (
 | 
				
			|||||||
	"golang.org/x/text/language"
 | 
						"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) {
 | 
					func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
 | 
				
			||||||
	if entering {
 | 
						if entering {
 | 
				
			||||||
		n := node.(*Attention)
 | 
							n := node.(*Attention)
 | 
				
			||||||
@@ -37,38 +37,93 @@ func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast
 | 
				
			|||||||
	return ast.WalkContinue, nil
 | 
						return ast.WalkContinue, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (g *ASTTransformer) transformBlockquote(v *ast.Blockquote, reader text.Reader) (ast.WalkStatus, error) {
 | 
					func (g *ASTTransformer) extractBlockquoteAttentionEmphasis(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
 | 
				
			||||||
	// We only want attention blockquotes when the AST looks like:
 | 
						if firstParagraph.ChildCount() < 1 {
 | 
				
			||||||
	// > Text("[") Text("!TYPE") Text("]")
 | 
							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
 | 
					func (g *ASTTransformer) extractBlockquoteAttention2(firstParagraph ast.Node, reader text.Reader) (string, []ast.Node) {
 | 
				
			||||||
	firstParagraph := v.FirstChild()
 | 
						if firstParagraph.ChildCount() < 2 {
 | 
				
			||||||
	g.applyElementDir(firstParagraph)
 | 
							return "", nil
 | 
				
			||||||
	if firstParagraph.ChildCount() < 3 {
 | 
					 | 
				
			||||||
		return ast.WalkContinue, nil
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	node1, ok := firstParagraph.FirstChild().(*ast.Text)
 | 
						node1, ok := firstParagraph.FirstChild().(*ast.Text)
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		return ast.WalkContinue, nil
 | 
							return "", nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	node2, ok := node1.NextSibling().(*ast.Text)
 | 
						node2, ok := node1.NextSibling().(*ast.Text)
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		return ast.WalkContinue, nil
 | 
							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 "", nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						node1, ok := firstParagraph.FirstChild().(*ast.Text)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return "", nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						node2, ok := node1.NextSibling().(*ast.Text)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return "", nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	node3, ok := node2.NextSibling().(*ast.Text)
 | 
						node3, ok := node2.NextSibling().(*ast.Text)
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		return ast.WalkContinue, nil
 | 
							return "", nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	val1 := string(node1.Segment.Value(reader.Source()))
 | 
						val1 := string(node1.Segment.Value(reader.Source()))
 | 
				
			||||||
	val2 := string(node2.Segment.Value(reader.Source()))
 | 
						val2 := string(node2.Segment.Value(reader.Source()))
 | 
				
			||||||
	val3 := string(node3.Segment.Value(reader.Source()))
 | 
						val3 := string(node3.Segment.Value(reader.Source()))
 | 
				
			||||||
	if val1 != "[" || val3 != "]" || !strings.HasPrefix(val2, "!") {
 | 
						if val1 != "[" || val3 != "]" || !strings.HasPrefix(val2, "!") {
 | 
				
			||||||
		return ast.WalkContinue, nil
 | 
							return "", nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// grab attention type from markdown source
 | 
					 | 
				
			||||||
	attentionType := strings.ToLower(val2[1:])
 | 
						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
 | 
							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, NewAttention(attentionType))
 | 
				
			||||||
	attentionParagraph.AppendChild(attentionParagraph, emphasis)
 | 
						attentionParagraph.AppendChild(attentionParagraph, emphasis)
 | 
				
			||||||
	firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph)
 | 
						firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph)
 | 
				
			||||||
	firstParagraph.RemoveChild(firstParagraph, node1)
 | 
						for _, processed := range processedNodes {
 | 
				
			||||||
	firstParagraph.RemoveChild(firstParagraph, node2)
 | 
							firstParagraph.RemoveChild(firstParagraph, processed)
 | 
				
			||||||
	firstParagraph.RemoveChild(firstParagraph, node3)
 | 
						}
 | 
				
			||||||
	if firstParagraph.ChildCount() == 0 {
 | 
						if firstParagraph.ChildCount() == 0 {
 | 
				
			||||||
		firstParagraph.Parent().RemoveChild(firstParagraph.Parent(), firstParagraph)
 | 
							firstParagraph.Parent().RemoveChild(firstParagraph.Parent(), firstParagraph)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user