feat: implemented wiki links for both HTML and Gemtext
This commit is contained in:
parent
45f26437ff
commit
cd9c8989dc
47 changed files with 670 additions and 106 deletions
|
@ -9,6 +9,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown.Gemtext",
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown.Gemtext.Tests", "tests\MfGames.Markdown.Gemtext.Tests\MfGames.Markdown.Gemtext.Tests.csproj", "{D2703B25-9AF7-49FF-93A4-CB124560F2A9}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B4837F83-8560-4AC9-B1E3-6B8C0545A65B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown", "src\MfGames.Markdown\MfGames.Markdown.csproj", "{482E332F-9E72-4F02-B528-9CF04AE05E82}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Markdown.Tests", "tests\MfGames.Markdown.Tests\MfGames.Markdown.Tests.csproj", "{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -46,9 +52,35 @@ Global
|
|||
{D2703B25-9AF7-49FF-93A4-CB124560F2A9}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D2703B25-9AF7-49FF-93A4-CB124560F2A9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D2703B25-9AF7-49FF-93A4-CB124560F2A9}.Release|x86.Build.0 = Release|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x64.Build.0 = Release|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{2A1DE43D-544D-4CE0-ACC8-D15497BBCECA} = {954BA984-D50E-4D1C-880F-EAE678EF6945}
|
||||
{D2703B25-9AF7-49FF-93A4-CB124560F2A9} = {954BA984-D50E-4D1C-880F-EAE678EF6945}
|
||||
{D2703B25-9AF7-49FF-93A4-CB124560F2A9} = {B4837F83-8560-4AC9-B1E3-6B8C0545A65B}
|
||||
{482E332F-9E72-4F02-B528-9CF04AE05E82} = {954BA984-D50E-4D1C-880F-EAE678EF6945}
|
||||
{3E2AD98D-D1A1-48DF-B94F-A470982DAC9B} = {B4837F83-8560-4AC9-B1E3-6B8C0545A65B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
34
README.md
34
README.md
|
@ -1,3 +1,33 @@
|
|||
# MfGames.Markdown.Gemtext CIL
|
||||
# MfGames.Markdown CIL
|
||||
|
||||
An extension for [Markdig](https://github.com/xoofx/markdig) that converts Markdown into Gemtext.
|
||||
This is a set of libraries for working with Markdown in C#. Most of the code are extensions in [MarkDig](https://github.com/xoofx/markdig), an extensible library for converting Markdown.
|
||||
|
||||
The library includes the following:
|
||||
|
||||
- An extension for converting wiki links, such as `[[MfGames]]` into a link based on the title. This is for both HTML and Gemtext.
|
||||
- A output library for using MarkDig to generate Gemtext for Gemini pods.
|
||||
|
||||
The documentation is rather light at the moment, but the tests are set up to show these can be used.
|
||||
|
||||
## Usage
|
||||
|
||||
These library are not on nuget.org (for various reasons). To use them, set up your NuGet.config to pull them from their repository.
|
||||
|
||||
```
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<add key="mfgames.com" value="https://src.mfgames.com/api/packages/mfgames-cil/nuget/index.json" protocolVersion="3" />
|
||||
</packageSources>
|
||||
<packageSourceMapping>
|
||||
<packageSource key="nuget.org">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="mfgames.com">
|
||||
<package pattern="MfGames.*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
||||
```
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Set up logging.
|
||||
log() { echo "🛠️ $(basename $0): $@"; }
|
||||
|
||||
# Move into the top level.
|
||||
cd $(dirname $0)/..
|
||||
|
||||
./scripts/setup.sh || exit 1
|
||||
|
||||
echo "$(basename $0): building project"
|
||||
log "building project"
|
||||
dotnet build
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
npm install --ci
|
||||
dotnet restore
|
||||
dotnet build
|
|
@ -1,5 +0,0 @@
|
|||
npm install --ci
|
||||
dotnet restore
|
||||
dotnet build
|
||||
npm install --ci
|
||||
npx semantic-release
|
|
@ -1,9 +0,0 @@
|
|||
npm install --ci
|
||||
npx commitlint-gitlab-ci -x @commitlint/config-conventional
|
||||
dotnet restore
|
||||
dotnet build
|
||||
dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=../artifacts/{assembly}-test-result.xml;MethodFormat=Default;FailureBodyFormat=Verbose" --collect:"XPlat Code Coverage"
|
||||
dotnet new tool-manifest
|
||||
dotnet tool install dotnet-reportgenerator-globaltool
|
||||
dotnet tool run reportgenerator -reports:src/*/TestResults/*/coverage.cobertura.xml -targetdir:./coverage "-reporttypes:Cobertura;TextSummary"
|
||||
grep "Line coverage" coverage/Summary.txt
|
|
@ -1,39 +1,44 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Set up logging.
|
||||
log() { echo "️🚢 $(basename $0): $@"; }
|
||||
|
||||
# Move into the root folder and make sure we're set up.
|
||||
cd $(dirname $0)/..
|
||||
|
||||
./scripts/setup.sh || exit 1
|
||||
|
||||
# Verify the input.
|
||||
if [ "x$GITEA_TOKEN" = "x" ]
|
||||
then
|
||||
echo "the environment variable GITEA_TOKEN is not defined"
|
||||
log "the environment variable GITEA_TOKEN is not defined"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up everything from the previous runs.
|
||||
echo "$(basename $0): cleaning project"
|
||||
log "cleaning project"
|
||||
dotnet clean
|
||||
|
||||
# Version the file based on the Git repository.
|
||||
echo "$(basename $0): setting project version"
|
||||
log "setting project version"
|
||||
(cd src && dotnet dotnet-gitversion /updateprojectfiles)
|
||||
SEMVER="v$(dotnet gitversion /output json | jq -r .SemVer)"
|
||||
|
||||
if [ "x$SEMVER" = "x" ]
|
||||
then
|
||||
echo "$(basename $0): cannot figure out the semantic version"
|
||||
log "cannot figure out the semantic version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build to pick up the new version.
|
||||
echo "$(basename $0): building project $SEMVER"
|
||||
log "building project $SEMVER"
|
||||
dotnet build || exit 1
|
||||
|
||||
# Create and publish the NuGet packages.
|
||||
echo "$(basename $0): creating NuGet packages"
|
||||
log "creating NuGet packages"
|
||||
dotnet pack -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg || exit 1
|
||||
|
||||
echo "$(basename $0): publishing NuGet package"
|
||||
log "publishing NuGet package"
|
||||
dotnet nuget remove source mfgames.com >& /dev/null
|
||||
dotnet nuget add source --name mfgames.com --username dmoonfire --password $GITEA_TOKEN https://src.mfgames.com/api/packages/mfgames-cil/nuget/index.json --store-password-in-clear-text || exit 1
|
||||
dotnet nuget push --skip-duplicate --source mfgames.com src/*/bin/Debug/*.nupkg || exit 1
|
||||
|
@ -41,11 +46,11 @@ dotnet nuget push --skip-duplicate --source mfgames.com src/*/bin/Debug/*.nupkg
|
|||
# Tag and push, but only if we don't have a tag.
|
||||
if ! git tag | grep $SEMVER >& /dev/null
|
||||
then
|
||||
echo "$(basename $0): tagging and pushing"
|
||||
log "tagging and pushing"
|
||||
git remote add publish https://dmoonfire:$GITEA_TOKEN@src.mfgames.com/mfgames-cil/$(basename $(git config --get remote.origin.url))
|
||||
git tag $SEMVER
|
||||
git push publish $SEMVER || exit 1
|
||||
git remote remove publish
|
||||
else
|
||||
echo "$(basename $0): not tagging, already exists"
|
||||
log "not tagging, already exists"
|
||||
fi
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Set up logging.
|
||||
log() { echo "📦️ $(basename $0): $@";
|
||||
|
||||
# Normalize our environment.
|
||||
cd $(dirname $0)/..
|
||||
|
||||
|
@ -8,7 +11,7 @@ for e in dotnet lefthook prettier nixfmt
|
|||
do
|
||||
if ! which $e >& /dev/null
|
||||
then
|
||||
echo "Cannot find '$e' in the path"
|
||||
log "Cannot find '$e' in the path"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
@ -16,12 +19,12 @@ done
|
|||
# Make sure we have lefthook is installed.
|
||||
if [ ! -f .git/hooks/pre-commit ]
|
||||
then
|
||||
echo "$(basename $0): installing lefthook"
|
||||
log "installing lefthook"
|
||||
lefthook install
|
||||
fi
|
||||
|
||||
# Make sure our tools are installed.
|
||||
echo "$(basename $0): install .NET tools"
|
||||
log "install .NET tools"
|
||||
dotnet tool restore
|
||||
|
||||
# Everything is good.
|
||||
|
|
|
@ -2,6 +2,7 @@ using Markdig;
|
|||
using Markdig.Extensions.SmartyPants;
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Extensions
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
|
||||
|
@ -26,7 +27,8 @@ namespace MfGames.Markdown.Gemtext.Extensions
|
|||
return;
|
||||
}
|
||||
|
||||
var heading = gemtext.ObjectRenderers.Find<HeadingRenderer>();
|
||||
HeadingRenderer? heading =
|
||||
gemtext.ObjectRenderers.Find<HeadingRenderer>();
|
||||
|
||||
if (heading != null)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Extensions
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Extensions
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Markdig;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext
|
||||
|
|
|
@ -9,12 +9,11 @@
|
|||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>Dylan Moonfire</Authors>
|
||||
<Company>Moonfire Games</Company>
|
||||
<RepositoryUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-gemtext-cil</RepositoryUrl>
|
||||
<RepositoryUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<PackageTags>ecs</PackageTags>
|
||||
<PackageProjectUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-gemtext-cil</PackageProjectUrl>
|
||||
<PackageProjectUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</PackageProjectUrl>
|
||||
<PackageLicense>MIT</PackageLicense>
|
||||
<Description>A Markdown extension to render Markdown in Gemtext.</Description>
|
||||
<Description>A MarkDig extension to render Markdown in Gemtext.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks
|
|||
renderer.EnsureTwoLines();
|
||||
|
||||
// Go through each list item and write them out.
|
||||
foreach (var item in listBlock)
|
||||
foreach (Block? item in listBlock)
|
||||
{
|
||||
// If the list only contains a link, then we just render the
|
||||
// link instead.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
|
||||
using Markdig.Extensions.SmartyPants;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines
|
||||
|
@ -25,7 +26,7 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines
|
|||
// write out each link which is already formatted.
|
||||
renderer.WriteLine();
|
||||
|
||||
foreach (var link in renderer.GatheredLinks)
|
||||
foreach (string? link in renderer.GatheredLinks)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
renderer.Write(link);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
|
|
11
src/MfGames.Markdown/Extensions/WikiLink.cs
Normal file
11
src/MfGames.Markdown/Extensions/WikiLink.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace MfGames.Markdown.Extensions;
|
||||
|
||||
public class WikiLink : LinkInline
|
||||
{
|
||||
public WikiLink()
|
||||
{
|
||||
this.IsClosed = false;
|
||||
}
|
||||
}
|
47
src/MfGames.Markdown/Extensions/WikiLinkExtension.cs
Normal file
47
src/MfGames.Markdown/Extensions/WikiLinkExtension.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using Markdig;
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Translate `[[Bob]]` into `/bob/`.
|
||||
/// </summary>
|
||||
public class WikiLinkExtension : IMarkdownExtension
|
||||
{
|
||||
public WikiLinkExtension()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public WikiLinkExtension(WikiLinkOptions? options)
|
||||
{
|
||||
this.Options = options ?? new WikiLinkOptions();
|
||||
}
|
||||
|
||||
public WikiLinkOptions Options { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
WikiLinkInlineParser? parser = pipeline.InlineParsers
|
||||
.FindExact<WikiLinkInlineParser>();
|
||||
|
||||
if (parser != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
parser = new WikiLinkInlineParser(this.Options);
|
||||
pipeline.InlineParsers.InsertBefore<LinkInlineParser>(parser);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(
|
||||
MarkdownPipeline pipeline,
|
||||
IMarkdownRenderer renderer)
|
||||
{
|
||||
// No setup needed here because we're using LinkInline which does the
|
||||
// bulk of the work.
|
||||
}
|
||||
}
|
112
src/MfGames.Markdown/Extensions/WikiLinkInlineParser.cs
Normal file
112
src/MfGames.Markdown/Extensions/WikiLinkInlineParser.cs
Normal file
|
@ -0,0 +1,112 @@
|
|||
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) == '\\';
|
||||
}
|
||||
}
|
31
src/MfGames.Markdown/Extensions/WikiLinkOptions.cs
Normal file
31
src/MfGames.Markdown/Extensions/WikiLinkOptions.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
|
||||
using Markdig.Helpers;
|
||||
|
||||
namespace MfGames.Markdown.Extensions;
|
||||
|
||||
public class WikiLinkOptions
|
||||
{
|
||||
public WikiLinkOptions()
|
||||
{
|
||||
this.GetUrl = a => a;
|
||||
this.IsTrailingLink = a => a.IsAlpha() || a == '\'';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The callback to determine the link from the given wiki link. This does
|
||||
/// not include trailing additions or use the label (e.g., `(ab|cd)` would
|
||||
/// get `ab` as the parameters of this function.
|
||||
/// </summary>
|
||||
public Func<string, string> GetUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// A callback to determine if the text after the link should be merged
|
||||
/// with the link label. This allows links such as [[Dale]]'s to be turned
|
||||
/// into "Dale's" but pointing to "Dale" as a page.
|
||||
/// </para>
|
||||
/// <para>The default is to include any character or the apostrophe.</para>
|
||||
/// </summary>
|
||||
public Func<char, bool> IsTrailingLink { get; set; }
|
||||
}
|
23
src/MfGames.Markdown/MfGames.Markdown.csproj
Normal file
23
src/MfGames.Markdown/MfGames.Markdown.csproj
Normal file
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>Dylan Moonfire</Authors>
|
||||
<Company>Moonfire Games</Company>
|
||||
<RepositoryUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<PackageProjectUrl>https://gitlab.com/mfgames-cil/mfgames-markdown-cil</PackageProjectUrl>
|
||||
<PackageLicense>MIT</PackageLicense>
|
||||
<Description>Various extensions for MarkDig and classes for working with Markdown.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.30.3"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,10 +1,11 @@
|
|||
using Markdig;
|
||||
using MfGames.Markdown.Gemtext;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class CodeInlineTests
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class HeaderTests
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class ImageLinkTests
|
||||
{
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using Markdig;
|
||||
using MfGames.Markdown.Gemtext;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class IncreaseHeaderDepthsAfterFirstTests
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class LinkTests
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class ListTests
|
||||
{
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>MfGames.Markdown.Gemini.Tests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MfGames.TestSetup" Version="1.0.6"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1"/>
|
||||
<PackageReference Include="JunitXml.TestLogger" Version="3.0.114"/>
|
||||
<PackageReference Include="xunit" Version="2.4.2"/>
|
||||
|
@ -21,6 +21,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\MfGames.Markdown.Gemtext\MfGames.Markdown.Gemtext.csproj"/>
|
||||
<ProjectReference Include="..\..\src\MfGames.Markdown\MfGames.Markdown.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using Markdig;
|
||||
using MfGames.Markdown.Gemtext;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests the various functionality of the ParagraphLinkHandling and
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class PlainTextTests
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
|
||||
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_base_url.py
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
|
||||
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_codeblock.py
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using MfGames.Markdown.Gemtext;
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
|
||||
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_list.py
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using Markdig;
|
||||
using MfGames.Markdown.Gemtext;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
|
||||
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
|
||||
{
|
||||
/// <summary>
|
||||
/// Runs through various plain input tests.
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
using Markdig;
|
||||
|
||||
using MfGames.Markdown.Gemtext;
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests.PythonInspired
|
||||
namespace MfGames.Markdown.Gemtext.Tests.PythonInspired
|
||||
{
|
||||
/// <summary>
|
||||
/// https://github.com/makeworld-the-better-one/md2gemini/blob/master/tests/test_strip_html.py
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using Markdig;
|
||||
using Markdig.Extensions.SmartyPants;
|
||||
using MfGames.Markdown.Gemtext;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class QuoteTests
|
||||
{
|
||||
|
|
|
@ -2,12 +2,11 @@ using ConsoleTableExt;
|
|||
|
||||
using Markdig;
|
||||
|
||||
using MfGames.Markdown.Gemtext;
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace MfGames.Markdown.Gemini.Tests
|
||||
namespace MfGames.Markdown.Gemtext.Tests
|
||||
{
|
||||
public class TableTests
|
||||
{
|
||||
|
|
56
tests/MfGames.Markdown.Gemtext.Tests/WikiLinkTests.cs
Normal file
56
tests/MfGames.Markdown.Gemtext.Tests/WikiLinkTests.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using Markdig;
|
||||
|
||||
using MfGames.Markdown.Extensions;
|
||||
using MfGames.Markdown.Gemtext.Extensions;
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
using MfGames.TestSetup;
|
||||
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests the functionality of the WriteFiles().
|
||||
/// </summary>
|
||||
public class WikiLinkTest : TestBase<TestContext>
|
||||
{
|
||||
public WikiLinkTest(ITestOutputHelper output)
|
||||
: base(output)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PossessiveLabeledWikiLinkGemtext()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = MarkdownGemtext
|
||||
.ToGemtext(
|
||||
"[[Test|Label]]'s",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("=> ^test$ Label's", result);
|
||||
}
|
||||
|
||||
private static MarkdownPipeline CreatePipeline()
|
||||
{
|
||||
// Convert all titles to slugs.
|
||||
WikiLinkOptions options = new()
|
||||
{
|
||||
GetUrl = (title) => string.Format(
|
||||
"^{0}$",
|
||||
title.ToLowerInvariant().Replace(" ", "-")),
|
||||
};
|
||||
|
||||
// Create the pipeline and return the results.
|
||||
MarkdownPipelineBuilder builder = new MarkdownPipelineBuilder()
|
||||
.Use(new WikiLinkExtension(options))
|
||||
.Use(new SetBlockLinkHandling(BlockLinkHandling.DocumentEnd));
|
||||
|
||||
// Build the pipeline and return it.
|
||||
MarkdownPipeline pipeline = builder.Build();
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
}
|
28
tests/MfGames.Markdown.Tests/MfGames.Markdown.Tests.csproj
Normal file
28
tests/MfGames.Markdown.Tests/MfGames.Markdown.Tests.csproj
Normal file
|
@ -0,0 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.30.3"/>
|
||||
<PackageReference Include="MfGames.TestSetup" Version="1.0.6"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1"/>
|
||||
<PackageReference Include="JunitXml.TestLogger" Version="3.0.114"/>
|
||||
<PackageReference Include="xunit" Version="2.4.2"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\MfGames.Markdown\MfGames.Markdown.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
188
tests/MfGames.Markdown.Tests/WikiLinkTests.cs
Normal file
188
tests/MfGames.Markdown.Tests/WikiLinkTests.cs
Normal file
|
@ -0,0 +1,188 @@
|
|||
using Markdig;
|
||||
|
||||
using MfGames.Markdown.Extensions;
|
||||
using MfGames.TestSetup;
|
||||
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace MfGames.Markdown.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests the functionality of the WriteFiles().
|
||||
/// </summary>
|
||||
public class WikiLinkTest : TestBase<TestContext>
|
||||
{
|
||||
public WikiLinkTest(ITestOutputHelper output)
|
||||
: base(output)
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BareStringHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown.ToHtml(
|
||||
"This is text.",
|
||||
pipeline);
|
||||
|
||||
Assert.Equal("<p>This is text.</p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BlankStringHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown.ToHtml(
|
||||
"",
|
||||
pipeline);
|
||||
|
||||
Assert.Equal("", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabeledWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test|Label]]",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Label</a></p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PossessiveLabeledWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test|Label]]'s",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Label's</a></p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PossessiveWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test]]'s",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Test's</a></p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PunctuationLabeledWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test|Label]].",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Label</a>.</p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PunctuationWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test]].",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Test</a>.</p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SentenceWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"This is a [[test]] of this system.",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal(
|
||||
"<p>This is a <a href=\"^test$\">test</a> of this system.</p>\n",
|
||||
result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SimpleWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test]]",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Test</a></p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StandardLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown.ToHtml(
|
||||
"[Test](https://test/)",
|
||||
pipeline);
|
||||
|
||||
Assert.Equal("<p><a href=\"https://test/\">Test</a></p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TrailingLabeledWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test|Label]]s",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Labels</a></p>\n", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TrailingWikiLinkHtml()
|
||||
{
|
||||
MarkdownPipeline pipeline = CreatePipeline();
|
||||
string result = Markdig.Markdown
|
||||
.ToHtml(
|
||||
"[[Test]]s",
|
||||
pipeline)
|
||||
.Replace("%5E", "^");
|
||||
|
||||
Assert.Equal("<p><a href=\"^test$\">Tests</a></p>\n", result);
|
||||
}
|
||||
|
||||
private static MarkdownPipeline CreatePipeline()
|
||||
{
|
||||
WikiLinkOptions options = new()
|
||||
{
|
||||
GetUrl = (title) => string.Format(
|
||||
"^{0}$",
|
||||
title.ToLowerInvariant().Replace(" ", "-")),
|
||||
};
|
||||
|
||||
MarkdownPipelineBuilder? builder = new MarkdownPipelineBuilder()
|
||||
.Use(new WikiLinkExtension(options));
|
||||
MarkdownPipeline? pipeline = builder.Build();
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
}
|
Reference in a new issue