Class Sealed
public sealed class AdmonitionParser : BlockParser

Namespace: Moka.Docs.Parsing.Markdown

Parses ::: type [title] blocks.

Inheritance

Inherits from: BlockParser

Constructors

NameDescription
AdmonitionParser() Creates a new admonition parser.

AdmonitionParser()

AdmonitionParser.AdmonitionParser()

Creates a new admonition parser.

Methods

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;
    }
}
Was this page helpful?