using System.Text; using System.Windows; using System.Windows.Documents; using ColorCode; using ColorCode.Styling; using ColorCode.Wpf; using Markdig.Parsers; using Markdig.Renderers; using Markdig.Renderers.Wpf; using Markdig.Syntax; #nullable enable namespace Markdig.Wpf.ColorCode; public class ColorCodeBlockRenderer : WpfObjectRenderer { private readonly CodeBlockRenderer _underlyingCodeBlockRenderer; private readonly StyleDictionary _styleDictionary; /// /// Create a new with the specified and . /// /// The underlying CodeBlockRenderer to handle unsupported languages. /// A StyleDictionary for custom styling. public ColorCodeBlockRenderer(CodeBlockRenderer underlyingCodeBlockRenderer, StyleDictionary styleDictionary) { _underlyingCodeBlockRenderer = underlyingCodeBlockRenderer; _styleDictionary = styleDictionary; } /// /// Writes the specified to the . /// /// The renderer. /// The code block to render. protected override void Write(WpfRenderer renderer, CodeBlock codeBlock) { if (codeBlock is not FencedCodeBlock fencedCodeBlock || codeBlock.Parser is not FencedCodeBlockParser fencedCodeBlockParser) { _underlyingCodeBlockRenderer.Write(renderer, codeBlock); return; } var language = ExtractLanguage(fencedCodeBlock, fencedCodeBlockParser); if (language is null) { _underlyingCodeBlockRenderer.Write(renderer, codeBlock); return; } var code = ExtractCode(codeBlock); var formatter = new RichTextBoxFormatter(_styleDictionary); var paragraph = new Paragraph(); paragraph.SetResourceReference(FrameworkContentElement.StyleProperty, Styles.CodeBlockStyleKey); formatter.FormatInlines(code, language, paragraph.Inlines); renderer.WriteBlock(paragraph); } private static ILanguage? ExtractLanguage(IFencedBlock fencedCodeBlock, FencedCodeBlockParser parser) { var languageId = fencedCodeBlock.Info!.Replace(parser.InfoPrefix!, string.Empty); return string.IsNullOrWhiteSpace(languageId) ? null : Languages.FindById(languageId); } private static string ExtractCode(LeafBlock leafBlock) { var code = new StringBuilder(); var lines = leafBlock.Lines.Lines; //var totalLines = lines.Length; var totalLines = lines == null ? 0 : lines.Length; for (var index = 0; index < totalLines; index++) { var line = lines[index]; var slice = line.Slice; if (slice.Text == null) { continue; } var lineText = slice.Text.Substring(slice.Start, slice.Length); if (index > 0) { code.AppendLine(); } code.Append(lineText); } return code.ToString(); } }