Skip to content

Improve Alert parsing perf #866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Markdig/Extensions/Alerts/AlertBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public AlertBlock(StringSlice kind) : base(null)
}

/// <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; }

Expand Down
39 changes: 23 additions & 16 deletions src/Markdig/Extensions/Alerts/AlertInlineParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -25,27 +28,30 @@ public AlertInlineParser()

public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
// 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 (slice.PeekChar() != '!')
{
return false;
}

var saved = slice;
var c = slice.NextChar();
if (c != '!')
// 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)
{
slice = saved;
return false;
}

c = slice.NextChar(); // Skip !
StringSlice saved = slice;

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;
Expand Down Expand Up @@ -76,13 +82,13 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice)
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;
}
Expand All @@ -103,8 +109,9 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice)
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!;
Expand Down
2 changes: 1 addition & 1 deletion src/Markdig/MarkdownPipeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ protected override void Reset(HtmlRenderer instance)
}
}

internal readonly struct RentedHtmlRenderer : IDisposable
internal readonly ref struct RentedHtmlRenderer : IDisposable
{
private readonly HtmlRendererCache _cache;
public readonly HtmlRenderer Instance;
Expand Down
2 changes: 1 addition & 1 deletion src/Markdig/Syntax/MarkdownObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public string ToPositionText()
return Unsafe.As<T>(storage.Trivia);
}

private class DataEntriesAndTrivia
private sealed class DataEntriesAndTrivia
{
private struct DataEntry(object key, object value)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Markdig/Syntax/QuoteBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public QuoteBlock(BlockParser? parser) : base(parser)

/// <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;

Expand Down