summaryrefslogtreecommitdiffstats
path: root/modules/markup/markdown/callout/github_legacy.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/markup/markdown/callout/github_legacy.go')
-rw-r--r--modules/markup/markdown/callout/github_legacy.go78
1 files changed, 78 insertions, 0 deletions
diff --git a/modules/markup/markdown/callout/github_legacy.go b/modules/markup/markdown/callout/github_legacy.go
new file mode 100644
index 0000000..96354b1
--- /dev/null
+++ b/modules/markup/markdown/callout/github_legacy.go
@@ -0,0 +1,78 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package callout
+
+import (
+ "strings"
+
+ "github.com/yuin/goldmark/ast"
+ "github.com/yuin/goldmark/parser"
+ "github.com/yuin/goldmark/text"
+)
+
+// Transformer for GitHub's legacy callout markup.
+type GitHubLegacyCalloutTransformer struct{}
+
+func (g *GitHubLegacyCalloutTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
+ supportedCalloutTypes := map[string]bool{"Note": true, "Warning": true}
+
+ _ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
+ if !entering {
+ return ast.WalkContinue, nil
+ }
+
+ if v, ok := n.(*ast.Blockquote); ok {
+ if v.ChildCount() == 0 {
+ return ast.WalkContinue, nil
+ }
+
+ // The first paragraph contains the callout type.
+ firstParagraph := v.FirstChild()
+ if firstParagraph.ChildCount() < 1 {
+ return ast.WalkContinue, nil
+ }
+
+ // In the legacy GitHub callout markup, the first node of the first
+ // paragraph should be an emphasis.
+ calloutNode, ok := firstParagraph.FirstChild().(*ast.Emphasis)
+ if !ok {
+ return ast.WalkContinue, nil
+ }
+ calloutText := string(calloutNode.Text(reader.Source()))
+ calloutType := strings.ToLower(calloutText)
+ // We only support "Note" and "Warning" callouts in legacy mode,
+ // match only those.
+ if _, has := supportedCalloutTypes[calloutText]; !has {
+ return ast.WalkContinue, nil
+ }
+
+ // Set the attention attribute on the emphasis
+ calloutNode.SetAttributeString("class", []byte("attention-"+calloutType))
+
+ // color the blockquote
+ v.SetAttributeString("class", []byte("attention-header attention-"+calloutType))
+
+ // Create new paragraph.
+ attentionParagraph := ast.NewParagraph()
+ attentionParagraph.SetAttributeString("class", []byte("attention-title"))
+
+ // Move the callout node to the paragraph and insert the paragraph.
+ attentionParagraph.AppendChild(attentionParagraph, NewAttention(calloutType))
+ attentionParagraph.AppendChild(attentionParagraph, calloutNode)
+ firstParagraph.Parent().InsertBefore(firstParagraph.Parent(), firstParagraph, attentionParagraph)
+ firstParagraph.RemoveChild(firstParagraph, calloutNode)
+
+ // Remove softbreak line if there's one.
+ if firstParagraph.ChildCount() >= 1 {
+ softBreakNode, ok := firstParagraph.FirstChild().(*ast.Text)
+ if ok && softBreakNode.SoftLineBreak() {
+ firstParagraph.RemoveChild(firstParagraph, softBreakNode)
+ }
+ }
+ }
+
+ return ast.WalkContinue, nil
+ })
+}