A few straggling files that got left out of the prior commit

This commit is contained in:
Ryan McGrath 2019-05-26 00:27:47 -07:00
parent 6833e39d52
commit bb44f31dda
No known key found for this signature in database
GPG key ID: 811674B62B666830
6 changed files with 1494 additions and 0 deletions

123
styles/src/engine.rs Normal file
View file

@ -0,0 +1,123 @@
//! Implements a Theme Engine. This behaves a bit differently depending on
//! the mode your application is compiled in.
//!
//! - In `debug`, it scans a few places and loads any CSS files that are
//! necessary. It will also hot-reload CSS files as they change.
//! - In `release`, it scans those same places, and compiles your CSS into
//! your resulting binary. The hot-reloading functionality is not in release,
//! however it can be enabled if desired.
//!
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::StylesList;
use crate::styles::Style;
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>>
}
/// The `ThemeEngine` controls loading themes and registering associated
/// styles.
#[derive(Debug)]
pub struct ThemeEngine {
pub dirs: Vec<PathBuf>,
pub themes: RwLock<HashMap<String, StyleSheet>>
}
impl ThemeEngine {
/// Creates a new 'ThemeEngine` instance.
pub fn new() -> ThemeEngine {
// This env var is set by Cargo... so if this code breaks, there's
// bigger concerns, lol
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()) }
}
/// Registers a stylesheet (typically created by the `styles! {}` macro) for a given
/// theme.
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;
}
// if let Some(existing_stylesheet) = self.themes.get_mut(key) {
// *existing_stylesheet.merge(stylesheet);
//}
}
/// Given a theme key, style keys, and a style, configures the style for layout
/// and appearance.
pub fn configure_style_for_keys_in_theme(&self, theme: &str, keys: &StylesList, style: &mut Style) {
let themes = self.themes.read().unwrap();
match themes.get(theme) {
Some(theme) => {
for key in &keys.0 {
theme.apply_styles(key, style);
}
},
None => {
eprintln!("No styles for theme!");
}
}
}
/// The same logic as `configure_style_for_keys_in_theme`, but defaults to the default theme.
pub fn configure_style_for_keys(&self, keys: &StylesList, style: &mut Style) {
self.configure_style_for_keys_in_theme("default", keys, style)
}
}
/// Utility method for reading a config file from the `CARGO_MANIFEST_DIR`. Hat tip to
/// [askama](https://github.com/djc/askama) for this!
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()
}
}