From 7478c230c7cd3e7328803d89abe591d0b61c41e4 Mon Sep 17 00:00:00 2001 From: Alex Schroeder Date: Sat, 16 Sep 2023 14:31:14 +0200 Subject: [PATCH] Add parser.RegisterInline example --- examples/inline.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 examples/inline.go diff --git a/examples/inline.go b/examples/inline.go new file mode 100644 index 0000000..4c570bd --- /dev/null +++ b/examples/inline.go @@ -0,0 +1,83 @@ +package main + +// example for https://blog.kowalczyk.info/article/cxn3/advanced-markdown-processing-in-go.html + +import ( + "fmt" + + "github.com/gomarkdown/markdown" + "github.com/gomarkdown/markdown/ast" + "github.com/gomarkdown/markdown/parser" + + "bytes" + "net/url" +) + +// mds shows the two extensions provided in this example. The tricky +// part about the wiki link example is that we need to defer to the +// original code in the library if the opening square bracket we're +// looking at is not a wiki link. +var mds = `This is a [[wiki link]]. + +#markdown #example` + +// wikiLink returns an inline parser function. This indirection is +// required because we want to call the previous definition in case +// this is not a wikiLink. +func wikiLink(p *parser.Parser, fn func(p *parser.Parser, data []byte, offset int) (int, ast.Node)) func(p *parser.Parser, data []byte, offset int) (int, ast.Node) { + return func (p *parser.Parser, original []byte, offset int) (int, ast.Node) { + data := original[offset:] + n := len(data) + // minimum: [[X]] + if n < 5 || data[1] != '[' { + return fn(p, original, offset) + } + i := 2 + for i+1 < n && data[i] != ']' && data[i+1] != ']' { + i++ + } + text := data[2:i+1] + link := &ast.Link{ + Destination: []byte(url.PathEscape(string(text))), + } + ast.AppendChild(link, &ast.Text{Leaf: ast.Leaf{Literal: text}}) + return i+3, link + } +} + +// hashtag links every hashtag to a search for that tag. How this +// search is then handled is of course a different problem. For your +// own code, you probably need to use a different destination URL. +func hashtag(p *parser.Parser, data []byte, offset int) (int, ast.Node) { + data = data[offset:] + i := 0 + n := len(data) + for i < n && !parser.IsSpace(data[i]) { + i++ + } + if i == 0 { + return 0, nil + } + link := &ast.Link{ + Destination: append([]byte("/search?q=%23"), data[1:i]...), + } + text := bytes.ReplaceAll(data[0:i], []byte("_"), []byte(" ")) + ast.AppendChild(link, &ast.Text{Leaf: ast.Leaf{Literal: text}}) + return i, link +} + +func inlineExample() { + md := []byte(mds) + + parser := parser.New() + prev := parser.RegisterInline('[', nil) + parser.RegisterInline('[', wikiLink(parser, prev)) + parser.RegisterInline('#', hashtag) + html := markdown.ToHTML(md, parser, nil) + + fmt.Printf("--- Markdown:\n%s\n\n--- HTML:\n%s\n", md, html) +} + +func main() { + inlineExample() +}