A couple years ago I decided to stop using Windows Live Writer for authoring blog posts and build my own publishing tools using markdown and VSCode. Live Writer was a fantastic tool during its heyday, but some features started to feel cumbersome. Adding code into a blog post, as one example.
This blog uses SyntaxHighlighter to render code blocks, which requires HTML in a specific format. With WLW the HTML formatting required a toggle into HTML mode, or using an extension which was no longer supported in the OSS version of WLW.
What I really wanted was to author a post in markdown and use simple code fences to place code into a post.
``` csharp
public void AnOdeToCode()
{
}
```
Simple!
All I'd need is a markdown processor that would allow me to add some custom rendering for code fences.
Markdig is a fast, powerful, CommonMark compliant, extensible Markdown processor for .NET. Thanks to Rick Strahl for bringing the library to my attention. I use Markdig in my tools to transform a markdown file into HTML for posting here on the site.
There are at least a couple different techniques you can use to write an extension for Markdig. What I needed was an extension point to render SyntaxHighlighter flavored HTML for every code fence in a post. With Markdig, this means adding an HtmlOBjectRenderer into the processing pipeline.
public class PreCodeRenderer : HtmlObjectRenderer<CodeBlock>
{
private CodeBlockRenderer originalCodeBlockRenderer;
public PreCodeRenderer(CodeBlockRenderer originalCodeBlockRenderer = null)
{
this.originalCodeBlockRenderer = originalCodeBlockRenderer ?? new CodeBlockRenderer();
}
public bool OutputAttributesOnPre { get; set; }
protected override void Write(HtmlRenderer renderer, CodeBlock obj)
{
renderer.EnsureLine();
var fencedCodeBlock = obj as FencedCodeBlock;
if (fencedCodeBlock?.Info != null)
{
renderer.Write($"<pre class=\"brush: {fencedCodeBlock.Info}; gutter: false; toolbar: false; \">");
renderer.EnsureLine();
renderer.WriteLeafRawLines(obj, true, true);
renderer.WriteLine("</pre>");
}
else
{
originalCodeBlockRenderer.Write(renderer, obj);
}
}
}
Note that the Info property of a FencedCodeBlock will contain the info string, which is commonly used to specify the language of the code (csharp, xml, javascript, plain, go). The renderer builds a pre tag that SyntaxHighlighter will know how to use. The last step, the easy step, is to add PerCodeRenderer into a MarkdownPipelineBuilder before telling Markdig to process your markdown.
OdeToCode by K. Scott Allen