use std::borrow::Cow;
use pulldown_cmark::Event;
use pulldown_cmark::Parser;
use pulldown_cmark::Tag;
use pulldown_cmark::TagEnd;
use tracing::debug;
use tracing::error;
use super::super::link::Link;
use super::super::link::LinkBuilder;
#[derive(Debug, PartialEq, Copy, Clone)]
enum Where {
Elsewhere,
InLink, InImageInLink,
}
pub(crate) fn extract_links<'input>(parser: &mut Parser<'input>) -> Vec<Link<'input>> {
let mut state: Vec<(Where, LinkBuilder<'input>)> = Vec::new();
let mut links: Vec<Link<'input>> = Vec::new();
for event in parser {
match event {
Event::Start(Tag::Link {
link_type,
dest_url,
title,
id,
}) => {
debug!(
"Link: link_type: {:?}, url: {}, title: {}, id: {}",
link_type, dest_url, title, id
);
state.push((
Where::InLink,
LinkBuilder::from_type_url_title(
link_type,
dest_url.into(),
title.into(),
id.into(),
),
));
}
ref e @ Event::End(TagEnd::Link) => {
debug!("{:?}", e);
let (whr, link_builder) = state.pop().unwrap(); assert_eq!(whr, Where::InLink);
links.push(link_builder.build());
}
Event::Start(Tag::Image {
link_type,
dest_url,
title,
id,
}) if !state.is_empty() => {
debug!(
"image: link type: {:?}, image url: {}, image title: {}, label: {}",
link_type, dest_url, title, id
);
let (whr, link_builder) = state.pop().unwrap();
assert_eq!(whr, Where::InLink);
state.push((
Where::InImageInLink,
link_builder.set_image(link_type, dest_url.into(), title.into(), id.into()),
));
}
ref e @ Event::End(TagEnd::Image) if !state.is_empty() => {
debug!("{:?}", e);
let (whr, link_builder) = state.pop().unwrap();
assert_eq!(whr, Where::InImageInLink);
state.push((Where::InLink, link_builder));
}
Event::Text(t)
if state.last().map_or(Where::Elsewhere, |s| s.0) == Where::InImageInLink =>
{
debug!("Event::Text({:?})", t);
let (whr, link_builder) = state.pop().unwrap();
assert_eq!(whr, Where::InImageInLink);
state.push((whr, link_builder.add_image_alt_text(Cow::from(t))));
}
Event::Text(t) if !state.is_empty() => {
debug!("Event::Text({:?})", t);
let (whr, link_builder) = state.pop().unwrap();
assert_eq!(whr, Where::InLink);
state.push((whr, link_builder.add_text(Cow::from(t))));
}
Event::Code(c) if !state.is_empty() => {
debug!("code: {}", c);
let (whr, link_builder) = state.pop().unwrap();
state.push((whr, link_builder.add_text(c.into())));
}
ref e if !state.is_empty() => {
error!("Unhandled event while 'in link': {:?}", e);
}
ref e => {
debug!("Ignored: {:?}", e);
}
}
}
assert!(state.is_empty());
links
}
#[cfg(test)]
mod test {
}