self.out.write_str(" self.out.write_str(" {
- if dst.is_empty() {
+ Container::Link(dst, ty) => {
+ if matches!(ty, LinkType::Span(SpanLinkType::Unresolved)) {
self.out.write_str(" {
CodeBlock { lang: Option<&'s str> },
/// An inline divider element.
Span,
- /// An inline link with a destination URL.
+ /// An inline link, the first field is either a destination URL or an unresolved tag.
Link(CowStr<'s>, LinkType),
- /// An inline image with a source URL. Inner Str objects compose the alternative text.
+ /// An inline image, the first field is either a destination URL or an unresolved tag. Inner
+ /// Str objects compose the alternative text.
Image(CowStr<'s>, SpanLinkType),
/// An inline verbatim string.
Verbatim,
@@ -333,6 +334,8 @@ pub enum SpanLinkType {
Inline,
/// In the form `[text][tag]` or `[tag][]`.
Reference,
+ /// Like reference, but the tag is unresolved.
+ Unresolved,
}
/// The type of an inline link.
@@ -729,29 +732,30 @@ impl<'s> Parser<'s> {
let link_def =
self.pre_pass.link_definitions.get(tag.as_ref()).cloned();
- let url = if let Some((url, attrs_def)) = link_def {
+ let (url_or_tag, ty) = if let Some((url, attrs_def)) = link_def {
attributes.union(attrs_def);
- url
+ (url, SpanLinkType::Reference)
} else {
- self.pre_pass
- .heading_id_by_tag(tag.as_ref())
- .map_or_else(|| "".into(), |id| format!("#{}", id).into())
+ self.pre_pass.heading_id_by_tag(tag.as_ref()).map_or_else(
+ || (tag, SpanLinkType::Unresolved),
+ |id| (format!("#{}", id).into(), SpanLinkType::Reference),
+ )
};
if matches!(c, inline::Container::ReferenceLink) {
- Container::Link(url, LinkType::Span(SpanLinkType::Reference))
+ Container::Link(url_or_tag, LinkType::Span(ty))
} else {
- Container::Image(url, SpanLinkType::Reference)
+ Container::Image(url_or_tag, ty)
}
}
inline::Container::Autolink => {
let url = self.inlines.src(inline.span);
- let url = if url.contains('@') {
- format!("mailto:{}", url).into()
+ let ty = if url.contains('@') {
+ LinkType::Email
} else {
- url
+ LinkType::AutoLink
};
- Container::Link(url, LinkType::AutoLink)
+ Container::Link(url, ty)
}
};
if matches!(inline.kind, inline::EventKind::Enter(_)) {
@@ -1298,6 +1302,32 @@ mod test {
);
}
+ #[test]
+ fn link_reference_unresolved() {
+ test_parse!(
+ "[text][tag]",
+ Start(Paragraph, Attributes::new()),
+ Start(
+ Link("tag".into(), LinkType::Span(SpanLinkType::Unresolved)),
+ Attributes::new()
+ ),
+ Str("text".into()),
+ End(Link("tag".into(), LinkType::Span(SpanLinkType::Unresolved))),
+ End(Paragraph),
+ );
+ test_parse!(
+ "![text][tag]",
+ Start(Paragraph, Attributes::new()),
+ Start(
+ Image("tag".into(), SpanLinkType::Unresolved),
+ Attributes::new()
+ ),
+ Str("text".into()),
+ End(Image("tag".into(), SpanLinkType::Unresolved)),
+ End(Paragraph),
+ );
+ }
+
#[test]
fn link_reference_multiline() {
test_parse!(
diff --git a/tests/bench/skip b/tests/bench/skip
index d9afe9e..33a6308 100644
--- a/tests/bench/skip
+++ b/tests/bench/skip
@@ -1,3 +1,3 @@
block_list_flat:large list marker number
-inline_links_flat:escaped attributes, empty hrefs
+inline_links_flat:space before img, img attrs order
inline_links_nested:empty link text
diff --git a/tests/suite/skip b/tests/suite/skip
index aea68c3..e9c249e 100644
--- a/tests/suite/skip
+++ b/tests/suite/skip
@@ -10,7 +10,6 @@ e1f5b5e:untrimmed whitespace before linebreak
07888f3:div close within raw block
8423412:heading id conflict with existing id
00a46ed:clear inline formatting from link tags
-a8e17c3:empty href
c0a3dec:escape in url
e66af00:url container precedence
61876cf:roman alpha ambiguity