use crate::print::*;
use crate::util::md_tools::md_events::*;
use pulldown_cmark::{CowStr, Event, LinkType, Tag, TagEnd};
#[derive(Default)]
pub(crate) struct LinkAdjuster {
self_item: Option<syn::Item>,
copy_guard: Option<String>,
in_self_shortcut: bool,
}
impl LinkAdjuster {
pub fn new() -> Self {
Default::default()
}
pub fn with_self_item(mut self, self_item: Option<syn::Item>) -> Self {
self.self_item = self_item;
self
}
pub fn with_copy_guard(mut self, copy_guard: Option<String>) -> Self {
self.copy_guard = copy_guard;
self
}
pub fn is_guard_target(&self, url: &str) -> bool {
self.copy_guard.as_ref().is_some_and(|x| url.starts_with(x))
}
pub fn adjust<'i>(&mut self, event: &Event<'i>) -> Event<'i> {
let event = &self.adjust_for_guard(event);
let event = &self.adjust_for_embed(event);
let event = &self.adjust_for_self(event);
event.clone()
}
fn adjust_for_guard<'i>(&self, event: &Event<'i>) -> Event<'i> {
let Some(url_event) = UrlEvent::try_new_link(event) else {
return event.clone();
};
if !self.is_guard_target(&url_event.dest_url()) {
return event.clone();
}
Event::Start(Tag::Link {
dest_url: CowStr::Borrowed(""),
title: url_event.title(),
id: url_event.id(),
link_type: match url_event.link_type() {
LinkType::Reference => LinkType::ReferenceUnknown,
LinkType::Collapsed => LinkType::CollapsedUnknown,
LinkType::Shortcut => LinkType::ShortcutUnknown,
LinkType::Inline => LinkType::ShortcutUnknown,
_ => return event.clone(),
},
})
}
fn adjust_for_embed<'i>(&self, event: &Event<'i>) -> Event<'i> {
match event {
Event::Start(Tag::Link { .. }) => {
let url_event = UrlEvent::try_new_link(event).unwrap();
let link_type = Self::to_embeding_type(&url_event.link_type());
url_event.with_link_type(link_type).to_link()
}
Event::Start(Tag::Image { .. }) => {
let url_event = UrlEvent::try_new_image(event).unwrap();
let link_type = Self::to_embeding_type(&url_event.link_type());
url_event.with_link_type(link_type).to_image()
}
_ => event.clone(),
}
}
fn adjust_for_self<'i>(&mut self, event: &Event<'i>) -> Event<'i> {
if !Self::is_link_with_self(event) && !self.in_self_shortcut {
return event.clone();
}
if !self.in_self_shortcut {
self.in_self_shortcut = true;
} else {
if Self::is_link_end(event) {
self.in_self_shortcut = false;
}
return match TextEvent::try_new(event) {
None => event.clone(),
Some(x) => {
let text = &doc_share_self::replace_text(&x.text);
x.with_text(text).to_event()
}
};
}
let link = UrlEvent::try_new_link(event).unwrap();
let self_item = self.self_item.as_ref();
let new_id = doc_share_self::replace_url(&link.id(), self_item);
let new_url = doc_share_self::replace_url(&link.dest_url(), self_item);
let use_url = !new_url.is_empty();
link.with_link_type(LinkType::Inline)
.with_dest_url(if use_url { &new_url } else { &new_id })
.to_link()
}
fn is_link_with_self(event: &Event) -> bool {
match UrlEvent::try_new_link(event) {
None => false,
Some(x) => {
let id_has_self = doc_share_self::is_target(&x.id());
let url_has_self = doc_share_self::is_target(&x.dest_url());
id_has_self || url_has_self
}
}
}
fn is_link_end(event: &Event) -> bool {
matches!(event, Event::End(TagEnd::Link))
}
fn to_embeding_type(link_type: &LinkType) -> LinkType {
match link_type {
LinkType::Reference => LinkType::Inline,
LinkType::Collapsed => LinkType::Inline,
LinkType::Shortcut => LinkType::Inline,
_ => *link_type,
}
}
}