...

Source file src/github.com/yuin/goldmark/parser/setext_headings.go

Documentation: github.com/yuin/goldmark/parser

     1  package parser
     2  
     3  import (
     4  	"github.com/yuin/goldmark/ast"
     5  	"github.com/yuin/goldmark/text"
     6  	"github.com/yuin/goldmark/util"
     7  )
     8  
     9  var temporaryParagraphKey = NewContextKey()
    10  
    11  type setextHeadingParser struct {
    12  	HeadingConfig
    13  }
    14  
    15  func matchesSetextHeadingBar(line []byte) (byte, bool) {
    16  	start := 0
    17  	end := len(line)
    18  	space := util.TrimLeftLength(line, []byte{' '})
    19  	if space > 3 {
    20  		return 0, false
    21  	}
    22  	start += space
    23  	level1 := util.TrimLeftLength(line[start:end], []byte{'='})
    24  	c := byte('=')
    25  	var level2 int
    26  	if level1 == 0 {
    27  		level2 = util.TrimLeftLength(line[start:end], []byte{'-'})
    28  		c = '-'
    29  	}
    30  	if util.IsSpace(line[end-1]) {
    31  		end -= util.TrimRightSpaceLength(line[start:end])
    32  	}
    33  	if !((level1 > 0 && start+level1 == end) || (level2 > 0 && start+level2 == end)) {
    34  		return 0, false
    35  	}
    36  	return c, true
    37  }
    38  
    39  // NewSetextHeadingParser return a new BlockParser that can parse Setext headings.
    40  func NewSetextHeadingParser(opts ...HeadingOption) BlockParser {
    41  	p := &setextHeadingParser{}
    42  	for _, o := range opts {
    43  		o.SetHeadingOption(&p.HeadingConfig)
    44  	}
    45  	return p
    46  }
    47  
    48  func (b *setextHeadingParser) Trigger() []byte {
    49  	return []byte{'-', '='}
    50  }
    51  
    52  func (b *setextHeadingParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) {
    53  	last := pc.LastOpenedBlock().Node
    54  	if last == nil {
    55  		return nil, NoChildren
    56  	}
    57  	paragraph, ok := last.(*ast.Paragraph)
    58  	if !ok || paragraph.Parent() != parent {
    59  		return nil, NoChildren
    60  	}
    61  	line, segment := reader.PeekLine()
    62  	c, ok := matchesSetextHeadingBar(line)
    63  	if !ok {
    64  		return nil, NoChildren
    65  	}
    66  	level := 1
    67  	if c == '-' {
    68  		level = 2
    69  	}
    70  	node := ast.NewHeading(level)
    71  	node.Lines().Append(segment)
    72  	pc.Set(temporaryParagraphKey, last)
    73  	return node, NoChildren | RequireParagraph
    74  }
    75  
    76  func (b *setextHeadingParser) Continue(node ast.Node, reader text.Reader, pc Context) State {
    77  	return Close
    78  }
    79  
    80  func (b *setextHeadingParser) Close(node ast.Node, reader text.Reader, pc Context) {
    81  	heading := node.(*ast.Heading)
    82  	segment := node.Lines().At(0)
    83  	heading.Lines().Clear()
    84  	tmp := pc.Get(temporaryParagraphKey).(*ast.Paragraph)
    85  	pc.Set(temporaryParagraphKey, nil)
    86  	if tmp.Lines().Len() == 0 {
    87  		next := heading.NextSibling()
    88  		segment = segment.TrimLeftSpace(reader.Source())
    89  		if next == nil || !ast.IsParagraph(next) {
    90  			para := ast.NewParagraph()
    91  			para.Lines().Append(segment)
    92  			heading.Parent().InsertAfter(heading.Parent(), heading, para)
    93  		} else {
    94  			next.(ast.Node).Lines().Unshift(segment)
    95  		}
    96  		heading.Parent().RemoveChild(heading.Parent(), heading)
    97  	} else {
    98  		heading.SetLines(tmp.Lines())
    99  		heading.SetBlankPreviousLines(tmp.HasBlankPreviousLines())
   100  		tp := tmp.Parent()
   101  		if tp != nil {
   102  			tp.RemoveChild(tp, tmp)
   103  		}
   104  	}
   105  
   106  	if b.Attribute {
   107  		parseLastLineAttributes(node, reader, pc)
   108  	}
   109  
   110  	if b.AutoHeadingID {
   111  		id, ok := node.AttributeString("id")
   112  		if !ok {
   113  			generateAutoHeadingID(heading, reader, pc)
   114  		} else {
   115  			pc.IDs().Put(id.([]byte))
   116  		}
   117  	}
   118  }
   119  
   120  func (b *setextHeadingParser) CanInterruptParagraph() bool {
   121  	return true
   122  }
   123  
   124  func (b *setextHeadingParser) CanAcceptIndentedLine() bool {
   125  	return false
   126  }
   127  

View as plain text