This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
mfgames-markdown-cil/src/MfGames.Markdown/Extensions/WikiLinkInlineParser.cs

113 lines
3 KiB
C#

using System.Linq;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Syntax.Inlines;
namespace MfGames.Markdown.Extensions;
public class WikiLinkInlineParser : InlineParser
{
private readonly WikiLinkOptions options;
public WikiLinkInlineParser(WikiLinkOptions options)
{
this.options = options;
this.OpeningCharacters = new[] { '[' };
}
/// <inheritdoc />
public override bool Match(
InlineProcessor processor,
ref StringSlice slice)
{
// We are looking for the `[[` opening for the tag and that the first
// one isn't escaped.
if (IsNotDelimiter(slice, '['))
{
return false;
}
// We need to loop over the entire link, including the `[[` and `]]`
// while keeping track since we'll swallow additional characters beyond
// the link.
int linkStart = slice.Start;
int linkEnd = slice.Start;
slice.Start += 2;
// Our content starts after the double '[['.
int contentStart = slice.Start;
// We need to find the end of the link (the `]]`).
while (IsNotDelimiter(slice, ']'))
{
slice.NextChar();
linkEnd = slice.Start;
}
// Pull out the components before we adjust for the ']]' for the end.
int contentEnd = linkEnd;
// Finish skipping over the `]]`.
slice.NextChar();
slice.NextChar();
// Format the label and the URL.
string content = slice.Text.Substring(
contentStart,
contentEnd - contentStart);
string[] contentParts = content.Split('|', 2);
string label = contentParts.Last();
string url = this.options.GetUrl(contentParts.First());
// Add in any trailing components. This merges the `'s` from
// `[[Dale]]'s` into the label.
while (this.options.IsTrailingLink(slice.CurrentChar))
{
label += slice.CurrentChar;
slice.NextChar();
linkEnd++;
}
// Create the link that we're replacing.
WikiLink link = new()
{
Span =
{
Start = processor.GetSourcePosition(
linkStart,
out int line,
out int column),
},
Line = line,
Column = column,
Url = url,
IsClosed = true,
};
link.AppendChild(
new LiteralInline()
{
Line = line,
Column = column,
Content = new StringSlice(label),
IsClosed = true,
});
// Replace the inline and then indicate we have a match.
processor.Inline = link;
return true;
}
private static bool IsNotDelimiter(
StringSlice slice,
char delimiter)
{
return slice.CurrentChar != delimiter
|| slice.PeekChar() != delimiter
|| slice.PeekCharExtra(-1) == '\\';
}
}