package parser
import (
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
var temporaryParagraphKey = NewContextKey ()
type setextHeadingParser struct {
HeadingConfig
}
func matchesSetextHeadingBar(line []byte ) (byte , bool ) {
start := 0
end := len (line )
space := util .TrimLeftLength (line , []byte {' ' })
if space > 3 {
return 0 , false
}
start += space
level1 := util .TrimLeftLength (line [start :end ], []byte {'=' })
c := byte ('=' )
var level2 int
if level1 == 0 {
level2 = util .TrimLeftLength (line [start :end ], []byte {'-' })
c = '-'
}
if util .IsSpace (line [end -1 ]) {
end -= util .TrimRightSpaceLength (line [start :end ])
}
if !((level1 > 0 && start +level1 == end ) || (level2 > 0 && start +level2 == end )) {
return 0 , false
}
return c , true
}
func NewSetextHeadingParser (opts ...HeadingOption ) BlockParser {
p := &setextHeadingParser {}
for _ , o := range opts {
o .SetHeadingOption (&p .HeadingConfig )
}
return p
}
func (b *setextHeadingParser ) Trigger () []byte {
return []byte {'-' , '=' }
}
func (b *setextHeadingParser ) Open (parent ast .Node , reader text .Reader , pc Context ) (ast .Node , State ) {
last := pc .LastOpenedBlock ().Node
if last == nil {
return nil , NoChildren
}
paragraph , ok := last .(*ast .Paragraph )
if !ok || paragraph .Parent () != parent {
return nil , NoChildren
}
line , segment := reader .PeekLine ()
c , ok := matchesSetextHeadingBar (line )
if !ok {
return nil , NoChildren
}
level := 1
if c == '-' {
level = 2
}
node := ast .NewHeading (level )
node .Lines ().Append (segment )
pc .Set (temporaryParagraphKey , last )
return node , NoChildren | RequireParagraph
}
func (b *setextHeadingParser ) Continue (node ast .Node , reader text .Reader , pc Context ) State {
return Close
}
func (b *setextHeadingParser ) Close (node ast .Node , reader text .Reader , pc Context ) {
heading := node .(*ast .Heading )
segment := node .Lines ().At (0 )
heading .Lines ().Clear ()
tmp := pc .Get (temporaryParagraphKey ).(*ast .Paragraph )
pc .Set (temporaryParagraphKey , nil )
if tmp .Lines ().Len () == 0 {
next := heading .NextSibling ()
segment = segment .TrimLeftSpace (reader .Source ())
if next == nil || !ast .IsParagraph (next ) {
para := ast .NewParagraph ()
para .Lines ().Append (segment )
heading .Parent ().InsertAfter (heading .Parent (), heading , para )
} else {
next .Lines ().Unshift (segment )
}
heading .Parent ().RemoveChild (heading .Parent (), heading )
} else {
heading .SetLines (tmp .Lines ())
heading .SetBlankPreviousLines (tmp .HasBlankPreviousLines ())
tp := tmp .Parent ()
if tp != nil {
tp .RemoveChild (tp , tmp )
}
}
if b .Attribute {
parseLastLineAttributes (node , reader , pc )
}
if b .AutoHeadingID {
id , ok := node .AttributeString ("id" )
if !ok {
generateAutoHeadingID (heading , reader , pc )
} else {
pc .IDs ().Put (id .([]byte ))
}
}
}
func (b *setextHeadingParser ) CanInterruptParagraph () bool {
return true
}
func (b *setextHeadingParser ) CanAcceptIndentedLine () bool {
return false
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .