diff --git a/src/blog_post/heading.rs b/src/blog_post/heading.rs index d889bf2..109c65a 100644 --- a/src/blog_post/heading.rs +++ b/src/blog_post/heading.rs @@ -9,6 +9,11 @@ pub(crate) struct Heading { impl Heading { pub(crate) fn new(heading: &organic::types::Heading<'_>) -> Result { - Ok(Heading { title: Vec::new() }) + let title = heading + .title + .iter() + .map(Object::new) + .collect::, _>>()?; + Ok(Heading { title }) } } diff --git a/src/blog_post/mod.rs b/src/blog_post/mod.rs index fde7fc4..b8ff674 100644 --- a/src/blog_post/mod.rs +++ b/src/blog_post/mod.rs @@ -5,7 +5,9 @@ mod element; mod heading; mod object; mod page; +mod plain_text; mod section; +mod util; pub(crate) use convert::convert_blog_post_page_to_render_context; pub(crate) use definition::BlogPost; pub(crate) use document_element::DocumentElement; diff --git a/src/blog_post/object.rs b/src/blog_post/object.rs index d28ee34..b758ac3 100644 --- a/src/blog_post/object.rs +++ b/src/blog_post/object.rs @@ -1,2 +1,44 @@ +use crate::error::CustomError; + +use super::plain_text::PlainText; + #[derive(Debug)] -pub(crate) enum Object {} +pub(crate) enum Object { + PlainText(PlainText), +} + +impl Object { + pub(crate) fn new(obj: &organic::types::Object<'_>) -> Result { + match obj { + organic::types::Object::Bold(_) => todo!(), + organic::types::Object::Italic(_) => todo!(), + organic::types::Object::Underline(_) => todo!(), + organic::types::Object::StrikeThrough(_) => todo!(), + organic::types::Object::Code(_) => todo!(), + organic::types::Object::Verbatim(_) => todo!(), + organic::types::Object::PlainText(plain_text) => { + Ok(Object::PlainText(PlainText::new(plain_text)?)) + } + organic::types::Object::RegularLink(_) => todo!(), + organic::types::Object::RadioLink(_) => todo!(), + organic::types::Object::RadioTarget(_) => todo!(), + organic::types::Object::PlainLink(_) => todo!(), + organic::types::Object::AngleLink(_) => todo!(), + organic::types::Object::OrgMacro(_) => todo!(), + organic::types::Object::Entity(_) => todo!(), + organic::types::Object::LatexFragment(_) => todo!(), + organic::types::Object::ExportSnippet(_) => todo!(), + organic::types::Object::FootnoteReference(_) => todo!(), + organic::types::Object::Citation(_) => todo!(), + organic::types::Object::CitationReference(_) => todo!(), + organic::types::Object::InlineBabelCall(_) => todo!(), + organic::types::Object::InlineSourceBlock(_) => todo!(), + organic::types::Object::LineBreak(_) => todo!(), + organic::types::Object::Target(_) => todo!(), + organic::types::Object::StatisticsCookie(_) => todo!(), + organic::types::Object::Subscript(_) => todo!(), + organic::types::Object::Superscript(_) => todo!(), + organic::types::Object::Timestamp(_) => todo!(), + } + } +} diff --git a/src/blog_post/plain_text.rs b/src/blog_post/plain_text.rs new file mode 100644 index 0000000..e62191f --- /dev/null +++ b/src/blog_post/plain_text.rs @@ -0,0 +1,17 @@ +use crate::blog_post::util::coalesce_whitespace; +use crate::error::CustomError; + +#[derive(Debug)] +pub(crate) struct PlainText { + source: String, +} + +impl PlainText { + pub(crate) fn new( + plain_text: &organic::types::PlainText<'_>, + ) -> Result { + Ok(PlainText { + source: coalesce_whitespace(plain_text.source).into_owned(), + }) + } +} diff --git a/src/blog_post/util.rs b/src/blog_post/util.rs new file mode 100644 index 0000000..b482b98 --- /dev/null +++ b/src/blog_post/util.rs @@ -0,0 +1,48 @@ +use std::borrow::Cow; + +/// Removes all whitespace from a string. +/// +/// Example: "foo bar" => "foobar" and "foo \n bar" => "foobar". +#[allow(dead_code)] +pub(crate) fn coalesce_whitespace(input: &str) -> Cow<'_, str> { + let mut state = CoalesceWhitespace::Normal; + for (offset, c) in input.char_indices() { + match (&mut state, c) { + (CoalesceWhitespace::Normal, ' ' | '\t' | '\r' | '\n') => { + let mut ret = String::with_capacity(input.len()); + ret.push_str(&input[..offset]); + ret.push(' '); + state = CoalesceWhitespace::HasWhitespace { + in_whitespace: true, + ret, + }; + } + (CoalesceWhitespace::Normal, _) => {} + ( + CoalesceWhitespace::HasWhitespace { in_whitespace, ret }, + ' ' | '\t' | '\r' | '\n', + ) => { + if !*in_whitespace { + *in_whitespace = true; + ret.push(' '); + } + } + (CoalesceWhitespace::HasWhitespace { in_whitespace, ret }, _) => { + *in_whitespace = false; + ret.push(c); + } + } + } + match state { + CoalesceWhitespace::Normal => Cow::Borrowed(input), + CoalesceWhitespace::HasWhitespace { + in_whitespace: _, + ret, + } => Cow::Owned(ret), + } +} + +enum CoalesceWhitespace { + Normal, + HasWhitespace { in_whitespace: bool, ret: String }, +}