pub mod defaults;
pub mod settings;
use self::{
defaults::DEFAULT_CONFIG,
settings::{Config, Flags, LayoutItem},
};
use dirs::config_dir;
use json5;
use once_cell::sync::Lazy;
use std::io::Write;
use std::path::PathBuf;
use std::{
collections::HashMap,
fs::{self, File},
};
static DEFAULT_CONFIG_CACHE: Lazy<Config> = Lazy::new(|| {
json5::from_str(DEFAULT_CONFIG).unwrap_or_else(|e| panic!("Built-in default config is invalid JSON: {e}"))
});
fn load_config() -> Result<Config, String> {
let path = config_file("config.jsonc");
let data = fs::read_to_string(&path)
.map_err(|e| format!("Failed to read config.jsonc ({}): {}", path.display(), e))?;
load_config_from_str(&data)
}
fn load_config_from_str(data: &str) -> Result<Config, String> {
json5::from_str(data).map_err(|e| format!("Invalid JSONC in config.jsonc: {}", e))
}
pub fn load_config_at(path: Option<&str>) -> Result<Config, String> {
match path {
Some(custom_path) => {
let data = fs::read_to_string(custom_path)
.map_err(|err| format!("Failed to read config at {}: {}", custom_path, err))?;
load_config_from_str(&data)
}
None => load_config(),
}
}
pub fn default_config() -> Config {
DEFAULT_CONFIG_CACHE.clone()
}
pub fn default_layout() -> Vec<LayoutItem> {
default_config().layout
}
pub fn load_print_layout() -> Vec<LayoutItem> {
let layout = load_config().unwrap_or_else(|e| {
eprintln!("leenfetch: config error: {e}; using defaults");
default_config()
}).layout;
if layout.is_empty() {
default_layout()
} else {
layout
}
}
pub fn load_flags() -> Flags {
load_config().unwrap_or_else(|e| {
eprintln!("leenfetch: config error: {e}; using defaults");
default_config()
}).flags
}
pub fn generate_config_files() -> HashMap<String, bool> {
let mut results = HashMap::new();
let result = save_to_config_file("config.jsonc", DEFAULT_CONFIG).is_ok();
results.insert("config.jsonc".to_string(), result);
results
}
fn save_to_config_file(file_name: &str, content: &str) -> std::io::Result<()> {
let path = config_file(file_name);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
let mut file = File::create(&path)?;
file.write_all(content.as_bytes())?;
Ok(())
}
pub fn delete_config_files() -> HashMap<String, bool> {
let mut results = HashMap::new();
let file = "config.jsonc";
let result = delete_config_file(file).is_ok();
results.insert(file.to_string(), result);
results
}
fn delete_config_file(file_name: &str) -> std::io::Result<()> {
let path = config_file(file_name);
if path.exists() {
std::fs::remove_file(path)?;
}
Ok(())
}
fn config_file(name: &str) -> PathBuf {
config_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join("leenfetch")
.join(name)
}
pub fn ensure_config_files_exist() -> HashMap<String, bool> {
let mut results = HashMap::new();
let filename = "config.jsonc";
let created = ensure_config_file_exists(filename, DEFAULT_CONFIG).unwrap_or(false);
results.insert(filename.to_string(), created);
results
}
fn ensure_config_file_exists(file_name: &str, default_content: &str) -> std::io::Result<bool> {
let path = config_file(file_name);
if path.exists() {
return Ok(false); }
save_to_config_file(file_name, default_content)?;
Ok(true) }