From 259b3fc0e26113258f44f5d3f1c0775a1ed640da Mon Sep 17 00:00:00 2001 From: Huck Boles Date: Mon, 15 May 2023 19:14:10 -0500 Subject: [PATCH] implemented header block and settings --- src/builder.rs | 149 +++++++++++++++++++++++++++--------------------- src/metafile.rs | 58 +++++++++++++++++-- src/parser.rs | 4 +- 3 files changed, 140 insertions(+), 71 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index df25a84..b50cb66 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,14 +1,14 @@ -use crate::{log, parse_file, MetaFile, Options, Src, Sub}; +use crate::{parse_file, MetaFile, Src, Sub}; use color_eyre::{eyre::bail, Result}; use pandoc::{InputFormat, InputKind, OutputFormat, OutputKind, Pandoc, PandocOutput}; -use std::{ - collections::HashMap, - fs, - path::{Path, PathBuf}, -}; +use std::{collections::HashMap, fs}; pub fn build_metafile(file: &MetaFile) -> Result { - let html = get_source_html(file, file.opts)?; + if file.header.blank { + return Ok(String::new()); + } + + let html = get_source_html(file)?; let pattern = get_pattern("base", file)?; let mut base = parse_file(pattern, file.opts)?; @@ -21,14 +21,11 @@ pub fn build_metafile(file: &MetaFile) -> Result { Ok(output) } -pub fn write_file(path: &Path, html: String, opts: &Options) -> Result<()> { - let dest = find_dest(path, opts)?; - // want newline to end file - fs::write(dest, html)?; - Ok(()) -} - fn metafile_to_string(file: &MetaFile) -> Result { + if file.header.blank { + return Ok(String::new()); + } + let mut output = String::default(); let mut arrays = false; @@ -56,25 +53,22 @@ fn metafile_to_string(file: &MetaFile) -> Result { } if arrays { - log!(file.opts, "\t\t\texpanding arrays", 4); expand_arrays(output, file) } else { Ok(output) } } -fn get_source_html(file: &MetaFile, opts: &Options) -> Result { - log!(opts, "\tbuilding source", 2); - let file = metafile_to_string(file)?; +fn get_source_html(file: &MetaFile) -> Result { + let string = metafile_to_string(file)?; - if opts.no_pandoc { - return Ok(file); + if file.opts.no_pandoc || !file.header.pandoc { + return Ok(string); } - log!(opts, "\t\tcalling pandoc", 3); let mut pandoc = Pandoc::new(); pandoc - .set_input(InputKind::Pipe(file)) + .set_input(InputKind::Pipe(string)) .set_output(OutputKind::Pipe) .set_input_format(InputFormat::Markdown, vec![]) .set_output_format(OutputFormat::Html, vec![]); @@ -88,44 +82,42 @@ fn get_source_html(file: &MetaFile, opts: &Options) -> Result { fn get_pattern(key: &str, file: &MetaFile) -> Result { // SOURCE is already expanded in the initial build_metafile() call - // we just need to return that if key == "SOURCE" { - log!(file.opts, "\t\t\treturning SOURCE", 4); if let Some(source) = file.patterns.get("SOURCE") { return Ok(source.to_string()); } } - log!(file.opts, format!("\t\tpattern: {}", key), 3); - // anything not defined should have a default.meta file to fall back to let mut filename: String; if let Some(name) = file.get_pat(key) { filename = name.to_string(); } else { + // anything not defined should have a default.meta file to fall back to filename = "default".to_string() } + // BLANK returns nothing, so no more processing needs to be done + if filename == "BLANK" { + return Ok(String::from("")); + }; + + // DEFAULT override for patterns overriding globals + if filename == "DEFAULT" { + filename = "default".to_string(); + } + // if we're building from base pattern we need to wait on // parsing/expansion so we can build and convert source to html // we just want to return the string right now if key == "base" { - log!(file.opts, "\t\t\treturning base", 4); let pattern_path = key.to_string() + "/" + &filename; let mut path = file.opts.pattern.join(pattern_path); path.set_extension("meta"); - let base = fs::read_to_string(&path)?; - return Ok(base); - } - - // BLANK returns nothing, so no more processing needs to be done - if filename == "BLANK" { - return Ok(String::from("")); - }; - - // DEFAULT override for patterns defined higher in chain - if filename == "DEFAULT" { - filename = "default".to_string(); + return match fs::read_to_string(&path) { + Ok(str) => Ok(str), + Err(_) => bail!("could not find base file {}", path.display()), + }; } let pattern_path = key.replace('.', "/") + "/" + &filename; @@ -153,15 +145,6 @@ fn get_variable(key: &str, file: &MetaFile) -> Result { } } -fn find_dest(path: &Path, opts: &Options) -> Result { - let path = path.canonicalize()?; - - let mut path = opts.build.join(path.strip_prefix(&opts.source)?); - path.set_extension("html"); - - Ok(path) -} - fn expand_arrays(input: String, file: &MetaFile) -> Result { let map: HashMap = file .source @@ -226,8 +209,11 @@ fn get_max_size(map: &HashMap) -> usize { #[cfg(test)] mod tests { use super::*; - fn build_options() -> Result { - let dir = PathBuf::from("files/site").canonicalize()?; + use crate::Options; + use std::path::PathBuf; + + fn unit_test(test: &str, result: &str) -> Result<()> { + let dir = PathBuf::from("files/test_site").canonicalize()?; let mut opts = Options::new(); opts.root = dir.clone(); @@ -236,32 +222,67 @@ mod tests { opts.pattern = dir.join("pattern"); opts.clean = true; - Ok(opts) + let test_dir = opts.source.join("unit_tests"); + let mut file_path = test_dir.join(test); + file_path.set_extension("meta"); + let file = MetaFile::build(file_path, &opts)?; + + let output = build_metafile(&file)?; + + assert_eq!(output, result); + + Ok(()) } #[test] fn test_find_dest() -> Result<()> { - let opts = build_options()?; - let path = opts.source.join("dir1/dir.meta"); - assert_eq!(find_dest(&path, &opts)?, opts.build.join("dir1/dir.html")); + unit_test("find_dest", "\n\n\n") + } + + #[test] + fn test_blank() -> Result<()> { + unit_test("blank/blank_pattern", "")?; + unit_test("blank/blank_variable", "\n\n")?; + unit_test("blank/blank_array", "\n\n")?; + Ok(()) + } + + #[test] + fn test_comment() -> Result<()> { + unit_test("blank/comment", "\n\n\n")?; + unit_test( + "blank/inline_comment", + "\n

inline comment

\n\n", + )?; + Ok(()) + } + + #[test] + fn test_expand() -> Result<()> { + unit_test( + "expand/variable_in_source", + "\n

GOOD

\n\n", + )?; + unit_test("expand/variable_in_pattern", "\nGOOD\n")?; + unit_test("expand/array_in_source", "\n

12345

\n\n")?; + unit_test("expand/array_in_pattern", "\n12345\n")?; + unit_test("expand/pattern_in_source", "

GOOD

\n")?; + unit_test("expand/pattern_in_pattern", "\nGOOD\nGOOD\n\n")?; Ok(()) } #[test] - fn test_metafile_to_string() -> Result<()> { - let opts = build_options()?; - let path = opts.source.join("dir1/sub_dir1/deep2/deep.meta"); - let expanded = "GOOD"; - assert_eq!(build_metafile(&MetaFile::build(path, &opts)?)?, expanded); + fn test_override() -> Result<()> { + unit_test("override/variable", "\n

GOOD

\n\n")?; + unit_test("override/pattern", "\nGOOD\nGOOD\n\n")?; Ok(()) } #[test] - fn test_get_pattern() -> Result<()> { - let opts = build_options()?; - let file = MetaFile::new(&opts); - let pat = get_pattern("header", &file)?; - assert_eq!(pat, "
HEADER
"); + #[ignore = "fix global variables"] + fn test_global() -> Result<()> { + unit_test("global/variable", "GOODGOOD\n")?; + unit_test("global/pattern", "GOODGOOD")?; Ok(()) } } diff --git a/src/metafile.rs b/src/metafile.rs index cb821da..05b811f 100644 --- a/src/metafile.rs +++ b/src/metafile.rs @@ -1,4 +1,4 @@ -use crate::{build_metafile, parse_file, write_file, Options}; +use crate::{build_metafile, parse_file, Options}; use color_eyre::{ eyre::{bail, eyre}, Result, @@ -6,11 +6,49 @@ use color_eyre::{ use std::collections::HashMap; use std::{fs, path::PathBuf}; +#[derive(Debug, Clone, Default)] +pub struct Header { + pub blank: bool, + pub panic_default: bool, + pub panic_undefined: bool, + pub filetype: String, + pub pandoc: bool, +} + +impl Header { + pub fn new() -> Self { + Self { + blank: false, + panic_default: false, + panic_undefined: false, + filetype: String::from("html"), + pandoc: true, + } + } +} + +impl From> for Header { + fn from(value: HashMap) -> Self { + let mut header = Header::new(); + for (key, val) in value.iter() { + match &key[..] { + "blank" => header.blank = val == "true", + "panic_default" => header.panic_default = val == "true", + "panic_undefined" => header.panic_undefined = val == "true", + "pandoc" => header.pandoc = val == "true", + "filetype" => header.filetype = val.to_string(), + _ => continue, + } + } + header + } +} + #[derive(Debug, Clone)] pub struct MetaFile<'a> { pub opts: &'a Options, pub path: PathBuf, - pub header: HashMap, + pub header: Header, pub variables: HashMap, pub arrays: HashMap>, pub patterns: HashMap, @@ -32,7 +70,7 @@ impl<'a> MetaFile<'a> { Self { opts, path: PathBuf::new(), - header: HashMap::new(), + header: Header::new(), variables: HashMap::new(), arrays: HashMap::new(), patterns: HashMap::new(), @@ -40,6 +78,16 @@ impl<'a> MetaFile<'a> { } } + pub fn dest(&self) -> Result { + let mut path = self + .opts + .build + .join(self.path.strip_prefix(&self.opts.source)?); + path.set_extension("html"); + + Ok(path) + } + pub fn name(&self) -> Result { if self.path.starts_with(&self.opts.source) { // in source dir, we want the file name without the '.meta' extension @@ -65,7 +113,7 @@ impl<'a> MetaFile<'a> { .unwrap_or_default(); Ok(name) } else { - color_eyre::eyre::bail!("could not get name from: {:#?}", self); + color_eyre::eyre::bail!("could not get name from: {}", self.path.display()); } } @@ -182,7 +230,7 @@ impl<'a> DirNode<'a> { file.merge(&self.global); match build_metafile(file) { Ok(str) => { - write_file(&file.path, str, file.opts)?; + fs::write(file.dest()?, str)?; } Err(e) => { if self.opts.force { diff --git a/src/parser.rs b/src/parser.rs index 817302b..af6bc7e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,4 @@ -use crate::{source, MetaFile, Options, Src, Sub}; +use crate::{source, Header, MetaFile, Options, Src, Sub}; use color_eyre::{eyre::WrapErr, Result}; use pest::{ iterators::{Pair, Pairs}, @@ -27,7 +27,7 @@ fn parse_pair<'a>(pair: Pair, opts: &'a Options) -> MetaFile<'a> { for pair in pair.into_inner() { match pair.as_rule() { Rule::source => meta_file.source = parse_source(pair.into_inner()), - Rule::header => meta_file.header = parse_defs(pair.into_inner()), + Rule::header => meta_file.header = Header::from(parse_defs(pair.into_inner())), Rule::var_def => meta_file.variables = parse_defs(pair.into_inner()), Rule::arr_def => meta_file.arrays = parse_array_defs(pair.into_inner()), Rule::pat_def => meta_file.patterns = parse_defs(pair.into_inner()), -- 2.44.2