An IMarkdownPlugin is a composition boundary. Its single Register method adds one or more focused capabilities to MarkdownPluginRegistry.
using ProMarkdown.Services;
public sealed class ProductMarkdownPlugin : IMarkdownPlugin
{
public void Register(MarkdownPluginRegistry registry)
{
ArgumentNullException.ThrowIfNull(registry);
registry
.AddParserPlugin(new ProductParserPlugin())
.AddBlockRenderingPlugin(new ProductBlockRenderer())
.AddInlineRenderingPlugin(new ProductInlineRenderer())
.AddBlockTemplateProvider(new ProductTemplateProvider())
.AddEditorPlugin(new ProductEditorPlugin());
}
}
A plugin does not need to implement every category. Keep parsing, rendering, editing, and template logic in separate classes so each can be tested and ordered independently.
| Registration method | Contract | Responsibility |
|---|---|---|
AddParserPlugin |
IMarkdownParserPlugin |
Configure Markdig and optionally transform source. |
AddBlockRenderingPlugin |
IMarkdownBlockRenderingPlugin |
Render a block AST node as native Avalonia content. |
AddInlineRenderingPlugin |
IMarkdownInlineRenderingPlugin |
Render an inline AST node as an inline or embedded control. |
AddEditorPlugin |
IMarkdownEditorPlugin |
Resolve source-mapped nodes and create an editor control. |
AddBlockTemplateProvider |
IMarkdownBlockTemplateProvider |
Supply insert-before/after templates to editors. |
AddPlugin |
IMarkdownPlugin |
Invoke another composite plugin's registration. |
All registration methods reject null and return the registry, so fluent registration is safe.
Each focused contract has an Order property with a default value of zero. Lower values run first.
Return false from a renderer when it cannot produce a result so later plugins or the core renderer can handle the node. Use a negative order only when the extension must precede built-in or general fallback behavior.
Pass the plugin to the controller and editing service:
IMarkdownPlugin[] plugins = [new ProductMarkdownPlugin()];
markdownView.RenderController = MarkdownRenderingServices.CreateController(plugins);
markdownView.EditingService = MarkdownRenderingServices.CreateEditingService(plugins);
The factory adds core editor plugins and the thematic-break renderer before registering your list. It then builds immutable ordered service collections. Reuse those services rather than rebuilding them for each document.
IsCurrentRender() before publishing delayed render results.BaseUri behavior stays consistent.