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.Gemtext/Renderers/Gemtext/Inlines/LinkInlineRenderer.cs

125 lines
4.1 KiB
C#

using System.IO;
using Markdig.Syntax.Inlines;
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines
{
/// <summary>
/// A Gemtext renderer for a <see cref="LinkInline" />.
/// </summary>
/// <seealso cref="GemtextObjectRenderer{LinkInline}" />
public class LinkInlineRenderer : GemtextObjectRenderer<LinkInline>
{
/// <summary>
/// Writes out any gathered links in a block.
/// </summary>
/// <param name="renderer">The renderer being used.</param>
public static void WriteGatheredLinks(GemtextRenderer renderer)
{
// If we have no gathered links, then there is nothing to do.
if (renderer.GatheredLinks.Count <= 0)
{
return;
}
// Put some space between the previous object and this one, then
// write out each link which is already formatted.
renderer.WriteLine();
foreach (var link in renderer.GatheredLinks)
{
renderer.WriteLine();
renderer.Write(link);
}
// Clear out the list of links.
renderer.GatheredLinks.Clear();
}
protected override void Write(GemtextRenderer renderer, LinkInline link)
{
// Figure out the various states we have.
bool outside = !renderer.LinkInsideBlock;
bool insert = !outside
&& renderer.BlockLinkHandling == BlockLinkHandling.InsertLine;
bool gather = !outside
&& renderer.BlockLinkHandling switch
{
BlockLinkHandling.DocumentEnd => true,
BlockLinkHandling.ParagraphEnd => true,
_ => false,
};
bool hasText = link.FirstChild != null;
bool footnotes = renderer.EndLinkInlineFormatting
== EndLinkInlineFormatting.Footnote;
// Bare links and ones where we insert into the paragraph have
// their own line.
string? url = link.GetDynamicUrl != null
? link.GetDynamicUrl() ?? link.Url
: link.Url;
if (outside || insert)
{
// Make sure we are at the beginning of the line before
// rendering the link.
renderer.EnsureLine();
renderer.Write("=> ");
renderer.Write(url);
// If we have text, we need a space after the URL and before
// the text.
if (hasText)
{
renderer.Write(" ");
}
}
// Render the text for the link if we have it.
if (hasText)
{
renderer.WriteChildren(link);
}
// If we are gathering, then write out a footnote.
if (gather)
{
int footnoteNumber = renderer.NextFootnoteNumber++;
string linkText = footnotes
? footnoteNumber + ": " + url
: GetLinkText(link);
if (footnotes)
{
renderer.Write($"[{footnoteNumber}]");
}
renderer.GatheredLinks.Add("=> " + url + " " + linkText);
}
// If we are inserting a line in the paragraph, we need a final
// newline so the text of the paragraph continues on the next
// line.
if (insert)
{
renderer.WriteLine();
}
}
private static string GetLinkText(LinkInline link)
{
// This little bit of nasty code basically spins up a new renderer
// to get the text of the link by itself. Then we return that
// directly so it can be rendered as a link.
StringWriter writer = new();
GemtextRenderer renderer = new(writer);
renderer.WriteChildren(link);
writer.Close();
string text = writer.ToString();
return text;
}
}
}