rework link parsing loop

This commit is contained in:
Kyle Lin 2023-06-29 12:07:24 +08:00
parent fe3eae3f31
commit b1d232a6da

View File

@ -50,7 +50,7 @@ use crate::html::render::small_url_encode;
use crate::html::toc::TocBuilder;
use pulldown_cmark::{
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag,
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag,
};
#[cfg(test)]
@ -1240,6 +1240,7 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
pub(crate) struct MarkdownLink {
pub kind: LinkType,
pub link: String,
pub display_text: String,
pub range: MarkdownLinkRange,
}
@ -1263,8 +1264,8 @@ impl MarkdownLinkRange {
}
}
pub(crate) fn markdown_links<R>(
md: &str,
pub(crate) fn markdown_links<'md, R>(
md: &'md str,
preprocess_link: impl Fn(MarkdownLink) -> Option<R>,
) -> Vec<R> {
if md.is_empty() {
@ -1375,13 +1376,17 @@ pub(crate) fn markdown_links<R>(
MarkdownLinkRange::Destination(range.clone())
};
Parser::new_with_broken_link_callback(
let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
let mut event_iter = Parser::new_with_broken_link_callback(
md,
main_body_opts(),
Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
Some(&mut broken_link_callback),
)
.into_offset_iter()
.filter_map(|(event, span)| match event {
.into_offset_iter();
let mut links = Vec::new();
while let Some((event, span)) = event_iter.next() {
match event {
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
let range = match link_type {
// Link is pulled from the link itself.
@ -1396,11 +1401,47 @@ pub(crate) fn markdown_links<R>(
}
LinkType::Autolink | LinkType::Email => unreachable!(),
};
preprocess_link(MarkdownLink { kind: link_type, range, link: dest.into_string() })
let display_text =
collect_link_data(&mut event_iter).map_or(String::new(), CowStr::into_string);
if let Some(link) = preprocess_link(MarkdownLink {
kind: link_type,
display_text,
link: dest.into_string(),
range,
}) {
links.push(link);
}
_ => None,
})
.collect()
}
_ => {}
}
}
links
}
fn collect_link_data<'input, 'callback>(
event_iter: &mut OffsetIter<'input, 'callback>,
) -> Option<CowStr<'input>> {
let mut display_text = None;
while let Some((event, _span)) = event_iter.next() {
match event {
Event::Text(code) => {
display_text = Some(code);
}
Event::Code(code) => {
display_text = Some(code);
}
Event::End(_) => {
break;
}
_ => {}
}
}
display_text
}
#[derive(Debug)]