Broke up modules

This commit is contained in:
KitsuneCafe 2024-02-02 20:20:27 -05:00
parent 2bebd0e540
commit 07f304066a
7 changed files with 212 additions and 124 deletions

18
Cargo.lock generated
View file

@ -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",
]

View file

@ -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"

31
src/config.rs Normal file
View file

@ -0,0 +1,31 @@
use std::str::FromStr;
use serde::Deserialize;
#[derive(Debug, Default, Deserialize)]
pub(crate) struct Config {
pub theme: Option<String>,
pub themes: Vec<String>,
}
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<Self, Self::Err> {
toml::from_str(s)
}
}

39
src/context.rs Normal file
View file

@ -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<P: AsRef<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<P: AsRef<Path>>(&mut self, path: &P, value: &tera::Value) {
self.inner
.insert(Self::normalize_path(path).trim_start_matches('.'), &value);
}
pub fn get<P: AsRef<Path>>(&self, path: &P) -> Option<&tera::Value> {
self.inner.get(&Self::normalize_path(path))
}
}

36
src/error.rs Normal file
View file

@ -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<String> for Error {
fn from(value: String) -> Self {
Self { message: value }
}
}
impl From<PatternError> for Error {
fn from(value: PatternError) -> Self {
Self {
message: value.to_string(),
}
}
}
impl From<StripPrefixError> for Error {
fn from(value: StripPrefixError) -> Self {
Self {
message: value.to_string(),
}
}
}
impl From<Error> for IOError {
fn from(value: Error) -> Self {
IOError::new(ErrorKind::Other, value.message)
}
}

52
src/file_path.rs Normal file
View file

@ -0,0 +1,52 @@
use std::path::{PathBuf, Path, StripPrefixError};
use crate::error::Error;
#[derive(Debug, Clone)]
pub(crate) struct FilePath<'a, P: AsRef<Path>> {
pub input: PathBuf,
pub root_dir: PathBuf,
pub output: &'a P,
}
impl<'a, P: AsRef<Path> + '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<S: AsRef<str>>(path: &S) -> bool {
!path.as_ref().contains("*")
}
fn strip_wildcards<P2: AsRef<Path> + ?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<P2: AsRef<Path>>(&self, value: &'a P2) -> Result<PathBuf, Error> {
value
.as_ref()
.strip_prefix(&self.root_dir)
.map(|path| self.output.as_ref().join(path))
.map_err(Error::from)
}
pub fn strip_root<P2: AsRef<Path>>(&self, value: &'a P2) -> Result<&Path, StripPrefixError> {
value.as_ref().strip_prefix(&self.root_dir)
}
}

View file

@ -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<String> for RoxyError {
fn from(value: String) -> Self {
Self { message: value }
}
}
impl From<PatternError> for RoxyError {
fn from(value: PatternError) -> Self {
Self {
message: value.to_string(),
}
}
}
impl From<StripPrefixError> for RoxyError {
fn from(value: StripPrefixError) -> Self {
Self {
message: value.to_string(),
}
}
}
impl From<RoxyError> for Error {
fn from(value: RoxyError) -> Self {
Error::new(ErrorKind::Other, value.message)
}
}
fn get_files<P: AsRef<Path> + std::fmt::Debug>(path: &P) -> Result<Vec<PathBuf>, RoxyError> {
fn get_files<P: AsRef<Path> + std::fmt::Debug>(path: &P) -> Result<Vec<PathBuf>, 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<PathBuf> = glob(path)?
.filter_map(|x| x.ok())
@ -69,89 +48,21 @@ fn get_files<P: AsRef<Path> + std::fmt::Debug>(path: &P) -> Result<Vec<PathBuf>,
Ok(files)
}
#[derive(Debug, Clone)]
struct FilePath<'a, P: AsRef<Path>> {
input: PathBuf,
root_dir: PathBuf,
output: &'a P,
}
impl<'a, P: AsRef<Path> + '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<S: AsRef<str>>(path: &S) -> bool {
!path.as_ref().contains("*")
}
fn strip_wildcards<P2: AsRef<Path> + ?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<P2: AsRef<Path>>(&self, value: &'a P2) -> Result<PathBuf, RoxyError> {
value
.as_ref()
.strip_prefix(&self.root_dir)
.map(|path| self.output.as_ref().join(path))
.map_err(RoxyError::from)
}
pub fn strip_root<P2: AsRef<Path>>(&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<P: AsRef<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<P: AsRef<Path>>(&mut self, path: &P, value: &tera::Value) {
self.inner
.insert(Self::normalize_path(path).trim_start_matches('.'), &value);
}
fn get<P: AsRef<Path>>(&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::<Config>(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(())
}