// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Syntax.Inlines;
namespace Markdig.Syntax;
///
/// A link reference definition (Section 4.7 CommonMark specs)
///
///
public class LinkReferenceDefinition : LeafBlock
{
private TriviaProperties? _trivia => TryGetDerivedTrivia();
private TriviaProperties Trivia => GetOrSetDerivedTrivia();
///
/// Creates an inline link for the specified .
///
/// State of the inline.
/// The link reference.
/// The child.
/// An inline link or null to use the default implementation
public delegate Inline CreateLinkInlineDelegate(InlineProcessor inlineState, LinkReferenceDefinition linkRef, Inline? child = null);
///
/// Initializes a new instance of the class.
///
public LinkReferenceDefinition() : base(null)
{
IsOpen = false;
}
///
/// Initializes a new instance of the class.
///
/// The label.
/// The URL.
/// The title.
public LinkReferenceDefinition(string? label, string? url, string? title) : this()
{
Label = label;
Url = url;
Title = title;
}
///
/// Gets or sets the label. Text is normalized according to spec.
///
/// https://spec.commonmark.org/0.29/#matches
public string? Label { get; set; }
///
/// The label span
///
public SourceSpan LabelSpan;
///
/// Non-normalized Label (includes trivia)
/// Trivia: only parsed when is enabled, otherwise
/// .
///
public StringSlice LabelWithTrivia { get => _trivia?.LabelWithTrivia ?? StringSlice.Empty; set => Trivia.LabelWithTrivia = value; }
///
/// Whitespace before the .
/// Trivia: only parsed when is enabled, otherwise
/// .
///
public StringSlice TriviaBeforeUrl { get => _trivia?.TriviaBeforeUrl ?? StringSlice.Empty; set => Trivia.TriviaBeforeUrl = value; }
///
/// Gets or sets the URL.
///
public string? Url { get; set; }
///
/// The URL span
///
public SourceSpan UrlSpan;
///
/// Non-normalized .
/// Trivia: only parsed when is enabled, otherwise
/// .
///
public StringSlice UnescapedUrl { get => _trivia?.UnescapedUrl ?? StringSlice.Empty; set => Trivia.UnescapedUrl = value; }
///
/// True when the is enclosed in point brackets in the source document.
/// Trivia: only parsed when is enabled, otherwise
/// false.
///
public bool UrlHasPointyBrackets { get => _trivia?.UrlHasPointyBrackets ?? false; set => Trivia.UrlHasPointyBrackets = value; }
///
/// gets or sets the whitespace before a .
/// Trivia: only parsed when is enabled, otherwise
/// .
///
public StringSlice TriviaBeforeTitle { get => _trivia?.TriviaBeforeTitle ?? StringSlice.Empty; set => Trivia.TriviaBeforeTitle = value; }
///
/// Gets or sets the title.
///
public string? Title { get; set; }
///
/// The title span
///
public SourceSpan TitleSpan;
///
/// Non-normalized .
/// Trivia: only parsed when is enabled, otherwise
/// .
///
public StringSlice UnescapedTitle { get => _trivia?.UnescapedTitle ?? StringSlice.Empty; set => Trivia.UnescapedTitle = value; }
///
/// Gets or sets the character the is enclosed in.
/// Trivia: only parsed when is enabled, otherwise \0.
///
public char TitleEnclosingCharacter { get => _trivia?.TitleEnclosingCharacter ?? default; set => Trivia.TitleEnclosingCharacter = value; }
///
/// Gets or sets the create link inline callback for this instance.
///
///
/// This callback is called when an inline link is matching this reference definition.
///
public CreateLinkInlineDelegate? CreateLinkInline { get; set; }
///
/// Tries to the parse the specified text into a definition.
///
/// Type of the text
/// The text.
/// The block.
/// true if parsing is successful; false otherwise
public static bool TryParse(ref T text, [NotNullWhen(true)] out LinkReferenceDefinition? block) where T : ICharIterator
{
block = null;
var startSpan = text.Start;
if (!LinkHelper.TryParseLinkReferenceDefinition(ref text, out string? label, out string? url, out string? title, out SourceSpan labelSpan, out SourceSpan urlSpan, out SourceSpan titleSpan))
{
return false;
}
block = new LinkReferenceDefinition(label, url, title)
{
LabelSpan = labelSpan,
UrlSpan = urlSpan,
TitleSpan = titleSpan,
Span = new SourceSpan(startSpan, titleSpan.End > 0 ? titleSpan.End: urlSpan.End)
};
return true;
}
///
/// Tries to the parse the specified text into a definition.
///
/// Type of the text
/// The text.
/// The block.
///
///
///
///
///
///
///
/// true if parsing is successful; false otherwise
public static bool TryParseTrivia(
ref T text,
[NotNullWhen(true)] out LinkReferenceDefinition? block,
out SourceSpan triviaBeforeLabel,
out SourceSpan labelWithTrivia,
out SourceSpan triviaBeforeUrl,
out SourceSpan unescapedUrl,
out SourceSpan triviaBeforeTitle,
out SourceSpan unescapedTitle,
out SourceSpan triviaAfterTitle) where T : ICharIterator
{
block = null;
var startSpan = text.Start;
if (!LinkHelper.TryParseLinkReferenceDefinitionTrivia(
ref text,
out triviaBeforeLabel,
out string? label,
out labelWithTrivia,
out triviaBeforeUrl,
out string? url,
out unescapedUrl,
out bool urlHasPointyBrackets,
out triviaBeforeTitle,
out string? title,
out unescapedTitle,
out char titleEnclosingCharacter,
out NewLine newLine,
out triviaAfterTitle,
out SourceSpan labelSpan,
out SourceSpan urlSpan,
out SourceSpan titleSpan))
{
return false;
}
block = new LinkReferenceDefinition(label, url, title)
{
UrlHasPointyBrackets = urlHasPointyBrackets,
TitleEnclosingCharacter = titleEnclosingCharacter,
//LabelWithWhitespace = labelWithWhitespace,
LabelSpan = labelSpan,
UrlSpan = urlSpan,
//UnescapedUrl = unescapedUrl,
//UnescapedTitle = unescapedTitle,
TitleSpan = titleSpan,
Span = new SourceSpan(startSpan, titleSpan.End > 0 ? titleSpan.End : urlSpan.End),
NewLine = newLine,
};
return true;
}
private sealed class TriviaProperties
{
public StringSlice LabelWithTrivia;
public StringSlice TriviaBeforeUrl;
public StringSlice UnescapedUrl;
public bool UrlHasPointyBrackets;
public StringSlice TriviaBeforeTitle;
public StringSlice UnescapedTitle;
public char TitleEnclosingCharacter;
}
}