use crate::flow::AddressablePiece;
use crate::text_block::TextBlock;
use frontend::common::format_runs::InlineContent;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LinkExtent {
pub start: usize,
pub end: usize,
pub href: String,
pub text: String,
}
fn href_of(piece: &AddressablePiece) -> Option<&str> {
match piece.content {
InlineContent::Text(_) => piece.format.anchor_href.as_deref(),
_ => None,
}
}
pub(crate) fn link_extent_at(block: &TextBlock, position: usize) -> Option<LinkExtent> {
let pieces = block.addressable_inline_pieces();
let hit = pieces
.iter()
.rposition(|p| p.start <= position && position <= p.end)?;
let anchor = [hit, hit.saturating_sub(1), (hit + 1).min(pieces.len())]
.into_iter()
.filter(|&i| i < pieces.len())
.find(|&i| {
href_of(&pieces[i]).is_some()
&& pieces[i].start <= position
&& position <= pieces[i].end
})?;
let href = href_of(&pieces[anchor])?.to_string();
let mut first = anchor;
while first > 0 && href_of(&pieces[first - 1]) == Some(href.as_str()) {
first -= 1;
}
let mut last = anchor;
while last + 1 < pieces.len() && href_of(&pieces[last + 1]) == Some(href.as_str()) {
last += 1;
}
let text = pieces[first..=last]
.iter()
.filter_map(|p| match &p.content {
InlineContent::Text(t) => Some(t.as_str()),
_ => None,
})
.collect::<String>();
Some(LinkExtent {
start: pieces[first].start,
end: pieces[last].end,
href,
text,
})
}