var LinkReferenceParagraphTransformer = &linkReferenceParagraphTransformer {}
func (p *linkReferenceParagraphTransformer ) Transform (node *ast .Paragraph , reader text .Reader , pc Context ) {
lines := node .Lines ()
block := text .NewBlockReader (reader .Source (), lines )
removes := [][2 ]int {}
for {
start , end := parseLinkReferenceDefinition (block , pc )
if start > -1 {
if start == end {
end ++
}
removes = append (removes , [2 ]int {start , end })
continue
}
break
}
offset := 0
for _ , remove := range removes {
if lines .Len () == 0 {
break
}
s := lines .Sliced (remove [1 ]-offset , lines .Len ())
lines .SetSliced (0 , remove [0 ]-offset )
lines .AppendAll (s )
offset = remove [1 ]
}
if lines .Len () == 0 {
t := ast .NewTextBlock ()
t .SetBlankPreviousLines (node .HasBlankPreviousLines ())
node .Parent ().ReplaceChild (node .Parent (), node , t )
return
}
node .SetLines (lines )
}
func parseLinkReferenceDefinition (block text .Reader , pc Context ) (int , int ) {
block .SkipSpaces ()
line , segment := block .PeekLine ()
if line == nil {
return -1 , -1
}
startLine , _ := block .Position ()
width , pos := util .IndentWidth (line , 0 )
if width > 3 {
return -1 , -1
}
if width != 0 {
pos ++
}
if line [pos ] != '[' {
return -1 , -1
}
open := segment .Start + pos + 1
closes := -1
block .Advance (pos + 1 )
for {
line , segment = block .PeekLine ()
if line == nil {
return -1 , -1
}
closure := util .FindClosure (line , '[' , ']' , false , false )
if closure > -1 {
closes = segment .Start + closure
next := closure + 1
if next >= len (line ) || line [next ] != ':' {
return -1 , -1
}
block .Advance (next + 1 )
break
}
block .AdvanceLine ()
}
if closes < 0 {
return -1 , -1
}
label := block .Value (text .NewSegment (open , closes ))
if util .IsBlank (label ) {
return -1 , -1
}
block .SkipSpaces ()
destination , ok := parseLinkDestination (block )
if !ok {
return -1 , -1
}
line , segment = block .PeekLine ()
isNewLine := line == nil || util .IsBlank (line )
endLine , _ := block .Position ()
_ , spaces , _ := block .SkipSpaces ()
opener := block .Peek ()
if opener != '"' && opener != '\'' && opener != '(' {
if !isNewLine {
return -1 , -1
}
ref := NewReference (label , destination , nil )
pc .AddReference (ref )
return startLine , endLine + 1
}
if spaces == 0 {
return -1 , -1
}
block .Advance (1 )
open = -1
closes = -1
closer := opener
if opener == '(' {
closer = ')'
}
for {
line , segment = block .PeekLine ()
if line == nil {
return -1 , -1
}
if open < 0 {
open = segment .Start
}
closure := util .FindClosure (line , opener , closer , false , true )
if closure > -1 {
closes = segment .Start + closure
block .Advance (closure + 1 )
break
}
block .AdvanceLine ()
}
if closes < 0 {
return -1 , -1
}
line , segment = block .PeekLine ()
if line != nil && !util .IsBlank (line ) {
if !isNewLine {
return -1 , -1
}
title := block .Value (text .NewSegment (open , closes ))
ref := NewReference (label , destination , title )
pc .AddReference (ref )
return startLine , endLine
}
title := block .Value (text .NewSegment (open , closes ))
endLine , _ = block .Position ()
ref := NewReference (label , destination , title )
pc .AddReference (ref )
return startLine , endLine + 1