use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct Config {
pub default_depth: u32,
pub default_method: u8,
pub case_insensitive: bool,
pub include_dirs: bool,
pub binary_check_bytes: usize,
pub max_line_length: usize,
pub threads: usize,
pub verbose: bool,
pub show_size: bool,
pub show_modified: bool,
pub max_results: usize,
pub color_index: String,
pub color_path: String,
pub color_line_num: String,
pub color_line_text: String,
pub color_header: String,
pub color_count: String,
pub color_error: String,
pub color_warn: String,
pub color_info: String,
pub color_pattern: String,
pub exclude_dirs: String,
pub default_include: String,
}
impl Default for Config {
fn default() -> Self {
Self {
default_depth: 1,
default_method: 1,
case_insensitive: true,
include_dirs: true,
binary_check_bytes: 1024,
max_line_length: 10_000,
threads: 0,
verbose: false,
show_size: false,
show_modified: false,
max_results: 0,
color_index: "#FF88FF".into(),
color_path: "#FFFF00".into(),
color_line_num: "#FF4444".into(),
color_line_text: "#00FFFF".into(),
color_header: "#FFFFFF".into(),
color_count: "#00FFFF".into(),
color_error: "#FF3333".into(),
color_warn: "#FFAA00".into(),
color_info: "#00FF88".into(),
color_pattern: "#FF00FF".into(),
exclude_dirs: ".git,node_modules,.svn,__pycache__,.hg,target,.cache".into(),
default_include: "".into(),
}
}
}
impl Config {
pub fn load() -> Self {
if let Ok(cfg) = Self::load_from_path(PathBuf::from("fsearch.toml")) {
return cfg;
}
if let Some(config_dir) = dirs::config_dir() {
let user_cfg = config_dir.join("fsearch").join("config.toml");
if let Ok(cfg) = Self::load_from_path(user_cfg) {
return cfg;
}
}
Self::default()
}
fn load_from_path(path: PathBuf) -> Result<Self> {
let text = std::fs::read_to_string(&path)
.with_context(|| format!("reading {}", path.display()))?;
let cfg: Self =
toml::from_str(&text).with_context(|| format!("parsing {}", path.display()))?;
Ok(cfg)
}
pub fn write_default() -> Result<PathBuf> {
let config_dir = dirs::config_dir()
.context("cannot determine user config directory")?
.join("fsearch");
std::fs::create_dir_all(&config_dir).context("creating config directory")?;
let path = config_dir.join("config.toml");
let text =
toml::to_string_pretty(&Self::default()).context("serialising default config")?;
let commented = format!(
"# fsearch configuration\n\
# Location: {}\n\
# All values are defaults. Remove the leading '#' to override.\n\n",
path.display()
) + &text
.lines()
.map(|l| {
if l.starts_with('[') || l.is_empty() {
l.to_string()
} else {
format!("# {}", l)
}
})
.collect::<Vec<_>>()
.join("\n");
std::fs::write(&path, commented).context("writing config file")?;
Ok(path)
}
pub fn excluded_dirs(&self) -> Vec<String> {
self.exclude_dirs
.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect()
}
}