package md import ( "errors" "strings" "github.com/yuin/goldmark" "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" ) var propertiesContextKey = parser.NewContextKey() type propertiesData struct { properties map[string]string Error error } type propertiesExtension struct { } func (e *propertiesExtension) Extend(m goldmark.Markdown) { m.Parser().AddOptions( parser.WithBlockParsers( util.Prioritized(&propertiesParser{}, 0), ), ) } type propertiesParser struct { } func (p *propertiesParser) Trigger() []byte { return []byte{'-'} } func (p *propertiesParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) { lineNumber, _ := reader.Position() if lineNumber != 0 { return nil, parser.NoChildren } line, _ := reader.PeekLine() if isSeparator(line) { return ast.NewTextBlock(), parser.NoChildren } return nil, parser.NoChildren } func (p *propertiesParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State { line, segment := reader.PeekLine() if isSeparator(line) && !util.IsBlank(line) { reader.Advance(segment.Len()) return parser.Close } node.Lines().Append(segment) return parser.Continue | parser.NoChildren } func (p *propertiesParser) Close(node ast.Node, reader text.Reader, pc parser.Context) { lines := node.Lines() data := &propertiesData{ make(map[string]string), nil, } pc.Set(propertiesContextKey, data) for i := 0; i < lines.Len(); i++ { segment := lines.At(i) line := string(segment.Value(reader.Source())) index := strings.IndexRune(line, ':') if index == -1 { data.Error = errors.New("invalid property line") break } key := strings.TrimSpace(line[:index]) value := strings.TrimSpace(line[index+1:]) data.properties[key] = value } node.Parent().RemoveChild(node.Parent(), node) } func (p *propertiesParser) CanInterruptParagraph() bool { return false } func (p *propertiesParser) CanAcceptIndentedLine() bool { return false } func isSeparator(line []byte) bool { line = util.TrimRightSpace(util.TrimLeftSpace(line)) for i := 0; i < len(line); i++ { if line[i] != '-' { return false } } return true }