Skip to content

LinkInlines created via AutoLinkParser are incorrectly rendered with RoundtripRenderer #919

@geffner

Description

@geffner

Sample code:

using System;
using System.IO;
using Markdig;
using Markdig.Renderers.Roundtrip;

public class Program
{
	public static void Main()
	{
		MarkdownPipeline Pipeline = new MarkdownPipelineBuilder()
			.DisableHtml()
			.UseAutoLinks()
			.EnableTrackTrivia()
			.Build();
		var markdownDocument = Markdown.Parse("http://example.com/", Pipeline);
		using StringWriter sanitizedStringWriter = new();
        RoundtripRenderer sanitizedTextRenderer = new(sanitizedStringWriter);
        sanitizedTextRenderer.Write(markdownDocument);
        Console.WriteLine(sanitizedStringWriter.ToString());
	}
}

Expected output is one of the following:

  • [http://example.com/](http://example.com/)
  • <http://example.com/>

Actual output:
[http://example.com/]()

The actual output consists of a broken hyperlink for the following reason.

When markdig parses Markdown and identifies a URL as an autolink, it creates a LinkInline for it and sets the .Url field to be the URL for the link.
/src/Markdig/Extensions/AutoLinks/AutoLinkParser.cs:

        var inline = new LinkInline()
        {
            Span =
            {
                Start = processor.GetSourcePosition(startPosition, out int line, out int column),
            },
            Line = line,
            Column = column,
───────▶    Url = c == 'w' ? ((Options.UseHttpsForWWWLinks ? "https://" : "http://") + link) : link,
            IsClosed = true,
            IsAutoLink = true,
        };

However, when this LinkInline object is rendered back to Markdown, only the object's .UnescapedUrl field is used, not the .Url field. And since that .UnescapedUrl field is never assigned a value, it ends up getting rendered as an empty string.
/src/Markdig/Renderers/Roundtrip/Inlines/LinkInlineRenderer.cs:

                renderer.Write('(');
                renderer.Write(link.TriviaBeforeUrl);
                if (link.UrlHasPointyBrackets)
                {
                    renderer.Write('<');
                }
───────────▶    renderer.Write(link.UnescapedUrl);
                if (link.UrlHasPointyBrackets)
                {
                    renderer.Write('>');
                }
                renderer.Write(link.TriviaAfterUrl);

                if (!string.IsNullOrEmpty(link.Title))
                {
                    var open = link.TitleEnclosingCharacter;
                    var close = link.TitleEnclosingCharacter;
                    if (link.TitleEnclosingCharacter == '(')
                    {
                        close = ')';
                    }
                    renderer.Write(open);
                    renderer.Write(link.UnescapedTitle);
                    renderer.Write(close);
                    renderer.Write(link.TriviaAfterTitle);
                }

                renderer.Write(')');

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions