From 89d2d5e0319b2f09ccea83014be34c20fc2b01cd Mon Sep 17 00:00:00 2001 From: Thomas Miceli Date: Sun, 13 Oct 2024 20:32:43 +0200 Subject: [PATCH] Works for inline svg --- go.mod | 2 +- go.sum | 4 +- internal/render/checkbox.go | 65 +++++++++++++++++++++++++++++++++ internal/render/markdown.go | 62 +------------------------------ internal/render/svgtoimg.go | 73 +++++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 63 deletions(-) create mode 100644 internal/render/checkbox.go create mode 100644 internal/render/svgtoimg.go diff --git a/go.mod b/go.mod index 40ce77d7..e4505abf 100644 --- a/go.mod +++ b/go.mod @@ -97,7 +97,7 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.etcd.io/bbolt v1.3.10 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.23.0 // indirect diff --git a/go.sum b/go.sum index b8c707ac..32236c8b 100644 --- a/go.sum +++ b/go.sum @@ -232,8 +232,8 @@ golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= diff --git a/internal/render/checkbox.go b/internal/render/checkbox.go new file mode 100644 index 00000000..94e64dd0 --- /dev/null +++ b/internal/render/checkbox.go @@ -0,0 +1,65 @@ +package render + +import ( + "bufio" + "bytes" + "github.com/Kunde21/markdownfmt/v3" + "github.com/rs/zerolog/log" + "github.com/yuin/goldmark/ast" + astex "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/text" + "strconv" +) + +type checkboxTransformer struct{} + +func (t *checkboxTransformer) Transform(node *ast.Document, _ text.Reader, _ parser.Context) { + i := 1 + err := ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + if _, ok := n.(*astex.TaskCheckBox); ok { + listitem := n.Parent().Parent() + listitem.SetAttribute([]byte("data-checkbox-nb"), []byte(strconv.Itoa(i))) + i += 1 + } + } + return ast.WalkContinue, nil + }) + if err != nil { + log.Err(err) + } +} + +func Checkbox(content string, checkboxNb int) (string, error) { + buf := bytes.Buffer{} + w := bufio.NewWriter(&buf) + + source := []byte(content) + markdown := markdownfmt.NewGoldmark() + reader := text.NewReader(source) + document := markdown.Parser().Parse(reader) + + i := 1 + err := ast.Walk(document, func(n ast.Node, entering bool) (ast.WalkStatus, error) { + if entering { + if listItem, ok := n.(*astex.TaskCheckBox); ok { + if i == checkboxNb { + listItem.IsChecked = !listItem.IsChecked + } + i += 1 + } + } + return ast.WalkContinue, nil + }) + if err != nil { + return "", err + } + + if err = markdown.Renderer().Render(w, source, document); err != nil { + return "", err + } + _ = w.Flush() + + return buf.String(), nil +} diff --git a/internal/render/markdown.go b/internal/render/markdown.go index 8e821ac1..77fcbbea 100644 --- a/internal/render/markdown.go +++ b/internal/render/markdown.go @@ -1,24 +1,17 @@ package render import ( - "bufio" "bytes" - "github.com/Kunde21/markdownfmt/v3" "github.com/alecthomas/chroma/v2/formatters/html" - "github.com/rs/zerolog/log" "github.com/thomiceli/opengist/internal/db" "github.com/thomiceli/opengist/internal/git" "github.com/yuin/goldmark" emoji "github.com/yuin/goldmark-emoji" highlighting "github.com/yuin/goldmark-highlighting/v2" - "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/extension" - astex "github.com/yuin/goldmark/extension/ast" "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" "go.abhg.dev/goldmark/mermaid" - "strconv" ) func MarkdownGistPreview(gist *db.Gist) (RenderedGist, error) { @@ -57,63 +50,12 @@ func newMarkdown() goldmark.Markdown { highlighting.WithFormatOptions(html.WithClasses(true))), emoji.Emoji, &mermaid.Extender{}, + &svgToImg{}, ), goldmark.WithParserOptions( parser.WithASTTransformers( - util.Prioritized(&CheckboxTransformer{}, 10000), + util.Prioritized(&checkboxTransformer{}, 10000), ), ), ) } - -type CheckboxTransformer struct{} - -func (t *CheckboxTransformer) Transform(node *ast.Document, _ text.Reader, _ parser.Context) { - i := 1 - err := ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { - if entering { - if _, ok := n.(*astex.TaskCheckBox); ok { - listitem := n.Parent().Parent() - listitem.SetAttribute([]byte("data-checkbox-nb"), []byte(strconv.Itoa(i))) - i += 1 - } - } - return ast.WalkContinue, nil - }) - if err != nil { - log.Err(err) - } -} - -func Checkbox(content string, checkboxNb int) (string, error) { - buf := bytes.Buffer{} - w := bufio.NewWriter(&buf) - - source := []byte(content) - markdown := markdownfmt.NewGoldmark() - reader := text.NewReader(source) - document := markdown.Parser().Parse(reader) - - i := 1 - err := ast.Walk(document, func(n ast.Node, entering bool) (ast.WalkStatus, error) { - if entering { - if listItem, ok := n.(*astex.TaskCheckBox); ok { - if i == checkboxNb { - listItem.IsChecked = !listItem.IsChecked - } - i += 1 - } - } - return ast.WalkContinue, nil - }) - if err != nil { - return "", err - } - - if err = markdown.Renderer().Render(w, source, document); err != nil { - return "", err - } - _ = w.Flush() - - return buf.String(), nil -} diff --git a/internal/render/svgtoimg.go b/internal/render/svgtoimg.go new file mode 100644 index 00000000..5f2d2228 --- /dev/null +++ b/internal/render/svgtoimg.go @@ -0,0 +1,73 @@ +package render + +import ( + "bytes" + "encoding/base64" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/text" + "github.com/yuin/goldmark/util" +) + +type svgToImg struct{} + +func (e *svgToImg) Extend(m goldmark.Markdown) { + m.Parser().AddOptions(parser.WithInlineParsers( + util.Prioritized(newInlineSvgParser(), 1), + )) + m.Renderer().AddOptions(renderer.WithNodeRenderers( + util.Prioritized(newInlineSvgRenderer(), 1), + )) +} + +type inlineSvgParser struct{} + +func newInlineSvgParser() parser.InlineParser { + return &inlineSvgParser{} +} + +func (p *inlineSvgParser) Trigger() []byte { + return []byte{'<'} +} + +func (p *inlineSvgParser) Parse(_ ast.Node, block text.Reader, pc parser.Context) ast.Node { + line, _ := block.PeekLine() + if bytes.HasPrefix(line, []byte("` + _, _ = w.Write([]byte(imgTag)) + return ast.WalkContinue, nil +}