//! configuration struct and implementations use std::{ collections::BTreeMap, env::var, fs::{ create_dir, read_to_string, File }, io::Error, path::PathBuf, process::exit }; use upon::Value as ContextValue; use toml::{ map::Map, Value }; use crate::{ error, util }; pub type Context = BTreeMap; pub type Table = toml::map::Map; /// configuration struct pub struct Config { pub dir: String, inner: Map } impl Config { /// create a new Config using the file at '$HOME/.config/oink/oink.toml' pub fn new() -> Config { // get base config dir let home = var("HOME").unwrap(); let mut dir = PathBuf::from(&home); dir.push(".config/oink"); if !dir.exists() { println!("missing directory at {dir:?}, creating..."); let setup = setup_dirs(&dir); if setup.is_err() { error::setup_dirs(&dir); } println!("created configuration directory, exiting..."); exit(0); } // read toml file let mut toml_path = dir.clone(); toml_path.push("oink.toml"); let raw = read_to_string(toml_path).unwrap(); let toml_conf: Value = toml::from_str(&raw).unwrap(); let inner = toml_conf.as_table().unwrap(); // return struct Config { dir: dir.to_string_lossy().to_string(), inner: inner.to_owned() } } /// build context from "vars" and "colors" config sections pub fn context(&self, target: &Table) -> Context { let mut output = Context::new(); // pull global vars if let Some(Value::Table(vars)) = self.inner.get("vars") { for (key, value) in vars.iter() { output.insert(key.to_owned(), value.as_str().into()); } } // pull target values for (key, value) in target.iter() { if key.to_uppercase() == *key { output.insert(key.to_owned(), value.as_str().unwrap().into()); } } // pull palette let palette_name: Option = if let Some(Value::String(name)) = target.get("use_palette") { Some(name.clone()) } else if let Some(Value::String(name)) = self.inner.get("use_palette") { Some(name.clone()) } else { None }; if let Some(Value::Array(array)) = self.inner.get("palette") { let palette = util::matches(array.to_owned(), palette_name.unwrap_or("default".to_string())); if let Some(Value::Table(palette)) = palette { let colors = Context::new(); for(key, value) in palette.iter() { output.insert(key.to_owned(), value.as_str().unwrap().into()); } output.insert("palette".to_string(), colors.into()); } } output } /// build array of targets from "target" array pub fn targets(&self) -> Vec> { let mut output = Vec::new(); let target_array: Option<&Value> = self.inner.get("target"); if target_array.is_some() { let target_array = target_array.unwrap().as_array().unwrap().to_owned(); for target in target_array { output.push(target.as_table().unwrap().to_owned()); } } output } } fn setup_dirs(path: &PathBuf) -> Result<(), Error> { // create main directory create_dir(path)?; // create template directory let mut templates = path.clone(); templates.push("templates/"); create_dir(templates)?; // create generated directory let mut generated = path.clone(); generated.push("generated/"); create_dir(generated)?; // create main toml let mut toml = path.clone(); toml.push("oink.toml"); File::create(toml)?; Ok(()) }