diff --git a/appview/pages/funcmap.go b/appview/pages/funcmap.go index 4997d0bb..58f2560c 100644 --- a/appview/pages/funcmap.go +++ b/appview/pages/funcmap.go @@ -29,6 +29,8 @@ import ( "github.com/go-enry/go-enry/v2" "github.com/yuin/goldmark" emoji "github.com/yuin/goldmark-emoji" + htmlparse "golang.org/x/net/html" + "golang.org/x/net/html/atom" "tangled.org/core/appview/cache" "tangled.org/core/appview/db" "tangled.org/core/appview/models" @@ -305,13 +307,6 @@ func (p *Pages) funcMap() template.FuncMap { } return v.Slice(0, min(n, v.Len())).Interface() }, - "markdown": func(text string) template.HTML { - rctx := p.rctx.Clone() - rctx.RendererType = markup.RendererTypeDefault - htmlString := rctx.RenderMarkdown(text) - sanitized := rctx.SanitizeDefault(htmlString) - return template.HTML(sanitized) - }, "markdownSegments": func(text string) []MarkdownSegment { rctx := p.rctx.Clone() rctx.RendererType = markup.RendererTypeDefault @@ -638,71 +633,59 @@ func (p *Pages) AvatarUrl(actor, size string) string { return baseUrl } -func splitCodeBlockSegments(html string) []MarkdownSegment { - var segments []MarkdownSegment - remaining := html - closeTag := `` - - for { - idx := strings.Index(remaining, `
`)
- if openEnd == -1 {
- remaining = remaining[idx:]
- continue
- }
- openEnd += idx
- openTag := remaining[idx : openEnd+1]
+func splitCodeBlockSegments(rawHTML string) []MarkdownSegment {
+ nodes, err := htmlparse.ParseFragment(strings.NewReader(rawHTML), &htmlparse.Node{
+ Type: htmlparse.ElementNode,
+ Data: "body",
+ DataAtom: atom.Body,
+ })
+ if err != nil {
+ return []MarkdownSegment{{HTML: template.HTML(rawHTML)}}
+ }
- if strings.Contains(openTag, `mermaid`) {
- closeIdx := strings.Index(remaining[openEnd+1:], closeTag)
- if closeIdx == -1 {
- remaining = remaining[idx:]
- continue
+ var segments []MarkdownSegment
+ var buf strings.Builder
+ for _, n := range nodes {
+ if n.Type == htmlparse.ElementNode && n.Data == "pre" {
+ if buf.Len() > 0 {
+ segments = append(segments, MarkdownSegment{HTML: template.HTML(buf.String())})
+ buf.Reset()
+ }
+ _ = htmlparse.Render(&buf, n)
+ isMermaid := false
+ for _, attr := range n.Attr {
+ if attr.Key == "class" && strings.Contains(attr.Val, "mermaid") {
+ isMermaid = true
+ break
+ }
}
- closeIdx += openEnd + 1
-
- if idx > 0 {
- segments = append(segments, MarkdownSegment{HTML: template.HTML(remaining[:idx])})
+ seg := MarkdownSegment{HTML: template.HTML(buf.String())}
+ if !isMermaid {
+ seg.IsCode = true
+ seg.Lines = countTextNewlines(n)
}
-
- preEnd := closeIdx + len(closeTag)
- preHTML := remaining[idx:preEnd]
- segments = append(segments, MarkdownSegment{
- HTML: template.HTML(preHTML),
- })
- remaining = remaining[preEnd:]
- continue
- }
-
- closeIdx := strings.Index(remaining[openEnd+1:], closeTag)
- if closeIdx == -1 {
- remaining = remaining[idx:]
- continue
+ segments = append(segments, seg)
+ buf.Reset()
+ } else {
+ _ = htmlparse.Render(&buf, n)
}
- closeIdx += openEnd + 1
+ }
+ if buf.Len() > 0 {
+ segments = append(segments, MarkdownSegment{HTML: template.HTML(buf.String())})
+ }
+ return segments
+}
- if idx > 0 {
- segments = append(segments, MarkdownSegment{HTML: template.HTML(remaining[:idx])})
+func countTextNewlines(n *htmlparse.Node) int {
+ count := 0
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if c.Type == htmlparse.TextNode {
+ count += strings.Count(c.Data, "\n")
+ } else {
+ count += countTextNewlines(c)
}
-
- preEnd := closeIdx + len(closeTag)
- preHTML := remaining[idx:preEnd]
- content := remaining[openEnd+1 : closeIdx]
- lines := strings.Count(content, "\n") + 1
- segments = append(segments, MarkdownSegment{
- HTML: template.HTML(preHTML),
- IsCode: true,
- Lines: lines,
- })
- remaining = remaining[preEnd:]
}
- return segments
+ return count
}
func (p *Pages) icon(name string, classes []string) (template.HTML, error) {