mirror of https://github.com/go-gitea/gitea.git
parent
fcc061ae44
commit
bd80225ec3
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue