From 59a91331ccb965dd7e792aca938775c11ea60ec0 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 23 Dec 2023 22:12:05 -0500 Subject: [PATCH] Add support for target links. --- src/context/target.rs | 12 +++++- src/intermediate/registry.rs | 6 +-- src/intermediate/regular_link.rs | 74 +++++++++++++++++++------------- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/src/context/target.rs b/src/context/target.rs index 5d9fede..de50c9e 100644 --- a/src/context/target.rs +++ b/src/context/target.rs @@ -14,9 +14,17 @@ pub(crate) struct RenderTarget { post_blank: organic::types::PostBlank, } -render!(RenderTarget, ITarget, original, _render_context, { +render!(RenderTarget, ITarget, original, render_context, { + let id = format!( + "{}{}", + render_context + .id_addition + .map(|id_addition| format!("sec{}.", id_addition)) + .unwrap_or_default(), + original.id + ); Ok(RenderTarget { - id: original.id.clone(), + id, post_blank: original.post_blank, }) }); diff --git a/src/intermediate/registry.rs b/src/intermediate/registry.rs index b5f6f7b..f9335b7 100644 --- a/src/intermediate/registry.rs +++ b/src/intermediate/registry.rs @@ -14,7 +14,7 @@ type IdCounter = u16; #[derive(Debug)] pub(crate) struct Registry<'orig, 'parse> { id_counter: IdCounter, - targets: HashMap<&'parse str, String>, + targets: HashMap, footnote_ids: Vec<(Option<&'parse str>, Vec)>, footnote_reference_counts: HashMap<&'parse str, usize>, on_deck_footnote_ids: HashMap<&'parse str, &'orig Vec>>, @@ -31,8 +31,8 @@ impl<'orig, 'parse> Registry<'orig, 'parse> { } } - pub(crate) fn get_target<'reg>(&'reg mut self, body: &'parse str) -> &'reg String { - self.targets.entry(body).or_insert_with(|| { + pub(crate) fn get_target>(&mut self, body: S) -> &String { + self.targets.entry(body.into()).or_insert_with(|| { self.id_counter += 1; format!("target_{}", self.id_counter) }) diff --git a/src/intermediate/regular_link.rs b/src/intermediate/regular_link.rs index faab0a7..fe0d19b 100644 --- a/src/intermediate/regular_link.rs +++ b/src/intermediate/regular_link.rs @@ -3,6 +3,7 @@ use url::Url; use super::get_web_path; use super::macros::intermediate; +use super::IntermediateContext; use super::IObject; use crate::context::RenderContext; @@ -30,7 +31,8 @@ intermediate!( ret }; let raw_link = original.get_raw_link(); - let target = LinkTarget::from_string(&raw_link)?; + let target = + LinkTarget::from_string(intermediate_context.clone(), raw_link.clone().into_owned())?; Ok(IRegularLink { raw_link: raw_link.into_owned(), children, @@ -47,38 +49,44 @@ pub(crate) enum LinkTarget { post_id: Option, subpath: String, }, + Target { + target_id: String, + }, } impl LinkTarget { - pub(crate) fn from_string>(input: S) -> Result { - fn impl_from_string(input: &str) -> Result { - let parsed = Url::parse(input); - if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed { - // For URLs to targets. - // TODO: This shouldn't be raw but instead a variant for targets. - return Ok(LinkTarget::Raw(input.to_owned())); - } - let parsed = parsed?; - match parsed.scheme() { - "post" => { - let post_id = parsed.host_str().map(str::to_owned); - let subpath = { - let subpath = parsed.path(); - if let Some(subpath) = subpath.strip_prefix('/') { - subpath - } else { - subpath - } - }; - Ok(LinkTarget::Post { - post_id, - subpath: subpath.to_owned(), - }) - } - _ => Ok(LinkTarget::Raw(input.to_owned())), - } + pub(crate) fn from_string( + intermediate_context: IntermediateContext<'_, '_>, + input: String, + ) -> Result { + let parsed = Url::parse(&input); + if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed { + let target_id = { + let mut registry = intermediate_context.registry.lock().unwrap(); + let target_id = registry.get_target(input).to_owned(); + target_id + }; + return Ok(LinkTarget::Target { target_id }); + } + let parsed = parsed?; + match parsed.scheme() { + "post" => { + let post_id = parsed.host_str().map(str::to_owned); + let subpath = { + let subpath = parsed.path(); + if let Some(subpath) = subpath.strip_prefix('/') { + subpath + } else { + subpath + } + }; + Ok(LinkTarget::Post { + post_id, + subpath: subpath.to_owned(), + }) + } + _ => Ok(LinkTarget::Raw(input.to_owned())), } - impl_from_string(input.as_ref()) } pub(crate) fn generate_final_target( @@ -105,6 +113,14 @@ impl LinkTarget { .map_or(Ok(None), |r| r.map(Some))?; Ok(path) } + LinkTarget::Target { target_id } => Ok(Some(format!( + "#{}{}", + render_context + .id_addition + .map(|id_addition| format!("sec{}.", id_addition)) + .unwrap_or_default(), + target_id + ))), } } }