diff --git a/cmd/goldmark/main.go b/cmd/goldmark/main.go new file mode 100644 index 0000000..e62b17a --- /dev/null +++ b/cmd/goldmark/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "bytes" + // "fmt" + + ofm "code.ndumas.com/ndumas/obsidian-markdown/goldmark" + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/parser" +) + +func main() { + m := goldmark.New(goldmark.WithExtensions( + ofm.ObsidianLinkExtension, + )) + + source := ` + # Hello goldmark-extensions + this is a [[wikilink]] in text + + [[wikilink]] starting a line + + ending a line with a [[wikilink]] + ` + + var buf bytes.Buffer + + context := parser.NewContext() + + err := m.Convert([]byte(source), &buf, parser.WithContext(context)) + if err != nil { + panic(err) + } + // fmt.Printf("%#+v\n", context) +} diff --git a/goldmark/links.go b/goldmark/links.go index d39647d..7e09004 100644 --- a/goldmark/links.go +++ b/goldmark/links.go @@ -2,7 +2,8 @@ package goldmark import ( "bytes" - "errors" + "fmt" + // "errors" "regexp" "github.com/yuin/goldmark" @@ -10,14 +11,90 @@ import ( "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" - - "gopkg.in/yaml.v2" ) -type ObsidianLinkExtension struct{} +var contextKeyMeta = parser.NewContextKey() + +func isSeparator(line []byte) bool { + r := regexp.MustCompile(`^\s*-{3,}\s*$`) + + return r.Match(line) +} + +type obsidianLinkParser struct{} + +var defaultLinkParser = &obsidianLinkParser{} + +func (b *obsidianLinkParser) Trigger() []byte { + // return []byte{'!', '[', ']'} + fmt.Println("obsidianLinkParser.Trigger()") + return []byte{'[', ']'} +} + +func (b *obsidianLinkParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node { + fmt.Println("obsidianLinkParser.Parse()") + return nil +} + +func (b *obsidianLinkParser) Open(parent ast.Node, block text.Reader, pc parser.Context) (ast.Node, parser.State) { + fmt.Println("obsidianLinkParser.Open()") + linenum, _ := block.Position() + if linenum != 0 { + return nil, parser.NoChildren + } + + line, _ := block.PeekLine() + + if isSeparator(line) { + return ast.NewTextBlock(), parser.NoChildren + } + + return nil, parser.NoChildren +} + +func (b *obsidianLinkParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State { + line, segment := reader.PeekLine() -func (ole *ObsidianLinkExtension) Extend(m goldmark.Markdown) { + if isSeparator(line) { + reader.Advance(segment.Len()) + + return parser.Close + } + + node.Lines().Append(segment) + + return parser.Continue | parser.NoChildren +} + +func (b *obsidianLinkParser) Close(node ast.Node, reader text.Reader, pc parser.Context) { + lines := node.Lines() + + var buf bytes.Buffer + + for i := 0; i < lines.Len(); i++ { + segment := lines.At(i) + buf.Write(segment.Value(reader.Source())) + } + pc.Set(contextKeyMeta, buf) + node.Parent().RemoveChild(node.Parent(), node) +} + +func (b *obsidianLinkParser) CanInterruptParagraph() bool { + return false +} + +func (b *obsidianLinkParser) CanAcceptIndentedLine() bool { + return false +} + +type obsidianLinkExtension struct{} + +func (ole *obsidianLinkExtension) Extend(m goldmark.Markdown) { m.Parser().AddOptions( - parser.WithBlockParsers(), + parser.WithInlineParsers( + util.Prioritized(defaultLinkParser, 0), + ), ) } + +var ObsidianLinkExtension = &obsidianLinkExtension{}