use crate::error::SiteError;
use crate::html::{parse, Content, Element, ElementTag, HtmlPage};
use crate::parser::WikitextParser;
use crate::site::Site;
use crate::util::{get_mtime, join_subpath, make_path_relative_to};
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(srcdir: &Path, filename: &Path) -> Result {
info!("input file: {}", filename.display());
let relative = make_path_relative_to(srcdir, filename).with_extension("");
let absolute = Path::new("/").join(&relative);
let name = relative
.file_name()
.unwrap_or_else(|| panic!("get filename from {}", relative.display()))
.to_string_lossy()
.to_string();
let data = std::fs::read(filename).map_err(|e| SiteError::FileRead(filename.into(), e))?;
let wikitext = String::from_utf8(data).map_err(|e| SiteError::Utf8(filename.into(), e))?;
let mtime = get_mtime(filename)?;
let meta = MetaBuilder::default()
.name(name)
.path(absolute)
.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: String,
title: Option,
path: PathBuf,
mtime: SystemTime,
}
impl PageMeta {
fn new(name: String, title: Option, path: PathBuf, mtime: SystemTime) -> Self {
trace!(
"PageMeta: name={:?} title={:?} path={:?} mtime={:?}",
name,
title,
path,
mtime,
);
Self {
name,
title,
path,
mtime,
}
}
pub fn destination_filename(&self, destdir: &Path) -> PathBuf {
join_subpath(destdir, &self.path).with_extension("html")
}
pub fn name(&self) -> &str {
&self.name
}
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
}
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn mtime(&self) -> SystemTime {
self.mtime
}
}
#[derive(Debug, Default)]
pub struct MetaBuilder {
name: String,
title: Option,
path: Option,
mtime: Option,
}
impl MetaBuilder {
pub fn build(self) -> PageMeta {
PageMeta::new(
self.name,
self.title,
self.path.expect("path set on MetaBuilder"),
self.mtime.expect("mtime set on MetaBuilder"),
)
}
pub fn name(mut self, name: String) -> Self {
self.name = name;
self
}
pub fn title(mut self, title: String) -> Self {
self.title = Some(title);
self
}
pub fn path(mut self, path: PathBuf) -> Self {
self.path = Some(path);
self
}
pub fn mtime(mut self, mtime: SystemTime) -> Self {
self.mtime = Some(mtime);
self
}
}