use crate::consts::{
DEFAULT_IGNORE_PATTERNS, DEFAULT_THEME, MAX_DIR_DEPTH, MAX_OPEN_FILES, STDOUT_DEV,
TAIL_BYTES,
};
use crate::utils::write_append;
use std::{
env,
fs::read_to_string,
io::{Error, ErrorKind},
path::Path,
};
use colored::Colorize;
use log::LevelFilter;
use ron::ser::{PrettyConfig, to_string_pretty};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Config {
pub output: Option<String>,
pub log_level: Option<String>,
pub max_open_files: Option<usize>,
pub tail_bytes: Option<u64>,
pub follow_links: Option<bool>,
pub max_dir_depth: Option<usize>,
#[serde(default = "default_ignore_patterns")]
pub ignore_patterns: Option<Vec<String>>,
#[serde(default = "default_theme")]
pub theme: Option<String>,
}
fn default_ignore_patterns() -> Option<Vec<String>> {
Some(
DEFAULT_IGNORE_PATTERNS
.iter()
.map(|pattern| pattern.to_string())
.collect(),
)
}
fn default_theme() -> Option<String> {
Some(DEFAULT_THEME.to_string())
}
impl Default for Config {
fn default() -> Self {
Config {
output: Some(String::from(STDOUT_DEV)),
log_level: Some(String::from("INFO")),
max_open_files: Some(MAX_OPEN_FILES),
tail_bytes: Some(TAIL_BYTES),
max_dir_depth: Some(MAX_DIR_DEPTH),
follow_links: Some(true),
ignore_patterns: default_ignore_patterns(),
theme: default_theme(),
}
}
}
impl Config {
pub fn load() -> Config {
let config = Config::get_or_create();
read_to_string(&config)
.and_then(|file_contents| {
ron::from_str(&file_contents).map_err(|err| {
let config_error = Error::new(ErrorKind::InvalidInput, err.to_string());
error!(
"Configuration error: {} in file: {}",
err.to_string().red(),
config.cyan()
);
config_error
})
})
.unwrap_or_default()
}
fn config_paths() -> [String; 3] {
let home = env::var("HOME").unwrap_or_default();
[
format!("{home}/.lw.conf"),
format!("{home}/.config/lw.conf"),
String::from("lw.conf"),
]
}
pub fn existing_config_path() -> Option<String> {
Self::config_paths()
.into_iter()
.find(|path| Path::new(path).exists())
}
pub fn default_config_path() -> String {
let [first, ..] = Self::config_paths();
first
}
pub fn get_or_create() -> String {
Self::existing_config_path().unwrap_or_else(|| {
let new_config_path = Self::default_config_path();
write_append(
&new_config_path,
&to_string_pretty(
&Config::default(),
PrettyConfig::new().new_line("\n".to_string()),
)
.unwrap_or_default(),
);
new_config_path
})
}
pub fn get_log_level(&self) -> LevelFilter {
let level = self.log_level.clone().unwrap_or_default();
match &level[..] {
"OFF" => LevelFilter::Off,
"ERROR" => LevelFilter::Error,
"WARN" => LevelFilter::Warn,
"INFO" => LevelFilter::Info,
"DEBUG" => LevelFilter::Debug,
"TRACE" => LevelFilter::Trace,
_ => LevelFilter::Info,
}
}
}