use std::fs;
use std::env;
use std::sync::RwLock;
use std::path::PathBuf;
use std::collections::HashMap;
use toml;
use serde::Deserialize;
use crate::stretch::style::Style;
use crate::StylesList;
use crate::styles::Appearance;
use crate::stylesheet::StyleSheet;
static CONFIG_FILE_NAME: &str = "alchemy.toml";
#[derive(Debug, Deserialize)]
struct RawConfig<'d> {
#[serde(borrow)]
general: Option<General<'d>>,
}
#[derive(Debug, Deserialize)]
struct General<'a> {
#[serde(borrow)]
dirs: Option<Vec<&'a str>>
}
#[derive(Debug)]
pub struct ThemeEngine {
pub dirs: Vec<PathBuf>,
pub themes: RwLock<HashMap<String, StyleSheet>>
}
impl ThemeEngine {
pub fn new() -> ThemeEngine {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let root = PathBuf::from(manifest_dir);
let default_dirs = vec![root.join("themes")];
let toml_contents = read_config_file();
let raw: RawConfig<'_> = toml::from_str(&toml_contents).expect(&format!("Invalid TOML in {}!", CONFIG_FILE_NAME));
let dirs = match raw.general {
Some(General { dirs }) => (
dirs.map_or(default_dirs, |v| {
v.into_iter().map(|dir| root.join(dir)).collect()
})
),
None => default_dirs
};
ThemeEngine { dirs, themes: RwLock::new(HashMap::new()) }
}
pub fn register_styles(&self, key: &str, stylesheet: StyleSheet) {
let mut themes = self.themes.write().unwrap();
if !themes.contains_key(key) {
themes.insert(key.to_string(), stylesheet);
return;
}
}
pub fn configure_style_for_keys_in_theme(
&self,
theme: &str,
keys: &StylesList,
style: &mut Style,
appearance: &mut Appearance
) {
let themes = self.themes.read().unwrap();
match themes.get(theme) {
Some(theme) => {
for key in &keys.0 {
theme.apply_styles(key, style, appearance);
}
},
None => {
eprintln!("No styles for theme!");
}
}
}
pub fn configure_styles_for_keys(&self, keys: &StylesList, style: &mut Style, appearance: &mut Appearance) {
self.configure_style_for_keys_in_theme("default", keys, style, appearance)
}
}
pub fn read_config_file() -> String {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let root = PathBuf::from(manifest_dir);
let filename = root.join(CONFIG_FILE_NAME);
if filename.exists() {
fs::read_to_string(&filename)
.expect(&format!("Unable to read {}", filename.to_str().unwrap()))
} else {
"".to_string()
}
}