From a4681f9565b77df04bc4cb3779552e7db0ac8a09 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 17 Aug 2023 15:24:43 +0200 Subject: [PATCH] Initial commit --- LICENSE | 21 +++++++++++++++++++++ README.md | 22 ++++++++++++++++++++++ ast.go | 22 ++++++++++++++++++++++ extend.go | 34 ++++++++++++++++++++++++++++++++++ extend_test.go | 22 ++++++++++++++++++++++ go.mod | 5 +++++ go.sum | 2 ++ parser.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ render.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 218 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 ast.go create mode 100644 extend.go create mode 100644 extend_test.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 parser.go create mode 100644 render.go diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d17bda6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Pierre-Olivier Mercier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4e5a64 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# goldmark-superscript + +[GoldMark](https://github.com/yuin/goldmark/) superscript extension. + +This implements the [`superscript`](https://pandoc.org/MANUAL.html#extension-bracketed_spans) of pandoc. + +```markdown +H~2~O is a liquid. 2^10^ is 1024. +``` + +```html +

H~2~O is a liquid. 210 is 1024.

+``` + +```go +var md = goldmark.New(superscript.Enable) +var source = []byte("H~2~O is a liquid. 2^10^ is 1024.") +err := md.Convert(source, os.Stdout) +if err != nil { + log.Fatal(err) +} +``` diff --git a/ast.go b/ast.go new file mode 100644 index 0000000..76fcdde --- /dev/null +++ b/ast.go @@ -0,0 +1,22 @@ +package superscript + +import ( + "fmt" + "strings" + + "github.com/yuin/goldmark/ast" +) + +// Kind is the kind of hashtag AST nodes. +var Kind = ast.NewNodeKind("Superscript") + +// Node is a parsed Superscript node. +type Node struct { + ast.BaseInline +} + +func (*Node) Kind() ast.NodeKind { return Kind } + +func (n *Node) Dump(src []byte, level int) { + fmt.Printf("%ssuperscript: \"%s\"\n", strings.Repeat(" ", level), n.Text(src)) +} diff --git a/extend.go b/extend.go new file mode 100644 index 0000000..21bdfdf --- /dev/null +++ b/extend.go @@ -0,0 +1,34 @@ +package superscript + +import ( + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/util" +) + +type Extender struct{} + +var ( + defaultParser = new(superscriptParser) + defaultRenderer = new(superscriptRenderer) +) + +func (e *Extender) Extend(m goldmark.Markdown) { + m.Parser().AddOptions( + parser.WithInlineParsers( + util.Prioritized(defaultParser, 100), + ), + ) + m.Renderer().AddOptions( + renderer.WithNodeRenderers( + util.Prioritized(defaultRenderer, 100), + ), + ) +} + +// Extension is a goldmark.Extender with markdown inline attributes support. +var Extension goldmark.Extender = new(Extender) + +// Enable is a goldmark.Option with inline attributes support. +var Enable = goldmark.WithExtensions(Extension) diff --git a/extend_test.go b/extend_test.go new file mode 100644 index 0000000..69ec925 --- /dev/null +++ b/extend_test.go @@ -0,0 +1,22 @@ +package superscript + +import ( + "log" + "os" + "testing" + + "github.com/yuin/goldmark" +) + +func TestAttributes(t *testing.T) { + source := []byte(` +H~2~O is a liquid. 2^10^ is 1024. +`) + + var md = goldmark.New(Enable) + err := md.Convert(source, os.Stdout) + if err != nil { + log.Fatal(err) + } + +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e343e9e --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/nemunaire/goldmark-superscript + +go 1.18 + +require github.com/yuin/goldmark v1.5.6 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3a4e29a --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/yuin/goldmark v1.5.6 h1:COmQAWTCcGetChm3Ig7G/t8AFAN00t+o8Mt4cf7JpwA= +github.com/yuin/goldmark v1.5.6/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/parser.go b/parser.go new file mode 100644 index 0000000..b6843d8 --- /dev/null +++ b/parser.go @@ -0,0 +1,46 @@ +package superscript + +import ( + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/parser" + "github.com/yuin/goldmark/text" +) + +type superscriptDelimiterProcessor struct { +} + +func (p *superscriptDelimiterProcessor) IsDelimiter(b byte) bool { + return b == '^' +} + +func (p *superscriptDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool { + return opener.Char == closer.Char +} + +func (p *superscriptDelimiterProcessor) OnMatch(consumes int) ast.Node { + return &Node{} +} + +var defaultEmphasisDelimiterProcessor = &superscriptDelimiterProcessor{} + +type superscriptParser struct { +} + +var defaultSuperscriptParser = &superscriptParser{} + +func (s *superscriptParser) Trigger() []byte { + return []byte{'^'} +} + +func (s *superscriptParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node { + before := block.PrecendingCharacter() + line, segment := block.PeekLine() + node := parser.ScanDelimiter(line, before, 1, defaultEmphasisDelimiterProcessor) + if node == nil { + return nil + } + node.Segment = segment.WithStop(segment.Start + node.OriginalLength) + block.Advance(node.OriginalLength) + pc.PushDelimiter(node) + return node +} diff --git a/render.go b/render.go new file mode 100644 index 0000000..ab812b4 --- /dev/null +++ b/render.go @@ -0,0 +1,44 @@ +package superscript + +import ( + "fmt" + + "github.com/yuin/goldmark/ast" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/renderer/html" + "github.com/yuin/goldmark/util" +) + +type superscriptRenderer struct{} + +func (r *superscriptRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + reg.Register(Kind, r.Render) +} + +func (r *superscriptRenderer) Render(w util.BufWriter, _ []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n, ok := node.(*Node) + if !ok { + return ast.WalkStop, fmt.Errorf("unexpected node %T, expected *Node", node) + } + + if entering { + if err := r.enter(w, n); err != nil { + return ast.WalkStop, err + } + } else { + r.exit(w, n) + } + + return ast.WalkContinue, nil +} + +func (r *superscriptRenderer) enter(w util.BufWriter, n *Node) error { + w.WriteString(``) + return nil +} + +func (r *superscriptRenderer) exit(w util.BufWriter, n *Node) { + w.WriteString("") +}