|
|
|
@ -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) |
|
|
|
|
} |
|
|
|
|