xoofx / markdig

A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET
BSD 2-Clause "Simplified" License
4.32k stars 447 forks source link

Strikethrough (~~) renders as empty angle brackets #709

Open daughtkom opened 1 year ago

daughtkom commented 1 year ago

I have a situation that I have worked around that seems like it might be a bug, but I acknowledge that this might be by design and that I have just misunderstood something.

I have this markdown in a variable named markdown:

To do:

~~add PDF link to board~~

I have added the emphasis extras and was having an issue. (I have tried both with and without EmphasisExtraOptions.Strikethrough.)

var pipeline = new MarkdownPipelineBuilder()
    .UseEmphasisExtras()
    .Build();
var doc = Markdown.Parse(markdown, pipeline);
var html = doc.ToHtml();

// I learned that it works if I pass the pipeline again to ToHtml in addition to passing to Parse above
// var html = doc.ToHtml(pipeline); 

The following is the generated HTML:

<p>To do:</p>
<p><>add PDF link to board</></p>

I have also tested with ~, +, ^, and all give the same result with empty tags.

I am using:

All that said, if I pass the pipeline again to the ToHtml call, it does render the tags correctly. I would have thought that since I created doc with the pipeline that I wouldn't need to use it again when calling ToHtml.

Is this a bug, or by design? Any suggestions what I am missing?

MihaZupan commented 1 year ago

Did you pass the pipeline to ToHtml/your renderer instance?

daughtkom commented 1 year ago

Did you pass the pipeline to ToHtml/your renderer instance?

That was the workaround that I mentioned at the bottom of my description, and that does work. I updated my description to include this.

This wasn't obvious since I had used pipeline with Parse to create the document. I haven't found much documentation so my usage was self-taught. I guess I thought that since the pipeline was used to create the document, that calling doc.ToHtml() would use the same pipeline.

Maybe not? If not, then does passing it in Markdown.Parse(markdown, pipeline) do anything?

MihaZupan commented 1 year ago

Markdig processes input in two stages:

Both of these are highly extensible. You can add parsers that change the shape of the syntax tree or add their own custom nodes. You can inspect/modify the syntax tree before rendering. You can then add renderers that understand those custom nodes and know what to do with them.

The pipeline represents the set of parsers and renderers to use. When using extensions (e.g. UseEmphasisExtras), you need the renderer to be aware of what sort of elements it can expect parsers to emit.

For your example input, the document represents the following:

MarkdownDocument
    ParagraphBlock
        LiteralInline
    ParagraphBlock
        EmphasisInline: DelimiterChar='~' Count=2
            LiteralInline

if you don't pass the pipeline to the renderer, the renderer doesn't know what to do with an EmphasisInline that has DelimiterChar='~'.


If you don't care about looking at the AST, you can also use the

string Markdown.ToHtml(string, MarkdownPipeline);

helper.

Docs could certainly be improved 😄

daughtkom commented 1 year ago

Thanks. That does help explain.