diff --git a/default_environment/templates/html/footnote_reference.dust b/default_environment/templates/html/footnote_reference.dust index ae1f616..a218064 100644 --- a/default_environment/templates/html/footnote_reference.dust +++ b/default_environment/templates/html/footnote_reference.dust @@ -1 +1 @@ -!!!!!!!! footnote_reference +{.label} diff --git a/org_test_documents/footnote_definitions.org b/org_test_documents/footnote_definitions.org new file mode 100644 index 0000000..8a15e71 --- /dev/null +++ b/org_test_documents/footnote_definitions.org @@ -0,0 +1,25 @@ +# Test proves that: +# +# - Anonymous references with identical content get unique IDs. +# - Unreferenced footnote definitions are dropped. +# - Footnote definitions that come before their first reference are dropped. + +foo[fn:2:something] + +bar[fn::something] + +baz[fn::something] + +cat[fn::something] + +dog[fn:3] + +[fn:3] ipsum + +[fn:4] lorem + +[fn:3] dolar + +[fn:5] not referenced + +stuff[fn:4] and things diff --git a/src/intermediate/footnote_reference.rs b/src/intermediate/footnote_reference.rs index cb393c2..b660a9c 100644 --- a/src/intermediate/footnote_reference.rs +++ b/src/intermediate/footnote_reference.rs @@ -3,13 +3,16 @@ use crate::error::CustomError; use super::registry::Registry; #[derive(Debug)] -pub(crate) struct IFootnoteReference {} +pub(crate) struct IFootnoteReference { + footnote_id: usize, +} impl IFootnoteReference { pub(crate) async fn new<'parse>( registry: &mut Registry<'parse>, original: &organic::types::FootnoteReference<'parse>, ) -> Result { - Ok(IFootnoteReference {}) + let footnote_id = registry.get_footnote_reference_id(original.label, &original.definition); + Ok(IFootnoteReference { footnote_id }) } } diff --git a/src/intermediate/registry.rs b/src/intermediate/registry.rs index d53e2ba..b7988d2 100644 --- a/src/intermediate/registry.rs +++ b/src/intermediate/registry.rs @@ -1,10 +1,13 @@ use std::collections::HashMap; +use organic::types::Object; + type IdCounter = u16; -pub(crate) struct Registry<'parse> { +pub(crate) struct Registry<'intermediate, 'parse> { id_counter: IdCounter, targets: HashMap<&'parse str, String>, + footnote_ids: Vec<(Option<&'parse str>, &Vec>)>, } impl<'parse> Registry<'parse> { @@ -12,6 +15,7 @@ impl<'parse> Registry<'parse> { Registry { id_counter: 0, targets: HashMap::new(), + footnote_ids: Vec::new(), } } @@ -21,4 +25,37 @@ impl<'parse> Registry<'parse> { format!("target_{}", self.id_counter) }) } + + /// Get a 0-indexed ID for a footnote. + /// + /// This needs to be incremented to be 1-indexed for render. + pub(crate) fn get_footnote_reference_id<'b>( + &'b mut self, + label: Option<&'parse str>, + definition: &'parse Vec>, + ) -> usize { + if let None = label { + // If it has no label then it must always get a new ID. + self.footnote_ids.push((None, definition)); + return self.footnote_ids.len(); + } + + if let Some(existing_id) = self + .footnote_ids + .iter() + .position(|(id, _definition)| *id == label) + { + if !definition.is_empty() { + let entry = self + .footnote_ids + .get_mut(existing_id) + .expect("If-statement proves this to be Some."); + entry.1 = definition; + } + existing_id + } else { + self.footnote_ids.push((label, definition)); + self.footnote_ids.len() + } + } }