lib: Add SpanLinkTag::Unresolved variant
keep the tag for unresolved links, and allow distinguishing between `[tag][tag with empty url]` and `[tag][non-existent tag]`. closes #26
This commit is contained in:
parent
05a4992d99
commit
a603ea2124
4 changed files with 42 additions and 12 deletions
|
@ -29,6 +29,7 @@ use crate::LinkType;
|
||||||
use crate::ListKind;
|
use crate::ListKind;
|
||||||
use crate::OrderedListNumbering::*;
|
use crate::OrderedListNumbering::*;
|
||||||
use crate::Render;
|
use crate::Render;
|
||||||
|
use crate::SpanLinkType;
|
||||||
|
|
||||||
pub struct Renderer;
|
pub struct Renderer;
|
||||||
|
|
||||||
|
@ -163,7 +164,7 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
|
||||||
Container::CodeBlock { .. } => self.out.write_str("<pre")?,
|
Container::CodeBlock { .. } => self.out.write_str("<pre")?,
|
||||||
Container::Span | Container::Math { .. } => self.out.write_str("<span")?,
|
Container::Span | Container::Math { .. } => self.out.write_str("<span")?,
|
||||||
Container::Link(dst, ty) => {
|
Container::Link(dst, ty) => {
|
||||||
if dst.is_empty() {
|
if matches!(ty, LinkType::Span(SpanLinkType::Unresolved)) {
|
||||||
self.out.write_str("<a")?;
|
self.out.write_str("<a")?;
|
||||||
} else {
|
} else {
|
||||||
self.out.write_str(r#"<a href=""#)?;
|
self.out.write_str(r#"<a href=""#)?;
|
||||||
|
|
48
src/lib.rs
48
src/lib.rs
|
@ -213,9 +213,10 @@ pub enum Container<'s> {
|
||||||
CodeBlock { lang: Option<&'s str> },
|
CodeBlock { lang: Option<&'s str> },
|
||||||
/// An inline divider element.
|
/// An inline divider element.
|
||||||
Span,
|
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),
|
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),
|
Image(CowStr<'s>, SpanLinkType),
|
||||||
/// An inline verbatim string.
|
/// An inline verbatim string.
|
||||||
Verbatim,
|
Verbatim,
|
||||||
|
@ -333,6 +334,8 @@ pub enum SpanLinkType {
|
||||||
Inline,
|
Inline,
|
||||||
/// In the form `[text][tag]` or `[tag][]`.
|
/// In the form `[text][tag]` or `[tag][]`.
|
||||||
Reference,
|
Reference,
|
||||||
|
/// Like reference, but the tag is unresolved.
|
||||||
|
Unresolved,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of an inline link.
|
/// The type of an inline link.
|
||||||
|
@ -729,19 +732,20 @@ impl<'s> Parser<'s> {
|
||||||
let link_def =
|
let link_def =
|
||||||
self.pre_pass.link_definitions.get(tag.as_ref()).cloned();
|
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);
|
attributes.union(attrs_def);
|
||||||
url
|
(url, SpanLinkType::Reference)
|
||||||
} else {
|
} else {
|
||||||
self.pre_pass
|
self.pre_pass.heading_id_by_tag(tag.as_ref()).map_or_else(
|
||||||
.heading_id_by_tag(tag.as_ref())
|
|| (tag, SpanLinkType::Unresolved),
|
||||||
.map_or_else(|| "".into(), |id| format!("#{}", id).into())
|
|id| (format!("#{}", id).into(), SpanLinkType::Reference),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches!(c, inline::Container::ReferenceLink) {
|
if matches!(c, inline::Container::ReferenceLink) {
|
||||||
Container::Link(url, LinkType::Span(SpanLinkType::Reference))
|
Container::Link(url_or_tag, LinkType::Span(ty))
|
||||||
} else {
|
} else {
|
||||||
Container::Image(url, SpanLinkType::Reference)
|
Container::Image(url_or_tag, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline::Container::Autolink => {
|
inline::Container::Autolink => {
|
||||||
|
@ -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]
|
#[test]
|
||||||
fn link_reference_multiline() {
|
fn link_reference_multiline() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
block_list_flat:large list marker number
|
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
|
inline_links_nested:empty link text
|
||||||
|
|
|
@ -10,7 +10,6 @@ e1f5b5e:untrimmed whitespace before linebreak
|
||||||
07888f3:div close within raw block
|
07888f3:div close within raw block
|
||||||
8423412:heading id conflict with existing id
|
8423412:heading id conflict with existing id
|
||||||
00a46ed:clear inline formatting from link tags
|
00a46ed:clear inline formatting from link tags
|
||||||
a8e17c3:empty href
|
|
||||||
c0a3dec:escape in url
|
c0a3dec:escape in url
|
||||||
e66af00:url container precedence
|
e66af00:url container precedence
|
||||||
61876cf:roman alpha ambiguity
|
61876cf:roman alpha ambiguity
|
||||||
|
|
Loading…
Reference in a new issue