Skip to content

Commit 965471f

Browse files
authored
Remove [CONTENT] markers and replace with better inline rendering method (#1337)
1 parent b748bd9 commit 965471f

24 files changed

+358
-135
lines changed

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<PackageVersion Include="Markdig" Version="0.41.1" />
4141
<PackageVersion Include="NetEscapades.EnumGenerators" Version="1.0.0-beta12" PrivateAssets="all" ExcludeAssets="runtime" />
4242
<PackageVersion Include="Proc" Version="0.9.1" />
43-
<PackageVersion Include="RazorSlices" Version="0.8.1" />
43+
<PackageVersion Include="RazorSlices" Version="0.9.1" />
4444
<PackageVersion Include="Samboy063.Tomlet" Version="6.0.0" />
4545
<PackageVersion Include="Slugify.Core" Version="4.0.1" />
4646
<PackageVersion Include="SoftCircuits.IniFileParser" Version="2.7.0" />
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Text;
6+
using Elastic.Markdown.Myst;
7+
using Markdig.Renderers;
8+
using Microsoft.Extensions.ObjectPool;
9+
10+
namespace Elastic.Markdown.Helpers;
11+
12+
internal static class DocumentationObjectPoolProvider
13+
{
14+
private static readonly ObjectPoolProvider PoolProvider = new DefaultObjectPoolProvider();
15+
16+
public static readonly ObjectPool<StringBuilder> StringBuilderPool = PoolProvider.CreateStringBuilderPool(256, 4 * 1024);
17+
public static readonly ObjectPool<ReusableStringWriter> StringWriterPool = PoolProvider.Create(new ReusableStringWriterPooledObjectPolicy());
18+
public static readonly ObjectPool<HtmlRenderSubscription> HtmlRendererPool = PoolProvider.Create(new HtmlRendererPooledObjectPolicy());
19+
20+
21+
private sealed class ReusableStringWriterPooledObjectPolicy : IPooledObjectPolicy<ReusableStringWriter>
22+
{
23+
public ReusableStringWriter Create() => new();
24+
25+
public bool Return(ReusableStringWriter obj)
26+
{
27+
obj.Reset();
28+
return true;
29+
}
30+
}
31+
32+
public sealed class HtmlRenderSubscription
33+
{
34+
public required HtmlRenderer HtmlRenderer { get; init; }
35+
public StringBuilder? RentedStringBuilder { get; internal set; }
36+
}
37+
38+
private sealed class HtmlRendererPooledObjectPolicy : IPooledObjectPolicy<HtmlRenderSubscription>
39+
{
40+
public HtmlRenderSubscription Create()
41+
{
42+
var stringBuilder = StringBuilderPool.Get();
43+
using var stringWriter = StringWriterPool.Get();
44+
stringWriter.SetStringBuilder(stringBuilder);
45+
var renderer = new HtmlRenderer(stringWriter);
46+
MarkdownParser.Pipeline.Setup(renderer);
47+
48+
return new HtmlRenderSubscription { HtmlRenderer = renderer, RentedStringBuilder = stringBuilder };
49+
}
50+
51+
public bool Return(HtmlRenderSubscription subscription)
52+
{
53+
//subscription.RentedStringBuilder = null;
54+
//return string builder
55+
if (subscription.RentedStringBuilder is not null)
56+
StringBuilderPool.Return(subscription.RentedStringBuilder);
57+
58+
subscription.RentedStringBuilder = null;
59+
60+
var renderer = subscription.HtmlRenderer;
61+
62+
//reset string writer
63+
((ReusableStringWriter)renderer.Writer).Reset();
64+
65+
// reseed string writer with string builder
66+
var stringBuilder = StringBuilderPool.Get();
67+
subscription.RentedStringBuilder = stringBuilder;
68+
((ReusableStringWriter)renderer.Writer).SetStringBuilder(stringBuilder);
69+
return true;
70+
}
71+
}
72+
73+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Text;
6+
7+
namespace Elastic.Markdown.Helpers;
8+
9+
internal sealed class ReusableStringWriter : TextWriter
10+
{
11+
private static UnicodeEncoding? CurrentEncoding;
12+
13+
private StringBuilder? _sb;
14+
15+
public override Encoding Encoding => CurrentEncoding ??= new UnicodeEncoding(false, false);
16+
17+
public void SetStringBuilder(StringBuilder sb) => _sb = sb;
18+
19+
public void Reset() => _sb = null;
20+
21+
public override void Write(char value) => _sb?.Append(value);
22+
23+
public override void Write(char[] buffer, int index, int count)
24+
{
25+
ArgumentNullException.ThrowIfNull(buffer);
26+
ArgumentOutOfRangeException.ThrowIfNegative(index);
27+
ArgumentOutOfRangeException.ThrowIfNegative(count);
28+
29+
if (buffer.Length - index < count)
30+
throw new ArgumentException("Out of range");
31+
32+
_ = _sb?.Append(buffer, index, count);
33+
}
34+
35+
public override void Write(ReadOnlySpan<char> buffer) => _sb?.Append(buffer);
36+
37+
public override void Write(string? value)
38+
{
39+
if (value is not null)
40+
_ = _sb?.Append(value);
41+
}
42+
43+
public override void Write(StringBuilder? value) => _sb?.Append(value);
44+
45+
public override void WriteLine(ReadOnlySpan<char> buffer)
46+
{
47+
_ = _sb?.Append(buffer);
48+
WriteLine();
49+
}
50+
51+
public override void WriteLine(StringBuilder? value)
52+
{
53+
_ = _sb?.Append(value);
54+
WriteLine();
55+
}
56+
57+
#region Task based Async APIs
58+
59+
public override Task WriteAsync(char value)
60+
{
61+
Write(value);
62+
return Task.CompletedTask;
63+
}
64+
65+
public override Task WriteAsync(string? value)
66+
{
67+
Write(value);
68+
return Task.CompletedTask;
69+
}
70+
71+
public override Task WriteAsync(char[] buffer, int index, int count)
72+
{
73+
Write(buffer, index, count);
74+
return Task.CompletedTask;
75+
}
76+
77+
public override Task WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
78+
{
79+
if (cancellationToken.IsCancellationRequested)
80+
return Task.FromCanceled(cancellationToken);
81+
82+
Write(buffer.Span);
83+
return Task.CompletedTask;
84+
}
85+
86+
public override Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken = default)
87+
{
88+
if (cancellationToken.IsCancellationRequested)
89+
return Task.FromCanceled(cancellationToken);
90+
91+
_ = _sb?.Append(value);
92+
return Task.CompletedTask;
93+
}
94+
95+
public override Task WriteLineAsync(char value)
96+
{
97+
WriteLine(value);
98+
return Task.CompletedTask;
99+
}
100+
101+
public override Task WriteLineAsync(string? value)
102+
{
103+
WriteLine(value);
104+
return Task.CompletedTask;
105+
}
106+
107+
public override Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken = default)
108+
{
109+
if (cancellationToken.IsCancellationRequested)
110+
return Task.FromCanceled(cancellationToken);
111+
112+
_ = _sb?.Append(value);
113+
WriteLine();
114+
return Task.CompletedTask;
115+
}
116+
117+
public override Task WriteLineAsync(char[] buffer, int index, int count)
118+
{
119+
WriteLine(buffer, index, count);
120+
return Task.CompletedTask;
121+
}
122+
123+
public override Task WriteLineAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
124+
{
125+
if (cancellationToken.IsCancellationRequested)
126+
return Task.FromCanceled(cancellationToken);
127+
128+
WriteLine(buffer.Span);
129+
return Task.CompletedTask;
130+
}
131+
132+
public override Task FlushAsync() => Task.CompletedTask;
133+
134+
#endregion
135+
}

src/Elastic.Markdown/IO/MarkdownFile.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ private YamlFrontMatter ReadYamlFrontMatter(string raw)
357357
}
358358
}
359359

360-
public string CreateHtml(MarkdownDocument document)
360+
public static string CreateHtml(MarkdownDocument document)
361361
{
362362
//we manually render title and optionally append an applies block embedded in yaml front matter.
363363
var h1 = document.Descendants<HeadingBlock>().FirstOrDefault(h => h.Level == 1);

src/Elastic.Markdown/Myst/CodeBlocks/EnhancedCodeBlockHtmlRenderer.cs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,14 @@ public class EnhancedCodeBlockHtmlRenderer : HtmlObjectRenderer<EnhancedCodeBloc
2020
private const int TabWidth = 4;
2121

2222
[SuppressMessage("Reliability", "CA2012:Use ValueTasks correctly")]
23-
private static void RenderRazorSlice<T>(RazorSlice<T> slice, HtmlRenderer renderer, EnhancedCodeBlock block)
24-
{
25-
var html = slice.RenderAsync().GetAwaiter().GetResult();
26-
var blocks = html.Split("[CONTENT]", 2, StringSplitOptions.RemoveEmptyEntries);
27-
_ = renderer.Write(blocks[0]);
28-
RenderCodeBlockLines(renderer, block);
29-
_ = renderer.Write(blocks[1]);
30-
}
23+
private static void RenderRazorSlice<T>(RazorSlice<T> slice, HtmlRenderer renderer) =>
24+
slice.RenderAsync(renderer.Writer).GetAwaiter().GetResult();
3125

3226
/// <summary>
3327
/// Renders the code block lines while also removing the common indentation level.
3428
/// Required because EnableTrackTrivia preserves extra indentation.
3529
/// </summary>
36-
private static void RenderCodeBlockLines(HtmlRenderer renderer, EnhancedCodeBlock block)
30+
public static void RenderCodeBlockLines(HtmlRenderer renderer, EnhancedCodeBlock block)
3731
{
3832
var commonIndent = GetCommonIndent(block);
3933
var hasCode = false;
@@ -134,10 +128,11 @@ protected override void Write(HtmlRenderer renderer, EnhancedCodeBlock block)
134128
CrossReferenceName = string.Empty,// block.CrossReferenceName,
135129
Language = block.Language,
136130
Caption = block.Caption,
137-
ApiCallHeader = block.ApiCallHeader
131+
ApiCallHeader = block.ApiCallHeader,
132+
EnhancedCodeBlock = block
138133
});
139134

140-
RenderRazorSlice(slice, renderer, block);
135+
RenderRazorSlice(slice, renderer);
141136
if (!block.InlineAnnotations && callOuts.Count > 0)
142137
{
143138
var index = block.Parent!.IndexOf(block);
@@ -240,7 +235,6 @@ private static void RenderAppliesToHtml(HtmlRenderer renderer, AppliesToDirectiv
240235
var slice = ApplicableToDirective.Create(appliesTo);
241236
if (appliesTo is null || appliesTo == FrontMatter.ApplicableTo.All)
242237
return;
243-
var html = slice.RenderAsync().GetAwaiter().GetResult();
244-
_ = renderer.Write(html);
238+
slice.RenderAsync(renderer.Writer).GetAwaiter().GetResult();
245239
}
246240
}

0 commit comments

Comments
 (0)