Add support for target links.
format Build format has succeeded Details
build-natter Build build-natter has succeeded Details
rust-clippy Build rust-clippy has succeeded Details
rust-test Build rust-test has succeeded Details

This commit is contained in:
Tom Alexander 2023-12-23 22:12:05 -05:00
parent d2ea6b6a0f
commit 59a91331cc
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
3 changed files with 58 additions and 34 deletions

View File

@ -14,9 +14,17 @@ pub(crate) struct RenderTarget {
post_blank: organic::types::PostBlank, 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 { Ok(RenderTarget {
id: original.id.clone(), id,
post_blank: original.post_blank, post_blank: original.post_blank,
}) })
}); });

View File

@ -14,7 +14,7 @@ type IdCounter = u16;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Registry<'orig, 'parse> { pub(crate) struct Registry<'orig, 'parse> {
id_counter: IdCounter, id_counter: IdCounter,
targets: HashMap<&'parse str, String>, targets: HashMap<String, String>,
footnote_ids: Vec<(Option<&'parse str>, Vec<IAstNode>)>, footnote_ids: Vec<(Option<&'parse str>, Vec<IAstNode>)>,
footnote_reference_counts: HashMap<&'parse str, usize>, footnote_reference_counts: HashMap<&'parse str, usize>,
on_deck_footnote_ids: HashMap<&'parse str, &'orig Vec<Element<'parse>>>, on_deck_footnote_ids: HashMap<&'parse str, &'orig Vec<Element<'parse>>>,
@ -31,8 +31,8 @@ impl<'orig, 'parse> Registry<'orig, 'parse> {
} }
} }
pub(crate) fn get_target<'reg>(&'reg mut self, body: &'parse str) -> &'reg String { pub(crate) fn get_target<S: Into<String>>(&mut self, body: S) -> &String {
self.targets.entry(body).or_insert_with(|| { self.targets.entry(body.into()).or_insert_with(|| {
self.id_counter += 1; self.id_counter += 1;
format!("target_{}", self.id_counter) format!("target_{}", self.id_counter)
}) })

View File

@ -3,6 +3,7 @@ use url::Url;
use super::get_web_path; use super::get_web_path;
use super::macros::intermediate; use super::macros::intermediate;
use super::IntermediateContext;
use super::IObject; use super::IObject;
use crate::context::RenderContext; use crate::context::RenderContext;
@ -30,7 +31,8 @@ intermediate!(
ret ret
}; };
let raw_link = original.get_raw_link(); 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 { Ok(IRegularLink {
raw_link: raw_link.into_owned(), raw_link: raw_link.into_owned(),
children, children,
@ -47,38 +49,44 @@ pub(crate) enum LinkTarget {
post_id: Option<String>, post_id: Option<String>,
subpath: String, subpath: String,
}, },
Target {
target_id: String,
},
} }
impl LinkTarget { impl LinkTarget {
pub(crate) fn from_string<S: AsRef<str>>(input: S) -> Result<LinkTarget, CustomError> { pub(crate) fn from_string(
fn impl_from_string(input: &str) -> Result<LinkTarget, CustomError> { intermediate_context: IntermediateContext<'_, '_>,
let parsed = Url::parse(input); input: String,
if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed { ) -> Result<LinkTarget, CustomError> {
// For URLs to targets. let parsed = Url::parse(&input);
// TODO: This shouldn't be raw but instead a variant for targets. if let Err(url::ParseError::RelativeUrlWithoutBase) = parsed {
return Ok(LinkTarget::Raw(input.to_owned())); let target_id = {
} let mut registry = intermediate_context.registry.lock().unwrap();
let parsed = parsed?; let target_id = registry.get_target(input).to_owned();
match parsed.scheme() { target_id
"post" => { };
let post_id = parsed.host_str().map(str::to_owned); return Ok(LinkTarget::Target { target_id });
let subpath = { }
let subpath = parsed.path(); let parsed = parsed?;
if let Some(subpath) = subpath.strip_prefix('/') { match parsed.scheme() {
subpath "post" => {
} else { let post_id = parsed.host_str().map(str::to_owned);
subpath let subpath = {
} let subpath = parsed.path();
}; if let Some(subpath) = subpath.strip_prefix('/') {
Ok(LinkTarget::Post { subpath
post_id, } else {
subpath: subpath.to_owned(), subpath
}) }
} };
_ => Ok(LinkTarget::Raw(input.to_owned())), 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( pub(crate) fn generate_final_target(
@ -105,6 +113,14 @@ impl LinkTarget {
.map_or(Ok(None), |r| r.map(Some))?; .map_or(Ok(None), |r| r.map(Some))?;
Ok(path) 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
))),
} }
} }
} }