parser: apply link def attrs to link
This commit is contained in:
parent
9fdd402d07
commit
2e4a9147aa
2 changed files with 63 additions and 15 deletions
15
src/attr.rs
15
src/attr.rs
|
@ -58,6 +58,21 @@ impl<'s> Attributes<'s> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Combine all attributes from both objects, prioritizing self on conflicts.
|
||||||
|
pub fn union(&mut self, other: Self) {
|
||||||
|
if let Some(attrs0) = &mut self.0 {
|
||||||
|
if let Some(mut attrs1) = other.0 {
|
||||||
|
for (attr, val) in attrs1.drain(..) {
|
||||||
|
if !attrs0.iter().any(|(a, _)| *a == attr) {
|
||||||
|
attrs0.push((attr, val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.0 = other.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn add(&mut self, attr: &'s str, val: CowStr<'s>) {
|
fn add(&mut self, attr: &'s str, val: CowStr<'s>) {
|
||||||
if self.0.is_none() {
|
if self.0.is_none() {
|
||||||
self.0 = Some(Vec::new().into());
|
self.0 = Some(Vec::new().into());
|
||||||
|
|
63
src/lib.rs
63
src/lib.rs
|
@ -318,7 +318,7 @@ pub struct Parser<'s> {
|
||||||
src: &'s str,
|
src: &'s str,
|
||||||
|
|
||||||
/// Link definitions encountered during block parse, written once.
|
/// Link definitions encountered during block parse, written once.
|
||||||
link_definitions: std::collections::HashMap<&'s str, CowStr<'s>>,
|
link_definitions: std::collections::HashMap<&'s str, (CowStr<'s>, attr::Attributes<'s>)>,
|
||||||
|
|
||||||
/// Block tree cursor.
|
/// Block tree cursor.
|
||||||
tree: block::Tree,
|
tree: block::Tree,
|
||||||
|
@ -347,17 +347,24 @@ impl<'s> Parser<'s> {
|
||||||
let link_definitions = {
|
let link_definitions = {
|
||||||
let mut branch = tree.clone();
|
let mut branch = tree.clone();
|
||||||
let mut defs = std::collections::HashMap::new();
|
let mut defs = std::collections::HashMap::new();
|
||||||
|
let mut attr_prev: Option<Span> = None;
|
||||||
while let Some(e) = branch.next() {
|
while let Some(e) = branch.next() {
|
||||||
if let tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) =
|
if let tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) =
|
||||||
e.kind
|
e.kind
|
||||||
{
|
{
|
||||||
let tag = e.span.of(src);
|
let tag = e.span.of(src);
|
||||||
|
let attrs =
|
||||||
|
attr_prev.map_or_else(Attributes::new, |sp| attr::parse(sp.of(src)));
|
||||||
let url = match branch.count_children() {
|
let url = match branch.count_children() {
|
||||||
0 => "".into(),
|
0 => "".into(),
|
||||||
1 => branch.take_inlines().next().unwrap().of(src).trim().into(),
|
1 => branch.take_inlines().next().unwrap().of(src).trim().into(),
|
||||||
_ => branch.take_inlines().map(|sp| sp.of(src).trim()).collect(),
|
_ => branch.take_inlines().map(|sp| sp.of(src).trim()).collect(),
|
||||||
};
|
};
|
||||||
defs.insert(tag, url);
|
defs.insert(tag, (url, attrs));
|
||||||
|
} else if let tree::EventKind::Atom(block::Atom::Attributes) = e.kind {
|
||||||
|
attr_prev = Some(e.span);
|
||||||
|
} else {
|
||||||
|
attr_prev = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defs
|
defs
|
||||||
|
@ -386,7 +393,7 @@ impl<'s> Parser<'s> {
|
||||||
let mut inline = parser.next();
|
let mut inline = parser.next();
|
||||||
|
|
||||||
let mut first_is_attr = false;
|
let mut first_is_attr = false;
|
||||||
let attributes = inline.as_ref().map_or_else(Attributes::new, |inl| {
|
let mut attributes = inline.as_ref().map_or_else(Attributes::new, |inl| {
|
||||||
if let inline::EventKind::Attributes = inl.kind {
|
if let inline::EventKind::Attributes = inl.kind {
|
||||||
first_is_attr = true;
|
first_is_attr = true;
|
||||||
attr::parse(self.inlines.slice(inl.span))
|
attr::parse(self.inlines.slice(inl.span))
|
||||||
|
@ -433,20 +440,19 @@ impl<'s> Parser<'s> {
|
||||||
},
|
},
|
||||||
SpanLinkType::Inline,
|
SpanLinkType::Inline,
|
||||||
),
|
),
|
||||||
inline::Container::ReferenceLink => Container::Link(
|
inline::Container::ReferenceLink | inline::Container::ReferenceImage => {
|
||||||
self.link_definitions
|
let (url, attrs_def) = self
|
||||||
|
.link_definitions
|
||||||
.get(self.inlines.src(inline.span).replace('\n', " ").as_str())
|
.get(self.inlines.src(inline.span).replace('\n', " ").as_str())
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| "".into()),
|
.unwrap_or_else(|| ("".into(), Attributes::new()));
|
||||||
LinkType::Span(SpanLinkType::Reference),
|
attributes.union(attrs_def);
|
||||||
),
|
if matches!(c, inline::Container::ReferenceLink) {
|
||||||
inline::Container::ReferenceImage => Container::Image(
|
Container::Link(url, LinkType::Span(SpanLinkType::Reference))
|
||||||
self.link_definitions
|
} else {
|
||||||
.get(self.inlines.src(inline.span).replace('\n', " ").as_str())
|
Container::Image(url, SpanLinkType::Reference)
|
||||||
.cloned()
|
}
|
||||||
.unwrap_or_else(|| "".into()),
|
}
|
||||||
SpanLinkType::Reference,
|
|
||||||
),
|
|
||||||
inline::Container::Autolink => todo!("{:?}", c),
|
inline::Container::Autolink => todo!("{:?}", c),
|
||||||
};
|
};
|
||||||
if matches!(inline.kind, inline::EventKind::Enter(_)) {
|
if matches!(inline.kind, inline::EventKind::Enter(_)) {
|
||||||
|
@ -921,6 +927,33 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn link_reference_attrs() {
|
||||||
|
test_parse!(
|
||||||
|
concat!(
|
||||||
|
"[text][tag]{b=c}\n",
|
||||||
|
"\n",
|
||||||
|
"{a=b}\n",
|
||||||
|
"[tag]: url\n",
|
||||||
|
"\n",
|
||||||
|
"para\n",
|
||||||
|
),
|
||||||
|
Start(Paragraph, Attributes::new()),
|
||||||
|
Start(
|
||||||
|
Link("url".into(), LinkType::Span(SpanLinkType::Reference)),
|
||||||
|
[("b", "c"), ("a", "b")].into_iter().collect(),
|
||||||
|
),
|
||||||
|
Str("text".into()),
|
||||||
|
End(Link("url".into(), LinkType::Span(SpanLinkType::Reference))),
|
||||||
|
End(Paragraph),
|
||||||
|
Atom(Blankline),
|
||||||
|
Atom(Blankline),
|
||||||
|
Start(Paragraph, Attributes::new()),
|
||||||
|
Str("para".into()),
|
||||||
|
End(Paragraph),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn footnote_references() {
|
fn footnote_references() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
|
|
Loading…
Reference in a new issue