Token ProcessLinkOrImageOrFootnote()
{
// Link or image?
TokenType token_type = SkipChar('!') ? TokenType.img : TokenType.link;
// Opening '['
if (!SkipChar('['))
return null;
// Is it a foonote?
var savepos=Position;
if (m_Markdown.ExtraMode && token_type==TokenType.link && SkipChar('^'))
{
SkipLinespace();
// Parse it
string id;
if (SkipFootnoteID(out id) && SkipChar(']'))
{
// Look it up and create footnote reference token
int footnote_index = m_Markdown.ClaimFootnote(id);
if (footnote_index >= 0)
{
// Yes it's a footnote
return CreateToken(TokenType.footnote, new FootnoteReference(footnote_index, id));
}
}
// Rewind
Position = savepos;
}
if (DisableLinks && token_type==TokenType.link)
return null;
bool extraMode = m_Markdown.ExtraMode;
// Find the closing square bracket, allowing for nesting, watching for
// escapable characters
Mark();
int depth = 1;
while (!Eof)
{
char ch = Current;
if (ch == '[')
{
depth++;
}
else if (ch == ']')
{
depth--;
if (depth == 0)
break;
}
this.SkipEscapableChar(extraMode);
}
// Quit if end
if (Eof)
return null;
// Get the link text and unescape it
string link_text = Utils.UnescapeString(Extract(), extraMode);
// The closing ']'
SkipForward(1);
// Save position in case we need to rewind
savepos = Position;
// Inline links must follow immediately
if (SkipChar('('))
{
// Extract the url and title
var link_def = LinkDefinition.ParseLinkTarget(this, null, m_Markdown.ExtraMode);
if (link_def==null)
return null;
// Closing ')'
SkipWhitespace();
if (!SkipChar(')'))
return null;
List<string> specialAttributes = null;
if(extraMode && DoesMatch('{'))
{
int end;
specialAttributes = Utils.StripSpecialAttributes(this.Input, this.Position, out end);
if(specialAttributes != null)
{
Position = end;
}
}
// Create the token
return CreateToken(token_type, new LinkInfo(link_def, link_text, specialAttributes));
}
// Optional space or tab
if (!SkipChar(' '))
SkipChar('\t');
// If there's line end, we're allow it and as must line space as we want
// before the link id.
if (Eol)
{
SkipEol();
SkipLinespace();
}
// Reference link?
string link_id = null;
if (Current == '[')
{
// Skip the opening '['
SkipForward(1);
// Find the start/end of the id
Mark();
if (!Find(']'))
return null;
// Extract the id
link_id = Extract();
// Skip closing ']'
SkipForward(1);
}
else
{
// Rewind to just after the closing ']'
Position = savepos;
}
// Link id not specified?
if (string.IsNullOrEmpty(link_id))
{
// Use the link text (implicit reference link)
link_id = Utils.NormalizeLineEnds(link_text);
// If the link text has carriage returns, normalize
// to spaces
if (!object.ReferenceEquals(link_id, link_text))
{
while (link_id.Contains(" \n"))
link_id = link_id.Replace(" \n", "\n");
link_id = link_id.Replace("\n", " ");
}
}
// Find the link definition abort if not defined
var def = m_Markdown.GetLinkDefinition(link_id);
if (def == null)
return null;
// Create a token.
// [FB]: Currently not supported: special attributes on reference links.
return CreateToken(token_type, new LinkInfo(def, link_text, null));
}