From 07f304066a1f14894d968e08029b58e0f50a0c6a Mon Sep 17 00:00:00 2001 From: KitsuneCafe <10284516+kitsunecafe@users.noreply.github.com> Date: Fri, 2 Feb 2024 20:20:27 -0500 Subject: [PATCH] Broke up modules --- Cargo.lock | 18 +++++- Cargo.toml | 1 + src/config.rs | 31 +++++++++ src/context.rs | 39 ++++++++++++ src/error.rs | 36 +++++++++++ src/file_path.rs | 52 ++++++++++++++++ src/main.rs | 159 +++++++++++------------------------------------ 7 files changed, 212 insertions(+), 124 deletions(-) create mode 100644 src/config.rs create mode 100644 src/context.rs create mode 100644 src/error.rs create mode 100644 src/file_path.rs diff --git a/Cargo.lock b/Cargo.lock index a267464..0a81449 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -824,6 +824,7 @@ dependencies = [ "roxy_core", "roxy_markdown_parser", "roxy_markdown_tera_rewriter", + "roxy_syntect", "roxy_tera_parser", "serde", "syntect", @@ -848,15 +849,28 @@ dependencies = [ [[package]] name = "roxy_markdown_tera_rewriter" version = "0.1.0" +source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-markdown-tera-rewriter.git#5c33c0c2625c239694c8b7bb16f5da902cfd5e44" dependencies = [ "once_cell", "regex", "roxy_core", ] +[[package]] +name = "roxy_syntect" +version = "0.1.0" +source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-syntect.git#0cdfa876f9ca13be475dfac77b0d37ebb7d45da3" +dependencies = [ + "once_cell", + "regex", + "roxy_core", + "syntect", +] + [[package]] name = "roxy_tera_parser" version = "0.1.0" +source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-tera-parser.git#d8bd4aa1f0bbe4f9982ae17711ed69fead71c327" dependencies = [ "once_cell", "regex", @@ -1370,9 +1384,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.36" +version = "0.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818ce546a11a9986bc24f93d0cdf38a8a1a400f1473ea8c82e59f6e0ffab9249" +checksum = "a7cad8365489051ae9f054164e459304af2e7e9bb407c958076c8bf4aef52da5" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 4d9a889..63c03fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ syntect = "5.1.0" roxy_markdown_parser = { git = "https://fem.mint.lgbt/kitsunecafe/roxy-markdown-parser.git" } roxy_tera_parser = { git = "https://fem.mint.lgbt/kitsunecafe/roxy-tera-parser.git" } roxy_markdown_tera_rewriter = { git = "https://fem.mint.lgbt/kitsunecafe/roxy-markdown-tera-rewriter.git" } +roxy_syntect = { git = "https://fem.mint.lgbt/kitsunecafe/roxy-syntect.git" } roxy_core = { git = "https://fem.mint.lgbt/kitsunecafe/roxy-core.git" } clap = { version = "4.4.17", features = ["derive"] } toml = "0.8.8" diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..065fbe6 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,31 @@ +use std::str::FromStr; + +use serde::Deserialize; + +#[derive(Debug, Default, Deserialize)] +pub(crate) struct Config { + pub theme: Option, + pub themes: Vec, +} + +impl Config { + pub fn merge(self, other: Config) -> Self { + Self { + theme: self.theme.or(other.theme), + themes: if self.themes.is_empty() { + other.themes + } else { + self.themes + }, + } + } +} + +impl FromStr for Config { + type Err = toml::de::Error; + + fn from_str(s: &str) -> Result { + toml::from_str(s) + } +} + diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..419f5d7 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,39 @@ +use std::path::{Path, MAIN_SEPARATOR_STR}; + +#[derive(Debug)] +pub(crate) struct Context { + inner: tera::Context, +} + +impl Context { + pub fn new() -> Self { + Self { + inner: tera::Context::new(), + } + } + + pub fn to_inner(&self) -> &tera::Context { + &self.inner + } + + pub fn normalize_path>(path: &P) -> String { + path.as_ref() + .with_extension("") + .to_string_lossy() + .trim() + .split(MAIN_SEPARATOR_STR) + .fold(String::new(), |a, b| format!("{a}.{b}")) + .trim_matches('.') + .to_string() + } + + pub fn insert>(&mut self, path: &P, value: &tera::Value) { + self.inner + .insert(Self::normalize_path(path).trim_start_matches('.'), &value); + } + + pub fn get>(&self, path: &P) -> Option<&tera::Value> { + self.inner.get(&Self::normalize_path(path)) + } +} + diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..5cce282 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,36 @@ +use std::{io::{Error as IOError, ErrorKind}, path::StripPrefixError}; + +use glob::PatternError; +#[derive(Debug)] +pub struct Error { + message: String, +} + +impl From for Error { + fn from(value: String) -> Self { + Self { message: value } + } +} + +impl From for Error { + fn from(value: PatternError) -> Self { + Self { + message: value.to_string(), + } + } +} + +impl From for Error { + fn from(value: StripPrefixError) -> Self { + Self { + message: value.to_string(), + } + } +} + +impl From for IOError { + fn from(value: Error) -> Self { + IOError::new(ErrorKind::Other, value.message) + } +} + diff --git a/src/file_path.rs b/src/file_path.rs new file mode 100644 index 0000000..bfecc60 --- /dev/null +++ b/src/file_path.rs @@ -0,0 +1,52 @@ +use std::path::{PathBuf, Path, StripPrefixError}; + +use crate::error::Error; + +#[derive(Debug, Clone)] +pub(crate) struct FilePath<'a, P: AsRef> { + pub input: PathBuf, + pub root_dir: PathBuf, + pub output: &'a P, +} + +impl<'a, P: AsRef + 'a> FilePath<'a, P> { + pub fn new(input: &'a P, output: &'a P) -> Self { + Self { + input: Self::make_recursive(input), + root_dir: Self::strip_wildcards(input), + output, + } + } + + fn make_recursive(path: &'a P) -> PathBuf { + path.as_ref().join("**/*") + } + + fn has_no_wildcard>(path: &S) -> bool { + !path.as_ref().contains("*") + } + + fn strip_wildcards + ?Sized>(path: &'a P2) -> PathBuf { + path.as_ref() + .ancestors() + .map(Path::to_str) + .flatten() + .find(Self::has_no_wildcard) + .map_or_else(|| PathBuf::new(), PathBuf::from) + } + + pub fn to_output>(&self, value: &'a P2) -> Result { + value + .as_ref() + .strip_prefix(&self.root_dir) + .map(|path| self.output.as_ref().join(path)) + .map_err(Error::from) + } + + pub fn strip_root>(&self, value: &'a P2) -> Result<&Path, StripPrefixError> { + value.as_ref().strip_prefix(&self.root_dir) + } +} + + + diff --git a/src/main.rs b/src/main.rs index 8082166..8e39c2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,29 @@ +pub mod error; +pub mod context; +pub mod config; +mod file_path; + use clap::Parser as Clap; +use config::Config; +use context::Context; +use file_path::FilePath; +use crate::error::Error; use roxy_markdown_parser::MarkdownParser; -use roxy_markdown_tera_rewriter::{MarkdownTeraRewriter, MarkdownTeraPreformatter}; +use roxy_markdown_tera_rewriter::{MarkdownTeraPreformatter, MarkdownTeraRewriter}; +use roxy_syntect::SyntectParser; use roxy_tera_parser::{TeraParser, TeraParserOptions}; use std::{ - fs::File, - io::{BufReader, Error, ErrorKind, Read}, - path::{self, Path, PathBuf, StripPrefixError}, + fs::{self, File}, + io::{BufReader, Read}, + path::{Path, PathBuf}, }; use toml::Table; -use glob::{glob, PatternError}; +use glob::glob; use roxy_core::roxy::{Parser, Roxy}; +const DEFAULT_THEME: &'static str = "base16-ocean.dark"; + #[derive(Clap)] #[command(name = "Roxy")] #[command(author = "KitsuneCafe")] @@ -22,44 +34,11 @@ pub struct Options { pub output: String, } -#[derive(Debug)] -struct RoxyError { - message: String, -} - -impl From for RoxyError { - fn from(value: String) -> Self { - Self { message: value } - } -} - -impl From for RoxyError { - fn from(value: PatternError) -> Self { - Self { - message: value.to_string(), - } - } -} - -impl From for RoxyError { - fn from(value: StripPrefixError) -> Self { - Self { - message: value.to_string(), - } - } -} - -impl From for Error { - fn from(value: RoxyError) -> Self { - Error::new(ErrorKind::Other, value.message) - } -} - -fn get_files + std::fmt::Debug>(path: &P) -> Result, RoxyError> { +fn get_files + std::fmt::Debug>(path: &P) -> Result, Error> { let path = path .as_ref() .to_str() - .ok_or_else(|| RoxyError::from(format!("{path:?} is not a valid path.")))?; + .ok_or_else(|| Error::from(format!("{path:?} is not a valid path.")))?; let files: Vec = glob(path)? .filter_map(|x| x.ok()) @@ -69,89 +48,21 @@ fn get_files + std::fmt::Debug>(path: &P) -> Result, Ok(files) } -#[derive(Debug, Clone)] -struct FilePath<'a, P: AsRef> { - input: PathBuf, - root_dir: PathBuf, - output: &'a P, -} - -impl<'a, P: AsRef + 'a> FilePath<'a, P> { - pub fn new(input: &'a P, output: &'a P) -> Self { - Self { - input: Self::make_recursive(input), - root_dir: Self::strip_wildcards(input), - output, - } - } - - fn make_recursive(path: &'a P) -> PathBuf { - path.as_ref().join("**/*") - } - - fn has_no_wildcard>(path: &S) -> bool { - !path.as_ref().contains("*") - } - - fn strip_wildcards + ?Sized>(path: &'a P2) -> PathBuf { - path.as_ref() - .ancestors() - .map(Path::to_str) - .flatten() - .find(Self::has_no_wildcard) - .map_or_else(|| PathBuf::new(), PathBuf::from) - } - - pub fn to_output>(&self, value: &'a P2) -> Result { - value - .as_ref() - .strip_prefix(&self.root_dir) - .map(|path| self.output.as_ref().join(path)) - .map_err(RoxyError::from) - } - - pub fn strip_root>(&self, value: &'a P2) -> Result<&Path, StripPrefixError> { - value.as_ref().strip_prefix(&self.root_dir) - } -} - -#[derive(Debug)] -struct Context { - pub inner: tera::Context, -} - -impl Context { - fn new() -> Self { - Self { - inner: tera::Context::new(), - } - } - - fn normalize_path>(path: &P) -> String { - path.as_ref() - .with_extension("") - .to_string_lossy() - .trim() - .split(path::MAIN_SEPARATOR_STR) - .fold(String::new(), |a, b| format!("{a}.{b}")) - .trim_matches('.') - .to_string() - } - - fn insert>(&mut self, path: &P, value: &tera::Value) { - self.inner - .insert(Self::normalize_path(path).trim_start_matches('.'), &value); - } - - fn get>(&self, path: &P) -> Option<&tera::Value> { - self.inner.get(&Self::normalize_path(path)) - } -} - -fn main() -> Result<(), RoxyError> { +fn main() -> Result<(), Error> { let opts = Options::parse(); let file_path = FilePath::new(&opts.input, &opts.output); + + let config_path = file_path.input.with_file_name("config.toml"); + let config = fs::read_to_string(&config_path).map_or_else( + |_| Config::default(), + |f| { + toml::from_str::(f.as_str()) + .unwrap() + .merge(Config::default()) + }, + ); + let files = get_files(&file_path.input)?; let (meta, files): (Vec<&PathBuf>, Vec<&PathBuf>) = files.iter().partition(|f| f.extension().unwrap() == "toml"); @@ -172,11 +83,15 @@ fn main() -> Result<(), RoxyError> { ); } + let theme = config.theme.unwrap_or(DEFAULT_THEME.to_string()); for file in files { let mut parser = Parser::new(); let mut preformatter = MarkdownTeraPreformatter::new(); parser.push(&mut preformatter); + let mut syntect = SyntectParser::new(&theme.as_str()); + parser.push(&mut syntect); + let mut md = MarkdownParser::new(); parser.push(&mut md); @@ -194,10 +109,10 @@ fn main() -> Result<(), RoxyError> { let mut tera = tera::Tera::default(); let mut html = TeraParser::new(&mut tera, TeraParserOptions::default()); - html.add_context(&context.inner); + html.add_context(context.to_inner()); parser.push(&mut html); + Roxy::process_file(&file, &output_path, &mut parser).unwrap(); } Ok(()) } -