Request for help/sample #269

Closed
opened 2026-01-29 14:32:21 +00:00 by claunia · 11 comments
Owner

Originally created by @picrap on GitHub (Jan 29, 2019).

Hi, I'm trying to create a custom parser/custom renderer, and I'm quite desperate 😢
I want to create an extension that may simply change the severity (warning, error) of a text between exclamation marks, so !!this is a warning!! and !!!this is an error!!! would generate in HTML a <span> with the right color. I want blocks, because I want to be able to use inner emphasis, such as !!I'm not **happy**!!.

So I started Implement my own BlockParser and BlockRenderer both using my own ContainerBlock, however the ContainerBlock has no children. I've looked at the markdig source code which I don't understand much, so I'm basically lost. How have my ContainerBlock children filled?

Originally created by @picrap on GitHub (Jan 29, 2019). Hi, I'm trying to create a custom parser/custom renderer, and I'm quite desperate 😢 I want to create an extension that may simply change the severity (warning, error) of a text between exclamation marks, so `!!this is a warning!!` and `!!!this is an error!!!` would generate in HTML a `<span>` with the right color. I want blocks, because I want to be able to use inner emphasis, such as `!!I'm not **happy**!!`. So I started Implement my own `BlockParser` and `BlockRenderer` both using my own `ContainerBlock`, however the `ContainerBlock` has no children. I've looked at the `markdig` source code which I don't understand much, so I'm basically lost. How have my `ContainerBlock` children filled?
claunia added the question label 2026-01-29 14:32:21 +00:00
Author
Owner

@xoofx commented on GitHub (Jan 29, 2019):

If it is a span, it means that it's not a block, so you are likely looking for an inline parser. From the many extensions, find one that has a similar syntax and try to adapt it.

@xoofx commented on GitHub (Jan 29, 2019): If it is a span, it means that it's not a block, so you are likely looking for an inline parser. From the [many extensions](https://github.com/lunet-io/markdig/tree/master/src/Markdig/Extensions), find one that has a similar syntax and try to adapt it.
Author
Owner

@picrap commented on GitHub (Jan 29, 2019):

What is the difference between a span and a block? (Because I also implemented a span and got the same empty children sequence).

@picrap commented on GitHub (Jan 29, 2019): What is the difference between a span and a block? (Because I also implemented a span and got the same empty children sequence).
Author
Owner

@xoofx commented on GitHub (Jan 29, 2019):

What is the difference between a span and a block? (Because I also implemented a span and got the same empty children sequence).

Not sure to understand. You know the difference in HTML no?

@xoofx commented on GitHub (Jan 29, 2019): > What is the difference between a span and a block? (Because I also implemented a span and got the same empty children sequence). Not sure to understand. You know the difference in HTML no?
Author
Owner

@picrap commented on GitHub (Jan 29, 2019):

So it's a pure layout difference?
Also, I read the "many extensions", none of them really helped 😭

@picrap commented on GitHub (Jan 29, 2019): So it's a pure layout difference? Also, I read the "many extensions", none of them really helped 😭
Author
Owner

@xoofx commented on GitHub (Jan 29, 2019):

Also, I read the "many extensions", none of them really helped

Sorry, but I really don't have time to help. You have to do your homework here. Many extensions are very simple. First you need to understand the difference between an inline and a block in CommonMark specs. In markdig, we are just replicating what is in CommonMark, we have block parsers (e.g fenced code blocks) and inline parsers (e.g emphasis, links...) Then you need to find an extension that has a similar syntax that you want to achieve and adapt it. The closest maybe is Custom containers and their specs

@xoofx commented on GitHub (Jan 29, 2019): > Also, I read the "many extensions", none of them really helped Sorry, but I really don't have time to help. You have to do your homework here. Many extensions are very simple. First you need to understand the difference between an inline and a block in [CommonMark specs](https://spec.commonmark.org/0.28/). In markdig, we are just replicating what is in CommonMark, we have block parsers (e.g fenced code blocks) and inline parsers (e.g emphasis, links...) Then you need to find an extension that has a similar syntax that you want to achieve and adapt it. The closest maybe is [Custom containers](https://github.com/lunet-io/markdig/tree/master/src/Markdig/Extensions/CustomContainers) and their [specs](https://github.com/lunet-io/markdig/blob/master/src/Markdig.Tests/Specs/CustomContainerSpecs.md#inline-custom-container)
Author
Owner

@picrap commented on GitHub (Jan 29, 2019):

EDIT: I cooled down. Thanks for links.

@picrap commented on GitHub (Jan 29, 2019): EDIT: I cooled down. Thanks for links.
Author
Owner

@MihaZupan commented on GitHub (Jan 29, 2019):

This is adapted from Custom Containers

class Program
{
    static void Main(string[] args)
    {
        var pipelineBuilder = new MarkdownPipelineBuilder()
            .Use<WarningSpanExtension>();

        var pipeline = pipelineBuilder.Build();
        string markdown = "This is some text !!with a **serious** warning!!";

        string html = Markdown.ToHtml(markdown, pipeline);
        Console.WriteLine(html);
    }
}

public class WarningInline : EmphasisInline { }
public class HtmlWarningInlineRenderer : HtmlObjectRenderer<WarningInline>
{
    protected override void Write(HtmlRenderer renderer, WarningInline obj)
    {
        renderer.Write("<span style=\"color:blue\"").WriteAttributes(obj).Write(">");
        renderer.WriteChildren(obj);
        renderer.Write("</span>");
    }
}
public class WarningSpanExtension : IMarkdownExtension
{
    public void Setup(MarkdownPipelineBuilder pipeline)
    {
        var inlineParser = pipeline.InlineParsers.Find<EmphasisInlineParser>();
        if (inlineParser != null && !inlineParser.HasEmphasisChar('!'))
        {
            inlineParser.EmphasisDescriptors.Add(new EmphasisDescriptor('!', 2, 2, true));
            var previousCreateEmphasisInline = inlineParser.CreateEmphasisInline;
            inlineParser.CreateEmphasisInline = (emphasisChar, strong) =>
            {
                if (strong && emphasisChar == '!')
                {
                    return new WarningInline();
                }
                return previousCreateEmphasisInline?.Invoke(emphasisChar, strong);
            };
        }
    }

    public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
    {
        if (renderer is HtmlRenderer htmlRenderer)
        {
            if (!htmlRenderer.ObjectRenderers.Contains<HtmlWarningInlineRenderer>())
            {
                htmlRenderer.ObjectRenderers.Insert(0, new HtmlWarningInlineRenderer());
            }
            if (!htmlRenderer.ObjectRenderers.Contains<HtmlWarningInlineRenderer>())
            {
                htmlRenderer.ObjectRenderers.Insert(0, new HtmlWarningInlineRenderer());
            }
        }
    }
}
@MihaZupan commented on GitHub (Jan 29, 2019): This is adapted from Custom Containers ```csharp class Program { static void Main(string[] args) { var pipelineBuilder = new MarkdownPipelineBuilder() .Use<WarningSpanExtension>(); var pipeline = pipelineBuilder.Build(); string markdown = "This is some text !!with a **serious** warning!!"; string html = Markdown.ToHtml(markdown, pipeline); Console.WriteLine(html); } } public class WarningInline : EmphasisInline { } public class HtmlWarningInlineRenderer : HtmlObjectRenderer<WarningInline> { protected override void Write(HtmlRenderer renderer, WarningInline obj) { renderer.Write("<span style=\"color:blue\"").WriteAttributes(obj).Write(">"); renderer.WriteChildren(obj); renderer.Write("</span>"); } } public class WarningSpanExtension : IMarkdownExtension { public void Setup(MarkdownPipelineBuilder pipeline) { var inlineParser = pipeline.InlineParsers.Find<EmphasisInlineParser>(); if (inlineParser != null && !inlineParser.HasEmphasisChar('!')) { inlineParser.EmphasisDescriptors.Add(new EmphasisDescriptor('!', 2, 2, true)); var previousCreateEmphasisInline = inlineParser.CreateEmphasisInline; inlineParser.CreateEmphasisInline = (emphasisChar, strong) => { if (strong && emphasisChar == '!') { return new WarningInline(); } return previousCreateEmphasisInline?.Invoke(emphasisChar, strong); }; } } public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { if (renderer is HtmlRenderer htmlRenderer) { if (!htmlRenderer.ObjectRenderers.Contains<HtmlWarningInlineRenderer>()) { htmlRenderer.ObjectRenderers.Insert(0, new HtmlWarningInlineRenderer()); } if (!htmlRenderer.ObjectRenderers.Contains<HtmlWarningInlineRenderer>()) { htmlRenderer.ObjectRenderers.Insert(0, new HtmlWarningInlineRenderer()); } } } } ```
Author
Owner

@MihaZupan commented on GitHub (Jan 29, 2019):

In theory, triple characters could be added the same way, but currently the underlying Emphasis parser only works with max 2, so that'll have to be patched first for this approach.

Look at the Custom Containers extension source to see how it does the triple opening character for blocks.

@MihaZupan commented on GitHub (Jan 29, 2019): In theory, triple characters could be added the same way, but currently the underlying Emphasis parser only works with max 2, so that'll have to be patched first for this approach. Look at the Custom Containers extension source to see how it does the triple opening character for blocks.
Author
Owner

@MihaZupan commented on GitHub (Jan 29, 2019):

The example above is literally the same as found in CC, with the name changed and ':' set to '!'

@MihaZupan commented on GitHub (Jan 29, 2019): The example above is literally the same as found in CC, with the name changed and ':' set to '!'
Author
Owner

@picrap commented on GitHub (Jan 29, 2019):

Hi, thanks.
The point I missed when opening this issue is that the bool Match(InlineProcessor processor, ref StringSlice slice) method should only insert as new block its own markup, then let the process deal with the following inlines. My mistake was to insert the whole part between opening and closing marks. Things are getting clearer now.
Again, thanks.

@picrap commented on GitHub (Jan 29, 2019): Hi, thanks. The point I missed when opening this issue is that the `bool Match(InlineProcessor processor, ref StringSlice slice)` method should only insert as new block its own markup, then let the process deal with the following inlines. My mistake was to insert the whole part between opening and closing marks. Things are getting clearer now. Again, thanks.
Author
Owner

@MihaZupan commented on GitHub (Jan 29, 2019):

With #301, doing this with the Emphasis parser should work properly.

@MihaZupan commented on GitHub (Jan 29, 2019): With #301, doing this with the Emphasis parser should work properly.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/markdig#269