From 9f6902d2dbe3f3b26b220c356a42803bbe7914f0 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 3 Jun 2025 16:59:30 +0200 Subject: [PATCH] Remove [CONTENT] markers and replace with better inline rendering method --- Directory.Packages.props | 2 +- .../DocumentationObjectPoolProvider.cs | 73 ++++++++++ .../Helpers/ReusableStringWriter.cs | 135 ++++++++++++++++++ src/Elastic.Markdown/IO/MarkdownFile.cs | 2 +- .../EnhancedCodeBlockHtmlRenderer.cs | 20 +-- .../Myst/Directives/DirectiveHtmlRenderer.cs | 94 ++++++------ .../Directives/DirectiveMarkdownExtension.cs | 8 +- .../Myst/Directives/IncludeBlock.cs | 1 + src/Elastic.Markdown/Myst/MarkdownParser.cs | 69 ++++----- .../Slices/Directives/Admonition.cshtml | 4 +- .../Slices/Directives/Code.cshtml | 2 +- .../Slices/Directives/Dropdown.cshtml | 2 +- .../Slices/Directives/Figure.cshtml | 2 +- .../Slices/Directives/Image.cshtml | 2 +- .../Slices/Directives/Step.cshtml | 2 +- .../Slices/Directives/Stepper.cshtml | 2 +- .../Slices/Directives/TabItem.cshtml | 2 +- .../Slices/Directives/TabSet.cshtml | 2 +- .../Slices/Directives/Version.cshtml | 3 +- .../Slices/Directives/_ViewModels.cs | 56 ++++++-- src/Elastic.Markdown/Slices/HtmlWriter.cs | 2 +- .../Directives/DirectiveBaseTests.cs | 2 +- .../Inline/InlneBaseTests.cs | 2 +- tests/authoring/Blocks/Admonitions.fs | 8 +- 24 files changed, 363 insertions(+), 134 deletions(-) create mode 100644 src/Elastic.Markdown/Helpers/DocumentationObjectPoolProvider.cs create mode 100644 src/Elastic.Markdown/Helpers/ReusableStringWriter.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 7efb7dacc..b42466577 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -40,7 +40,7 @@ - + diff --git a/src/Elastic.Markdown/Helpers/DocumentationObjectPoolProvider.cs b/src/Elastic.Markdown/Helpers/DocumentationObjectPoolProvider.cs new file mode 100644 index 000000000..ba774b949 --- /dev/null +++ b/src/Elastic.Markdown/Helpers/DocumentationObjectPoolProvider.cs @@ -0,0 +1,73 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Text; +using Elastic.Markdown.Myst; +using Markdig.Renderers; +using Microsoft.Extensions.ObjectPool; + +namespace Elastic.Markdown.Helpers; + +internal static class DocumentationObjectPoolProvider +{ + private static readonly ObjectPoolProvider PoolProvider = new DefaultObjectPoolProvider(); + + public static readonly ObjectPool StringBuilderPool = PoolProvider.CreateStringBuilderPool(256, 4 * 1024); + public static readonly ObjectPool StringWriterPool = PoolProvider.Create(new ReusableStringWriterPooledObjectPolicy()); + public static readonly ObjectPool HtmlRendererPool = PoolProvider.Create(new HtmlRendererPooledObjectPolicy()); + + + private sealed class ReusableStringWriterPooledObjectPolicy : IPooledObjectPolicy + { + public ReusableStringWriter Create() => new(); + + public bool Return(ReusableStringWriter obj) + { + obj.Reset(); + return true; + } + } + + public sealed class HtmlRenderSubscription + { + public required HtmlRenderer HtmlRenderer { get; init; } + public StringBuilder? RentedStringBuilder { get; internal set; } + } + + private sealed class HtmlRendererPooledObjectPolicy : IPooledObjectPolicy + { + public HtmlRenderSubscription Create() + { + var stringBuilder = StringBuilderPool.Get(); + using var stringWriter = StringWriterPool.Get(); + stringWriter.SetStringBuilder(stringBuilder); + var renderer = new HtmlRenderer(stringWriter); + MarkdownParser.Pipeline.Setup(renderer); + + return new HtmlRenderSubscription { HtmlRenderer = renderer, RentedStringBuilder = stringBuilder }; + } + + public bool Return(HtmlRenderSubscription subscription) + { + //subscription.RentedStringBuilder = null; + //return string builder + if (subscription.RentedStringBuilder is not null) + StringBuilderPool.Return(subscription.RentedStringBuilder); + + subscription.RentedStringBuilder = null; + + var renderer = subscription.HtmlRenderer; + + //reset string writer + ((ReusableStringWriter)renderer.Writer).Reset(); + + // reseed string writer with string builder + var stringBuilder = StringBuilderPool.Get(); + subscription.RentedStringBuilder = stringBuilder; + ((ReusableStringWriter)renderer.Writer).SetStringBuilder(stringBuilder); + return true; + } + } + +} diff --git a/src/Elastic.Markdown/Helpers/ReusableStringWriter.cs b/src/Elastic.Markdown/Helpers/ReusableStringWriter.cs new file mode 100644 index 000000000..c3749064f --- /dev/null +++ b/src/Elastic.Markdown/Helpers/ReusableStringWriter.cs @@ -0,0 +1,135 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Text; + +namespace Elastic.Markdown.Helpers; + +internal sealed class ReusableStringWriter : TextWriter +{ + private static UnicodeEncoding? CurrentEncoding; + + private StringBuilder? _sb; + + public override Encoding Encoding => CurrentEncoding ??= new UnicodeEncoding(false, false); + + public void SetStringBuilder(StringBuilder sb) => _sb = sb; + + public void Reset() => _sb = null; + + public override void Write(char value) => _sb?.Append(value); + + public override void Write(char[] buffer, int index, int count) + { + ArgumentNullException.ThrowIfNull(buffer); + ArgumentOutOfRangeException.ThrowIfNegative(index); + ArgumentOutOfRangeException.ThrowIfNegative(count); + + if (buffer.Length - index < count) + throw new ArgumentException("Out of range"); + + _ = _sb?.Append(buffer, index, count); + } + + public override void Write(ReadOnlySpan buffer) => _sb?.Append(buffer); + + public override void Write(string? value) + { + if (value is not null) + _ = _sb?.Append(value); + } + + public override void Write(StringBuilder? value) => _sb?.Append(value); + + public override void WriteLine(ReadOnlySpan buffer) + { + _ = _sb?.Append(buffer); + WriteLine(); + } + + public override void WriteLine(StringBuilder? value) + { + _ = _sb?.Append(value); + WriteLine(); + } + + #region Task based Async APIs + + public override Task WriteAsync(char value) + { + Write(value); + return Task.CompletedTask; + } + + public override Task WriteAsync(string? value) + { + Write(value); + return Task.CompletedTask; + } + + public override Task WriteAsync(char[] buffer, int index, int count) + { + Write(buffer, index, count); + return Task.CompletedTask; + } + + public override Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + if (cancellationToken.IsCancellationRequested) + return Task.FromCanceled(cancellationToken); + + Write(buffer.Span); + return Task.CompletedTask; + } + + public override Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken = default) + { + if (cancellationToken.IsCancellationRequested) + return Task.FromCanceled(cancellationToken); + + _ = _sb?.Append(value); + return Task.CompletedTask; + } + + public override Task WriteLineAsync(char value) + { + WriteLine(value); + return Task.CompletedTask; + } + + public override Task WriteLineAsync(string? value) + { + WriteLine(value); + return Task.CompletedTask; + } + + public override Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken = default) + { + if (cancellationToken.IsCancellationRequested) + return Task.FromCanceled(cancellationToken); + + _ = _sb?.Append(value); + WriteLine(); + return Task.CompletedTask; + } + + public override Task WriteLineAsync(char[] buffer, int index, int count) + { + WriteLine(buffer, index, count); + return Task.CompletedTask; + } + + public override Task WriteLineAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + if (cancellationToken.IsCancellationRequested) + return Task.FromCanceled(cancellationToken); + + WriteLine(buffer.Span); + return Task.CompletedTask; + } + + public override Task FlushAsync() => Task.CompletedTask; + + #endregion +} diff --git a/src/Elastic.Markdown/IO/MarkdownFile.cs b/src/Elastic.Markdown/IO/MarkdownFile.cs index 3c533824e..ae33d71bd 100644 --- a/src/Elastic.Markdown/IO/MarkdownFile.cs +++ b/src/Elastic.Markdown/IO/MarkdownFile.cs @@ -354,7 +354,7 @@ private YamlFrontMatter ReadYamlFrontMatter(string raw) } } - public string CreateHtml(MarkdownDocument document) + public static string CreateHtml(MarkdownDocument document) { //we manually render title and optionally append an applies block embedded in yaml front matter. var h1 = document.Descendants().FirstOrDefault(h => h.Level == 1); diff --git a/src/Elastic.Markdown/Myst/CodeBlocks/EnhancedCodeBlockHtmlRenderer.cs b/src/Elastic.Markdown/Myst/CodeBlocks/EnhancedCodeBlockHtmlRenderer.cs index 8b697f71d..40fdd26e6 100644 --- a/src/Elastic.Markdown/Myst/CodeBlocks/EnhancedCodeBlockHtmlRenderer.cs +++ b/src/Elastic.Markdown/Myst/CodeBlocks/EnhancedCodeBlockHtmlRenderer.cs @@ -20,20 +20,14 @@ public class EnhancedCodeBlockHtmlRenderer : HtmlObjectRenderer(RazorSlice slice, HtmlRenderer renderer, EnhancedCodeBlock block) - { - var html = slice.RenderAsync().GetAwaiter().GetResult(); - var blocks = html.Split("[CONTENT]", 2, StringSplitOptions.RemoveEmptyEntries); - _ = renderer.Write(blocks[0]); - RenderCodeBlockLines(renderer, block); - _ = renderer.Write(blocks[1]); - } + private static void RenderRazorSlice(RazorSlice slice, HtmlRenderer renderer) => + slice.RenderAsync(renderer.Writer).GetAwaiter().GetResult(); /// /// Renders the code block lines while also removing the common indentation level. /// Required because EnableTrackTrivia preserves extra indentation. /// - private static void RenderCodeBlockLines(HtmlRenderer renderer, EnhancedCodeBlock block) + public static void RenderCodeBlockLines(HtmlRenderer renderer, EnhancedCodeBlock block) { var commonIndent = GetCommonIndent(block); var hasCode = false; @@ -134,10 +128,11 @@ protected override void Write(HtmlRenderer renderer, EnhancedCodeBlock block) CrossReferenceName = string.Empty,// block.CrossReferenceName, Language = block.Language, Caption = block.Caption, - ApiCallHeader = block.ApiCallHeader + ApiCallHeader = block.ApiCallHeader, + EnhancedCodeBlock = block }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); if (!block.InlineAnnotations && callOuts.Count > 0) { var index = block.Parent!.IndexOf(block); @@ -240,7 +235,6 @@ private static void RenderAppliesToHtml(HtmlRenderer renderer, AppliesToDirectiv var slice = ApplicableToDirective.Create(appliesTo); if (appliesTo is null || appliesTo == FrontMatter.ApplicableTo.All) return; - var html = slice.RenderAsync().GetAwaiter().GetResult(); - _ = renderer.Write(html); + slice.RenderAsync(renderer.Writer).GetAwaiter().GetResult(); } } diff --git a/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs b/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs index 66f01d151..6721ac15a 100644 --- a/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs +++ b/src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using Elastic.Markdown.Diagnostics; -using Elastic.Markdown.Myst.InlineParsers; using Elastic.Markdown.Myst.InlineParsers.Substitution; using Elastic.Markdown.Myst.Settings; using Elastic.Markdown.Slices.Directives; @@ -22,7 +21,7 @@ namespace Elastic.Markdown.Myst.Directives; /// An HTML renderer for a . /// /// -public class DirectiveHtmlRenderer(MarkdownParser markdownParser) : HtmlObjectRenderer +public class DirectiveHtmlRenderer : HtmlObjectRenderer { protected override void Write(HtmlRenderer renderer, DirectiveBlock directiveBlock) { @@ -61,16 +60,16 @@ protected override void Write(HtmlRenderer renderer, DirectiveBlock directiveBlo if (includeBlock.Literal) WriteLiteralIncludeBlock(renderer, includeBlock); else - WriteIncludeBlock(renderer, includeBlock, markdownParser); + WriteIncludeBlock(renderer, includeBlock); return; case SettingsBlock settingsBlock: - WriteSettingsBlock(renderer, settingsBlock, markdownParser); + WriteSettingsBlock(renderer, settingsBlock); return; case StepperBlock stepperBlock: - WriteStepperBlock(renderer, stepperBlock, markdownParser); + WriteStepperBlock(renderer, stepperBlock); return; case StepBlock stepBlock: - WriteStepBlock(renderer, stepBlock, markdownParser); + WriteStepBlock(renderer, stepBlock); return; default: // if (!string.IsNullOrEmpty(directiveBlock.Info) && !directiveBlock.Info.StartsWith('{')) @@ -89,6 +88,7 @@ private static void WriteImage(HtmlRenderer renderer, ImageBlock block) var slice = Image.Create(new ImageViewModel { + DirectiveBlock = block, Label = block.Label, Align = block.Align, Alt = block.Alt ?? string.Empty, @@ -100,23 +100,24 @@ private static void WriteImage(HtmlRenderer renderer, ImageBlock block) Screenshot = block.Screenshot, ImageUrl = imageUrl, }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); } - private static void WriteStepperBlock(HtmlRenderer renderer, StepperBlock block, MarkdownParser _) + private static void WriteStepperBlock(HtmlRenderer renderer, StepperBlock block) { - var slice = Stepper.Create(new StepperViewModel()); - RenderRazorSlice(slice, renderer, block); + var slice = Stepper.Create(new StepperViewModel { DirectiveBlock = block }); + RenderRazorSlice(slice, renderer); } - private static void WriteStepBlock(HtmlRenderer renderer, StepBlock block, MarkdownParser _) + private static void WriteStepBlock(HtmlRenderer renderer, StepBlock block) { var slice = Step.Create(new StepViewModel { + DirectiveBlock = block, Title = block.Title, Anchor = block.Anchor }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); } private static void WriteFigure(HtmlRenderer renderer, ImageBlock block) @@ -127,6 +128,7 @@ private static void WriteFigure(HtmlRenderer renderer, ImageBlock block) : block.ImageUrl; var slice = Figure.Create(new ImageViewModel { + DirectiveBlock = block, Label = block.Label, Align = block.Align, Alt = block.Alt ?? string.Empty, @@ -138,7 +140,7 @@ private static void WriteFigure(HtmlRenderer renderer, ImageBlock block) Screenshot = block.Screenshot, ImageUrl = imageUrl, }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); } private static void WriteChildren(HtmlRenderer renderer, DirectiveBlock directiveBlock) => @@ -148,61 +150,65 @@ private static void WriteVersion(HtmlRenderer renderer, VersionBlock block) { var slice = Slices.Directives.Version.Create(new VersionViewModel { + DirectiveBlock = block, Directive = block.Directive, Title = block.Title, VersionClass = block.Class }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); } private static void WriteAdmonition(HtmlRenderer renderer, AdmonitionBlock block) { var slice = Admonition.Create(new AdmonitionViewModel { + DirectiveBlock = block, Directive = block.Admonition, CrossReferenceName = block.CrossReferenceName, Classes = block.Classes, Title = block.Title, Open = block.DropdownOpen.GetValueOrDefault() ? "open" : null }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); } private static void WriteDropdown(HtmlRenderer renderer, DropdownBlock block) { var slice = Dropdown.Create(new AdmonitionViewModel { + DirectiveBlock = block, Directive = block.Admonition, CrossReferenceName = block.CrossReferenceName, Classes = block.Classes, Title = block.Title, Open = block.DropdownOpen.GetValueOrDefault() ? "open" : null }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); } private static void WriteTabSet(HtmlRenderer renderer, TabSetBlock block) { - var slice = TabSet.Create(new TabSetViewModel()); - RenderRazorSlice(slice, renderer, block); + var slice = TabSet.Create(new TabSetViewModel { DirectiveBlock = block }); + RenderRazorSlice(slice, renderer); } private static void WriteTabItem(HtmlRenderer renderer, TabItemBlock block) { var slice = TabItem.Create(new TabItemViewModel { + DirectiveBlock = block, Index = block.Index, Title = block.Title, TabSetIndex = block.TabSetIndex, SyncKey = block.SyncKey, TabSetGroupKey = block.TabSetGroupKey }); - RenderRazorSlice(slice, renderer, block); + RenderRazorSlice(slice, renderer); } private static void WriteMermaid(HtmlRenderer renderer, MermaidBlock block) { - var slice = Mermaid.Create(new MermaidViewModel()); + var slice = Mermaid.Create(new MermaidViewModel { DirectiveBlock = block }); RenderRazorSliceRawContent(slice, renderer, block); } @@ -222,13 +228,14 @@ private static void WriteLiteralIncludeBlock(HtmlRenderer renderer, IncludeBlock CrossReferenceName = null, Language = block.Language, Caption = null, - ApiCallHeader = null + ApiCallHeader = null, + RawIncludedFileContents = content }); - RenderRazorSlice(slice, renderer, content); + RenderRazorSlice(slice, renderer); } } - private static void WriteIncludeBlock(HtmlRenderer renderer, IncludeBlock block, MarkdownParser parser) + private static void WriteIncludeBlock(HtmlRenderer renderer, IncludeBlock block) { if (!block.Found || block.IncludePath is null) return; @@ -236,13 +243,15 @@ private static void WriteIncludeBlock(HtmlRenderer renderer, IncludeBlock block, var snippet = block.Build.ReadFileSystem.FileInfo.New(block.IncludePath); var parentPath = block.Context.MarkdownParentPath ?? block.Context.MarkdownSourcePath; - var document = parser.ParseSnippetAsync(snippet, parentPath, block.Context.YamlFrontMatter, default).GetAwaiter().GetResult(); + var document = MarkdownParser.ParseSnippetAsync(block.Build, block.Context, snippet, parentPath, block.Context.YamlFrontMatter, default) + .GetAwaiter().GetResult(); - var html = document.ToHtml(parser.Pipeline); + var html = document.ToHtml(MarkdownParser.Pipeline); _ = renderer.Write(html); } - private static void WriteSettingsBlock(HtmlRenderer renderer, SettingsBlock block, MarkdownParser parser) + [SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly")] + private static void WriteSettingsBlock(HtmlRenderer renderer, SettingsBlock block) { if (!block.Found || block.IncludePath is null) return; @@ -270,44 +279,21 @@ private static void WriteSettingsBlock(HtmlRenderer renderer, SettingsBlock bloc SettingsCollection = settings, RenderMarkdown = s => { - var document = parser.ParseStringAsync(s, block.IncludeFrom, block.Context.YamlFrontMatter); - var html = document.ToHtml(parser.Pipeline); + var document = MarkdownParser.ParseMarkdownStringAsync(block.Build, block.Context, s, block.IncludeFrom, block.Context.YamlFrontMatter, MarkdownParser.Pipeline); + var html = document.ToHtml(MarkdownParser.Pipeline); return html; } }); - RenderRazorSliceNoContent(slice, renderer); - } - - [SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly")] - private static void RenderRazorSlice(RazorSlice slice, HtmlRenderer renderer, string contents) - { var html = slice.RenderAsync().GetAwaiter().GetResult(); - var blocks = html.Split("[CONTENT]", 2, StringSplitOptions.RemoveEmptyEntries); - _ = renderer - .Write(blocks[0]) - .Write(contents) - .Write(blocks[1]); - } - - [SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly")] - private static void RenderRazorSlice(RazorSlice slice, HtmlRenderer renderer, DirectiveBlock obj) - { - var html = slice.RenderAsync().GetAwaiter().GetResult(); - var blocks = html.Split("[CONTENT]", 2, StringSplitOptions.RemoveEmptyEntries); - _ = renderer.Write(blocks[0]); - renderer.WriteChildren(obj); - _ = renderer.Write(blocks[1]); + _ = renderer.Write(html); } [SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly")] - private static void RenderRazorSliceNoContent(RazorSlice slice, HtmlRenderer renderer) - { - var html = slice.RenderAsync().GetAwaiter().GetResult(); - _ = renderer.Write(html); - } + private static void RenderRazorSlice(RazorSlice slice, HtmlRenderer renderer) => slice.RenderAsync(renderer.Writer).GetAwaiter().GetResult(); [SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly")] private static void RenderRazorSliceRawContent(RazorSlice slice, HtmlRenderer renderer, DirectiveBlock obj) + where T : DirectiveViewModel { var html = slice.RenderAsync().GetAwaiter().GetResult(); var blocks = html.Split("[CONTENT]", 2, StringSplitOptions.RemoveEmptyEntries); diff --git a/src/Elastic.Markdown/Myst/Directives/DirectiveMarkdownExtension.cs b/src/Elastic.Markdown/Myst/Directives/DirectiveMarkdownExtension.cs index c4246baa6..bf3f3875c 100644 --- a/src/Elastic.Markdown/Myst/Directives/DirectiveMarkdownExtension.cs +++ b/src/Elastic.Markdown/Myst/Directives/DirectiveMarkdownExtension.cs @@ -13,9 +13,9 @@ namespace Elastic.Markdown.Myst.Directives; public static class DirectiveMarkdownBuilderExtensions { - public static MarkdownPipelineBuilder UseDirectives(this MarkdownPipelineBuilder pipeline, MarkdownParser markdownParser) + public static MarkdownPipelineBuilder UseDirectives(this MarkdownPipelineBuilder pipeline) { - pipeline.Extensions.AddIfNotAlready(new DirectiveMarkdownExtension(markdownParser)); + pipeline.Extensions.AddIfNotAlready(new DirectiveMarkdownExtension()); return pipeline; } } @@ -24,7 +24,7 @@ public static MarkdownPipelineBuilder UseDirectives(this MarkdownPipelineBuilder /// Extension to allow custom containers. /// /// -public class DirectiveMarkdownExtension(MarkdownParser markdownParser) : IMarkdownExtension +public class DirectiveMarkdownExtension() : IMarkdownExtension { public void Setup(MarkdownPipelineBuilder pipeline) { @@ -53,7 +53,7 @@ public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) if (!renderer.ObjectRenderers.Contains()) { // Must be inserted before CodeBlockRenderer - _ = renderer.ObjectRenderers.InsertBefore(new DirectiveHtmlRenderer(markdownParser)); + _ = renderer.ObjectRenderers.InsertBefore(new DirectiveHtmlRenderer()); } _ = renderer.ObjectRenderers.Replace(new SectionedHeadingRenderer()); diff --git a/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs b/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs index 9afddc444..82d4fcbbd 100644 --- a/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/IncludeBlock.cs @@ -83,4 +83,5 @@ private void ExtractInclusionPath(ParserContext context) Found = false; } } + } diff --git a/src/Elastic.Markdown/Myst/MarkdownParser.cs b/src/Elastic.Markdown/Myst/MarkdownParser.cs index 8fb336545..48ee7cecf 100644 --- a/src/Elastic.Markdown/Myst/MarkdownParser.cs +++ b/src/Elastic.Markdown/Myst/MarkdownParser.cs @@ -53,40 +53,45 @@ private Task ParseFromFile( return ParseAsync(path, context, pipeline, ctx); } - public Task ParseSnippetAsync(IFileInfo path, IFileInfo parentPath, YamlFrontMatter? matter, Cancel ctx) - { - var state = new ParserState(Build) - { - MarkdownSourcePath = path, - YamlFrontMatter = matter, - DocumentationFileLookup = Resolvers.DocumentationFileLookup, - CrossLinkResolver = Resolvers.CrossLinkResolver, - ParentMarkdownPath = parentPath - }; - var context = new ParserContext(state); - return ParseAsync(path, context, Pipeline, ctx); - } - public MarkdownDocument ParseStringAsync(string markdown, IFileInfo path, YamlFrontMatter? matter) => ParseMarkdownStringAsync(markdown, path, matter, Pipeline); public MarkdownDocument MinimalParseStringAsync(string markdown, IFileInfo path, YamlFrontMatter? matter) => ParseMarkdownStringAsync(markdown, path, matter, MinimalPipeline); - private MarkdownDocument ParseMarkdownStringAsync(string markdown, IFileInfo path, YamlFrontMatter? matter, MarkdownPipeline pipeline) + private MarkdownDocument ParseMarkdownStringAsync(string markdown, IFileInfo path, YamlFrontMatter? matter, MarkdownPipeline pipeline) => + ParseMarkdownStringAsync(Build, Resolvers, markdown, path, matter, pipeline); + + public static MarkdownDocument ParseMarkdownStringAsync(BuildContext build, IParserResolvers resolvers, string markdown, IFileInfo path, YamlFrontMatter? matter, MarkdownPipeline pipeline) { - var state = new ParserState(Build) + var state = new ParserState(build) { MarkdownSourcePath = path, YamlFrontMatter = matter, - DocumentationFileLookup = Resolvers.DocumentationFileLookup, - CrossLinkResolver = Resolvers.CrossLinkResolver + DocumentationFileLookup = resolvers.DocumentationFileLookup, + CrossLinkResolver = resolvers.CrossLinkResolver }; var context = new ParserContext(state); var markdownDocument = Markdig.Markdown.Parse(markdown, pipeline, context); return markdownDocument; } + public static Task ParseSnippetAsync(BuildContext build, IParserResolvers resolvers, IFileInfo path, IFileInfo parentPath, + YamlFrontMatter? matter, Cancel ctx) + { + var state = new ParserState(build) + { + MarkdownSourcePath = path, + YamlFrontMatter = matter, + DocumentationFileLookup = resolvers.DocumentationFileLookup, + CrossLinkResolver = resolvers.CrossLinkResolver, + ParentMarkdownPath = parentPath + }; + var context = new ParserContext(state); + return ParseAsync(path, context, Pipeline, ctx); + } + + private static async Task ParseAsync( IFileInfo path, MarkdownParserContext context, @@ -108,35 +113,35 @@ private static async Task ParseAsync( } // ReSharper disable once InconsistentNaming - private MarkdownPipeline? _minimalPipelineCached; + private static MarkdownPipeline? MinimalPipelineCached; - private MarkdownPipeline MinimalPipeline + private static MarkdownPipeline MinimalPipeline { get { - if (_minimalPipelineCached is not null) - return _minimalPipelineCached; + if (MinimalPipelineCached is not null) + return MinimalPipelineCached; var builder = new MarkdownPipelineBuilder() .UseYamlFrontMatter() .UseInlineAnchors() .UseHeadingsWithSlugs() - .UseDirectives(this); + .UseDirectives(); _ = builder.BlockParsers.TryRemove(); - _minimalPipelineCached = builder.Build(); - return _minimalPipelineCached; + MinimalPipelineCached = builder.Build(); + return MinimalPipelineCached; } } // ReSharper disable once InconsistentNaming - private MarkdownPipeline? _pipelineCached; + private static MarkdownPipeline? PipelineCached; - public MarkdownPipeline Pipeline + public static MarkdownPipeline Pipeline { get { - if (_pipelineCached is not null) - return _pipelineCached; + if (PipelineCached is not null) + return PipelineCached; var builder = new MarkdownPipelineBuilder() .UseInlineAnchors() @@ -150,7 +155,7 @@ public MarkdownPipeline Pipeline .UseYamlFrontMatter() .UseGridTables() .UsePipeTables() - .UseDirectives(this) + .UseDirectives() .UseDefinitionLists() .UseEnhancedCodeBlocks() .UseHtmxLinkInlineRenderer() @@ -158,8 +163,8 @@ public MarkdownPipeline Pipeline .UseWhiteSpaceNormalizer() .UseHardBreaks(); _ = builder.BlockParsers.TryRemove(); - _pipelineCached = builder.Build(); - return _pipelineCached; + PipelineCached = builder.Build(); + return PipelineCached; } } } diff --git a/src/Elastic.Markdown/Slices/Directives/Admonition.cshtml b/src/Elastic.Markdown/Slices/Directives/Admonition.cshtml index 17c1c6539..f46c90c0b 100644 --- a/src/Elastic.Markdown/Slices/Directives/Admonition.cshtml +++ b/src/Elastic.Markdown/Slices/Directives/Admonition.cshtml @@ -34,7 +34,5 @@ } @Model.Title -
- [CONTENT] -
+
@Model.RenderBlock()
diff --git a/src/Elastic.Markdown/Slices/Directives/Code.cshtml b/src/Elastic.Markdown/Slices/Directives/Code.cshtml index ea87e8e87..5178bc778 100644 --- a/src/Elastic.Markdown/Slices/Directives/Code.cshtml +++ b/src/Elastic.Markdown/Slices/Directives/Code.cshtml @@ -8,6 +8,6 @@ } -
@if (!string.IsNullOrEmpty(Model.ApiCallHeader)) { @Model.ApiCallHeader }[CONTENT]
+
@if (!string.IsNullOrEmpty(Model.ApiCallHeader)) { @Model.ApiCallHeader }@(Model.RenderBlock())
diff --git a/src/Elastic.Markdown/Slices/Directives/Dropdown.cshtml b/src/Elastic.Markdown/Slices/Directives/Dropdown.cshtml index 5a202f3ba..dab81f367 100644 --- a/src/Elastic.Markdown/Slices/Directives/Dropdown.cshtml +++ b/src/Elastic.Markdown/Slices/Directives/Dropdown.cshtml @@ -13,6 +13,6 @@ diff --git a/src/Elastic.Markdown/Slices/Directives/Figure.cshtml b/src/Elastic.Markdown/Slices/Directives/Figure.cshtml index 42dcf3a2d..febd026ab 100644 --- a/src/Elastic.Markdown/Slices/Directives/Figure.cshtml +++ b/src/Elastic.Markdown/Slices/Directives/Figure.cshtml @@ -3,6 +3,6 @@ @Model.Alt
-

[CONTENT]

+

@Model.RenderBlock()

\ No newline at end of file diff --git a/src/Elastic.Markdown/Slices/Directives/Image.cshtml b/src/Elastic.Markdown/Slices/Directives/Image.cshtml index 3ffc31854..42f80b987 100644 --- a/src/Elastic.Markdown/Slices/Directives/Image.cshtml +++ b/src/Elastic.Markdown/Slices/Directives/Image.cshtml @@ -2,7 +2,7 @@ @inherits RazorSlice @(Model.Alt == string.Empty ? HtmlString.Empty : new HtmlString(Model.Alt)) - [CONTENT] + @Model.RenderBlock()
- Hello, World! +

Hello, World!

@@ -71,7 +71,7 @@ type ``nested admonition in list`` () = Note
- Hello, World! +

Hello, World!

@@ -130,7 +130,7 @@ type ``nested admonition in list 2`` () = Note
- Hello, World! +

Hello, World!

@@ -188,7 +188,7 @@ type ``nested admonition in list 3`` () = Note
- Hello, World! +

Hello, World!