Class
Sealed
public sealed class AdmonitionParser : BlockParser
Namespace: Moka.Docs.Parsing.Markdown
Parses
::: type [title] blocks.Inheritance
Inherits from: BlockParser
Constructors
| Name | Description |
|---|---|
AdmonitionParser() |
Creates a new admonition parser. |
AdmonitionParser()
AdmonitionParser.AdmonitionParser()
Creates a new admonition parser.
Methods
| Name | Description |
|---|---|
TryContinue(BlockProcessor processor, Block block) override |
|
TryOpen(BlockProcessor processor) override |
Type Relationships
classDiagram
style AdmonitionParser fill:#f9f,stroke:#333,stroke-width:2px
AdmonitionParser --|> BlockParser : inherits
View Source
/// <summary>
/// Parses <c>::: type [title]</c> blocks.
/// </summary>
public sealed class AdmonitionParser : BlockParser
{
private static readonly HashSet<string> _validTypes = new(StringComparer.OrdinalIgnoreCase)
{
"note",
"tip",
"warning",
"danger",
"info",
"caution",
"important"
};
/// <summary>Creates a new admonition parser.</summary>
public AdmonitionParser()
{
OpeningCharacters = [':'];
}
/// <inheritdoc/>
public override BlockState TryOpen(BlockProcessor processor)
{
if (processor.IsCodeIndent)
{
return BlockState.None;
}
StringSlice line = processor.Line;
int start = line.Start;
// Must start with :::
if (line.CurrentChar != ':')
{
return BlockState.None;
}
int colons = MarkdigHelpers.CountAndSkipChar(ref line, ':');
if (colons < 3)
{
return BlockState.None;
}
line.TrimStart();
string remaining = line.ToString().Trim();
if (string.IsNullOrEmpty(remaining))
{
return BlockState.None;
}
// Parse type and optional title
int spaceIndex = remaining.IndexOf(' ');
string type;
string? title = null;
if (spaceIndex > 0)
{
type = remaining[..spaceIndex];
title = remaining[(spaceIndex + 1)..].Trim();
if (string.IsNullOrEmpty(title))
{
title = null;
}
}
else
{
type = remaining;
}
if (!_validTypes.Contains(type))
{
return BlockState.None;
}
var block = new AdmonitionBlock(this)
{
AdmonitionType = type.ToLowerInvariant(),
Title = title,
Span = new SourceSpan(start, line.End),
Column = processor.Column
};
processor.NewBlocks.Push(block);
return BlockState.ContinueDiscard;
}
/// <inheritdoc/>
public override BlockState TryContinue(BlockProcessor processor, Block block)
{
StringSlice line = processor.Line;
// Check for closing :::
if (line.CurrentChar == ':')
{
StringSlice saved = line;
int colons = MarkdigHelpers.CountAndSkipChar(ref line, ':');
if (colons >= 3)
{
string after = line.ToString().Trim();
if (string.IsNullOrEmpty(after))
{
block.UpdateSpanEnd(line.End);
return BlockState.BreakDiscard;
}
}
// Restore if not closing
processor.Line = saved;
}
return BlockState.Continue;
}
}