use crate::error::SiteError; use crate::html::{parse, Content, Element, ElementTag, HtmlPage}; use crate::name::Name; use crate::parser::WikitextParser; use crate::site::Site; use crate::util::get_mtime; use crate::wikitext::Snippet; use log::{info, trace}; use std::path::{Path, PathBuf}; use std::time::SystemTime; #[derive(Debug, Eq, PartialEq)] pub struct WikitextPage { meta: PageMeta, wikitext: String, } impl WikitextPage { pub fn new(meta: PageMeta, wikitext: String) -> Self { Self { meta, wikitext } } pub fn read(name: &Name) -> Result { info!("input file: {}", name); let src = name.source_path(); let data = std::fs::read(&src).map_err(|e| SiteError::FileRead(src.into(), e))?; let wikitext = String::from_utf8(data).map_err(|e| SiteError::Utf8(src.into(), e))?; let mtime = get_mtime(src)?; let meta = MetaBuilder::default() .name(name.clone()) .mtime(mtime) .build(); Ok(Self::new(meta, wikitext)) } pub fn meta(&self) -> &PageMeta { &self.meta } pub fn wikitext(&self) -> &str { &self.wikitext } } #[derive(Debug)] pub struct UnprocessedPage { meta: PageMeta, snippets: Vec, } impl UnprocessedPage { pub fn new(meta: PageMeta, parser: &mut WikitextParser) -> Result { Ok(Self { meta, snippets: Self::snippets(parser)?, }) } pub fn meta(&self) -> &PageMeta { &self.meta } fn snippets(parser: &mut WikitextParser) -> Result, SiteError> { let mut snippets = vec![]; while let Some(snippet) = parser.parse()? { snippets.push(snippet); } Ok(snippets) } pub fn process(&self, site: &mut Site) -> Result { let mut meta = self.meta.clone(); let mut m = String::new(); for snippet in self.snippets.iter() { m.push_str(&snippet.process(site, &mut meta)?); } Ok(MarkdownPage::new(m, meta)) } } #[derive(Debug, Clone, Eq, PartialEq)] pub struct MarkdownPage { meta: PageMeta, markdown: String, } impl MarkdownPage { fn new(markdown: String, meta: PageMeta) -> Self { Self { markdown, meta } } pub fn markdown(&self) -> &str { &self.markdown } pub fn meta(&self) -> &PageMeta { &self.meta } pub fn body_to_html(&self) -> Result { let head = Element::new(ElementTag::Head); let body = parse(self.markdown())?; Ok(HtmlPage::new(head, body)) } pub fn to_html(&self) -> Result { let mut title = Element::new(ElementTag::Title); title.push_child(Content::Text(self.meta.title().into())); let mut head = Element::new(ElementTag::Head); head.push_child(Content::Elt(title)); let body = parse(self.markdown())?; trace!("MarkdownPage::to_html: head={:?}", head); Ok(HtmlPage::new(head, body)) } } #[derive(Debug, Clone, Eq, PartialEq)] pub struct PageMeta { name: Name, title: Option, mtime: SystemTime, } impl PageMeta { fn new(name: Name, title: Option, mtime: SystemTime) -> Self { trace!( "PageMeta: name={:?} title={:?} mtime={:?}", name, title, mtime, ); Self { name, title, mtime } } pub fn destination_filename(&self) -> PathBuf { self.name.destination_path().into() } pub fn set_title(&mut self, title: String) { trace!("PageMeta::set_title: title={:?}", title); self.title = Some(title); } pub fn title(&self) -> &str { if let Some(title) = &self.title { title } else { self.name.page_name() } } pub fn path(&self) -> &Path { self.name.page_path() } pub fn mtime(&self) -> SystemTime { self.mtime } } #[derive(Debug, Default)] pub struct MetaBuilder { name: Option, title: Option, mtime: Option, } impl MetaBuilder { pub fn build(self) -> PageMeta { PageMeta::new( self.name.expect("name set on MetaBuilder"), self.title, self.mtime.expect("mtime set on MetaBuilder"), ) } pub fn name(mut self, name: Name) -> Self { self.name = Some(name); self } pub fn title(mut self, title: String) -> Self { self.title = Some(title); self } pub fn mtime(mut self, mtime: SystemTime) -> Self { self.mtime = Some(mtime); self } }