From cdb0a541554aa4a16fc71b6425225e8c603c83b8 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Thu, 2 Oct 2025 12:03:06 +0200 Subject: feat(markdown): support external link and image (without source) --- mardown/ast_external.go | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 mardown/ast_external.go (limited to 'mardown/ast_external.go') diff --git a/mardown/ast_external.go b/mardown/ast_external.go new file mode 100644 index 0000000..87fb880 --- /dev/null +++ b/mardown/ast_external.go @@ -0,0 +1,141 @@ +package mardown + +import ( + "fmt" + "html/template" +) + +type astLink struct { + content block + href block +} + +func (a *astLink) Eval() (template.HTML, error) { + content, err := a.content.Eval() + if err != nil { + return "", err + } + href, err := a.href.Eval() + if err != nil { + return "", err + } + return template.HTML(fmt.Sprintf(`%s`, href, content)), nil +} + +type astImage struct { + alt block + src block + source *astParagraph +} + +func (a *astImage) Eval() (template.HTML, error) { + alt, err := a.alt.Eval() + if err != nil { + return "", err + } + src, err := a.src.Eval() + if err != nil { + return "", err + } + if a.source == nil { + return template.HTML(fmt.Sprintf(`
%s
`, alt, src)), nil + } + source, err := a.source.Eval() + if err != nil { + return "", err + } + return template.HTML(fmt.Sprintf(`
%s
%s
`, alt, src, source)), nil +} + +func external(lxs *lexers) (block, error) { + tp := lxs.Current().Value + if !lxs.Next() { + return astLiteral(tp), nil + } + lxs.Before() // because we call Next + var b block + var err error + switch tp { + case "![": + b, err = image(lxs) + case "[": + b, err = link(lxs) + default: + b = astLiteral(tp) + } + return b, err +} + +func link(lxs *lexers) (block, error) { + lk := new(astLink) + start := lxs.current + content, href, _, ok := parseExternal(lxs, 1) + if !ok { + return reset(lxs, start), nil + } + lk.content = astLiteral(content) + lk.href = astLiteral(href) + return lk, nil +} + +func image(lxs *lexers) (block, error) { + img := new(astImage) + start := lxs.current + alt, src, _, ok := parseExternal(lxs, 2) + if !ok { + return reset(lxs, start), nil + } + img.alt = astLiteral(alt) + img.src = astLiteral(src) + //img.source = astLiteral(source) + return img, nil +} + +func parseExternal(lxs *lexers, maxBreak int) (string, string, string, bool) { + next := false + var s string + var first string + var end string + n := 0 + for lxs.Next() && n < maxBreak { + switch lxs.Current().Type { + case lexerBreak: + n++ + case lexerExternal: + if n > 0 && (first == "" || end == "") { + return "", "", "", false + } + n = 0 + if !next { + if lxs.Current().Value != "](" || !lxs.Next() { + return "", "", "", false + } + lxs.Before() // because we called Next + first = s + s = "" + next = true + } else { + if lxs.Current().Value != ")" { + return "", "", "", false + } + if maxBreak == 1 { + return first, s, "", true + } + end = s + s = "" + } + default: + n = 0 + s += lxs.Current().Value + } + } + if maxBreak == 1 { + return "", "", "", false + } + return first, end, s, true +} + +func reset(lxs *lexers, start int) block { + lxs.current = start + return astLiteral(lxs.Current().Value) +} -- cgit v1.2.3