Files
2026-05-24 09:40:19 +02:00

110 lines
2.2 KiB
Go

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
}