summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/yuin/goldmark/parser/setext_headings.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/yuin/goldmark/parser/setext_headings.go')
-rw-r--r--vendor/github.com/yuin/goldmark/parser/setext_headings.go126
1 files changed, 126 insertions, 0 deletions
diff --git a/vendor/github.com/yuin/goldmark/parser/setext_headings.go b/vendor/github.com/yuin/goldmark/parser/setext_headings.go
new file mode 100644
index 0000000000..686efe179c
--- /dev/null
+++ b/vendor/github.com/yuin/goldmark/parser/setext_headings.go
@@ -0,0 +1,126 @@
+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
+}
+
+// NewSetextHeadingParser return a new BlockParser that can parse Setext headings.
+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.(ast.Node).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
+}