roftl/src/core/settings.rs

150 lines
3.5 KiB
Rust

use config::builder::DefaultState;
use config::ConfigError;
use config::{Config, ConfigBuilder};
use serde::Deserialize;
use std::collections::HashMap;
use std::convert::TryInto;
use std::path::Path;
#[derive(Debug, Deserialize)]
pub struct Color(f64, f64, f64, f64);
#[derive(Debug, Deserialize)]
pub struct ColorScheme {
base: Color,
border: Color,
highlight: Color,
divider: Color,
text: Color,
text_highlight: Color,
}
#[derive(Debug, Deserialize)]
pub struct Theme {
color_scheme: ColorScheme,
font: (String, i32),
border: f64,
divider: f64,
}
#[derive(Debug, Deserialize)]
pub enum Matcher {
Prefix,
Fuse,
Flex,
Skim,
}
impl Matcher {
pub fn init(&self) -> Box<dyn super::shared::Matcher> {
match self {
Matcher::Prefix => super::matcher::PrefixMatcher::new(),
Matcher::Fuse => super::matcher::FuseMatcher::new(),
Matcher::Flex => super::matcher::FlxMatcher::new(),
Matcher::Skim => super::matcher::SkimMatcher::new(),
}
}
}
#[derive(Debug, Deserialize)]
pub enum Source {
Apps,
Shell,
Windows,
Test,
}
impl Source {
pub fn init(&self) -> Box<dyn super::shared::Source> {
match self {
Source::Apps => super::sources::Apps::new(),
Source::Shell => super::sources::ShellHost::new(),
Source::Windows => super::sources::Window::new(),
Source::Test => super::sources::TestSource::new("ts1"),
}
}
}
#[derive(Debug, Deserialize)]
pub struct SourceConfig<T> {
matcher: Matcher,
source: T,
}
#[derive(Debug, Deserialize)]
pub struct Sources {
primary: SourceConfig<Source>,
additional: SourceConfig<Vec<Source>>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase", remote = "log::Level")]
enum LogLevelDef {
Error,
Warn,
Info,
Debug,
Trace,
}
#[derive(Debug, Deserialize)]
pub struct Settings {
#[serde(with = "LogLevelDef")]
log_level: log::Level,
completions: HashMap<String, String>,
sources: Sources,
theme: Theme,
}
impl Settings {
pub fn parse() -> Result<Self, ConfigError> {
let mut config: ConfigBuilder<DefaultState> = Config::builder();
let xdg_path_expanded = shellexpand::tilde("~/.config/roftl/config.toml");
let xdg_config_path = Path::new(xdg_path_expanded.as_ref());
let cwd_config_path = Path::new("default.toml");
if xdg_config_path.exists() {
config = config.add_source(config::File::from(xdg_config_path));
}
if cwd_config_path.exists() {
config = config.add_source(config::File::from(cwd_config_path));
}
config = config.add_source(
config::Environment::with_prefix("roftl")
.ignore_empty(true)
.separator("_"),
);
config.build()?.try_deserialize()
}
pub fn primary_matcher(&self) -> Box<dyn super::shared::Matcher> {
self.sources.primary.matcher.init()
}
pub fn primary_source(&self) -> Box<dyn super::shared::Source> {
self.sources.primary.source.init()
}
pub fn matcher(&self) -> Box<dyn super::shared::Matcher> {
self.sources.additional.matcher.init()
}
pub fn sources(&self) -> Vec<Box<dyn super::shared::Source>> {
self.sources
.additional
.source
.iter()
.map(|s| s.init())
.collect()
}
pub fn completions(&self) -> HashMap<String, String> {
self.completions.clone()
}
}