block .SetPosition (l , pos )
ssegment := text .NewSegment (last .Segment .Stop , segment .Start )
maybeReference := block .Value (ssegment )
ref , ok := pc .Reference (util .ToLinkReference (maybeReference ))
if !ok {
ast .MergeOrReplaceTextSegment (last .Parent (), last , last .Segment )
return nil
}
link = ast .NewLink ()
s .processLinkLabel (parent , link , last , pc )
link .Title = ref .Title ()
link .Destination = ref .Destination ()
}
if last .IsImage {
last .Parent ().RemoveChild (last .Parent (), last )
return ast .NewImage (link )
}
last .Parent ().RemoveChild (last .Parent (), last )
return link
}
func (s *linkParser ) containsLink (last *linkLabelState ) bool {
if last .IsImage {
return false
}
var c ast .Node
for c = last ; c != nil ; c = c .NextSibling () {
if _ , ok := c .(*ast .Link ); ok {
return true
}
}
return false
}
func processLinkLabelOpen (block text .Reader , pos int , isImage bool , pc Context ) *linkLabelState {
start := pos
if isImage {
start --
}
state := newLinkLabelState (text .NewSegment (start , pos +1 ), isImage )
pushLinkLabelState (pc , state )
block .Advance (1 )
return state
}
func (s *linkParser ) processLinkLabel (parent ast .Node , link *ast .Link , last *linkLabelState , pc Context ) {
var bottom ast .Node
if v := pc .Get (linkBottom ); v != nil {
bottom = v .(ast .Node )
}
pc .Set (linkBottom , nil )
ProcessDelimiters (bottom , pc )
for c := last .NextSibling (); c != nil ; {
next := c .NextSibling ()
parent .RemoveChild (parent , c )
link .AppendChild (link , c )
c = next
}
}
func (s *linkParser ) parseReferenceLink (parent ast .Node , last *linkLabelState , block text .Reader , pc Context ) (*ast .Link , bool ) {
_ , orgpos := block .Position ()
block .Advance (1 )
line , segment := block .PeekLine ()
endIndex := util .FindClosure (line , '[' , ']' , false , true )
if endIndex < 0 {
return nil , false
}
block .Advance (endIndex + 1 )
ssegment := segment .WithStop (segment .Start + endIndex )
maybeReference := block .Value (ssegment )
if util .IsBlank (maybeReference ) {
ssegment = text .NewSegment (last .Segment .Stop , orgpos .Start -1 )
maybeReference = block .Value (ssegment )
}
ref , ok := pc .Reference (util .ToLinkReference (maybeReference ))
if !ok {
return nil , true
}
link := ast .NewLink ()
s .processLinkLabel (parent , link , last , pc )
link .Title = ref .Title ()
link .Destination = ref .Destination ()
return link , true
}
func (s *linkParser ) parseLink (parent ast .Node , last *linkLabelState , block text .Reader , pc Context ) *ast .Link {
block .Advance (1 )
block .SkipSpaces ()
var title []byte
var destination []byte
var ok bool
if block .Peek () == ')' {
block .Advance (1 )
} else {
destination , ok = parseLinkDestination (block )
if !ok {
return nil
}
block .SkipSpaces ()
if block .Peek () == ')' {
block .Advance (1 )
} else {
title , ok = parseLinkTitle (block )
if !ok {
return nil
}
block .SkipSpaces ()
if block .Peek () == ')' {
block .Advance (1 )
} else {
return nil
}
}
}
link := ast .NewLink ()
s .processLinkLabel (parent , link , last , pc )
link .Destination = destination
link .Title = title
return link
}
func parseLinkDestination (block text .Reader ) ([]byte , bool ) {
block .SkipSpaces ()
line , _ := block .PeekLine ()
if block .Peek () == '<' {
i := 1
for i < len (line ) {
c := line [i ]
if c == '\\' && i < len (line )-1 && util .IsPunct (line [i +1 ]) {
i += 2
continue
} else if c == '>' {
block .Advance (i + 1 )
return line [1 :i ], true
}
i ++
}
return nil , false
}
opened := 0
i := 0
for i < len (line ) {
c := line [i ]
if c == '\\' && i < len (line )-1 && util .IsPunct (line [i +1 ]) {
i += 2
continue
} else if c == '(' {
opened ++
} else if c == ')' {
opened --
if opened < 0 {
break
}
} else if util .IsSpace (c ) {
break
}
i ++
}
block .Advance (i )
return line [:i ], len (line [:i ]) != 0
}
func parseLinkTitle (block text .Reader ) ([]byte , bool ) {
block .SkipSpaces ()
opener := block .Peek ()
if opener != '"' && opener != '\'' && opener != '(' {
return nil , false
}
closer := opener
if opener == '(' {
closer = ')'
}
savedLine , savedPosition := block .Position ()
var title []byte
for i := 0 ; ; i ++ {
line , _ := block .PeekLine ()
if line == nil {
block .SetPosition (savedLine , savedPosition )
return nil , false
}
offset := 0
if i == 0 {
offset = 1
}
pos := util .FindClosure (line [offset :], opener , closer , false , true )
if pos < 0 {
title = append (title , line [offset :]...)
block .AdvanceLine ()
continue
}
pos += offset + 1
block .Advance (pos )
if i == 0 {
return line [offset : pos -1 ], true
}
return append (title , line [offset :pos -1 ]...), true
}
}
func (s *linkParser ) CloseBlock (parent ast .Node , block text .Reader , pc Context ) {
tlist := pc .Get (linkLabelStateKey )
if tlist == nil {
return
}
for s := tlist .(*linkLabelState ); s != nil ; {
next := s .Next
removeLinkLabelState (pc , s )
s .Parent ().ReplaceChild (s .Parent (), s , ast .NewTextSegment (s .Segment ))
s = next
}