···
"github.com/microcosm-cc/bluemonday"
"github.com/yuin/goldmark"
···
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
+
htmlparse "golang.org/x/net/html"
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
···
if err := md.Convert([]byte(source), &buf); err != nil {
+
var processed strings.Builder
+
if err := postProcess(rctx, strings.NewReader(buf.String()), &processed); err != nil {
+
return processed.String()
+
func postProcess(ctx *RenderContext, input io.Reader, output io.Writer) error {
+
node, err := htmlparse.Parse(io.MultiReader(
+
strings.NewReader("<html><body>"),
+
strings.NewReader("</body></html>"),
+
return fmt.Errorf("failed to parse html: %w", err)
+
if node.Type == htmlparse.DocumentNode {
+
newNodes := make([]*htmlparse.Node, 0, 5)
+
if node.Data == "html" {
+
for node != nil && node.Data != "body" {
+
node = node.NextSibling
+
if node.Data == "body" {
+
child := node.FirstChild
+
newNodes = append(newNodes, child)
+
child = child.NextSibling
+
newNodes = append(newNodes, node)
+
for _, node := range newNodes {
+
if err := htmlparse.Render(output, node); err != nil {
+
return fmt.Errorf("failed to render processed html: %w", err)
+
func visitNode(ctx *RenderContext, node *htmlparse.Node) {
+
case htmlparse.ElementNode:
+
if node.Data == "img" {
+
for i, attr := range node.Attr {
+
attr.Val = ctx.imageFromKnotTransformer(attr.Val)
+
attr.Val = ctx.camoImageLinkTransformer(attr.Val)
+
for n := node.FirstChild; n != nil; n = n.NextSibling {
func (rctx *RenderContext) Sanitize(html string) string {
···
a.rctx.relativeLinkTransformer(n)
+
a.rctx.imageFromKnotAstTransformer(n)
+
a.rctx.camoImageLinkAstTransformer(n)
case RendererTypeDefault:
+
a.rctx.imageFromKnotAstTransformer(n)
+
a.rctx.camoImageLinkAstTransformer(n)
···
link.Destination = []byte(newPath)
+
func (rctx *RenderContext) imageFromKnotTransformer(dst string) string {
···
newPath := parsedURL.String()
+
func (rctx *RenderContext) imageFromKnotAstTransformer(img *ast.Image) {
+
dst := string(img.Destination)
+
img.Destination = []byte(rctx.imageFromKnotTransformer(dst))
// actualPath decides when to join the file path with the