use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub colors: ColorConfig,
pub display: DisplayConfig,
pub defaults: DefaultConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColorConfig {
#[serde(default = "default_header_color")]
pub header_color: String,
#[serde(default = "default_border_color")]
pub border_color: String,
#[serde(default = "default_fs_color")]
pub filesystem_color: String,
#[serde(default = "default_high_usage_color")]
pub high_usage_color: String,
#[serde(default = "default_warning_usage_color")]
pub warning_usage_color: String,
#[serde(default = "default_normal_usage_color")]
pub normal_usage_color: String,
#[serde(default = "default_avail_color")]
pub avail_color: String,
#[serde(default = "default_mount_color")]
pub mount_color: String,
#[serde(default = "default_timestamp_color")]
pub timestamp_color: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DisplayConfig {
#[serde(default = "default_true")]
pub show_type: bool,
#[serde(default = "default_false")]
pub show_inodes: bool,
#[serde(default = "default_block_size")]
pub default_block_size: u64,
#[serde(default = "default_table_style")]
pub table_style: String,
#[serde(default = "default_false")]
pub compact: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DefaultConfig {
#[serde(default = "default_true")]
pub human_readable: bool,
#[serde(default = "default_false")]
pub local_only: bool,
#[serde(default = "default_empty_vec")]
pub fs_types: Vec<String>,
#[serde(default = "default_exclude_types")]
pub exclude_types: Vec<String>,
}
fn default_header_color() -> String {
"#00FFFF".to_string()
}
fn default_border_color() -> String {
"#808080".to_string()
}
fn default_fs_color() -> String {
"#FFFFFF".to_string()
}
fn default_high_usage_color() -> String {
"#FF0000".to_string()
}
fn default_warning_usage_color() -> String {
"#FFFF00".to_string()
}
fn default_normal_usage_color() -> String {
"#00FF00".to_string()
}
fn default_avail_color() -> String {
"#00FF00".to_string()
}
fn default_mount_color() -> String {
"#00FFFF".to_string()
}
fn default_timestamp_color() -> String {
"#808080".to_string()
}
fn default_true() -> bool {
true
}
fn default_false() -> bool {
false
}
fn default_block_size() -> u64 {
1024
}
fn default_table_style() -> String {
"modern".to_string()
}
fn default_empty_vec() -> Vec<String> {
vec![]
}
fn default_exclude_types() -> Vec<String> {
vec![
"tmpfs".to_string(),
"devtmpfs".to_string(),
"squashfs".to_string(),
]
}
impl Default for Config {
fn default() -> Self {
Config {
colors: ColorConfig {
header_color: default_header_color(),
border_color: default_border_color(),
filesystem_color: default_fs_color(),
high_usage_color: default_high_usage_color(),
warning_usage_color: default_warning_usage_color(),
normal_usage_color: default_normal_usage_color(),
avail_color: default_avail_color(),
mount_color: default_mount_color(),
timestamp_color: default_timestamp_color(),
},
display: DisplayConfig {
show_type: true,
show_inodes: false,
default_block_size: 1024,
table_style: "modern".to_string(),
compact: false,
},
defaults: DefaultConfig {
human_readable: true,
local_only: false,
fs_types: vec![],
exclude_types: default_exclude_types(),
},
}
}
}
impl Config {
pub fn load(config_path: Option<&str>) -> Result<Config> {
if let Some(path) = config_path {
let content = std::fs::read_to_string(path)?;
return Ok(toml::from_str(&content)?);
}
if let Some(config_path) = get_default_config_path() {
if config_path.exists() {
let content = std::fs::read_to_string(&config_path)?;
return Ok(toml::from_str(&content)?);
}
}
Ok(Config::default())
}
pub fn generate_default_config() -> Result<()> {
if let Some(config_path) = get_default_config_path() {
if let Some(parent) = config_path.parent() {
std::fs::create_dir_all(parent)?;
}
let config = Config::default();
let toml_string = toml::to_string_pretty(&config)?;
std::fs::write(&config_path, toml_string)?;
println!("Default config created at: {}", config_path.display());
}
Ok(())
}
}
fn get_default_config_path() -> Option<PathBuf> {
if cfg!(target_os = "windows") {
std::env::var("APPDATA")
.ok()
.map(|p| PathBuf::from(p).join("df3").join("config.toml"))
} else if cfg!(target_os = "macos") {
dirs::home_dir().map(|p| {
p.join("Library")
.join("Application Support")
.join("df3")
.join("config.toml")
})
} else {
dirs::home_dir().map(|p| p.join(".config").join("df3").join("config.toml"))
}
}