Merge pull request #866 from MihaZupan/alert-perf

Improve Alert parsing perf
This commit is contained in:
Alexandre Mutel
2025-04-15 10:58:40 +02:00
committed by GitHub
5 changed files with 27 additions and 20 deletions

View File

@@ -22,7 +22,7 @@ public class AlertBlock : QuoteBlock
}
/// <summary>
/// Gets or sets the kind of the alert block (e.g `NOTE`, `TIP`, `IMPORTANT`, `WARNING`, `CAUTION`)
/// Gets or sets the kind of the alert block (e.g `NOTE`, `TIP`, `IMPORTANT`, `WARNING`, `CAUTION`).
/// </summary>
public StringSlice Kind { get; set; }

View File

@@ -15,6 +15,9 @@ namespace Markdig.Extensions.Alerts;
/// <seealso cref="InlineParser" />
public class AlertInlineParser : InlineParser
{
private static readonly TransformedStringCache s_alertTypeClassCache = new(
type => $"markdown-alert-{type.ToLowerInvariant()}");
/// <summary>
/// Initializes a new instance of the <see cref="AlertInlineParser"/> class.
/// </summary>
@@ -25,27 +28,30 @@ public class AlertInlineParser : InlineParser
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
if (slice.PeekChar() != '!')
{
return false;
}
// We expect the alert to be the first child of a quote block. Example:
// > [!NOTE]
// > This is a note
if (processor.Block is not ParagraphBlock paragraphBlock || paragraphBlock.Parent is not QuoteBlock quoteBlock || paragraphBlock.Inline?.FirstChild != null
|| quoteBlock is AlertBlock || quoteBlock.Parent is not MarkdownDocument)
if (processor.Block is not ParagraphBlock paragraphBlock ||
paragraphBlock.Parent is not QuoteBlock quoteBlock ||
paragraphBlock.Inline?.FirstChild != null ||
quoteBlock is AlertBlock ||
quoteBlock.Parent is not MarkdownDocument)
{
return false;
}
var saved = slice;
var c = slice.NextChar();
if (c != '!')
{
slice = saved;
return false;
}
StringSlice saved = slice;
c = slice.NextChar(); // Skip !
slice.SkipChar(); // Skip [
char c = slice.NextChar(); // Skip !
var start = slice.Start;
var end = start;
int start = slice.Start;
int end = start;
while (c.IsAlpha())
{
end = slice.Start;
@@ -76,13 +82,13 @@ public class AlertInlineParser : InlineParser
end = slice.Start;
if (c == '\n')
{
slice.NextChar(); // Skip \n
slice.SkipChar(); // Skip \n
}
}
}
else if (c == '\n')
{
slice.NextChar(); // Skip \n
slice.SkipChar(); // Skip \n
}
break;
}
@@ -103,8 +109,9 @@ public class AlertInlineParser : InlineParser
Column = quoteBlock.Column,
};
alertBlock.GetAttributes().AddClass("markdown-alert");
alertBlock.GetAttributes().AddClass($"markdown-alert-{alertType.ToString().ToLowerInvariant()}");
HtmlAttributes attributes = alertBlock.GetAttributes();
attributes.AddClass("markdown-alert");
attributes.AddClass(s_alertTypeClassCache.Get(alertType.AsSpan()));
// Replace the quote block with the alert block
var parentQuoteBlock = quoteBlock.Parent!;

View File

@@ -127,7 +127,7 @@ public sealed class MarkdownPipeline
}
}
internal readonly struct RentedHtmlRenderer : IDisposable
internal readonly ref struct RentedHtmlRenderer : IDisposable
{
private readonly HtmlRendererCache _cache;
public readonly HtmlRenderer Instance;

View File

@@ -153,7 +153,7 @@ public abstract class MarkdownObject : IMarkdownObject
return Unsafe.As<T>(storage.Trivia);
}
private class DataEntriesAndTrivia
private sealed class DataEntriesAndTrivia
{
private struct DataEntry(object key, object value)
{

View File

@@ -25,7 +25,7 @@ public class QuoteBlock : ContainerBlock
/// <summary>
/// Gets or sets the trivia per line of this QuoteBlock.
/// Trivia: only parsed when <see cref="MarkdownPipeline.TrackTrivia"/> is enabled, otherwise null.
/// Trivia: only parsed when <see cref="MarkdownPipeline.TrackTrivia"/> is enabled.
/// </summary>
public List<QuoteBlockLine> QuoteLines => Trivia;