use crate::{MetaError, MetaFile, Scope};
use eyre::Result;
-pub fn build_metafile(file: &MetaFile) -> Result<String, MetaError> {
+pub fn build_metafile(file: &MetaFile) -> Result<String, Box<MetaError>> {
if file.header.blank {
return Ok(String::new());
} else if file.header.ignore {
- return Err(MetaError::Ignored);
+ return Err(Box::new(MetaError::Ignored));
}
- let html = get_source_html(file)?;
+ let html = get_source_html(file).map_err(MetaError::from)?;
- let pattern = get_pattern("base", file)?;
- let mut base = crate::parse_string(pattern, file.opts)?;
+ let pattern = get_pattern("base", file).map_err(MetaError::from)?;
+ let mut base = crate::parse_string(pattern, file.opts).map_err(MetaError::from)?;
base.merge(file);
base.patterns.insert(Scope::into_global("SOURCE"), html);
- let output = metafile_to_string(&base)?;
+ let output = metafile_to_string(&base).map_err(MetaError::from)?;
Ok(output)
}
-use crate::{MetaFile, Scope, Src};
+use crate::{MetaError, MetaFile, Scope, Src};
use eyre::Result;
use std::collections::HashMap;
let name = file.name().unwrap_or_default();
let long_key = name + "." + key;
- let value = if let Some(val) = file.get_arr(&Scope::into_global(long_key.to_string())) {
+ let value = if let Some(val) = file.get_arr(&Scope::into_global(&long_key)) {
val
- } else if let Some(val) = file.get_arr(&Scope::into_local(long_key.to_string())) {
+ } else if let Some(val) = file.get_arr(&Scope::into_local(&long_key)) {
val
} else if let Some(val) = file.get_arr(&Scope::into_global(key)) {
val
} else if let Some(val) = file.get_arr(&Scope::into_local(key)) {
val
} else if file.opts.undefined {
- panic!("undefined array called: {}, {}", key, long_key);
+ panic!(
+ "{}",
+ MetaError::UndefinedExpand {
+ val: key.to_string(),
+ path: file.path.to_string_lossy().to_string(),
+ }
+ )
} else {
&[]
};
// loop to duplicate the output template for each array member
let mut expanded = String::new();
- for i in 0..get_max_size(&map) {
+ let size = match get_array_size(&map, file.header.equal_arrays) {
+ Ok(num) => Ok(num),
+ Err(e) => match e.as_ref() {
+ &MetaError::Array => Err(MetaError::UnequalArrays {
+ path: file.path.to_string_lossy().to_string(),
+ }),
+ _ => Err(MetaError::Unknown),
+ },
+ }?;
+ for i in 0..size {
// get a fresh copy of the file
let mut str = input.clone();
// replace each key in the file
Ok(expanded)
}
-fn get_max_size(map: &HashMap<String, &[String]>) -> usize {
+fn get_array_size(
+ map: &HashMap<String, &[String]>,
+ same_size: bool,
+) -> Result<usize, Box<MetaError>> {
+ if same_size {
+ let mut size = (0, false);
+ for val in map.values() {
+ if !size.1 {
+ size = (val.len(), true);
+ } else if size.0 != val.len() {
+ return Err(Box::new(MetaError::Array));
+ }
+ }
+ return Ok(size.0);
+ }
+
let mut max = 0;
for val in map.values() {
if max < val.len() {
max = val.len();
}
}
- max
+ Ok(max)
}
use crate::{MetaError, MetaFile, Src};
use eyre::Result;
+use pandoc::{InputFormat, InputKind, OutputFormat, OutputKind, Pandoc};
use super::array::*;
use super::*;
pub fn get_source_html(file: &MetaFile) -> Result<String> {
let string = metafile_to_string(file)?;
- if file.opts.no_pandoc || !file.header.pandoc || string == "" {
+ if file.opts.no_pandoc || !file.header.pandoc || string.is_empty() {
return Ok(string);
}
- let input: pandoc::InputFormat;
- let output: pandoc::OutputFormat;
- if let Ok(io) = get_pandoc_io(&file) {
+ let input: InputFormat;
+ let output: OutputFormat;
+ if let Ok(io) = get_pandoc_io(file) {
input = io.0;
output = io.1;
} else {
return Ok(string);
}
- let mut pandoc = pandoc::Pandoc::new();
+ let mut pandoc = Pandoc::new();
pandoc
- .set_input(pandoc::InputKind::Pipe(string))
- .set_output(pandoc::OutputKind::Pipe)
+ .set_input(InputKind::Pipe(string))
+ .set_output(OutputKind::Pipe)
.set_input_format(input, vec![])
.set_output_format(output, vec![]);
fn get_pandoc_io(
file: &MetaFile,
-) -> Result<(pandoc::InputFormat, pandoc::OutputFormat), MetaError> {
- let input: pandoc::InputFormat;
- let output: pandoc::OutputFormat;
-
+) -> Result<(pandoc::InputFormat, pandoc::OutputFormat), Box<MetaError>> {
let mut source_type = "";
if !file.header.source.is_empty() {
source_type = &file.header.source;
source_type = &file.opts.input;
}
- match source_type {
- "markdown" => input = pandoc::InputFormat::Markdown,
- "html" => input = pandoc::InputFormat::Html,
- "org" => input = pandoc::InputFormat::Org,
- "json" => input = pandoc::InputFormat::Json,
- "latex" => input = pandoc::InputFormat::Latex,
- _ => return Err(MetaError::Filetype.into()),
- }
+ let input = match source_type {
+ "markdown" => Ok(InputFormat::Markdown),
+ "html" => Ok(InputFormat::Html),
+ "org" => Ok(InputFormat::Org),
+ "json" => Ok(InputFormat::Json),
+ "latex" => Ok(InputFormat::Latex),
+ _ => Err(Box::new(MetaError::Filetype)),
+ }?;
let mut filetype = "";
if !file.header.filetype.is_empty() {
filetype = &file.opts.output;
}
- match filetype {
- "html" => output = pandoc::OutputFormat::Html,
- "markdown" => output = pandoc::OutputFormat::Markdown,
- "man" => output = pandoc::OutputFormat::Man,
- "txt" => output = pandoc::OutputFormat::Plain,
- "org" => output = pandoc::OutputFormat::Org,
- "json" => output = pandoc::OutputFormat::Json,
- "latex" => output = pandoc::OutputFormat::Latex,
- "asciidoc" => output = pandoc::OutputFormat::Asciidoc,
- "pdf" => output = pandoc::OutputFormat::Pdf,
- _ => return Err(MetaError::Filetype.into()),
- };
+ let output = match filetype {
+ "html" => Ok(OutputFormat::Html),
+ "markdown" => Ok(OutputFormat::Markdown),
+ "man" => Ok(OutputFormat::Man),
+ "txt" => Ok(OutputFormat::Plain),
+ "org" => Ok(OutputFormat::Org),
+ "json" => Ok(OutputFormat::Json),
+ "latex" => Ok(OutputFormat::Latex),
+ "asciidoc" => Ok(OutputFormat::Asciidoc),
+ "pdf" => Ok(OutputFormat::Pdf),
+ _ => Err(Box::new(MetaError::Filetype)),
+ }?;
Ok((input, output))
}
fn builder_tests() -> Result<()> {
clean_build_dir()?;
- let mut tests: Vec<(&str, &str)> = Vec::new();
- tests.push(("find_dest", "<html>\n</html>\n"));
- tests.push(("blank/blank_pattern", ""));
- tests.push(("blank/blank_variable", "<html>\n</html>\n"));
- tests.push(("blank/blank_array", "<html>\n</html>\n"));
- tests.push(("blank/comment", "<html>\n</html>\n"));
- tests.push((
- "blank/inline_comment",
- "<html>\n<p>inline comment</p>\n</html>\n",
- ));
- tests.push((
- "expand/variable_in_source",
- "<html>\n<p>GOOD</p>\n</html>\n",
- ));
- tests.push(("expand/variable_in_pattern", "<html>\nGOOD</html>\n"));
- tests.push(("expand/array_in_source", "<html>\n<p>12345</p>\n</html>\n"));
- tests.push(("expand/array_in_pattern", "<html>\n12345</html>\n"));
- tests.push(("expand/pattern_in_source", "<p>GOOD</p>\n"));
- tests.push(("expand/pattern_in_pattern", "<html>\nGOOD\nGOOD\n</html>\n"));
- tests.push(("override/variable", "<html>\n<p>GOOD</p>\n</html>\n"));
- tests.push(("override/pattern", "<html>\nGOOD\nGOOD\n</html>\n"));
- tests.push(("header/pandoc", "# This should not become html\n"));
- tests.push(("header/blank", ""));
+ let tests: Vec<(&str, &str)> = vec![
+ ("find_dest", "<html>\n</html>\n"),
+ ("blank/blank_pattern", ""),
+ ("blank/blank_variable", "<html>\n</html>\n"),
+ ("blank/blank_array", "<html>\n</html>\n"),
+ ("blank/comment", "<html>\n</html>\n"),
+ (
+ "blank/inline_comment",
+ "<html>\n<p>inline comment</p>\n</html>\n",
+ ),
+ (
+ "expand/variable_in_source",
+ "<html>\n<p>GOOD</p>\n</html>\n",
+ ),
+ ("expand/variable_in_pattern", "<html>\nGOOD</html>\n"),
+ ("expand/array_in_source", "<html>\n<p>12345</p>\n</html>\n"),
+ ("expand/array_in_pattern", "<html>\n12345</html>\n"),
+ ("expand/pattern_in_source", "<p>GOOD</p>\n"),
+ ("expand/pattern_in_pattern", "<html>\nGOOD\nGOOD\n</html>\n"),
+ ("override/variable", "<html>\n<p>GOOD</p>\n</html>\n"),
+ ("override/pattern", "<html>\nGOOD\nGOOD\n</html>\n"),
+ ("header/pandoc", "# This should not become html\n"),
+ ("header/blank", ""),
+ ];
let mut err = false;
let mut errs: Vec<Box<dyn Error>> = Vec::new();
if err {
for e in errs.iter() {
- eprintln!("{}", e.to_string());
+ eprintln!("{}", e);
}
return Err(eyre::eyre!("failed tests"));
}
pub fn get_variable(key: &str, file: &MetaFile) -> Result<String> {
let long_key = file.name()? + "." + key;
- if let Some(val) = file.get_var(&Scope::into_local(long_key.to_string())) {
+ if let Some(val) = file.get_var(&Scope::into_local(&long_key)) {
Ok(val.clone())
- } else if let Some(val) = file.get_var(&Scope::into_global(long_key.to_string())) {
+ } else if let Some(val) = file.get_var(&Scope::into_global(&long_key)) {
Ok(val.clone())
} else if let Some(val) = file.get_var(&Scope::into_local(key)) {
Ok(val.clone())
#[derive(Error, Debug)]
pub enum MetaError {
- #[error("unknown error")]
+ #[error("unknown internal error")]
Unknown,
- #[error("ignored")]
+ #[error("internal break switch")]
Ignored,
- #[error("filetype")]
+ #[error("internal filetype error")]
Filetype,
+ #[error("internal array error")]
+ Array,
+ #[error("mismatched array sizes in {path}")]
+ UnequalArrays { path: String },
#[error("could not find {path}")]
FileNotFound { path: String },
#[error("could not determine name from {file}")]
pub fn single_file(opts: &Options) -> Result<String> {
let path = opts.file.as_ref().ok_or(MetaError::Unknown)?;
- let source = match fs::read_to_string(&path) {
+ let source = match fs::read_to_string(path) {
Ok(str) => Ok(str),
Err(_) => Err(eyre::Error::from(MetaError::FileNotFound {
path: path.to_string_lossy().to_string(),
return metaforge::new_site(&opts);
}
- if let Some(_) = &opts.file {
+ if opts.file.is_some() {
let str = metaforge::single_file(&opts)?;
println!("{str}");
Ok(())
} else {
- return metaforge::build_site(&opts);
+ metaforge::build_site(&opts)
}
}
pub fn to_str(str: impl ToString) -> Self {
Src::Str(str.to_string())
}
+}
- pub fn to_string(&self) -> String {
+impl ToString for Src {
+ fn to_string(&self) -> String {
match self {
Src::Var(x) | Src::Arr(x) | Src::Pat(x) | Src::Str(x) => x.to_string(),
}
continue;
} else {
// we raise an ignored error to quickly abort any file parsing
- if let MetaError::Ignored = e {
+ if let MetaError::Ignored = *e {
continue;
// anything else gets wrapped up and passed up the calling chain
} else {
}
pub fn var_defined(&self, key: &str) -> bool {
- if self.variables.contains_key(&Scope::into_local(key))
+ self.variables.contains_key(&Scope::into_local(key))
|| self.variables.contains_key(&Scope::into_global(key))
- {
- true
- } else {
- false
- }
}
pub fn arr_defined(&self, key: &str) -> bool {
- if self.arrays.contains_key(&Scope::into_local(key))
+ self.arrays.contains_key(&Scope::into_local(key))
|| self.arrays.contains_key(&Scope::into_global(key))
- {
- true
- } else {
- false
- }
}
pub fn pat_defined(&self, key: &str) -> bool {
- if self.patterns.contains_key(&Scope::into_local(key))
+ self.patterns.contains_key(&Scope::into_local(key))
|| self.patterns.contains_key(&Scope::into_global(key))
- {
- true
- } else {
- false
- }
}
pub fn merge(&mut self, other: &Self) {
Scope::Global(str.to_string())
}
- pub fn to_string(&self) -> String {
- match self {
- Scope::Local(x) | Scope::Global(x) => x.to_string(),
- }
- }
-
pub fn is_global(&self) -> bool {
match self {
Scope::Local(_) => false,
Scope::Global(self.to_string())
}
}
+
+impl ToString for Scope {
+ fn to_string(&self) -> String {
+ match self {
+ Scope::Local(x) | Scope::Global(x) => x.to_string(),
+ }
+ }
+}