Skip to content

Commit

Permalink
Added extensions configuration point and PlantUmlExtension
Browse files Browse the repository at this point in the history
  • Loading branch information
cjlotz committed Jan 2, 2024
1 parent 6b3b82c commit 96abf81
Show file tree
Hide file tree
Showing 20 changed files with 406 additions and 22 deletions.
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<PackageVersion Include="OneOf" Version="3.0.263" />
<PackageVersion Include="OneOf.SourceGenerator" Version="3.0.263" />
<PackageVersion Include="PdfPig" Version="0.1.9-alpha-20231119-4537e" />
<PackageVersion Include="PlantUml.Net" Version="1.4.80" />
<PackageVersion Include="Spectre.Console" Version="0.48.0" />
<PackageVersion Include="Spectre.Console.Cli" Version="0.48.0" />
<PackageVersion Include="Stubble.Core" Version="1.10.8" />
Expand All @@ -46,4 +47,4 @@
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.4" />
<PackageVersion Include="xunit" Version="2.6.2" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<ItemGroup>
<PackageReference Include="Markdig" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="PlantUml.Net" />
</ItemGroup>

</Project>
15 changes: 14 additions & 1 deletion src/Docfx.MarkdigEngine.Extensions/MarkdownContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ public class MarkdownContext
/// <returns>Image url bound to the path</returns>
public delegate string GetImageLinkDelegate(string path, MarkdownObject origin, string altText);

/// <summary>
/// Allows configuration of extensions
/// </summary>
/// <param name="extension">Name of the extension being configured</param>
public delegate IReadOnlyDictionary<string, string> GetExtensionConfigurationDelegate(string extension);

/// <summary>
/// Reads a file as text.
/// </summary>
Expand All @@ -51,6 +57,11 @@ public class MarkdownContext
/// </summary>
public GetImageLinkDelegate GetImageLink { get; }

/// <summary>
/// Get the configuration for a given extension
/// </summary>
public GetExtensionConfigurationDelegate GetExtensionConfiguration { get; }

/// <summary>
/// Log info
/// </summary>
Expand Down Expand Up @@ -86,12 +97,14 @@ public MarkdownContext(
LogActionDelegate logError = null,
ReadFileDelegate readFile = null,
GetLinkDelegate getLink = null,
GetImageLinkDelegate getImageLink = null)
GetImageLinkDelegate getImageLink = null,
GetExtensionConfigurationDelegate getConfig = null)
{
_getToken = getToken ?? (_ => null);
ReadFile = readFile ?? ((a, b) => (a, a));
GetLink = getLink ?? ((a, b) => a);
GetImageLink = getImageLink ?? ((a, b, c) => a);
GetExtensionConfiguration = getConfig ?? (_ => null);
LogInfo = logInfo ?? ((a, b, c, d) => { });
LogSuggestion = logSuggestion ?? ((a, b, c, d) => { });
LogWarning = logWarning ?? ((a, b, c, d) => { });
Expand Down
15 changes: 11 additions & 4 deletions src/Docfx.MarkdigEngine.Extensions/MarkdownExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Docfx.MarkdigEngine.Extensions;

public static class MarkdownExtensions
{
public static MarkdownPipelineBuilder UseDocfxExtensions(this MarkdownPipelineBuilder pipeline, MarkdownContext context, Dictionary<string, string> notes = null)
public static MarkdownPipelineBuilder UseDocfxExtensions(this MarkdownPipelineBuilder pipeline, MarkdownContext context)
{
return pipeline
.UseMathematics()
Expand All @@ -24,7 +24,7 @@ public static MarkdownPipelineBuilder UseDocfxExtensions(this MarkdownPipelineBu
.UseIncludeFile(context)
.UseCodeSnippet(context)
.UseDFMCodeInfoPrefix()
.UseQuoteSectionNote(context, notes)
.UseQuoteSectionNote(context)
.UseXref()
.UseEmojiAndSmiley(false)
.UseTabGroup(context)
Expand All @@ -35,6 +35,7 @@ public static MarkdownPipelineBuilder UseDocfxExtensions(this MarkdownPipelineBu
.UseTripleColon(context)
.UseNoloc()
.UseResolveLink(context)
.UsePlantUml(context)
.RemoveUnusedExtensions();
}

Expand Down Expand Up @@ -99,9 +100,9 @@ public static MarkdownPipelineBuilder UseDFMCodeInfoPrefix(this MarkdownPipeline
return pipeline;
}

public static MarkdownPipelineBuilder UseQuoteSectionNote(this MarkdownPipelineBuilder pipeline, MarkdownContext context, Dictionary<string, string> notes = null)
public static MarkdownPipelineBuilder UseQuoteSectionNote(this MarkdownPipelineBuilder pipeline, MarkdownContext context)
{
pipeline.Extensions.AddIfNotAlready(new QuoteSectionNoteExtension(context, notes));
pipeline.Extensions.AddIfNotAlready(new QuoteSectionNoteExtension(context));
return pipeline;
}

Expand All @@ -111,6 +112,12 @@ public static MarkdownPipelineBuilder UseLineNumber(this MarkdownPipelineBuilder
return pipeline;
}

public static MarkdownPipelineBuilder UsePlantUml(this MarkdownPipelineBuilder pipeline, MarkdownContext context)
{
pipeline.Extensions.AddIfNotAlready(new PlantUmlExtension(context));
return pipeline;
}

public static MarkdownPipelineBuilder UseResolveLink(this MarkdownPipelineBuilder pipeline, MarkdownContext context)
{
pipeline.Extensions.AddIfNotAlready(new ResolveLinkExtension(context));
Expand Down
41 changes: 41 additions & 0 deletions src/Docfx.MarkdigEngine.Extensions/PlantUml/FormatterFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using PlantUml.Net;

namespace Docfx.MarkdigEngine.Extensions;

internal class FormatterFactory
{
private readonly DocfxPlantUmlSettings settings;

private OutputFormat OutputFormat => settings.OutputFormat;

public FormatterFactory(DocfxPlantUmlSettings settings)
{
this.settings = settings;
}

internal IOutputFormatter CreateOutputFormatter()
{
switch (OutputFormat)
{
case OutputFormat.Svg:
return new SvgOutputFormatter();

case OutputFormat.Ascii:
return new AsciiOutputFormatter();

case OutputFormat.Ascii_Unicode:
return new AsciiUnicodeOutputFormatter();

case OutputFormat.Png:
case OutputFormat.Eps:
case OutputFormat.Pdf:
case OutputFormat.Vdx:
case OutputFormat.Xmi:
case OutputFormat.Scxml:
case OutputFormat.Html:
case OutputFormat.LaTeX:
default:
throw new NotSupportedException($"output format {OutputFormat} is not currently supported");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Docfx.MarkdigEngine.Extensions;

internal interface IOutputFormatter
{
string FormatOutput(byte[] output);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

using static System.Text.Encoding;

namespace Docfx.MarkdigEngine.Extensions;

internal class AsciiOutputFormatter : IOutputFormatter
{
public AsciiOutputFormatter()
{
}

public string FormatOutput(byte[] output)
{
string ascii = ASCII.GetString(output);
return $"<div class=\"lang-plantUml\"><pre>{ascii}</pre></div>";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

using static System.Text.Encoding;

namespace Docfx.MarkdigEngine.Extensions;

internal class AsciiUnicodeOutputFormatter : IOutputFormatter
{
public AsciiUnicodeOutputFormatter()
{
}

public string FormatOutput(byte[] output)
{
string ascii = UTF8.GetString(output);
return $"<div class=\"lang-plantUml\"><pre>{ascii}</pre></div>";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using static System.Text.Encoding;

namespace Docfx.MarkdigEngine.Extensions;

internal class SvgOutputFormatter : IOutputFormatter
{
public SvgOutputFormatter()
{
}

public string FormatOutput(byte[] output)
{
string svg = UTF8.GetString(output);
return $"<div class=\"lang-plantUml\">{svg}</div>";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Markdig.Renderers;
using Markdig.Syntax;
using Markdig.Renderers.Html;
using PlantUml.Net;

namespace Docfx.MarkdigEngine.Extensions;

/// <summary>
/// An HTML renderer for a <see cref="CodeBlock"/> and <see cref="FencedCodeBlock"/>.
/// </summary>
/// <seealso cref="HtmlObjectRenderer{CodeBlock}" />
public class CustomCodeBlockRenderer : CodeBlockRenderer
{
private readonly MarkdownContext _context;
private readonly DocfxPlantUmlSettings _settings;
private readonly RendererFactory rendererFactory;
private readonly FormatterFactory formatterFactory;

/// <summary>
/// Initializes a new instance of the <see cref="CodeBlockRenderer"/> class.
/// </summary>
/// <param name="context"></param>
/// <param name="settings"></param>
public CustomCodeBlockRenderer(MarkdownContext context, DocfxPlantUmlSettings settings)
{
_context = context;
_settings = settings;

rendererFactory = new RendererFactory();
formatterFactory = new FormatterFactory(settings);
}

protected override void Write(HtmlRenderer renderer, CodeBlock obj)
{
if (obj is FencedCodeBlock fencedCodeBlock
&& fencedCodeBlock.Info is string info
&& info.Equals("plantuml", StringComparison.OrdinalIgnoreCase))
{
IPlantUmlRenderer plantUmlRenderer = rendererFactory.CreateRenderer(_settings);
IOutputFormatter outputFormatter = formatterFactory.CreateOutputFormatter();

// Get PlantUML code.
var plantUmlCode = fencedCodeBlock.Lines.ToString();

byte[] output = plantUmlRenderer.Render(plantUmlCode, _settings.OutputFormat);

renderer.EnsureLine();
renderer.Write(outputFormatter.FormatOutput(output));
renderer.EnsureLine();

return;
}

// Fallback to default CodeBlockRenderer
base.Write(renderer, obj);
}
}
69 changes: 69 additions & 0 deletions src/Docfx.MarkdigEngine.Extensions/PlantUml/PlantUmlExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Markdig;
using Markdig.Renderers;
using Markdig.Renderers.Html;
using PlantUml.Net;

namespace Docfx.MarkdigEngine.Extensions;

public class DocfxPlantUmlSettings : PlantUmlSettings
{
public DocfxPlantUmlSettings() : base()
{
}

public DocfxPlantUmlSettings(IReadOnlyDictionary<string, string> config) : this()
{
if (config.TryGetValue("remoteUrl", out var url))
RemoteUrl = url;
if (config.TryGetValue("outputFormat", out var format))
OutputFormat = Enum.Parse<OutputFormat>(format, true);
if (config.TryGetValue("javaPath", out var path))
JavaPath = path;
if (config.TryGetValue("localPlantUmlPath", out path))
LocalPlantUmlPath = path;
if (config.TryGetValue("localGraphvizDotPath", out path))
LocalGraphvizDotPath = path;
if (config.TryGetValue("renderingMode", out var renderMode))
RenderingMode = Enum.Parse<RenderingMode>(renderMode, true);
}

public OutputFormat OutputFormat { get; set; } = OutputFormat.Svg;
}

internal class PlantUmlExtension : IMarkdownExtension
{
private readonly MarkdownContext _context;
private readonly DocfxPlantUmlSettings _settings;

public PlantUmlExtension(MarkdownContext context)
{
_context = context;
_settings = new();

var config = _context.GetExtensionConfiguration("PlantUml");
if (config != null)
_settings = new DocfxPlantUmlSettings(config);
}

public void Setup(MarkdownPipelineBuilder pipeline)
{
}

public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
if (renderer is HtmlRenderer { ObjectRenderers: not null } htmlRenderer)
{
var customRenderer = new CustomCodeBlockRenderer(_context, _settings);
var renderers = htmlRenderer.ObjectRenderers;

if (renderers.Contains<CodeBlockRenderer>())
{
renderers.InsertBefore<CodeBlockRenderer>(customRenderer);
}
else
{
renderers.AddIfNotAlready(customRenderer);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Json.Serialization;
using Markdig;
using Markdig.Parsers;
using Markdig.Renderers;
using Markdig.Renderers.Html;
using Newtonsoft.Json;

namespace Docfx.MarkdigEngine.Extensions;

Expand All @@ -20,13 +22,14 @@ public class QuoteSectionNoteExtension : IMarkdownExtension
["CAUTION"] = "CAUTION",
};

public QuoteSectionNoteExtension(MarkdownContext context, Dictionary<string, string> notes = null)
public QuoteSectionNoteExtension(MarkdownContext context)
{
_context = context;

if (notes != null)
var config = _context.GetExtensionConfiguration("Alerts");
if (config != null)
{
foreach (var (key, value) in notes)
foreach (var (key, value) in config)
_notes[key] = value;
}
}
Expand Down
Loading

0 comments on commit 96abf81

Please sign in to comment.